diff --git a/BytecodeViewer 2.9.7.jar b/BytecodeViewer 2.9.7.jar
deleted file mode 100644
index fa82a758..00000000
Binary files a/BytecodeViewer 2.9.7.jar and /dev/null differ
diff --git a/BytecodeViewer 2.9.8-fatjar.jar b/BytecodeViewer 2.9.8-fatjar.jar
new file mode 100644
index 00000000..1613637d
Binary files /dev/null and b/BytecodeViewer 2.9.8-fatjar.jar differ
diff --git a/BytecodeViewer 2.9.8-preview-4.jar b/BytecodeViewer 2.9.8-preview-4.jar
deleted file mode 100644
index 844ae2da..00000000
Binary files a/BytecodeViewer 2.9.8-preview-4.jar and /dev/null differ
diff --git a/BytecodeViewer 2.9.8.jar b/BytecodeViewer 2.9.8.jar
new file mode 100644
index 00000000..56a56384
Binary files /dev/null and b/BytecodeViewer 2.9.8.jar differ
diff --git a/README.txt b/README.txt
index 89172507..ab894300 100644
--- a/README.txt
+++ b/README.txt
@@ -385,4 +385,33 @@ Changelog:
07/16/2015 - Removed the FileFilter classes.
07/16/2015 - Updated the decompiler class to make more sense.
07/16/2015 - Started working on BCV CLI.
-07/16/2015 - Finished BCV CLI.
\ No newline at end of file
+07/16/2015 - Finished BCV CLI.
+--- 2.9.8 ---:
+07/19/2015 - Fixed enjarify.
+07/20/2015 - Bibl sexified the boot loading time.
+07/20/2015 - Decode APK Resources is selected by default.
+07/20/2015 - Made the security manager slightly safer, it can still be targeted but not as obviously now.
+07/20/2015 - Added CLI to the boot page.
+07/21/2015 - Added support for offline mode in case you cannot connect to github for some reason. (kicks in after 7 seconds)
+07/21/2015 - Added fatjar option back, in case anyone wants a 100% portable version.
+07/21/2015 - Made it so it now shows the decompiler it's using - http://i.imgur.com/yMEzXwv.png.
+07/21/2015 - Rewrote the file system, it now shows the path of the jar it's got loaded.
+07/21/2015 - Now it shows if the decompiler is in editable mode or not.
+07/21/2015 - Fixed Enjarify bug from new security manager.
+07/22/2015 - Fixed a typo (Thanks affffsdsd)
+07/22/2015 - Finally added icons to the File Navigator, credits to http://famfamfam.com/lab/icons/silk/ for the icons.
+07/22/2015 - JD-GUI is now the default decompiler for GUI.
+07/22/2015 - Added Set Python 3.X to the UI.
+07/22/2015 - Fixed krakatau/export as jar bug introduced by file system update.
+07/22/2015 - Sped up krakatau decompiler/disassembler on big files.
+07/22/2015 - Made it so when you press enter on the file navigation pane it opens the class.
+07/22/2015 - The Quick file search now opens the files again.
+07/23/2015 - Fixed opening single files and file folders into BCV
+07/24/2015 - Added File>Reload Resources.
+07/26/2015 - Fixed the view pane refresh after toggling a viewer, it's now flawless.
+07/26/2015 - Fixed Krakatau Disassembler.
+07/26/2015 - Mibbzz is gay once again.
+07/30/2015 - Removed Janino Compiler & moved to Javac, it can now compile decompiled classes again.
+07/30/2015 - Affssdd fixed the File Navigator Pane's Quick Class Search.
+07/30/2015 - Fixed a process leak in KrakatauDisassembler.
+07/30/2015 - Started working on converting all the decompilers to launch in their own process in an effort to reduce BCV resources (only for non-fatjar version).
\ No newline at end of file
diff --git a/install/launch4j_config.xml b/install/launch4j_config.xml
index b7115b83..5bfb07cd 100644
--- a/install/launch4j_config.xml
+++ b/install/launch4j_config.xml
@@ -12,7 +12,7 @@
w32api/libuser32.a
w32api/libadvapi32.a
w32api/libshell32.a
- H:\Repo\BCV\bytecode-viewer\BytecodeViewer 2.9.7.jar
+ H:\Repo\BCV\bytecode-viewer\BytecodeViewer 2.9.8.jar
H:\Repo\BCV\bytecode-viewer\BytecodeViewer.exe
diff --git a/libs/commons-compiler-jdk.jar b/libs/commons-compiler-jdk.jar
deleted file mode 100644
index 08958698..00000000
Binary files a/libs/commons-compiler-jdk.jar and /dev/null differ
diff --git a/libs/janino.jar b/libs/janino.jar
new file mode 100644
index 00000000..79b946df
Binary files /dev/null and b/libs/janino.jar differ
diff --git a/src/org/codehaus/janino/Access.java b/src/org/codehaus/janino/Access.java
deleted file mode 100644
index ab6310b3..00000000
--- a/src/org/codehaus/janino/Access.java
+++ /dev/null
@@ -1,56 +0,0 @@
-
-/*
- * 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);
- }
-}
diff --git a/src/org/codehaus/janino/ByteArrayClassLoader.java b/src/org/codehaus/janino/ByteArrayClassLoader.java
deleted file mode 100644
index c6f3acd6..00000000
--- a/src/org/codehaus/janino/ByteArrayClassLoader.java
+++ /dev/null
@@ -1,74 +0,0 @@
-
-/*
- * 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 classes) { this.classes = classes; }
-
- /** @see #ByteArrayClassLoader(Map) */
- public
- ByteArrayClassLoader(Map classes, ClassLoader parent) {
- super(parent);
- this.classes = classes;
- }
-
- /**
- * Implements {@link ClassLoader#findClass(String)}.
- *
- * Notice that, although nowhere documented, no more than one thread at a time calls this
- * method, because {@link ClassLoader#loadClass(java.lang.String)} is
- * synchronized
.
- */
- @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 classes;
-}
diff --git a/src/org/codehaus/janino/CachingJavaSourceClassLoader.java b/src/org/codehaus/janino/CachingJavaSourceClassLoader.java
deleted file mode 100644
index 9e94e307..00000000
--- a/src/org/codehaus/janino/CachingJavaSourceClassLoader.java
+++ /dev/null
@@ -1,218 +0,0 @@
-
-/*
- * 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.
- *
- * 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)}.
- *
- * See {@link org.codehaus.janino.JavaSourceClassLoader#main(String[])} for an example how to use this class.
- *
- * Notice: 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 this 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.
- *
- * 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
- 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 m = new HashMap();
- m.put(className, bytecode);
- return m;
- }
- }
- }
-
- // Cache miss... generate the bytecode from source.
- Map bytecodes = super.generateBytecodes(className);
- if (bytecodes == null) return null;
-
- // Write the generated bytecodes to the class file cache.
- for (Map.Entry 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) {}
- }
- }
-}
diff --git a/src/org/codehaus/janino/ClassBodyEvaluator.java b/src/org/codehaus/janino/ClassBodyEvaluator.java
deleted file mode 100644
index 04efc2f2..00000000
--- a/src/org/codehaus/janino/ClassBodyEvaluator.java
+++ /dev/null
@@ -1,445 +0,0 @@
-
-/*
- * 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 optionalClassLoader
serves two purposes:
- *
- * It is used to look for classes referenced by the class body.
- * 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.
- *
- * 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
- * ClassBodyEvaluator cbe = new ClassBodyEvaluator();
- * cbe.cook(classBody);
- *
- * @see #ClassBodyEvaluator()
- * @see Cookable#cook(String)
- */
- public
- ClassBodyEvaluator(String classBody) throws CompileException { this.cook(classBody); }
-
- /**
- * Equivalent to
- * ClassBodyEvaluator cbe = new ClassBodyEvaluator();
- * cbe.cook(optionalFileName, is);
- *
- * @see #ClassBodyEvaluator()
- * @see Cookable#cook(String, InputStream)
- */
- public
- ClassBodyEvaluator(String optionalFileName, InputStream is) throws CompileException, IOException {
- this.cook(optionalFileName, is);
- }
-
- /**
- * Equivalent to
- * ClassBodyEvaluator cbe = new ClassBodyEvaluator();
- * cbe.cook(optionalFileName, reader);
- *
- * @see #ClassBodyEvaluator()
- * @see Cookable#cook(String, Reader)
- */
- public
- ClassBodyEvaluator(String optionalFileName, Reader reader) throws CompileException, IOException {
- this.cook(optionalFileName, reader);
- }
-
- /**
- * Equivalent to
- * ClassBodyEvaluator cbe = new ClassBodyEvaluator();
- * cbe.setParentClassLoader(optionalParentClassLoader);
- * cbe.cook(scanner);
- *
- * @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
- * ClassBodyEvaluator cbe = new ClassBodyEvaluator();
- * cbe.setExtendedType(optionalExtendedType);
- * cbe.setImplementedTypes(implementedTypes);
- * cbe.setParentClassLoader(optionalParentClassLoader);
- * cbe.cook(scanner);
- *
- * @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
- * ClassBodyEvaluator cbe = new ClassBodyEvaluator();
- * cbe.setClassName(className);
- * cbe.setExtendedType(optionalExtendedType);
- * cbe.setImplementedTypes(implementedTypes);
- * cbe.setParentClassLoader(optionalParentClassLoader);
- * cbe.cook(scanner);
- *
- * @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.
- *
- * If the optionalParser
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
- *
- * A class declaration with the configured name, superclass and interfaces
- * A method declaration with the given return type, name, parameter names and values and thrown exceptions
- *
- *
- * @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:
- *
- * 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);
- *
- *
- * @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:
- *
- * 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);
- *
- *
- * @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);
- }
- }
-}
diff --git a/src/org/codehaus/janino/ClassFileIClass.java b/src/org/codehaus/janino/ClassFileIClass.java
deleted file mode 100644
index c00abe37..00000000
--- a/src/org/codehaus/janino/ClassFileIClass.java
+++ /dev/null
@@ -1,438 +0,0 @@
-
-/*
- * 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 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 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 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 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 ("".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 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
- );
- }
-}
diff --git a/src/org/codehaus/janino/ClassLoaderIClassLoader.java b/src/org/codehaus/janino/ClassLoaderIClassLoader.java
deleted file mode 100644
index 225278c6..00000000
--- a/src/org/codehaus/janino/ClassLoaderIClassLoader.java
+++ /dev/null
@@ -1,95 +0,0 @@
-
-/*
- * 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
- *
- * ClassLoaderIClassLoader(Thread.currentThread().getContextClassLoader())
- *
- */
- 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;
-}
diff --git a/src/org/codehaus/janino/CodeContext.java b/src/org/codehaus/janino/CodeContext.java
deleted file mode 100644
index 0016b478..00000000
--- a/src/org/codehaus/janino/CodeContext.java
+++ /dev/null
@@ -1,1371 +0,0 @@
-
-/*
- * 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.DataOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.codehaus.janino.util.ClassFile;
-
-/**
- * The context of the compilation of a function (constructor or method). Manages generation of
- * byte code, the exception table, generation of line number tables, allocation of local variables,
- * determining of stack size and local variable table size and flow analysis.
- */
-@SuppressWarnings({ "rawtypes", "unchecked" }) public
-class CodeContext {
- private static final boolean DEBUG = false;
-
- private static final int INITIAL_SIZE = 128;
- private static final byte UNEXAMINED = -1;
- private static final byte INVALID_OFFSET = -2;
- private static final int MAX_STACK_SIZE = 254;
-
- private final ClassFile classFile;
- private final String functionName;
-
- private short maxStack;
- private short maxLocals;
- private byte[] code;
- private final Offset beginning;
- private final Inserter end;
- private Inserter currentInserter;
- private final List exceptionTableEntries;
-
- /** All the local variables that are allocated in any block in this {@link CodeContext}. */
- private final List allLocalVars = new ArrayList();
-
- /**
- * List of List of Java.LocalVariableSlot objects. Each List of Java.LocalVariableSlot is
- * the local variables allocated for a block. They are pushed and poped onto the list together
- * to make allocation of the next local variable slot easy.
- */
- private final List> scopedVars = new ArrayList();
-
- private short nextLocalVariableSlot;
- private final List relocatables = new ArrayList();
-
- /** Creates an empty "Code" attribute. */
- public
- CodeContext(ClassFile classFile, String functionName) {
- this.classFile = classFile;
- this.functionName = functionName;
-
- this.maxStack = 0;
- this.maxLocals = 0;
- this.code = new byte[CodeContext.INITIAL_SIZE];
- this.beginning = new Offset();
- this.end = new Inserter();
- this.currentInserter = this.end;
- this.exceptionTableEntries = new ArrayList();
-
- this.beginning.offset = 0;
- this.end.offset = 0;
- this.beginning.next = this.end;
- this.end.prev = this.beginning;
- }
-
- /** The {@link ClassFile} this context is related to. */
- public ClassFile
- getClassFile() { return this.classFile; }
-
-
- /**
- * Allocate space for a local variable of the given size (1 or 2)
- * on the local variable array.
- *
- * As a side effect, the "max_locals" field of the "Code" attribute
- * is updated.
- *
- * The only way to deallocate local variables is to
- * {@link #saveLocalVariables()} and later {@link
- * #restoreLocalVariables()}.
- *
- * @param size The number of slots to allocate (1 or 2)
- * @return The slot index of the allocated variable
- */
- public short
- allocateLocalVariable(short size) { return this.allocateLocalVariable(size, null, null).getSlotIndex(); }
-
- /**
- * Allocate space for a local variable of the given size (1 or 2)
- * on the local variable array.
- *
- * As a side effect, the "max_locals" field of the "Code" attribute
- * is updated.
- *
- * The only way to deallocate local variables is to
- * {@link #saveLocalVariables()} and later {@link
- * #restoreLocalVariables()}.
- * @param size Number of slots to use (1 or 2)
- * @param name The variable name, if it's null, the variable won't be written to the localvariabletable
- * @param type The variable type. if the name isn't null, the type is needed to write to the localvariabletable
- */
- public Java.LocalVariableSlot
- allocateLocalVariable(short size, String name, IClass type) {
- List currentVars = null;
-
- if (this.scopedVars.size() == 0) {
- throw new Error("saveLocalVariables must be called first");
- } else {
- currentVars = (List) this.scopedVars.get(this.scopedVars.size() - 1);
- }
-
- Java.LocalVariableSlot slot = new Java.LocalVariableSlot(name, this.nextLocalVariableSlot, type);
-
- if (slot.getName() != null) {
- slot.setStart(this.newOffset());
- }
-
- this.nextLocalVariableSlot += size;
- currentVars.add(slot);
- this.allLocalVars.add(slot);
-
- if (this.nextLocalVariableSlot > this.maxLocals) {
- this.maxLocals = this.nextLocalVariableSlot;
- }
-
- return slot;
- }
-
- /** Remembers the current size of the local variables array. */
- public List
- saveLocalVariables() {
-
- // Push empty list on the stack to hold a new block's local vars.
- List l = new ArrayList();
- this.scopedVars.add(l);
-
- return l;
- }
-
- /**
- * Restore the previous size of the local variables array. This MUST to be called for every call
- * to saveLocalVariables as it closes the variable extent for all the active local variables in
- * the current block.
- */
- public void
- restoreLocalVariables() {
-
- // Pop the list containing the current block's local vars.
- List slots = (
- (List) this.scopedVars.remove(this.scopedVars.size() - 1)
- );
- for (Java.LocalVariableSlot slot : slots) {
- if (slot.getName() != null) {
- slot.setEnd(this.newOffset());
- }
- }
- }
-
- /**
- *
- * @param dos
- * @param lineNumberTableAttributeNameIndex 0 == don't generate a "LineNumberTable" attribute
- * @throws IOException
- */
- protected void
- storeCodeAttributeBody(
- DataOutputStream dos,
- short lineNumberTableAttributeNameIndex,
- short localVariableTableAttributeNameIndex
- ) throws IOException {
- dos.writeShort(this.maxStack); // max_stack
- dos.writeShort(this.maxLocals); // max_locals
- dos.writeInt(this.end.offset); // code_length
- dos.write(this.code, 0, this.end.offset); // code
- dos.writeShort(this.exceptionTableEntries.size()); // exception_table_length
- for (ExceptionTableEntry exceptionTableEntry : this.exceptionTableEntries) { // exception_table
- dos.writeShort(exceptionTableEntry.startPC.offset);
- dos.writeShort(exceptionTableEntry.endPC.offset);
- dos.writeShort(exceptionTableEntry.handlerPC.offset);
- dos.writeShort(exceptionTableEntry.catchType);
- }
-
- List attributes = new ArrayList();
-
- // Add "LineNumberTable" attribute.
- if (lineNumberTableAttributeNameIndex != 0) {
- List lnt = new ArrayList();
- for (Offset o = this.beginning; o != null; o = o.next) {
- if (o instanceof LineNumberOffset) {
- lnt.add(new ClassFile.LineNumberTableAttribute.Entry(o.offset, ((LineNumberOffset) o).lineNumber));
- }
- }
- ClassFile.LineNumberTableAttribute.Entry[] lnte = (ClassFile.LineNumberTableAttribute.Entry[]) lnt.toArray(
- new ClassFile.LineNumberTableAttribute.Entry[lnt.size()]
- );
- attributes.add(new ClassFile.LineNumberTableAttribute(
- lineNumberTableAttributeNameIndex, // attributeNameIndex
- lnte // lineNumberTableEntries
- ));
- }
-
- // Add "LocalVariableTable" attribute.
- if (localVariableTableAttributeNameIndex != 0) {
- ClassFile.AttributeInfo ai = this.storeLocalVariableTable(dos, localVariableTableAttributeNameIndex);
-
- if (ai != null) attributes.add(ai);
- }
-
- dos.writeShort(attributes.size()); // attributes_count
- for (ClassFile.AttributeInfo attribute : attributes) { // attributes;
- attribute.store(dos);
- }
- }
-
- /**
- * @return A {@link org.codehaus.janino.util.ClassFile.LocalVariableTableAttribute} for this {@link CodeContext}
- */
- protected ClassFile.AttributeInfo
- storeLocalVariableTable(DataOutputStream dos, short localVariableTableAttributeNameIndex) {
- ClassFile cf = this.getClassFile();
- final List entryList = new ArrayList();
-
- for (Java.LocalVariableSlot slot : this.getAllLocalVars()) {
-
- if (slot.getName() != null) {
- String typeName = slot.getType().getDescriptor();
- short classSlot = cf.addConstantUtf8Info(typeName);
- short varNameSlot = cf.addConstantUtf8Info(slot.getName());
-
-// System.out.println("slot: " + slot + ", typeSlot: " + classSlot + ", varSlot: " + varNameSlot);
-
- ClassFile.LocalVariableTableAttribute.Entry entry = new ClassFile.LocalVariableTableAttribute.Entry(
- (short) slot.getStart().offset,
- (short) (slot.getEnd().offset - slot.getStart().offset),
- varNameSlot,
- classSlot,
- slot.getSlotIndex()
- );
- entryList.add(entry);
- }
- }
-
- if (entryList.size() > 0) {
- Object entries = entryList.toArray(new ClassFile.LocalVariableTableAttribute.Entry[entryList.size()]);
-
- return new ClassFile.LocalVariableTableAttribute(
- localVariableTableAttributeNameIndex,
- (ClassFile.LocalVariableTableAttribute.Entry[]) entries
- );
- } else {
- return null;
- }
- }
-
- /**
- * Checks the code for consistency; updates the "maxStack" member.
- *
- * Notice: On inconsistencies, a "RuntimeException" is thrown (KLUDGE).
- */
- public void
- flowAnalysis(String functionName) {
- if (CodeContext.DEBUG) {
- System.err.println("flowAnalysis(" + functionName + ")");
- }
-
- short[] stackSizes = new short[this.end.offset];
- Arrays.fill(stackSizes, CodeContext.UNEXAMINED);
-
- // Analyze flow from offset zero.
- this.flowAnalysis(
- functionName,
- this.code, // code
- this.end.offset, // codeSize
- 0, // offset
- (short) 0, // stackSize
- stackSizes // stackSizes
- );
-
- // Analyze flow from exception handler entry points.
- int analyzedExceptionHandlers = 0;
- while (analyzedExceptionHandlers != this.exceptionTableEntries.size()) {
- for (ExceptionTableEntry exceptionTableEntry : this.exceptionTableEntries) {
- if (stackSizes[exceptionTableEntry.startPC.offset] != CodeContext.UNEXAMINED) {
- this.flowAnalysis(
- functionName,
- this.code, // code
- this.end.offset, // codeSize
- exceptionTableEntry.handlerPC.offset, // offset
- (short) (stackSizes[exceptionTableEntry.startPC.offset] + 1), // stackSize
- stackSizes // stackSizes
- );
- ++analyzedExceptionHandlers;
- }
- }
- }
-
- // Check results and determine maximum stack size.
- this.maxStack = 0;
- for (int i = 0; i < stackSizes.length; ++i) {
- short ss = stackSizes[i];
- if (ss == CodeContext.UNEXAMINED) {
- if (CodeContext.DEBUG) {
- System.out.println(functionName + ": Unexamined code at offset " + i);
- return;
- } else {
- throw new JaninoRuntimeException(functionName + ": Unexamined code at offset " + i);
- }
- }
- if (ss > this.maxStack) this.maxStack = ss;
- }
- }
-
- private void
- flowAnalysis(
- String functionName,
- byte[] code, // Bytecode
- int codeSize, // Size
- int offset, // Current PC
- short stackSize, // Stack size on entry
- short[] stackSizes // Stack sizes in code
- ) {
- for (;;) {
- if (CodeContext.DEBUG) System.out.println("Offset = " + offset + ", stack size = " + stackSize);
-
- // Check current bytecode offset.
- if (offset < 0 || offset >= codeSize) {
- throw new JaninoRuntimeException(functionName + ": Offset out of range");
- }
-
- // Have we hit an area that has already been analyzed?
- int css = stackSizes[offset];
- if (css == stackSize) return; // OK.
- if (css == CodeContext.INVALID_OFFSET) throw new JaninoRuntimeException(functionName + ": Invalid offset");
- if (css != CodeContext.UNEXAMINED) {
- if (CodeContext.DEBUG) {
- System.err.println(
- functionName
- + ": Operand stack inconsistent at offset "
- + offset
- + ": Previous size "
- + css
- + ", now "
- + stackSize
- );
- return;
- } else {
- throw new JaninoRuntimeException(
- functionName
- + ": Operand stack inconsistent at offset "
- + offset
- + ": Previous size "
- + css
- + ", now "
- + stackSize
- );
- }
- }
- stackSizes[offset] = stackSize;
-
- // Analyze current opcode.
- byte opcode = code[offset];
- int operandOffset = offset + 1;
- short props;
- if (opcode == Opcode.WIDE) {
- opcode = code[operandOffset++];
- props = Opcode.WIDE_OPCODE_PROPERTIES[0xff & opcode];
- } else {
- props = Opcode.OPCODE_PROPERTIES[0xff & opcode];
- }
- if (props == Opcode.INVALID_OPCODE) {
- throw new JaninoRuntimeException(
- functionName
- + ": Invalid opcode "
- + (0xff & opcode)
- + " at offset "
- + offset
- );
- }
-
- switch (props & Opcode.SD_MASK) {
-
- case Opcode.SD_M4:
- case Opcode.SD_M3:
- case Opcode.SD_M2:
- case Opcode.SD_M1:
- case Opcode.SD_P0:
- case Opcode.SD_P1:
- case Opcode.SD_P2:
- stackSize += (props & Opcode.SD_MASK) - Opcode.SD_P0;
- break;
-
- case Opcode.SD_0:
- stackSize = 0;
- break;
-
- case Opcode.SD_GETFIELD:
- --stackSize;
- /* FALL THROUGH */
- case Opcode.SD_GETSTATIC:
- stackSize += this.determineFieldSize((short) (
- CodeContext.extract16BitValue(0, operandOffset, code)
- ));
- break;
-
- case Opcode.SD_PUTFIELD:
- --stackSize;
- /* FALL THROUGH */
- case Opcode.SD_PUTSTATIC:
- stackSize -= this.determineFieldSize((short) (
- CodeContext.extract16BitValue(0, operandOffset, code)
- ));
- break;
-
- case Opcode.SD_INVOKEVIRTUAL:
- case Opcode.SD_INVOKESPECIAL:
- case Opcode.SD_INVOKEINTERFACE:
- --stackSize;
- /* FALL THROUGH */
- case Opcode.SD_INVOKESTATIC:
- stackSize -= this.determineArgumentsSize((short) (
- CodeContext.extract16BitValue(0, operandOffset, code)
- ));
- break;
-
- case Opcode.SD_MULTIANEWARRAY:
- stackSize -= code[operandOffset + 2] - 1;
- break;
-
- default:
- throw new JaninoRuntimeException(functionName + ": Invalid stack delta");
- }
-
- if (stackSize < 0) {
- String msg = (
- this.classFile.getThisClassName()
- + '.'
- + functionName
- + ": Operand stack underrun at offset "
- + offset
- );
- if (CodeContext.DEBUG) {
- System.err.println(msg);
- return;
- } else {
- throw new JaninoRuntimeException(msg);
- }
- }
-
- if (stackSize > CodeContext.MAX_STACK_SIZE) {
- String msg = (
- this.classFile.getThisClassName()
- + '.'
- + functionName
- + ": Operand stack overflow at offset "
- + offset
- );
- if (CodeContext.DEBUG) {
- System.err.println(msg);
- return;
- } else {
- throw new JaninoRuntimeException(msg);
- }
- }
-
- switch (props & Opcode.OP1_MASK) {
-
- case 0:
- ;
- break;
-
- case Opcode.OP1_SB:
- case Opcode.OP1_UB:
- case Opcode.OP1_CP1:
- case Opcode.OP1_LV1:
- ++operandOffset;
- break;
-
- case Opcode.OP1_SS:
- case Opcode.OP1_CP2:
- case Opcode.OP1_LV2:
- operandOffset += 2;
- break;
-
- case Opcode.OP1_BO2:
- if (CodeContext.DEBUG) {
- System.out.println("Offset = " + offset);
- System.out.println("Operand offset = " + operandOffset);
- System.out.println(code[operandOffset]);
- System.out.println(code[operandOffset + 1]);
- }
- this.flowAnalysis(
- functionName,
- code, codeSize,
- CodeContext.extract16BitValue(offset, operandOffset, code),
- stackSize,
- stackSizes
- );
- operandOffset += 2;
- break;
-
- case Opcode.OP1_JSR:
- if (CodeContext.DEBUG) {
- System.out.println("Offset = " + offset);
- System.out.println("Operand offset = " + operandOffset);
- System.out.println(code[operandOffset]);
- System.out.println(code[operandOffset + 1]);
- }
- int targetOffset = CodeContext.extract16BitValue(offset, operandOffset, code);
- operandOffset += 2;
- if (stackSizes[targetOffset] == CodeContext.UNEXAMINED) {
- this.flowAnalysis(
- functionName,
- code, codeSize,
- targetOffset,
- (short) (stackSize + 1),
- stackSizes
- );
- }
- break;
-
- case Opcode.OP1_BO4:
- this.flowAnalysis(
- functionName,
- code, codeSize,
- CodeContext.extract32BitValue(offset, operandOffset, code),
- stackSize, stackSizes
- );
- operandOffset += 4;
- break;
-
- case Opcode.OP1_LOOKUPSWITCH:
- while ((operandOffset & 3) != 0) ++operandOffset;
- this.flowAnalysis(
- functionName,
- code, codeSize,
- CodeContext.extract32BitValue(offset, operandOffset, code),
- stackSize, stackSizes
- );
- operandOffset += 4;
-
- int npairs = CodeContext.extract32BitValue(0, operandOffset, code);
- operandOffset += 4;
-
- for (int i = 0; i < npairs; ++i) {
- operandOffset += 4; //skip match value
- this.flowAnalysis(
- functionName,
- code, codeSize,
- CodeContext.extract32BitValue(offset, operandOffset, code),
- stackSize, stackSizes
- );
- operandOffset += 4; //advance over offset
- }
- break;
-
- case Opcode.OP1_TABLESWITCH:
- while ((operandOffset & 3) != 0) ++operandOffset;
- this.flowAnalysis(
- functionName,
- code, codeSize,
- CodeContext.extract32BitValue(offset, operandOffset, code),
- stackSize, stackSizes
- );
- operandOffset += 4;
- int low = CodeContext.extract32BitValue(offset, operandOffset, code);
- operandOffset += 4;
- int hi = CodeContext.extract32BitValue(offset, operandOffset, code);
- operandOffset += 4;
- for (int i = low; i <= hi; ++i) {
- this.flowAnalysis(
- functionName,
- code, codeSize,
- CodeContext.extract32BitValue(offset, operandOffset, code),
- stackSize, stackSizes
- );
- operandOffset += 4;
- }
- break;
-
- default:
- throw new JaninoRuntimeException(functionName + ": Invalid OP1");
- }
-
- switch (props & Opcode.OP2_MASK) {
-
- case 0:
- ;
- break;
-
- case Opcode.OP2_SB:
- ++operandOffset;
- break;
-
- case Opcode.OP2_SS:
- operandOffset += 2;
- break;
-
- default:
- throw new JaninoRuntimeException(functionName + ": Invalid OP2");
- }
-
- switch (props & Opcode.OP3_MASK) {
-
- case 0:
- ;
- break;
-
- case Opcode.OP3_SB:
- ++operandOffset;
- break;
-
- default:
- throw new JaninoRuntimeException(functionName + ": Invalid OP3");
- }
-
- Arrays.fill(stackSizes, offset + 1, operandOffset, CodeContext.INVALID_OFFSET);
-
- if ((props & Opcode.NO_FALLTHROUGH) != 0) return;
- offset = operandOffset;
- }
- }
-
- /**
- * Extract a 16 bit value at offset in code and add bias to it
- *
- * @param bias An int to skew the final result by (useful for calculating relative offsets)
- * @param offset The position in the code array to extract the bytes from
- * @param code The array of bytes
- * @return An integer that treats the two bytes at position offset as an UNSIGNED SHORT
- */
- private static int
- extract16BitValue(int bias, int offset, byte[] code) {
- int res = bias + (
- ((code[offset]) << 8)
- + (code[offset + 1] & 0xff)
- );
- if (CodeContext.DEBUG) {
- System.out.println("extract16BitValue(bias, offset) = (" + bias + ", " + offset + ")");
- System.out.println("bytes = {" + code[offset] + ", " + code[offset + 1] + "}");
- System.out.println("result = " + res);
- }
- return res;
- }
-
- /**
- * Extract a 32 bit value at offset in code and add bias to it
- *
- * @param bias An int to skew the final result by (useful for calculating relative offsets)
- * @param offset The position in the code array to extract the bytes from
- * @param code The array of bytes
- * @return The 4 bytes at position offset + bias
- */
- private static int
- extract32BitValue(int bias, int offset, byte[] code) {
- int res = bias + (
- (code[offset] << 24)
- + ((0xff & code[offset + 1]) << 16)
- + ((0xff & code[offset + 2]) << 8)
- + (0xff & code[offset + 3])
- );
- if (CodeContext.DEBUG) {
- System.out.println("extract32BitValue(bias, offset) = (" + bias + ", " + offset + ")");
- System.out.println(
- ""
- + "bytes = {"
- + code[offset]
- + ", "
- + code[offset + 1]
- + ", "
- + code[offset + 2]
- + ", "
- + code[offset + 3]
- + "}"
- );
- System.out.println("result = " + res);
- }
- return res;
- }
-
- /** Fixes up all of the offsets and relocate() all relocatables. */
- public void
- fixUpAndRelocate() {
-
- // We do this in a loop to allow relocatables to adjust the size
- // of things in the byte stream. It is extremely unlikely, but possible
- // that a late relocatable will grow the size of the bytecode, and require
- // an earlier relocatable to switch from 32K mode to 64K mode branching
- do {
- this.fixUp();
- } while (!this.relocate());
- }
-
- /** Fixes up all offsets. */
- private void
- fixUp() {
- for (Offset o = this.beginning; o != this.end; o = o.next) {
- if (o instanceof FixUp) ((FixUp) o).fixUp();
- }
- }
-
- /**
- * Relocate all relocatables and aggregate their response into a single one
- * @return true if all of them relocated successfully
- * false if any of them needed to change size
- */
- private boolean
- relocate() {
- boolean finished = true;
- for (Relocatable relocatable : this.relocatables) {
-
- // Do not terminate earlier so that everything gets a chance to grow in the first pass changes the common
- // case for this to be O(n) instead of O(n**2).
- finished &= relocatable.relocate();
- }
- return finished;
- }
-
- /** Analyses the descriptor of the Fieldref and return its size. */
- private int
- determineFieldSize(short idx) {
- ClassFile.ConstantFieldrefInfo cfi = (
- (ClassFile.ConstantFieldrefInfo) this.classFile.getConstantPoolInfo(idx)
- );
- return Descriptor.size(cfi.getNameAndType(this.classFile).getDescriptor(this.classFile));
- }
-
- /**
- * Analyse the descriptor of the Methodref and return the sum of the
- * arguments' sizes minus the return value's size.
- */
- private int
- determineArgumentsSize(short idx) {
- ClassFile.ConstantPoolInfo cpi = this.classFile.getConstantPoolInfo(idx);
- ClassFile.ConstantNameAndTypeInfo nat = (
- cpi instanceof ClassFile.ConstantInterfaceMethodrefInfo
- ? ((ClassFile.ConstantInterfaceMethodrefInfo) cpi).getNameAndType(this.classFile)
- : ((ClassFile.ConstantMethodrefInfo) cpi).getNameAndType(this.classFile)
- );
- String desc = nat.getDescriptor(this.classFile);
-
- if (desc.charAt(0) != '(') throw new JaninoRuntimeException("Method descriptor does not start with \"(\"");
- int i = 1;
- int res = 0;
- for (;;) {
- switch (desc.charAt(i++)) {
- case ')':
- return res - Descriptor.size(desc.substring(i));
- case 'B': case 'C': case 'F': case 'I': case 'S': case 'Z':
- res += 1;
- break;
- case 'D': case 'J':
- res += 2;
- break;
- case '[':
- res += 1;
- while (desc.charAt(i) == '[') ++i;
- if ("BCFISZDJ".indexOf(desc.charAt(i)) != -1) { ++i; break; }
- if (desc.charAt(i) != 'L') throw new JaninoRuntimeException("Invalid char after \"[\"");
- ++i;
- while (desc.charAt(i++) != ';');
- break;
- case 'L':
- res += 1;
- while (desc.charAt(i++) != ';');
- break;
- default:
- throw new JaninoRuntimeException("Invalid method descriptor");
- }
- }
- }
-
- /**
- * Inserts a sequence of bytes at the current insertion position. Creates
- * {@link LineNumberOffset}s as necessary.
- *
- * @param lineNumber The line number that corresponds to the byte code, or -1
- * @param b
- */
- public void
- write(short lineNumber, byte[] b) {
- if (b.length == 0) return;
-
- int ico = this.currentInserter.offset;
- this.makeSpace(lineNumber, b.length);
- System.arraycopy(b, 0, this.code, ico, b.length);
- }
-
- /**
- * Inserts a byte at the current insertion position. Creates
- * {@link LineNumberOffset}s as necessary.
- *
- * This method is an optimization to avoid allocating small byte[] and ease
- * GC load.
- *
- * @param lineNumber The line number that corresponds to the byte code, or -1
- * @param b1
- */
- public void
- write(short lineNumber, byte b1) {
- int ico = this.currentInserter.offset;
- this.makeSpace(lineNumber, 1);
- this.code[ico] = b1;
- }
-
- /**
- * Inserts bytes at the current insertion position. Creates
- * {@link LineNumberOffset}s as necessary.
- *
- * This method is an optimization to avoid allocating small byte[] and ease
- * GC load.
- *
- * @param lineNumber The line number that corresponds to the byte code, or -1
- * @param b1
- * @param b2
- */
- public void
- write(short lineNumber, byte b1, byte b2) {
- int ico = this.currentInserter.offset;
- this.makeSpace(lineNumber, 2);
- this.code[ico++] = b1;
- this.code[ico] = b2;
- }
-
- /**
- * Inserts bytes at the current insertion position. Creates
- * {@link LineNumberOffset}s as necessary.
- *
- * This method is an optimization to avoid allocating small byte[] and ease
- * GC load.
- *
- * @param lineNumber The line number that corresponds to the byte code, or -1
- * @param b1
- * @param b2
- * @param b3
- */
- public void
- write(short lineNumber, byte b1, byte b2, byte b3) {
- int ico = this.currentInserter.offset;
- this.makeSpace(lineNumber, 3);
- this.code[ico++] = b1;
- this.code[ico++] = b2;
- this.code[ico] = b3;
- }
-
- /**
- * Inserts bytes at the current insertion position. Creates
- * {@link LineNumberOffset}s as necessary.
- *
- * This method is an optimization to avoid allocating small byte[] and ease
- * GC load.
- *
- * @param lineNumber The line number that corresponds to the byte code, or -1
- * @param b1
- * @param b2
- * @param b3
- * @param b4
- */
- public void
- write(short lineNumber, byte b1, byte b2, byte b3, byte b4) {
- int ico = this.currentInserter.offset;
- this.makeSpace(lineNumber, 4);
- this.code[ico++] = b1;
- this.code[ico++] = b2;
- this.code[ico++] = b3;
- this.code[ico] = b4;
- }
-
- /**
- * Add space for {@code size} bytes at current offset. Creates {@link LineNumberOffset}s as necessary.
- *
- * @param lineNumber The line number that corresponds to the byte code, or -1
- * @param size The size in bytes to inject
- */
- public void
- makeSpace(short lineNumber, int size) {
- if (size == 0) return;
-
- INSERT_LINE_NUMBER_OFFSET:
- if (lineNumber != -1) {
- Offset o;
- for (o = this.currentInserter.prev; o != this.beginning; o = o.prev) {
- if (o instanceof LineNumberOffset) {
- if (((LineNumberOffset) o).lineNumber == lineNumber) break INSERT_LINE_NUMBER_OFFSET;
- break;
- }
- }
- LineNumberOffset lno = new LineNumberOffset(this.currentInserter.offset, lineNumber);
- lno.prev = this.currentInserter.prev;
- lno.next = this.currentInserter;
-
- this.currentInserter.prev.next = lno;
- this.currentInserter.prev = lno;
- }
-
- int ico = this.currentInserter.offset;
- if (this.end.offset + size <= this.code.length) {
- // Optimization to avoid a trivial method call in the common case
- if (ico != this.end.offset) {
- System.arraycopy(this.code, ico, this.code, ico + size, this.end.offset - ico);
- }
- } else {
- byte[] oldCode = this.code;
- //double size to avoid horrible performance, but don't grow over our limit
- int newSize = Math.max(Math.min(oldCode.length * 2, 0xffff), oldCode.length + size);
- if (newSize > 0xffff) {
- throw new JaninoRuntimeException(
- "Code of method \""
- + this.functionName
- + "\" of class \""
- + this.classFile.getThisClassName()
- + "\" grows beyond 64 KB"
- );
- }
- this.code = new byte[newSize];
- System.arraycopy(oldCode, 0, this.code, 0, ico);
- System.arraycopy(oldCode, ico, this.code, ico + size, this.end.offset - ico);
- }
- Arrays.fill(this.code, ico, ico + size, (byte) 0);
- for (Offset o = this.currentInserter; o != null; o = o.next) o.offset += size;
- }
-
- /** @param lineNumber The line number that corresponds to the byte code, or -1 */
- public void
- writeShort(short lineNumber, int v) { this.write(lineNumber, (byte) (v >> 8), (byte) v); }
-
- /** @param lineNumber The line number that corresponds to the byte code, or -1 */
- public void
- writeBranch(short lineNumber, int opcode, final Offset dst) {
- this.relocatables.add(new Branch(opcode, dst));
- this.write(lineNumber, (byte) opcode, (byte) -1, (byte) -1);
- }
-
- private
- class Branch extends Relocatable {
-
- public
- Branch(int opcode, Offset destination) {
- this.opcode = opcode;
- this.source = CodeContext.this.newInserter();
- this.destination = destination;
- if (opcode == Opcode.JSR_W || opcode == Opcode.GOTO_W) {
- //no need to expand wide opcodes
- this.expanded = true;
- } else {
- this.expanded = false;
- }
- }
-
- @Override public boolean
- relocate() {
- if (this.destination.offset == Offset.UNSET) {
- throw new JaninoRuntimeException("Cannot relocate branch to unset destination offset");
- }
- int offset = this.destination.offset - this.source.offset;
-
- if (!this.expanded && (offset > Short.MAX_VALUE || offset < Short.MIN_VALUE)) {
- //we want to insert the data without skewing our source position,
- //so we will cache it and then restore it later.
- final int pos = this.source.offset;
- CodeContext.this.pushInserter(this.source);
- {
- // promotion to a wide instruction only requires 2 extra bytes
- // everything else requires a new GOTO_W instruction after a negated if
- CodeContext.this.makeSpace(
- (short) -1,
- this.opcode == Opcode.GOTO ? 2 : this.opcode == Opcode.JSR ? 2 : 5
- );
- }
- CodeContext.this.popInserter();
- this.source.offset = pos;
- this.expanded = true;
- return false;
- }
-
- final byte[] ba;
- if (!this.expanded) {
- //we fit in a 16-bit jump
- ba = new byte[] { (byte) this.opcode, (byte) (offset >> 8), (byte) offset };
- } else {
- if (this.opcode == Opcode.GOTO || this.opcode == Opcode.JSR) {
- ba = new byte[] {
- (byte) (this.opcode + 33), // GOTO => GOTO_W; JSR => JSR_W
- (byte) (offset >> 24),
- (byte) (offset >> 16),
- (byte) (offset >> 8),
- (byte) offset
- };
- } else
- {
- //exclude the if-statement from jump target
- //if jumping backwards this will increase the jump to go over it
- //if jumping forwards this will decrease the jump by it
- offset -= 3;
-
- // [if cond offset]
- //expands to
- // [if !cond skip_goto]
- // [GOTO_W offset]
- ba = new byte[] {
- CodeContext.invertBranchOpcode((byte) this.opcode),
- 0,
- 8, // Jump from this instruction past the GOTO_W
- Opcode.GOTO_W,
- (byte) (offset >> 24),
- (byte) (offset >> 16),
- (byte) (offset >> 8),
- (byte) offset
- };
- }
- }
- System.arraycopy(ba, 0, CodeContext.this.code, this.source.offset, ba.length);
- return true;
- }
-
- private boolean expanded; //marks whether this has been expanded to account for a wide branch
- private final int opcode;
- private final Inserter source;
- private final Offset destination;
- }
-
- /** E.g. {@link Opcode#IFLT} ("less than") inverts to {@link Opcode#IFGE} ("greater than or equal to"). */
- private static byte
- invertBranchOpcode(byte branchOpcode) {
- return ((Byte) CodeContext.BRANCH_OPCODE_INVERSION.get(new Byte(branchOpcode))).byteValue();
- }
-
- private static final Map
- BRANCH_OPCODE_INVERSION = CodeContext.createBranchOpcodeInversion();
- private static Map
- createBranchOpcodeInversion() {
- Map m = new HashMap();
- m.put(new Byte(Opcode.IF_ACMPEQ), new Byte(Opcode.IF_ACMPNE));
- m.put(new Byte(Opcode.IF_ACMPNE), new Byte(Opcode.IF_ACMPEQ));
- m.put(new Byte(Opcode.IF_ICMPEQ), new Byte(Opcode.IF_ICMPNE));
- m.put(new Byte(Opcode.IF_ICMPNE), new Byte(Opcode.IF_ICMPEQ));
- m.put(new Byte(Opcode.IF_ICMPGE), new Byte(Opcode.IF_ICMPLT));
- m.put(new Byte(Opcode.IF_ICMPLT), new Byte(Opcode.IF_ICMPGE));
- m.put(new Byte(Opcode.IF_ICMPGT), new Byte(Opcode.IF_ICMPLE));
- m.put(new Byte(Opcode.IF_ICMPLE), new Byte(Opcode.IF_ICMPGT));
- m.put(new Byte(Opcode.IFEQ), new Byte(Opcode.IFNE));
- m.put(new Byte(Opcode.IFNE), new Byte(Opcode.IFEQ));
- m.put(new Byte(Opcode.IFGE), new Byte(Opcode.IFLT));
- m.put(new Byte(Opcode.IFLT), new Byte(Opcode.IFGE));
- m.put(new Byte(Opcode.IFGT), new Byte(Opcode.IFLE));
- m.put(new Byte(Opcode.IFLE), new Byte(Opcode.IFGT));
- m.put(new Byte(Opcode.IFNULL), new Byte(Opcode.IFNONNULL));
- m.put(new Byte(Opcode.IFNONNULL), new Byte(Opcode.IFNULL));
- return Collections.unmodifiableMap(m);
- }
-
- /** Writes a four-byte offset (as it is used in TABLESWITCH and LOOKUPSWITCH) into this code context. */
- public void
- writeOffset(short lineNumber, Offset src, final Offset dst) {
- this.relocatables.add(new OffsetBranch(this.newOffset(), src, dst));
- this.write(lineNumber, (byte) -1, (byte) -1, (byte) -1, (byte) -1);
- }
-
- private
- class OffsetBranch extends Relocatable {
-
- public
- OffsetBranch(Offset where, Offset source, Offset destination) {
- this.where = where;
- this.source = source;
- this.destination = destination;
- }
-
- @Override public boolean
- relocate() {
- if (this.source.offset == Offset.UNSET || this.destination.offset == Offset.UNSET) {
- throw new JaninoRuntimeException("Cannot relocate offset branch to unset destination offset");
- }
- int offset = this.destination.offset - this.source.offset;
- byte[] ba = new byte[] {
- (byte) (offset >> 24),
- (byte) (offset >> 16),
- (byte) (offset >> 8),
- (byte) offset
- };
- System.arraycopy(ba, 0, CodeContext.this.code, this.where.offset, 4);
- return true;
- }
- private final Offset where, source, destination;
- }
-
- /** Creates and inserts an {@link CodeContext.Offset} at the current inserter's current position. */
- public Offset
- newOffset() {
- Offset o = new Offset();
- o.set();
- return o;
- }
-
- /**
- * Allocate an {@link Inserter}, set it to the current offset, and
- * insert it before the current offset.
- *
- * In clear text, this means that you can continue writing to the
- * "Code" attribute, then {@link #pushInserter(CodeContext.Inserter)} the
- * {@link Inserter}, then write again (which inserts bytes into the
- * "Code" attribute at the previously remembered position), and then
- * {@link #popInserter()}.
- */
- public Inserter
- newInserter() { Inserter i = new Inserter(); i.set(); return i; }
-
- /** @return The current inserter */
- public Inserter
- currentInserter() { return this.currentInserter; }
-
- /** Remember the current {@link Inserter}, then replace it with the new one. */
- public void
- pushInserter(Inserter ins) {
- if (ins.nextInserter != null) throw new JaninoRuntimeException("An Inserter can only be pushed once at a time");
- ins.nextInserter = this.currentInserter;
- this.currentInserter = ins;
- }
-
- /**
- * Replace the current {@link Inserter} with the remembered one (see
- * {@link #pushInserter(CodeContext.Inserter)}).
- */
- public void
- popInserter() {
- Inserter ni = this.currentInserter.nextInserter;
- if (ni == null) throw new JaninoRuntimeException("Code inserter stack underflow");
- this.currentInserter.nextInserter = null; // Mark it as "unpushed".
- this.currentInserter = ni;
- }
-
- /**
- * A class that represents an offset within a "Code" attribute.
- *
- * The concept of an "offset" is that if one writes into the middle of
- * a "Code" attribute, all offsets behind the insertion point are
- * automatically shifted.
- */
- public
- class Offset {
-
- /** The offset in the code attribute that this object represents. */
- int offset = Offset.UNSET;
-
- /** Links to preceding and succeding offsets. */
- Offset prev, next;
-
- /**
- * Special value for {@link #offset} which indicates that this {@link Offset} has not yet been {@link #set()}
- */
- static final int UNSET = -1;
-
- /**
- * Sets this "Offset" to the offset of the current inserter; inserts this "Offset" before the current inserter.
- */
- public void
- set() {
- if (this.offset != Offset.UNSET) throw new JaninoRuntimeException("Cannot \"set()\" Offset more than once");
-
- this.offset = CodeContext.this.currentInserter.offset;
-
- this.prev = CodeContext.this.currentInserter.prev;
- this.next = CodeContext.this.currentInserter;
- this.prev.next = this;
- this.next.prev = this;
- }
-
- /** @return The {@link CodeContext} that this {@link Offset} belongs to */
- public final CodeContext getCodeContext() { return CodeContext.this; }
-
- @Override public String
- toString() { return CodeContext.this.classFile.getThisClassName() + ": " + this.offset; }
- }
-
- /**
- * Add another entry to the "exception_table" of this code attribute (see JVMS 4.7.3).
- *
- * @param catchTypeFd null == "finally" clause
- */
- public void
- addExceptionTableEntry(Offset startPc, Offset endPc, Offset handlerPc, String catchTypeFd) {
- this.exceptionTableEntries.add(new ExceptionTableEntry(
- startPc,
- endPc,
- handlerPc,
- catchTypeFd == null ? (short) 0 : this.classFile.addConstantClassInfo(catchTypeFd)
- ));
- }
-
- /** Representation of an entry in the "exception_table" of a "Code" attribute (see JVMS 4.7.3). */
- private static
- class ExceptionTableEntry {
- ExceptionTableEntry(Offset startPc, Offset endPc, Offset handlerPc, short catchType) {
- this.startPC = startPc;
- this.endPC = endPc;
- this.handlerPC = handlerPc;
- this.catchType = catchType;
- }
- final Offset startPC, endPC, handlerPC;
- final short catchType; // 0 == "finally" clause
- }
-
- /** A class that implements an insertion point into a "Code" attribute. */
- public
- class Inserter extends Offset {
- private Inserter nextInserter; // null == not in "currentInserter" stack
- }
-
- /** An {@link Offset} who#s sole purpose is to later create a 'LneNumberTable' attribute. */
- public
- class LineNumberOffset extends Offset {
- private final int lineNumber;
-
- public
- LineNumberOffset(int offset, int lineNumber) {
- this.lineNumber = lineNumber;
- this.offset = offset;
- }
- }
-
- private abstract
- class Relocatable {
-
- /**
- * Relocate this object.
- * @return true if the relocation succeeded in place
- * false if the relocation grew the number of bytes required
- */
- public abstract boolean relocate();
- }
-
- /**
- * A throw-in interface that marks {@link CodeContext.Offset}s
- * as "fix-ups": During the execution of
- * {@link CodeContext#fixUp}, all "fix-ups" are invoked and
- * can do last touches to the code attribute.
- *
- * This is currently used for inserting the "padding bytes" into the
- * TABLESWITCH and LOOKUPSWITCH instructions.
- */
- public
- interface FixUp {
-
- /** @see FixUp */
- void fixUp();
- }
-
- /** @return All the local variables that are allocated in any block in this {@link CodeContext} */
- public List
- getAllLocalVars() { return this.allLocalVars; }
-
- /**
- * Removes all code between {@code from} and {@code to}. Also removes any {@link CodeContext.Relocatable}s existing
- * in that range.
- */
- public void
- removeCode(Offset from, Offset to) {
-
- if (from == to) return;
-
- int size = to.offset - from.offset;
- assert size >= 0;
-
- if (size == 0) return; // Short circuit.
-
- // Shift down the bytecode past 'to'.
- System.arraycopy(this.code, to.offset, this.code, from.offset, this.end.offset - to.offset);
-
- // Invalidate all offsets between 'from' and 'to'.
- // Remove all relocatables that originate between 'from' and 'to'.
- Set invalidOffsets = new HashSet();
- {
- Offset o = from.next;
-
- for (; o != to;) {
- if (o == null) {
- System.currentTimeMillis();
- }
- invalidOffsets.add(o);
-
- // Invalidate the offset for fast failure.
- o.offset = -77;
- o.prev = null;
- o = o.next;
- o.prev.next = null;
- }
-
- for (;; o = o.next) {
- o.offset -= size;
- if (o == this.end) break;
- }
- }
-
- // Invalidate all relocatables which originate or target a removed offset.
- for (Iterator it = this.relocatables.iterator(); it.hasNext();) {
- Relocatable r = (Relocatable) it.next();
-
- if (r instanceof Branch) {
- Branch b = (Branch) r;
-
- if (invalidOffsets.contains(b.source)) {
- it.remove();
- } else {
- assert !invalidOffsets.contains(b.destination);
- }
- }
-
- if (r instanceof OffsetBranch) {
- OffsetBranch ob = (OffsetBranch) r;
-
- if (invalidOffsets.contains(ob.source)) {
- it.remove();
- } else {
- assert !invalidOffsets.contains(ob.destination);
- }
- }
- }
-
- for (Iterator it = this.exceptionTableEntries.iterator(); it.hasNext();) {
- ExceptionTableEntry ete = (ExceptionTableEntry) it.next();
-
- // Start, end and handler must either ALL lie IN the range to remove or ALL lie outside.
-
- if (invalidOffsets.contains(ete.startPC)) {
- assert invalidOffsets.contains(ete.endPC);
- assert invalidOffsets.contains(ete.handlerPC);
- it.remove();
- } else {
- assert !invalidOffsets.contains(ete.endPC);
- assert !invalidOffsets.contains(ete.handlerPC);
- }
- }
-
- from.next = to;
- to.prev = from;
- }
-}
diff --git a/src/org/codehaus/janino/Compiler.java b/src/org/codehaus/janino/Compiler.java
deleted file mode 100644
index 8335608f..00000000
--- a/src/org/codehaus/janino/Compiler.java
+++ /dev/null
@@ -1,830 +0,0 @@
-
-/*
- * 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 javac tool.
- *
- * Usage:
- *
- * java org.codehaus.janino.Compiler \
- * [ -d destination-dir ] \
- * [ -sourcepath dirlist ] \
- * [ -classpath dirlist ] \
- * [ -extdirs dirlist ] \
- * [ -bootclasspath dirlist ] \
- * [ -encoding encoding ] \
- * [ -verbose ] \
- * [ -g:none ] \
- * [ -g:{source,lines,vars} ] \
- * [ -warn:pattern-list ] \
- * source-file ...
- * java org.codehaus.janino.Compiler -help
- *
- */
-@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() + " [ ] ... ...%n"
- + "%n"
- + "Supported s are:%n"
- + " -d Where to save class files%n"
- + " -sourcepath Where to look for other source files%n"
- + " -classpath Where to look for other class files%n"
- + " -extdirs Where to look for other class files%n"
- + " -bootclasspath Where to look for other class files%n"
- + " -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: 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 parsedCompilationUnits = new ArrayList();
-
- /**
- * Initialize a Java™ compiler with the given parameters.
- *
- * Classes are searched in the following order:
- *
- * If {@code optionalBootClassPath} is {@code null}:
- *
- * Through the system class loader of the JVM that runs JANINO
- *
- * If {@code optionalBootClassPath} is not {@code null}:
- *
- * Through the {@code optionalBootClassPath}
- *
- * If {@code optionalExtDirs} is not {@code null}:
- *
- * Through the {@code optionalExtDirs}
- *
- * Through the {@code classPath}
- * If {@code optionalSourcePath} is {@code null}:
- *
- * Through source files found on the {@code classPath}
- *
- * If {@code optionalSourcePath} is not {@code null}:
- *
- * Through source files found on the {@code sourcePath}
- *
- *
- *
- * The file name of a class file that represents class "pkg.Example"
- * is determined as follows:
- *
- *
- * If {@code optionalDestinationDirectory} is not {@link #NO_DESTINATION_DIRECTORY}:
- * {@code optionalDestinationDirectory /pkg/Example.class}
- *
- * 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}.)
- *
- *
- * @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}.
- *
- * 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. new
- * ClassLoaderIClassLoader(ClassLoader)
- * @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}.
- *
- * Passing {@code null} restores the default {@link ErrorHandler}.
- *
- * Notice that scan and parse errors are not 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.
- *
- * 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.
- *
- * 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
- *
- * A/B/com/acme/Main.java
- * ../C/com/acme/Main.java
- *
- * 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}.
- *
- * This method must be called exactly once after object construction.
- *
- * 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.
- *
- * 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.
- *
- * 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"
- *
- * 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:
- *
- * An already-parsed compilation unit
- * A class file in the output directory (if existant and younger than source file)
- * A source file in any of the source path directories
- * The parent class loader
- *
- * 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}.
- *
- * 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();
- }
- }
- }
-}
diff --git a/src/org/codehaus/janino/CompilerFactory.java b/src/org/codehaus/janino/CompilerFactory.java
deleted file mode 100644
index b105a8ff..00000000
--- a/src/org/codehaus/janino/CompilerFactory.java
+++ /dev/null
@@ -1,78 +0,0 @@
-
-/*
- * 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); }
- });
- }
-}
diff --git a/src/org/codehaus/janino/Descriptor.java b/src/org/codehaus/janino/Descriptor.java
deleted file mode 100644
index 0302cc35..00000000
--- a/src/org/codehaus/janino/Descriptor.java
+++ /dev/null
@@ -1,389 +0,0 @@
-
-/*
- * 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).
- * Typical descriptors are:
- *
- * I
Integer
- * [I
Array of integer
- * Lpkg1/pkg2/Cls;
Class
- * Lpkg1/pkg2/Outer$Inner;
Member class
- *
- */
-@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.
- *
- * 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 null
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 DESCRIPTOR_TO_CLASSNAME;
- static {
- Map 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 CLASS_NAME_TO_DESCRIPTOR;
-
- static {
- Map m = new HashMap();
- for (Map.Entry e : Descriptor.DESCRIPTOR_TO_CLASSNAME.entrySet()) {
- m.put(e.getValue(), e.getKey());
- }
- CLASS_NAME_TO_DESCRIPTOR = Collections.unmodifiableMap(m);
- }
-}
diff --git a/src/org/codehaus/janino/ExpressionEvaluator.java b/src/org/codehaus/janino/ExpressionEvaluator.java
deleted file mode 100644
index b6849cb9..00000000
--- a/src/org/codehaus/janino/ExpressionEvaluator.java
+++ /dev/null
@@ -1,445 +0,0 @@
-
-/*
- * 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.
- *
- * A number of "convenience constructors" exist that execute the set-up steps described for {@link
- * IExpressionEvaluator} instantly.
- *
- * 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.
- *
- * Example:
- *
- * 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
- *
- * Notice: The interfaceToImplement
must either be declared public
,
- * or with package scope in the root package (i.e. "no" package).
- *
- * On my system (Intel P4, 2 GHz, MS Windows XP, JDK 1.4.1), expression "x + 1"
- * evaluates as follows:
- *
- * Server JVM Client JVM
- * Normal EE 23.7 ns 64.0 ns
- * Fast EE 31.2 ns 42.2 ns
- *
- * (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
- * ExpressionEvaluator ee = new ExpressionEvaluator();
- * ee.setExpressionType(expressionType);
- * ee.setParameters(parameterNames, parameterTypes);
- * ee.cook(expression);
- *
- * @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
- * ExpressionEvaluator ee = new ExpressionEvaluator();
- * ee.setExpressionType(expressionType);
- * ee.setParameters(parameterNames, parameterTypes);
- * ee.setThrownExceptions(thrownExceptions);
- * ee.setParentClassLoader(optionalParentClassLoader);
- * ee.cook(expression);
- *
- * @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
- * 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);
- *
- * @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
- * 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
- makeStatements(int idx, Parser parser) throws CompileException, IOException {
- List 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;
- }
-
- /**
- *
- * {@link IExpressionEvaluator} ee = {@link CompilerFactoryFactory}.{@link
- * CompilerFactoryFactory#getDefaultCompilerFactory() getDefaultCompilerFactory}().{@link
- * ICompilerFactory#newExpressionEvaluator() newExpressionEvaluator}();
- * ee.setParentClassLoader(optionalParentClassLoader);
- * return ee.{@link #createFastEvaluator createFastEvaluator}(expression, interfaceToImplement, parameterNames);
- *
- *
- * @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 this
- * implementation of org.codehaus.commons.compiler
. 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 this
- * implementation of org.codehaus.commons.compiler
. 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.
- *
- * If any component starts with an upper-case letter, then ambiguous name is assumed to
- * be a type name.
- * Otherwise, it is assumed to be a parameter name.
- *
- *
- * @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 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()]);
- }
-}
diff --git a/src/org/codehaus/janino/FilterWarningHandler.java b/src/org/codehaus/janino/FilterWarningHandler.java
deleted file mode 100644
index 06252ab2..00000000
--- a/src/org/codehaus/janino/FilterWarningHandler.java
+++ /dev/null
@@ -1,56 +0,0 @@
-
-/*
- * 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 handlePatterns
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);
- }
- }
-}
diff --git a/src/org/codehaus/janino/IClass.java b/src/org/codehaus/janino/IClass.java
deleted file mode 100644
index 47fb4a73..00000000
--- a/src/org/codehaus/janino/IClass.java
+++ /dev/null
@@ -1,1146 +0,0 @@
-
-/*
- * 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.Arrays;
-import java.util.Collection;
-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.janino.Java.Annotation;
-
-/**
- * A simplified equivalent to "java.lang.reflect".
- *
- * 'JLS7' means a reference to the Java Language Specification, Java SE
- * 7 Edition
- */
-@SuppressWarnings({ "rawtypes", "unchecked" }) public abstract
-class IClass {
- private static final boolean DEBUG = false;
-
- /**
- * Special return value for {@link IField#getConstantValue()} indicating that the field does not have a
- * constant value.
- */
- public static final Object NOT_CONSTANT = new Object() {
- @Override public String toString() { return "NOT_CONSTANT"; }
- };
-
- /** The {@link IClass} object for the type VOID. */
- public static final IClass VOID = new PrimitiveIClass(Descriptor.VOID);
- /** The {@link IClass} object for the primitive type BYTE. */
- public static final IClass BYTE = new PrimitiveIClass(Descriptor.BYTE);
- /** The {@link IClass} object for the primitive type CHAR. */
- public static final IClass CHAR = new PrimitiveIClass(Descriptor.CHAR);
- /** The {@link IClass} object for the primitive type DOUBLE. */
- public static final IClass DOUBLE = new PrimitiveIClass(Descriptor.DOUBLE);
- /** The {@link IClass} object for the primitive type FLOAT. */
- public static final IClass FLOAT = new PrimitiveIClass(Descriptor.FLOAT);
- /** The {@link IClass} object for the primitive type INT. */
- public static final IClass INT = new PrimitiveIClass(Descriptor.INT);
- /** The {@link IClass} object for the primitive type LONG. */
- public static final IClass LONG = new PrimitiveIClass(Descriptor.LONG);
- /** The {@link IClass} object for the primitive type SHORT. */
- public static final IClass SHORT = new PrimitiveIClass(Descriptor.SHORT);
- /** The {@link IClass} object for the primitive type BOOLEAN. */
- public static final IClass BOOLEAN = new PrimitiveIClass(Descriptor.BOOLEAN);
-
- private static
- class PrimitiveIClass extends IClass {
- private final String fieldDescriptor;
-
- public
- PrimitiveIClass(String fieldDescriptor) { this.fieldDescriptor = fieldDescriptor; }
-
- @Override protected IClass getComponentType2() { return null; }
- @Override protected IClass[] getDeclaredIClasses2() { return new IClass[0]; }
- @Override protected IConstructor[] getDeclaredIConstructors2() { return new IConstructor[0]; }
- @Override protected IField[] getDeclaredIFields2() { return new IField[0]; }
- @Override protected IMethod[] getDeclaredIMethods2() { return new IMethod[0]; }
- @Override protected IClass getDeclaringIClass2() { return null; }
- @Override protected String getDescriptor2() { return this.fieldDescriptor; }
- @Override protected IClass[] getInterfaces2() { return new IClass[0]; }
- @Override protected IClass getOuterIClass2() { return null; }
- @Override protected IClass getSuperclass2() { return null; }
- @Override public boolean isAbstract() { return false; }
- @Override public boolean isArray() { return false; }
- @Override public boolean isFinal() { return true; }
- @Override public boolean isInterface() { return false; }
- @Override public boolean isPrimitive() { return true; }
- @Override public boolean isPrimitiveNumeric() { return Descriptor.isPrimitiveNumeric(this.fieldDescriptor); } // SUPPRESS CHECKSTYLE LineLength
- @Override public Access getAccess() { return Access.PUBLIC; }
- }
-
- /**
- * Returns all the constructors declared by the class represented by the
- * type. If the class has a default constructor, it is included.
- *
- * Returns an array with zero elements for an interface, array, primitive type or
- * "void".
- */
- public final IConstructor[]
- getDeclaredIConstructors() {
- if (this.declaredIConstructorsCache == null) {
- this.declaredIConstructorsCache = this.getDeclaredIConstructors2();
- }
- return this.declaredIConstructorsCache;
- }
- private IConstructor[] declaredIConstructorsCache;
-
- /** The uncached version of {@link #getDeclaredIConstructors()} which must be implemented by derived classes. */
- protected abstract IConstructor[] getDeclaredIConstructors2();
-
- /**
- * Returns the methods of the class or interface (but not inherited methods). For covariant methods, only the
- * method with the most derived return type is included.
- *
- * Returns an empty array for an array, primitive type or "void".
- */
- public final IMethod[]
- getDeclaredIMethods() {
- if (this.declaredIMethodsCache == null) {
- this.declaredIMethodsCache = this.getDeclaredIMethods2();
- }
- return this.declaredIMethodsCache;
- }
- private IMethod[] declaredIMethodsCache;
-
- /** The uncached version of {@link #getDeclaredIMethods()} which must be implemented by derived classes. */
- protected abstract IMethod[] getDeclaredIMethods2();
-
- /**
- * Returns all methods with the given name declared in the class or interface (but not inherited methods).
- *
- * Returns an empty array if no methods with that name are declared.
- *
- * @return an array of {@link IMethod}s that must not be modified
- */
- public final IMethod[]
- getDeclaredIMethods(String methodName) {
- if (this.declaredIMethodCache == null) {
- IMethod[] dims = this.getDeclaredIMethods();
-
- // Fill the map with "IMethod"s and "List"s.
- Map*/> m = new HashMap();
- for (IMethod dim : dims) {
- String mn = dim.getName();
- Object o = m.get(mn);
- if (o == null) {
- m.put(mn, dim);
- } else
- if (o instanceof IMethod) {
- List l = new ArrayList();
- l.add(o);
- l.add(dim);
- m.put(mn, l);
- } else {
- ((List) o).add(dim);
- }
- }
-
- // Convert "IMethod"s and "List"s to "IMethod[]"s.
- for (Map.Entry*/> me : m.entrySet()) {
- Object v = me.getValue();
- if (v instanceof IMethod) {
- me.setValue(new IMethod[] { (IMethod) v });
- } else {
- List l = (List) v;
- me.setValue(l.toArray(new IMethod[l.size()]));
- }
- }
- this.declaredIMethodCache = m;
- }
-
- IMethod[] methods = (IMethod[]) this.declaredIMethodCache.get(methodName);
- return methods == null ? IClass.NO_IMETHODS : methods;
- }
- private Map*/> declaredIMethodCache;
-
- /**
- * Returns all methods declared in the class or interface, its superclasses and its
- * superinterfaces.
- *
- * @return an array of {@link IMethod}s that must not be modified
- */
- public final IMethod[]
- getIMethods() throws CompileException {
- if (this.iMethodCache == null) {
- List iMethods = new ArrayList();
- this.getIMethods(iMethods);
- this.iMethodCache = (IMethod[]) iMethods.toArray(new IMethod[iMethods.size()]);
- }
- return this.iMethodCache;
- }
- private IMethod[] iMethodCache;
- private void
- getIMethods(List result) throws CompileException {
- IMethod[] ms = this.getDeclaredIMethods();
-
- SCAN_DECLARED_METHODS:
- for (IMethod candidate : ms) {
- String candidateDescriptor = candidate.getDescriptor();
- String candidateName = candidate.getName();
-
- // Check if a method with the same name and descriptor has been added before.
- for (IMethod oldMethod : result) {
- if (
- candidateName.equals(oldMethod.getName())
- && candidateDescriptor.equals(oldMethod.getDescriptor())
- ) continue SCAN_DECLARED_METHODS;
- }
- result.add(candidate);
- }
- IClass sc = this.getSuperclass();
- if (sc != null) sc.getIMethods(result);
-
- for (IClass ii : this.getInterfaces()) ii.getIMethods(result);
- }
-
- private static final IMethod[] NO_IMETHODS = new IMethod[0];
-
- /**
- * @return Whether this {@link IClass} (or its superclass or the interfaces it implements) has an {@link IMethod}
- * with the given name and parameter types
- */
- public final boolean
- hasIMethod(String methodName, IClass[] parameterTypes) throws CompileException {
- return this.findIMethod(methodName, parameterTypes) != null;
- }
-
- /**
- * @return The {@link IMethod} declared in this {@link IClass} (or its superclass or the interfaces it implements)
- * with the given name and parameter types, or {@code null} if an applicable method could not be found
- */
- public final IMethod
- findIMethod(String methodName, IClass[] parameterTypes) throws CompileException {
- {
- IMethod result = null;
- for (IMethod im : this.getDeclaredIMethods(methodName)) {
- if (
- Arrays.equals(im.getParameterTypes(), parameterTypes)
- && (result == null || result.getReturnType().isAssignableFrom(im.getReturnType()))
- ) result = im;
- }
- if (result != null) return result;
- }
-
- {
- IClass superclass = this.getSuperclass();
- if (superclass != null) {
- IMethod result = superclass.findIMethod(methodName, parameterTypes);
- if (result != null) return result;
- }
- }
-
- {
- IClass[] interfaces = this.getInterfaces();
- for (IClass interfacE : interfaces) {
- IMethod result = interfacE.findIMethod(methodName, parameterTypes);
- if (result != null) return result;
- }
- }
-
- return null;
- }
-
- /**
- * @return The {@link IConstructor} declared in this {@link IClass} with the given parameter types, or {@code null}
- * if an applicable constrcutor could not be found
- */
- public final IConstructor
- findIConstructor(IClass[] parameterTypes) throws CompileException {
- IConstructor[] ics = this.getDeclaredIConstructors();
- for (IConstructor ic : ics) {
- if (Arrays.equals(ic.getParameterTypes(), parameterTypes)) return ic;
- }
-
- return null;
- }
-
- /**
- * Returns the {@link IField}s declared in this {@link IClass} (but not inherited fields).
- *
- * @return An empty array for an array, primitive type or "void"
- */
- public final IField[]
- getDeclaredIFields() {
- Collection allFields = this.getDeclaredIFieldsCache().values();
- return (IField[]) allFields.toArray(new IField[allFields.size()]);
- }
-
- /** @return String fieldName => IField */
- private Map
- getDeclaredIFieldsCache() {
- if (this.declaredIFieldsCache == null) {
-
- IField[] fields = this.getDeclaredIFields2();
-
- Map m = new HashMap();
- for (IField f : fields) m.put(f.getName(), f);
- this.declaredIFieldsCache = m;
- }
- return this.declaredIFieldsCache;
- }
-
- /**
- * Returns the named {@link IField} declared in this {@link IClass} (does not work for inherited fields).
- *
- * @return null
iff this {@link IClass} does not declare an {@link IField} with that name
- */
- public final IField
- getDeclaredIField(String name) { return (IField) this.getDeclaredIFieldsCache().get(name); }
-
- /**
- * Clears the cache of declared fields which this class maintains in order to minimize the invocations of {@link
- * #getDeclaredIFields2()}.
- */
- protected void
- clearIFieldCaches() { this.declaredIFieldsCache = null; }
-
- private Map declaredIFieldsCache;
-
- /** Uncached version of {@link #getDeclaredIFields()}. */
- protected abstract IField[] getDeclaredIFields2();
-
- /**
- * Returns the synthetic fields of an anonymous or local class, in
- * the order in which they are passed to all constructors.
- */
- public IField[]
- getSyntheticIFields() { return new IField[0]; }
-
- /**
- * Returns the classes and interfaces declared as members of the class
- * (but not inherited classes and interfaces).
- * Returns an empty array for an array, primitive type or "void".
- */
- public final IClass[]
- getDeclaredIClasses() throws CompileException {
- if (this.declaredIClassesCache == null) {
- this.declaredIClassesCache = this.getDeclaredIClasses2();
- }
- return this.declaredIClassesCache;
- }
- private IClass[] declaredIClassesCache;
-
- /** @return The member types of this type */
- protected abstract IClass[] getDeclaredIClasses2() throws CompileException;
-
- /** @return If this class is a member class, the declaring class, otherwise {@code null} */
- public final IClass
- getDeclaringIClass() throws CompileException {
- if (!this.declaringIClassIsCached) {
- this.declaringIClassCache = this.getDeclaringIClass2();
- this.declaringIClassIsCached = true;
- }
- return this.declaringIClassCache;
- }
- private boolean declaringIClassIsCached;
- private IClass declaringIClassCache;
-
- /** @return If this class is a member class, the declaring class, otherwise {@code null} */
- protected abstract IClass getDeclaringIClass2() throws CompileException;
-
- /**
- * The following types have an "outer class":
- *
- * Anonymous classes declared in a non-static method of a class
- * Local classes declared in a non-static method of a class
- * Non-static member classes
- *
- *
- * @return The outer class of this type, or {@code null}
- */
- public final IClass
- getOuterIClass() throws CompileException {
- if (!this.outerIClassIsCached) {
- this.outerIClassCache = this.getOuterIClass2();
- this.outerIClassIsCached = true;
- }
- return this.outerIClassCache;
- }
- private boolean outerIClassIsCached;
- private IClass outerIClassCache;
-
- /** @see #getOuterIClass() */
- protected abstract IClass getOuterIClass2() throws CompileException;
-
- /**
- * Returns the superclass of the class.
- * Returns "null" for class "Object", interfaces, arrays, primitive types
- * and "void".
- */
- public final IClass
- getSuperclass() throws CompileException {
- if (!this.superclassIsCached) {
- this.superclassCache = this.getSuperclass2();
- this.superclassIsCached = true;
- if (this.superclassCache != null && this.superclassCache.isSubclassOf(this)) {
- throw new CompileException(
- "Class circularity detected for \"" + Descriptor.toClassName(this.getDescriptor()) + "\"",
- null
- );
- }
- }
- return this.superclassCache;
- }
- private boolean superclassIsCached;
- private IClass superclassCache;
-
- /** @see #getSuperclass() */
- protected abstract IClass getSuperclass2() throws CompileException;
-
- /** @return The accessibility of this type */
- public abstract Access getAccess();
-
- /**
- * Whether subclassing is allowed (JVMS 4.1 access_flags)
- * @return true
if subclassing is prohibited
- */
- public abstract boolean isFinal();
-
- /**
- * Returns the interfaces implemented by the class.
- * Returns the superinterfaces of the interface.
- * Returns "Cloneable" and "Serializable" for arrays.
- * Returns an empty array for primitive types and "void".
- */
- public final IClass[]
- getInterfaces() throws CompileException {
- if (this.interfacesCache == null) {
- this.interfacesCache = this.getInterfaces2();
- for (IClass ii : this.interfacesCache) {
- if (ii.implementsInterface(this)) {
- throw new CompileException(
- "Interface circularity detected for \"" + Descriptor.toClassName(this.getDescriptor()) + "\"",
- null
- );
- }
- }
- }
- return this.interfacesCache;
- }
- private IClass[] interfacesCache;
-
- /** @see #getInterfaces() */
- protected abstract IClass[] getInterfaces2() throws CompileException;
-
- /**
- * Whether the class may be instantiated (JVMS 4.1 access_flags)
- * @return true
if instantiation is prohibited
- */
- public abstract boolean isAbstract();
-
- /** Returns the field descriptor for the type as defined by JVMS 4.3.2. This method is fast. */
- public final String
- getDescriptor() {
- if (this.descriptorCache == null) {
- this.descriptorCache = this.getDescriptor2();
- }
- return this.descriptorCache;
- }
- private String descriptorCache;
-
- /** @return The field descriptor for the type as defined by JVMS 4.3.2. */
- protected abstract String getDescriptor2();
-
- /**
- * Convenience method that determines the field descriptors of an array of {@link IClass}es.
- * @see #getDescriptor()
- */
- public static String[]
- getDescriptors(IClass[] iClasses) {
- String[] descriptors = new String[iClasses.length];
- for (int i = 0; i < iClasses.length; ++i) descriptors[i] = iClasses[i].getDescriptor();
- return descriptors;
- }
-
- /**@return Whether this type represents an interface */
- public abstract boolean isInterface();
-
- /** @return Whether this type represents an array */
- public abstract boolean isArray();
-
- /** @return Whether this type represents a primitive type or "void" */
- public abstract boolean isPrimitive();
-
- /** @return Whether this type represents "byte", "short", "int", "long", "char", "float" or "double" */
- public abstract boolean isPrimitiveNumeric();
-
- /**
- * @return The component type of the array, or {@code null} for classes, interfaces, primitive types and {@code
- * void}
- */
- public final IClass
- getComponentType() {
- if (!this.componentTypeIsCached) {
- this.componentTypeCache = this.getComponentType2();
- this.componentTypeIsCached = true;
- }
- return this.componentTypeCache;
- }
- private boolean componentTypeIsCached;
- private IClass componentTypeCache;
-
- /** @see #getComponentType() */
- protected abstract IClass getComponentType2();
-
- @Override public String toString() { return Descriptor.toClassName(this.getDescriptor()); }
-
- /**
- * Determine if "this" is assignable from "that". This is true if "this" is identical with "that" (JLS7 5.1.1), or
- * if "that" is widening-primitive-convertible to "this" (JLS7 5.1.2), or if "that" is
- * widening-reference-convertible to "this" (JLS7 5.1.5).
- */
- public boolean
- isAssignableFrom(IClass that) throws CompileException {
-
- // Identity conversion, JLS7 5.1.1
- if (this == that) return true;
-
- // Widening primitive conversion, JLS7 5.1.2
- {
- String ds = that.getDescriptor() + this.getDescriptor();
- if (ds.length() == 2 && IClass.PRIMITIVE_WIDENING_CONVERSIONS.contains(ds)) return true;
- }
-
- // Widening reference conversion, JLS7 5.1.5
- {
-
- // JLS7 5.1.4.1: Target type is superclass of source class type.
- if (that.isSubclassOf(this)) return true;
-
- // JLS7 5.1.4.2: Source class type implements target interface type.
- // JLS7 5.1.4.4: Source interface type implements target interface type.
- if (that.implementsInterface(this)) return true;
-
- // JLS7 5.1.4.3 Convert "null" literal to any reference type.
- if (that == IClass.VOID && !this.isPrimitive()) return true;
-
- // JLS7 5.1.4.5: From any interface to type "Object".
- if (that.isInterface() && this.getDescriptor().equals(Descriptor.JAVA_LANG_OBJECT)) return true;
-
- if (that.isArray()) {
-
- // JLS7 5.1.4.6: From any array type to type "Object".
- if (this.getDescriptor().equals(Descriptor.JAVA_LANG_OBJECT)) return true;
-
- // JLS7 5.1.4.7: From any array type to type "Cloneable".
- if (this.getDescriptor().equals(Descriptor.JAVA_LANG_CLONEABLE)) return true;
-
- // JLS7 5.1.4.8: From any array type to type "java.io.Serializable".
- if (this.getDescriptor().equals(Descriptor.JAVA_IO_SERIALIZABLE)) return true;
-
- // JLS7 5.1.4.9: From SC[] to TC[] while SC if widening reference convertible to TC.
- if (this.isArray()) {
- IClass thisCt = this.getComponentType();
- IClass thatCt = that.getComponentType();
- if (!thisCt.isPrimitive() && thisCt.isAssignableFrom(thatCt)) return true;
- }
- }
- }
- return false;
- }
-
- private static final Set PRIMITIVE_WIDENING_CONVERSIONS = new HashSet();
- static {
- String[] pwcs = new String[] {
- Descriptor.BYTE + Descriptor.SHORT,
-
- Descriptor.BYTE + Descriptor.INT,
- Descriptor.SHORT + Descriptor.INT,
- Descriptor.CHAR + Descriptor.INT,
-
- Descriptor.BYTE + Descriptor.LONG,
- Descriptor.SHORT + Descriptor.LONG,
- Descriptor.CHAR + Descriptor.LONG,
- Descriptor.INT + Descriptor.LONG,
-
- Descriptor.BYTE + Descriptor.FLOAT,
- Descriptor.SHORT + Descriptor.FLOAT,
- Descriptor.CHAR + Descriptor.FLOAT,
- Descriptor.INT + Descriptor.FLOAT,
-
- Descriptor.LONG + Descriptor.FLOAT,
-
- Descriptor.BYTE + Descriptor.DOUBLE,
- Descriptor.SHORT + Descriptor.DOUBLE,
- Descriptor.CHAR + Descriptor.DOUBLE,
- Descriptor.INT + Descriptor.DOUBLE,
-
- Descriptor.LONG + Descriptor.DOUBLE,
-
- Descriptor.FLOAT + Descriptor.DOUBLE,
- };
- for (String pwc : pwcs) IClass.PRIMITIVE_WIDENING_CONVERSIONS.add(pwc);
- }
-
- /**
- * Returns true
if this class is an immediate or non-immediate
- * subclass of that
class.
- */
- public boolean
- isSubclassOf(IClass that) throws CompileException {
- for (IClass sc = this.getSuperclass(); sc != null; sc = sc.getSuperclass()) {
- if (sc == that) return true;
- }
- return false;
- }
-
- /**
- * If this
represents a class: Return true
if this class
- * directly or indirectly implements that
interface.
- *
- * If this
represents an interface: Return true
if this
- * interface directly or indirectly extends that
interface.
- */
- public boolean
- implementsInterface(IClass that) throws CompileException {
- for (IClass c = this; c != null; c = c.getSuperclass()) {
- IClass[] tis = c.getInterfaces();
- for (IClass ti : tis) {
- if (ti == that || ti.implementsInterface(that)) return true;
- }
- }
- return false;
- }
-
- /**
- * Get an {@link IClass} that represents an n-dimensional array of this type.
- *
- * @param n dimension count
- * @param objectType Required because the superclass of an array class is {@link Object} by definition
- */
- public IClass
- getArrayIClass(int n, IClass objectType) {
- IClass result = this;
- for (int i = 0; i < n; ++i) result = result.getArrayIClass(objectType);
- return result;
- }
-
- /**
- * Get an {@link IClass} that represents an array of this type.
- *
- * @param objectType Required because the superclass of an array class is {@link Object} by definition
- */
- public synchronized IClass
- getArrayIClass(IClass objectType) {
- if (this.arrayIClass == null) {
- this.arrayIClass = this.getArrayIClass2(objectType);
- }
- return this.arrayIClass;
- }
- private IClass arrayIClass;
-
- private IClass
- getArrayIClass2(final IClass objectType) {
- final IClass componentType = this;
- return new IClass() {
-
- @Override public IClass.IConstructor[] getDeclaredIConstructors2() { return new IClass.IConstructor[0]; }
-
- // Special trickery #17: Arrays override "Object.clone()", but without "throws
- // CloneNotSupportedException"!
- @Override public IClass.IMethod[]
- getDeclaredIMethods2() {
- return new IClass.IMethod[] {
- new IMethod() {
- @Override public String getName() { return "clone"; }
- @Override public IClass getReturnType() { return objectType; }
- @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 Annotation[] getAnnotations() { return new Annotation[0]; }
- }
- };
- }
-
- // CHECKSTYLE LineLength:OFF
- @Override public IClass.IField[] getDeclaredIFields2() { return new IClass.IField[0]; }
- @Override public IClass[] getDeclaredIClasses2() { return new IClass[0]; }
- @Override public IClass getDeclaringIClass2() { return null; }
- @Override public IClass getOuterIClass2() { return null; }
- @Override public IClass getSuperclass2() { return objectType; }
- @Override public IClass[] getInterfaces2() { return new IClass[0]; }
- @Override public String getDescriptor2() { return '[' + componentType.getDescriptor(); }
- @Override public Access getAccess() { return componentType.getAccess(); }
- @Override public boolean isFinal() { return true; }
- @Override public boolean isInterface() { return false; }
- @Override public boolean isAbstract() { return false; }
- @Override public boolean isArray() { return true; }
- @Override public boolean isPrimitive() { return false; }
- @Override public boolean isPrimitiveNumeric() { return false; }
- @Override public IClass getComponentType2() { return componentType; }
- // CHECKSTYLE LineLength:ON
-
- @Override public String toString() { return componentType.toString() + "[]"; }
- };
- }
-
- /**
- * If optionalName
is null
, find all {@link IClass}es visible in the
- * scope of the current class.
- *
- * If optionalName
is not null
, find the member {@link IClass}es
- * that has the given name. If the name is ambiguous (i.e. if more than one superclass,
- * interface of enclosing type declares a type with that name), then the size of the
- * returned array is greater than one.
- *
- * Examines superclasses, interfaces and enclosing type declarations.
- * @return an array of {@link IClass}es in unspecified order, possibly of length zero
- */
- IClass[]
- findMemberType(String optionalName) throws CompileException {
- IClass[] res = (IClass[]) this.memberTypeCache.get(optionalName);
- if (res == null) {
-
- // Notice: A type may be added multiply to the result set because we are in its scope
- // multiply. E.g. the type is a member of a superclass AND a member of an enclosing type.
- Set s = new HashSet();
- this.findMemberType(optionalName, s);
- res = s.isEmpty() ? IClass.ZERO_ICLASSES : (IClass[]) s.toArray(new IClass[s.size()]);
-
- this.memberTypeCache.put(optionalName, res);
- }
-
- return res;
- }
- private final Map memberTypeCache = new HashMap();
- private static final IClass[] ZERO_ICLASSES = new IClass[0];
- private void
- findMemberType(String optionalName, Collection result) throws CompileException {
-
- // Search for a type with the given name in the current class.
- IClass[] memberTypes = this.getDeclaredIClasses();
- if (optionalName == null) {
- result.addAll(Arrays.asList(memberTypes));
- } else {
- String memberDescriptor = Descriptor.fromClassName(
- Descriptor.toClassName(this.getDescriptor())
- + '$'
- + optionalName
- );
- for (final IClass mt : memberTypes) {
- if (mt.getDescriptor().equals(memberDescriptor)) {
- result.add(mt);
- return;
- }
- }
- }
-
- // Examine superclass.
- {
- IClass superclass = this.getSuperclass();
- if (superclass != null) superclass.findMemberType(optionalName, result);
- }
-
- // Examine interfaces.
- for (IClass i : this.getInterfaces()) i.findMemberType(optionalName, result);
-
- // Examine enclosing type declarations.
- {
- IClass declaringIClass = this.getDeclaringIClass();
- IClass outerIClass = this.getOuterIClass();
- if (declaringIClass != null) {
- declaringIClass.findMemberType(optionalName, result);
- }
- if (outerIClass != null && outerIClass != declaringIClass) {
- outerIClass.findMemberType(optionalName, result);
- }
- }
- }
-
- /**
- * Base for the members of an {@link IClass}. {@link IMember} are expected to be immutable, i.e. all getter methods
- * return constant values.
- */
- public
- interface IMember {
-
- /**
- * @return One of {@link Access#PRIVATE}, {@link Access#PROTECTED},
- * {@link Access#DEFAULT} and {@link Access#PUBLIC}.
- */
- Access getAccess();
-
- /** @return Modifiers and/or annotations of this member */
- Annotation[] getAnnotations();
-
- /** @return The {@link IClass} that declares this {@link IClass.IMember} */
- IClass getDeclaringIClass();
- }
-
- /** Base class for {@link IConstructor} and {@link IMethod}. */
- public abstract
- class IInvocable implements IMember {
-
- private boolean argsNeedAdjust;
-
- /** TODO */
- public void
- setArgsNeedAdjust(boolean newVal) { this.argsNeedAdjust = newVal; }
-
- /** TODO */
- public boolean
- argsNeedAdjust() { return this.argsNeedAdjust; }
-
- /**
- * @return Whether this invocable is 'variable arity', i.e. its last parameter has an ellipsis ('...') after
- * the type
- */
- public abstract boolean isVarargs();
-
- // Implement IMember.
-
- @Override public abstract Access getAccess();
- @Override public IClass getDeclaringIClass() { return IClass.this; }
-
- /** Returns the types of the parameters of this constructor or method. This method is fast. */
- public final IClass[]
- getParameterTypes() throws CompileException {
- if (this.parameterTypesCache == null) {
- this.parameterTypesCache = this.getParameterTypes2();
- }
- return this.parameterTypesCache;
- }
- private IClass[] parameterTypesCache;
-
- /** @return The types of the parameters of this constructor or method */
- public abstract IClass[]
- getParameterTypes2() throws CompileException;
-
- /** Returns the method descriptor of this constructor or method. This method is fast. */
- public final String
- getDescriptor() throws CompileException {
- if (this.descriptorCache == null) {
- this.descriptorCache = this.getDescriptor2();
- }
- return this.descriptorCache;
- }
- private String descriptorCache;
-
- /** Uncached implementation of {@link #getDescriptor()}. */
- public abstract String
- getDescriptor2() throws CompileException;
-
- /** Returns the types thrown by this constructor or method. This method is fast. */
- public final IClass[]
- getThrownExceptions() throws CompileException {
- if (this.thrownExceptionsCache == null) {
- this.thrownExceptionsCache = this.getThrownExceptions2();
- }
- return this.thrownExceptionsCache;
- }
- private IClass[] thrownExceptionsCache;
-
- /** @return The types thrown by this constructor or method */
- public abstract IClass[]
- getThrownExceptions2() throws CompileException;
-
- /**
- * @return Whether this {@link IInvocable} is more specific then {@code that} (in the sense of JLS7 15.12.2.5)
- */
- public boolean
- isMoreSpecificThan(IInvocable that) throws CompileException {
- if (IClass.DEBUG) System.out.print("\"" + this + "\".isMoreSpecificThan(\"" + that + "\") => ");
-
- // a variable-length argument is always less specific than a fixed arity.
- final boolean thatIsVararg;
-
- if ((thatIsVararg = that.isVarargs()) != this.isVarargs()) {
-
- // Only one of the two is varargs.
- return thatIsVararg;
- } else
- if (thatIsVararg) {
-
- // Both are varargs.
- final IClass[] thisParameterTypes = this.getParameterTypes();
- final IClass[] thatParameterTypes = that.getParameterTypes();
-
- IClass[] t, u;
- int n, k;
-
- if (thisParameterTypes.length >= thatParameterTypes.length) {
- t = thisParameterTypes;
- u = thatParameterTypes;
- n = t.length;
- k = u.length;
- IClass[] s = u;
- // this = T | T_n
- // that = U | U_k
- // n >= k
- // ignore generics, for now
-
- // T0, T1, ..., Tn-1, Tn[]
- // U0, U1, .., Uk[]
- final int kMinus1 = k - 1;
- for (int j = 0; j < kMinus1; ++j) {
- // expect T[j] <: S[j]
- if (!s[j].isAssignableFrom(t[j])) {
- return false;
- }
- }
-
- final IClass sk1 = s[kMinus1].getComponentType();
- final int nMinus1 = n - 1;
- for (int j = kMinus1; j < nMinus1; ++j) {
- // expect T[j] <: S[k -1]
- if (!sk1.isAssignableFrom(t[j])) {
- return false;
- }
- }
- if (!sk1.isAssignableFrom(t[nMinus1])) {
- return false;
- }
- } else {
- u = thisParameterTypes;
- t = thatParameterTypes;
- n = t.length;
- k = u.length;
- IClass[] s = t;
- // n >= k
- final int kMinus1 = k - 1;
- for (int j = 0; j < kMinus1; ++j) {
- // expect U[j] <: S[j]
- if (!s[j].isAssignableFrom(u[j])) {
- return false;
- }
- }
-
- final IClass uk1 = u[kMinus1].getComponentType();
- final int nMinus1 = n - 1;
- for (int j = kMinus1; j < nMinus1; ++j) {
- // expect U[k -1] <: S[j]
- if (!s[j].isAssignableFrom(uk1)) {
- return false;
- }
- }
- if (!s[nMinus1].getComponentType().isAssignableFrom(uk1)) {
- return false;
- }
- }
-
- return true;
- }
-
- // both are fixed arity
-
- // The following case is tricky: JLS7 says that the invocation is AMBIGUOUS, but only JAVAC 1.2 issues an
- // error; JAVAC 1.4.1, 1.5.0 and 1.6.0 obviously ignore the declaring type and invoke "A.meth(String)".
- // JLS7 is not clear about this. For compatibility with JAVA 1.4.1, 1.5.0 and 1.6.0, JANINO also ignores
- // the declaring type.
- //
- // See also JANINO-79 and JlsTests / 15.12.2.2
- // if (false) {
- // if (!that.getDeclaringIClass().isAssignableFrom(this.getDeclaringIClass())) {
- // if (IClass.DEBUG) System.out.println("falsE");
- // return false;
- // }
- // }
-
- IClass[] thisParameterTypes = this.getParameterTypes();
- IClass[] thatParameterTypes = that.getParameterTypes();
- for (int i = 0; i < thisParameterTypes.length; ++i) {
- if (!thatParameterTypes[i].isAssignableFrom(thisParameterTypes[i])) {
- if (IClass.DEBUG) System.out.println("false");
- return false;
- }
- }
- if (IClass.DEBUG) System.out.println("true");
- return !Arrays.equals(thisParameterTypes, thatParameterTypes);
- }
-
- /**
- * @return Whether this {@link IInvocable} is less specific then {@code that} (in the sense of JLS7 15.12.2.5)
- */
- public boolean
- isLessSpecificThan(IInvocable that) throws CompileException { return that.isMoreSpecificThan(this); }
-
- @Override public abstract String
- toString();
- }
-
- /** Representation of a constructor of an {@link IClass}. */
- public abstract
- class IConstructor extends IInvocable {
-
- /**
- * Opposed to {@link java.lang.reflect.Constructor#getParameterTypes()}, the
- * return value of this method does not include the optionally leading "synthetic
- * parameters".
- */
- @Override public abstract IClass[] getParameterTypes2() throws CompileException;
-
- /**
- * Opposed to {@link #getParameterTypes()}, the method descriptor returned by this method does include the
- * optionally leading synthetic parameters.
- */
- @Override public String
- getDescriptor2() throws CompileException {
- IClass[] parameterTypes = this.getParameterTypes();
-
- IClass outerIClass = IClass.this.getOuterIClass();
- if (outerIClass != null) {
- IClass[] tmp = new IClass[parameterTypes.length + 1];
- tmp[0] = outerIClass;
- System.arraycopy(parameterTypes, 0, tmp, 1, parameterTypes.length);
- parameterTypes = tmp;
- }
-
- return new MethodDescriptor(IClass.getDescriptors(parameterTypes), Descriptor.VOID).toString();
- }
-
- @Override public String
- toString() {
- StringBuilder sb = new StringBuilder(this.getDeclaringIClass().toString());
- sb.append('(');
- try {
- IClass[] parameterTypes = this.getParameterTypes();
- for (int i = 0; i < parameterTypes.length; ++i) {
- if (i > 0) sb.append(", ");
- sb.append(parameterTypes[i].toString());
- }
- } catch (CompileException ex) {
- sb.append("");
- }
- sb.append(')');
- return sb.toString();
- }
- }
-
- /** Representation of a method in an {@link IClass}. */
- public abstract
- class IMethod extends IInvocable {
-
- /** @return Whether this method is STATIC */
- public abstract boolean isStatic();
-
- /** @return Whether this method is ABSTRACT */
- public abstract boolean isAbstract();
-
- /** @return The return type of this method */
- public abstract IClass getReturnType() throws CompileException;
-
- /** @return The name of this method */
- public abstract String getName();
-
- @Override public String
- getDescriptor2() throws CompileException {
- return new MethodDescriptor(
- IClass.getDescriptors(this.getParameterTypes()),
- this.getReturnType().getDescriptor()
- ).toString();
- }
-
- @Override public String
- toString() {
- StringBuilder sb = new StringBuilder();
- sb.append(this.getAccess().toString()).append(' ');
- if (this.isStatic()) sb.append("static ");
- if (this.isAbstract()) sb.append("abstract ");
- try {
- sb.append(this.getReturnType().toString());
- } catch (CompileException ex) {
- sb.append("");
- }
- sb.append(' ');
- sb.append(this.getDeclaringIClass().toString());
- sb.append('.');
- sb.append(this.getName());
- sb.append('(');
- try {
- IClass[] parameterTypes = this.getParameterTypes();
- for (int i = 0; i < parameterTypes.length; ++i) {
- if (i > 0) sb.append(", ");
- sb.append(parameterTypes[i].toString());
- }
- } catch (CompileException ex) {
- sb.append("");
- }
- sb.append(')');
- try {
- IClass[] tes = this.getThrownExceptions();
- if (tes.length > 0) {
- sb.append(" throws ").append(tes[0]);
- for (int i = 1; i < tes.length; ++i) sb.append(", ").append(tes[i]);
- }
- } catch (CompileException ex) {
- sb.append("");
- }
- return sb.toString();
- }
- }
-
- /** Representation of a field of this {@link IClass}. */
- public abstract
- class IField implements IMember {
-
- // Implement IMember.
- @Override public abstract Access getAccess();
- @Override public IClass getDeclaringIClass() { return IClass.this; }
-
- /** @return Whether this field is STATIC */
- public abstract boolean isStatic();
-
- /** @return The type of this field */
- public abstract IClass getType() throws CompileException;
-
- /** @return The name this field */
- public abstract String getName();
-
- /** @return The descriptor of this field */
- public String getDescriptor() throws CompileException { return this.getType().getDescriptor(); }
-
- /**
- * Returns the value of the field if it is a compile-time constant value, i.e. the field is FINAL and its
- * initializer is a constant expression (JLS7 15.28, bullet 12).
- */
- public abstract Object getConstantValue() throws CompileException;
-
- @Override public String
- toString() { return this.getDeclaringIClass().toString() + "." + this.getName(); }
- }
-
- /**
- * This class caches the declared methods in order to minimize the invocations of {@link #getDeclaredIMethods2()}.
- */
- public void
- invalidateMethodCaches() {
- this.declaredIMethodsCache = null;
- this.declaredIMethodCache = null;
- }
-}
diff --git a/src/org/codehaus/janino/IClassLoader.java b/src/org/codehaus/janino/IClassLoader.java
deleted file mode 100644
index 04c7e31d..00000000
--- a/src/org/codehaus/janino/IClassLoader.java
+++ /dev/null
@@ -1,384 +0,0 @@
-
-/*
- * 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 null
if a class
- * for that descriptor
could not be found.
- *
- * Similar {@link java.lang.ClassLoader#findClass(java.lang.String)}, this method
- * must
- *
- * Get an {@link IClass} object from somewhere for the given type
- * Call {@link #defineIClass(IClass)} with that {@link IClass} object as
- * the argument
- * Return the {@link IClass} object
- *
- *
- * The format of a descriptor
is defined in JVMS 4.3.2. Typical
- * descriptors are:
- *
- * I
(Integer)
- * Lpkg1/pkg2/Cls;
(Class declared in package)
- * Lpkg1/pkg2/Outer$Inner;
Member class
- *
- * Notice that this method is never called for array types.
- *
- * 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 null
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.
- *
- * 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".
- *
- * The default for the optionalBootClassPath
is the path defined in
- * the system property "sun.boot.class.path", and the default for the
- * optionalExtensionDirs
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 loadedIClasses = new HashMap();
- private final Set unloadableIClasses = new HashSet();
-}
diff --git a/src/org/codehaus/janino/JaninoRuntimeException.java b/src/org/codehaus/janino/JaninoRuntimeException.java
deleted file mode 100644
index 3f928d92..00000000
--- a/src/org/codehaus/janino/JaninoRuntimeException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-
-/*
- * 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); }
-}
diff --git a/src/org/codehaus/janino/Java.java b/src/org/codehaus/janino/Java.java
deleted file mode 100644
index b90a3a06..00000000
--- a/src/org/codehaus/janino/Java.java
+++ /dev/null
@@ -1,4655 +0,0 @@
-
-/*
- * 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.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import org.codehaus.commons.compiler.CompileException;
-import org.codehaus.commons.compiler.Location;
-import org.codehaus.janino.CodeContext.Offset;
-import org.codehaus.janino.IClass.IMethod;
-import org.codehaus.janino.Java.FunctionDeclarator.FormalParameter;
-import org.codehaus.janino.Java.FunctionDeclarator.FormalParameters;
-import org.codehaus.janino.Visitor.BlockStatementVisitor;
-import org.codehaus.janino.Visitor.ElementValueVisitor;
-import org.codehaus.janino.Visitor.TypeArgumentVisitor;
-import org.codehaus.janino.util.Traverser;
-import org.codehaus.janino.util.iterator.ReverseListIterator;
-
-/**
- * This wrapper class defines classes that represent the elements of the
- * Java™ programming language.
- *
- * Notice:
- *
- * 'JLS7' refers to the Java Language Specification, Java SE 7
- * Edition .
- */
-@SuppressWarnings({ "rawtypes", "unchecked" }) public final
-class Java {
-
- private Java() {} // Don't instantiate me.
-
- /** Representation of a Java™ 'scope', e.g. a compilation unit, type, method or block. */
- public
- interface Scope {
-
- /** @return The scope that encloses this scope, or {@code null} */
- Scope getEnclosingScope();
- }
-
- /** This interface is implemented by objects which are associated with a location in the source code. */
- public
- interface Locatable {
-
- /** @return The location of this object */
- Location getLocation();
-
- /**
- * Throw a {@link CompileException} with the given message and this
- * object's location.
- *
- * @param message The message to report
- */
- void throwCompileException(String message) throws CompileException;
- }
-
- /** Abstract implementation of {@link Locatable}. */
- public abstract static
- class Located implements Locatable {
-
- /** Indication of 'no' or 'unknown' location. */
- public static final Located NOWHERE = new Located(Location.NOWHERE) {};
-
- private final Location location;
-
- protected
- Located(Location location) {
- //assert location != null;
- this.location = location;
- }
-
- // Implement "Locatable".
-
- @Override public Location
- getLocation() { return this.location; }
-
- @Override public void
- throwCompileException(String message) throws CompileException {
- throw new CompileException(message, this.location);
- }
- }
-
- /** Holds the result of {@link Parser#parseCompilationUnit}. */
- public static final
- class CompilationUnit implements Scope {
-
- /** A string that explains the 'file' (or similar resource) where this CU was loaded from. */
- public final String optionalFileName;
-
- /** The package declaration at the very top of this CU (if any). */
- public PackageDeclaration optionalPackageDeclaration;
-
- /** The IMPORT declarations in this CU. */
- public final List importDeclarations = new ArrayList();
-
- /** The top-level declarations in this CU. */
- public final List packageMemberTypeDeclarations = new ArrayList();
-
- public
- CompilationUnit(String optionalFileName) { this.optionalFileName = optionalFileName; }
-
- // Implement "Scope".
-
- @Override public Scope
- getEnclosingScope() { throw new JaninoRuntimeException("A compilation unit has no enclosing scope"); }
-
- /** Sets the package declaration of this CU. */
- public void
- setPackageDeclaration(PackageDeclaration packageDeclaration) {
- this.optionalPackageDeclaration = packageDeclaration;
- }
-
- /** Adds one IMPORT declaration to this CU. */
- public void
- addImportDeclaration(CompilationUnit.ImportDeclaration id) {
-
- // Conflicting imports are checked in UnitCompiler, not here.
- this.importDeclarations.add(id);
- }
-
- /** Adds one top-level type declaration to this CU. */
- public void
- addPackageMemberTypeDeclaration(PackageMemberTypeDeclaration pmtd) {
- this.packageMemberTypeDeclarations.add(pmtd);
- pmtd.setDeclaringCompilationUnit(this);
- }
-
- /** Gets all classes and interfaces declared in this compilation unit. */
- public PackageMemberTypeDeclaration[]
- getPackageMemberTypeDeclarations() {
- return (PackageMemberTypeDeclaration[]) this.packageMemberTypeDeclarations.toArray(
- new PackageMemberTypeDeclaration[this.packageMemberTypeDeclarations.size()]
- );
- }
-
- /**
- * Return the package member class or interface declared with the given name.
- * @param name Declared (i.e. not the fully qualified) name
- * @return null
if a package member type with that name is not declared in this compilation unit
- */
- public PackageMemberTypeDeclaration
- getPackageMemberTypeDeclaration(String name) {
- for (PackageMemberTypeDeclaration pmtd : this.packageMemberTypeDeclarations) {
- if (pmtd.getName().equals(name)) return pmtd;
- }
- return null;
- }
-
- /** Represents a 'single-type import declaration' like '{@code import java.util.Map;}'. */
- public static
- class SingleTypeImportDeclaration extends ImportDeclaration {
-
- /** The identifiers that constitute the type to be imported, e.g. 'java', 'util', 'Map'. */
- public final String[] identifiers;
-
- public
- SingleTypeImportDeclaration(Location location, String[] identifiers) {
- super(location);
- this.identifiers = identifiers;
- }
-
- @Override public final void
- accept(Visitor.ImportVisitor visitor) { visitor.visitSingleTypeImportDeclaration(this); }
-
- @Override public String
- toString() { return "import " + Java.join(this.identifiers, ".") + ';'; }
- }
-
- /** Represents a type-import-on-demand declaration like {@code import java.util.*;}. */
- public static
- class TypeImportOnDemandDeclaration extends ImportDeclaration {
-
- /** The identifiers that constitute the package or type to import from, e.g. 'java', 'util'. */
- public final String[] identifiers;
-
- public
- TypeImportOnDemandDeclaration(Location location, String[] identifiers) {
- super(location);
- this.identifiers = identifiers;
- }
-
- @Override public final void
- accept(Visitor.ImportVisitor visitor) {
- visitor.visitTypeImportOnDemandDeclaration(this);
- }
-
- @Override public String
- toString() { return "import " + Java.join(this.identifiers, ".") + ".*;"; }
- }
-
- /**
- * Represents a single static import declaration like
- * import java.util.Collections.EMPTY_MAP;
- */
- public static
- class SingleStaticImportDeclaration extends ImportDeclaration {
-
- /**
- * The identifiers that constitute the member to be imported, e.g. 'java', 'util', 'Collections',
- * 'EMPTY_MAP'.
- */
- public final String[] identifiers;
-
- public
- SingleStaticImportDeclaration(Location location, String[] identifiers) {
- super(location);
- this.identifiers = identifiers;
- }
-
- @Override public final void
- accept(Visitor.ImportVisitor visitor) {
- visitor.visitSingleStaticImportDeclaration(this);
- }
- }
-
- /**
- * Represents a static-import-on-demand declaration like
- * import java.util.Collections.*;
- */
- public static
- class StaticImportOnDemandDeclaration extends ImportDeclaration {
-
- /** The identifiers that constitute the type to import from, e.g. 'java', 'util', 'Collections'. */
- public final String[] identifiers;
-
- public
- StaticImportOnDemandDeclaration(Location location, String[] identifiers) {
- super(location);
- this.identifiers = identifiers;
- }
-
- @Override public final void
- accept(Visitor.ImportVisitor visitor) {
- visitor.visitStaticImportOnDemandDeclaration(this);
- }
- }
-
- /** Base class for the various IMPORT declarations. */
- public abstract static
- class ImportDeclaration extends Java.Located {
-
- public
- ImportDeclaration(Location location) { super(location); }
-
- /**
- * Invokes the '{@code visit...()}' method of {@link Visitor.ImportVisitor} for the concrete {@link
- * ImportDeclaration} type.
- */
- public abstract void accept(Visitor.ImportVisitor visitor);
- }
- }
-
- /** Representation of a Java ™ annotation. */
- public
- interface Annotation extends ElementValue {
-
- /**
- * Invokes the '{@code visit...()}' method of {@link Visitor.AnnotationVisitor} for the concrete {@link
- * Annotation} type.
- */
- void accept(Visitor.AnnotationVisitor visitor);
-
- /** Sets the enclosing scope for this annotation. */
- void setEnclosingScope(Scope enclosingScope);
-
- /** @return The type of this annotation */
- Type getType();
- }
-
- /** Repreentation of a 'marker annotation', i.e. an annotation without any elements in parentheses. */
- public static final
- class MarkerAnnotation implements Annotation {
-
- /** The type of this marker annotation. */
- public final Type type;
-
- public
- MarkerAnnotation(Type type) { this.type = type; }
-
- @Override public void
- setEnclosingScope(Scope enclosingScope) { this.type.setEnclosingScope(enclosingScope); }
-
- @Override public String toString() { return "@" + this.type; }
-
- @Override public Type
- getType() { return this.type; }
-
- @Override public void
- accept(Visitor.AnnotationVisitor visitor) { visitor.visitMarkerAnnotation(this); }
-
- @Override public void
- accept(Visitor.ElementValueVisitor visitor) { visitor.visitMarkerAnnotation(this); }
- }
-
- /**
- * Representation of a 'single-element annotation', i.e. an annotation followed by a single element in parentheses.
- */
- public static final
- class SingleElementAnnotation implements Annotation {
-
- /** The type of this single-element annotation. */
- public final Type type;
-
- /** The element value associated with this single-element annotation. */
- public final ElementValue elementValue;
-
- public
- SingleElementAnnotation(Type type, ElementValue elementValue) {
- this.type = type;
- this.elementValue = elementValue;
- }
-
- @Override public void
- setEnclosingScope(Scope enclosingScope) { this.type.setEnclosingScope(enclosingScope); }
-
- @Override public String toString() { return "@" + this.type + '(' + this.elementValue + ')'; }
-
- @Override public Type
- getType() { return this.type; }
-
- @Override public void
- accept(Visitor.AnnotationVisitor visitor) { visitor.visitSingleElementAnnotation(this); }
-
- @Override public void
- accept(Visitor.ElementValueVisitor visitor) { visitor.visitSingleElementAnnotation(this); }
- }
-
- /** A 'normal annotation', i.e. an annotation with multiple elements in parentheses and curly braces. */
- public static final
- class NormalAnnotation implements Annotation {
-
- /** The type of this normal annotation. */
- public final Type type;
-
- /** The element-value-pairs associated with this annotation. */
- public final ElementValuePair[] elementValuePairs;
-
- public
- NormalAnnotation(Type type, ElementValuePair[] elementValuePairs) {
- this.type = type;
- this.elementValuePairs = elementValuePairs;
- }
-
- @Override public Type
- getType() { return this.type; }
-
- @Override public String
- toString() {
- switch (this.elementValuePairs.length) {
- case 0: return "@" + this.type + "()";
- case 1: return "@" + this.type + "(" + this.elementValuePairs[0] + ")";
- default: return "@" + this.type + "(" + this.elementValuePairs[0] + ", ...)";
- }
- }
-
- @Override public void
- setEnclosingScope(Scope enclosingScope) { this.setEnclosingScope(enclosingScope); }
-
- @Override public void
- accept(Visitor.AnnotationVisitor visitor) { visitor.visitNormalAnnotation(this); }
-
- @Override public void
- accept(Visitor.ElementValueVisitor visitor) { visitor.visitNormalAnnotation(this); }
- }
-
- /** Representation of the modifier flags and annotations that are associated with a declaration. */
- public static
- class Modifiers {
-
- /** The or'ed constants declared in {@link Mod}. */
- public final short flags;
-
- /** The annotations. */
- public final Annotation[] annotations;
-
- /** A 'blank' {@link Modifiers} object: No flags, no annotations. */
- public
- Modifiers() {
- this.flags = Mod.NONE;
- this.annotations = new Annotation[0];
- }
-
- public
- Modifiers(short modifiers) {
- this.flags = modifiers;
- this.annotations = new Annotation[0];
- }
-
- public
- Modifiers(short modifiers, Annotation[] annotations) {
- this.flags = modifiers;
- this.annotations = annotations;
- }
-
- /** @return This object, with the given {@code modifiersToAdd} added. */
- public Modifiers
- add(int modifiersToAdd) {
- return new Modifiers((short) (this.flags | modifiersToAdd), this.annotations);
- }
-
- /** @return This object, with the given {@code modifiersToRemove} removed. */
- public Modifiers
- remove(int modifiersToRemove) {
- return new Modifiers((short) (this.flags & ~modifiersToRemove), this.annotations);
- }
-
- /**
- * @param newAccess One of {@link Mod#PUBLIC}, {@link Mod#PRIVATE}, {@link Mod#PROTECTED}, {@link Mod#PACKAGE}
- * @return This object, with the access changed to {@code newAccess}
- */
- public Modifiers
- changeAccess(int newAccess) {
- return new Modifiers((short) (this.flags & ~Mod.PPP | newAccess), this.annotations);
- }
- }
-
- /** Representation of a 'name = value' element in a {@link NormalAnnotation}. */
- public static
- class ElementValuePair {
-
- /** The element name. */
- public final String identifier;
-
- /** The element value. */
- public final ElementValue elementValue;
-
- public
- ElementValuePair(String identifier, ElementValue elementValue) {
- this.identifier = identifier;
- this.elementValue = elementValue;
- }
-
- @Override public String
- toString() { return this.identifier + " = " + this.elementValue; }
- }
-
- /** Base of the possible element values in a {@link NormalAnnotation}. */
- public
- interface ElementValue {
-
- /**
- * Invokes the '{@code visit...()}' method of {@link Visitor.ElementValueVisitor} for the concrete {@link
- * ElementValue} type.
- */
- void accept(Visitor.ElementValueVisitor visitor);
- }
-
- /**
- * An element value in the form of an array initializer, e.g. 'SuppressWarnings({ "null", "unchecked"
- * })
'.
- */
- public static
- class ElementValueArrayInitializer implements ElementValue {
-
- /** The element values in the body of the array initializer. */
- public final ElementValue[] elementValues;
-
- public
- ElementValueArrayInitializer(ElementValue[] elementValues) {
- this.elementValues = elementValues;
- }
-
- @Override public String
- toString() {
- switch (this.elementValues.length) {
- case 0: return "{}";
- case 1: return "{ " + this.elementValues[0] + " }";
- default: return "{ " + this.elementValues[0] + ", ... }";
- }
- }
-
- @Override public void
- accept(Visitor.ElementValueVisitor visitor) { visitor.visitElementValueArrayInitializer(this); }
- }
-
- /** Representation of a package declaration like {@code package com.acme.tools;}. */
- public static
- class PackageDeclaration extends Located {
-
- /** The package name, e.g. '{@code com.acme.tools}'. */
- public final String packageName;
-
- public
- PackageDeclaration(Location location, String packageName) {
- super(location);
- this.packageName = packageName;
- }
- }
-
- /** Base for the various kinds of type declarations, e.g. top-level class, member interface, local class. */
- public
- interface TypeDeclaration extends Locatable, Scope {
-
- /** @return The or'ed modifier flags of the type, as defined in {@link Mod} */
- short getModifierFlags();
-
- /** @return The annotations of this {@link TypeDeclaration} */
- Annotation[] getAnnotations();
-
- /**
- * Return the member type with the given name.
- * @return null
if a member type with that name is not declared
- */
- MemberTypeDeclaration getMemberTypeDeclaration(String name);
-
- /** @return The (possibly empty) set of member types declared inside this {@link TypeDeclaration} */
- Collection getMemberTypeDeclarations();
-
- /**
- * Return the first method declared with the given name. (Does not honor inherited methods.)
- *
- * @return null
if a method with this name is not declared
- */
- MethodDeclarator getMethodDeclaration(String name);
-
- /**
- * @return The list of methods declared in this {@link TypeDeclaration}, not including methods declared in
- * supertypes
- */
- List getMethodDeclarations();
-
- /** Determines the effective class name, e.g. "pkg.Outer$Inner". */
- String getClassName();
-
- /** Creates a unique name for a local class or interface. */
- String createLocalTypeName(String localTypeName);
-
- /** Creates a unique name for an anonymous class. */
- String createAnonymousClassName();
-
- /**
- * Invokes the '{@code visit...()}' method of {@link Visitor.TypeDeclarationVisitor} for the concrete {@link
- * TypeDeclaration} type.
- */
- void accept(Visitor.TypeDeclarationVisitor visitor);
- }
-
- /**
- * Representation of a Java™ element that can be annotated with a DOC comment ('/** ...
- * */
').
- */
- public
- interface DocCommentable {
-
- /** @return The doc comment of the object or {@code null} */
- String getDocComment();
-
- /**
- * Returns true
if the object has a doc comment and
- * the @deprecated
tag appears in the doc
- * comment.
- */
- boolean hasDeprecatedDocTag();
- }
-
- /**
- * Represents a class or interface declaration on compilation unit level. These are called "package member types"
- * because they are immediate members of a package.
- */
- public
- interface PackageMemberTypeDeclaration extends NamedTypeDeclaration {
-
- /** Sets the {@link CompilationUnit} in which this top-level type is declared. */
- void setDeclaringCompilationUnit(CompilationUnit declaringCompilationUnit);
-
- /** @return The {@link CompilationUnit} in which this top-level type is declared. */
- CompilationUnit getDeclaringCompilationUnit();
- }
-
- /**
- * Represents a class or interface declaration where the immediately enclosing scope is
- * another class or interface declaration.
- */
- public interface MemberTypeDeclaration extends NamedTypeDeclaration, TypeBodyDeclaration {}
-
- /**
- * Represents the declaration of a class or an interface that has a name. (All type
- * declarations are named, except for anonymous classes.)
- */
- public
- interface NamedTypeDeclaration extends TypeDeclaration {
-
- /** @return The declared (not the fully qualified) name of the class or interface */
- String getName();
-
- /** @return The declared type parameters */
- TypeParameter[] getOptionalTypeParameters();
- }
-
- /**
- * Represents the declaration of an inner class, i.e. a class that exists in the context of
- * zero or more "enclosing instances". These are anonymous classes, local classes and member
- * classes.
- */
- interface InnerClassDeclaration extends TypeDeclaration {
-
- /**
- * Inner classes have zero or more synthetic fields that hold references to their enclosing
- * context:
- *
- * this$n
- *
- * (Mandatory for non-private non-static member classes; optional for private non-static
- * member classes, local classes in non-static context, and anonymous classes in
- * non-static context; forbidden for static member classes, local classes in static
- * context, and anonymous classes in static context)
- * Holds a reference to the immediately enclosing instance. n
is
- * N-1 for the Nth nesting level; e.g. the public non-static member class of a
- * package member class has a synthetic field this$0
.
- *
- * val$local-variable-name
- *
- * (Allowed for local classes and anonymous classes; forbidden for member classes)
- * Hold copies of final
local variables of the defining context.
- *
- *
- * Notice that these fields are not included in the {@link IClass.IField} array returned
- * by {@link IClass#getDeclaredIFields2()}.
- *
- * If a synthetic field with the same name exists already, then it must have the same
- * type and the redefinition is ignored.
- * @param iField
- */
- void defineSyntheticField(IClass.IField iField) throws CompileException;
- }
-
- /** Abstract implementation of {@link TypeDeclaration}. */
- public abstract static
- class AbstractTypeDeclaration implements TypeDeclaration {
- private final Location location;
- private final Modifiers modifiers;
- private final List declaredMethods = new ArrayList();
- private final List declaredClassesAndInterfaces = new ArrayList();
- private Scope enclosingScope;
-
- /** Holds the resolved type during compilation. */
- IClass resolvedType;
-
- public
- AbstractTypeDeclaration(Location location, Modifiers modifiers) {
- this.location = location;
- this.modifiers = modifiers;
- }
-
- @Override public short
- getModifierFlags() { return this.modifiers.flags; }
-
- @Override public Annotation[]
- getAnnotations() { return this.modifiers.annotations; }
-
- /** Sets the enclosing scope of this {@link TypeDeclaration}. */
- public void
- setEnclosingScope(Scope enclosingScope) {
- if (this.enclosingScope != null && enclosingScope != this.enclosingScope) {
- throw new JaninoRuntimeException(
- "Enclosing scope is already set for type declaration \""
- + this.toString()
- + "\" at "
- + this.getLocation()
- );
- }
- this.enclosingScope = enclosingScope;
- }
-
- @Override public Scope
- getEnclosingScope() { return this.enclosingScope; }
-
- /**
- * Invalidates the method cache of the {@link #resolvedType}. This is necessary when methods are added
- * during compilation
- */
- public void
- invalidateMethodCaches() {
- if (this.resolvedType != null) {
- this.resolvedType.invalidateMethodCaches();
- }
- }
-
- /** Adds one {@link MemberTypeDeclaration} to this type. */
- public void
- addMemberTypeDeclaration(MemberTypeDeclaration mcoid) {
- this.declaredClassesAndInterfaces.add(mcoid);
- mcoid.setDeclaringType(this);
- }
-
- /** Adds one {@link MethodDeclarator} to this type. */
- public void
- addDeclaredMethod(MethodDeclarator method) {
- this.declaredMethods.add(method);
- method.setDeclaringType(this);
- }
-
- // Implement TypeDeclaration.
-
- @Override public Collection
- getMemberTypeDeclarations() { return this.declaredClassesAndInterfaces; }
-
- @Override public MemberTypeDeclaration
- getMemberTypeDeclaration(String name) {
- for (MemberTypeDeclaration mtd : this.declaredClassesAndInterfaces) {
- if (mtd.getName().equals(name)) return mtd;
- }
- return null;
- }
-
- @Override public MethodDeclarator
- getMethodDeclaration(String name) {
- for (MethodDeclarator md : this.declaredMethods) {
- if (md.name.equals(name)) return md;
- }
- return null;
- }
-
- @Override public List
- getMethodDeclarations() { return this.declaredMethods; }
-
- @Override public String
- createLocalTypeName(String localTypeName) {
- return (
- this.getClassName()
- + '$'
- + ++this.localClassCount
- + '$'
- + localTypeName
- );
- }
-
- @Override public String
- createAnonymousClassName() {
- return (
- this.getClassName()
- + '$'
- + ++this.anonymousClassCount
- );
- }
-
- // Implement "Locatable".
-
- @Override public Location
- getLocation() { return this.location; }
-
- @Override public void
- throwCompileException(String message) throws CompileException {
- throw new CompileException(message, this.location);
- }
-
- @Override public abstract String
- toString();
-
- /** For naming anonymous classes. */
- public int anonymousClassCount;
-
- /** For naming local classes. */
- public int localClassCount;
- }
-
- /** Base for the various class declaration kinds. */
- public abstract static
- class ClassDeclaration extends AbstractTypeDeclaration {
-
- /** List of {@link ConstructorDeclarator}s of this class. */
- public final List constructors = new ArrayList();
-
- /**
- * List of {@link TypeBodyDeclaration}s of this class: Field declarations (both static and non-static),
- * (static and non-static) initializers (a.k.a. "class initializers" and "instance initializers").
- */
- public final List variableDeclaratorsAndInitializers = new ArrayList();
-
- public
- ClassDeclaration(Location location, Modifiers modifiers) {
- super(location, modifiers);
- }
-
- /** Adds one {@link ConstructorDeclarator} to this class. */
- public void
- addConstructor(ConstructorDeclarator cd) {
- this.constructors.add(cd);
- cd.setDeclaringType(this);
- }
-
- /** Adds one field declaration to this class. */
- public void
- addFieldDeclaration(FieldDeclaration fd) {
- this.variableDeclaratorsAndInitializers.add(fd);
- fd.setDeclaringType(this);
-
- // Clear resolved type cache.
- if (this.resolvedType != null) this.resolvedType.clearIFieldCaches();
- }
-
- /** Adds one initializer to this class. */
- public void
- addInitializer(Initializer i) {
- this.variableDeclaratorsAndInitializers.add(i);
- i.setDeclaringType(this);
-
- // Clear resolved type cache.
- if (this.resolvedType != null) this.resolvedType.clearIFieldCaches();
- }
-
- // Compile time members.
-
- // Forward-implement InnerClassDeclaration.
-
- /** @see Java.InnerClassDeclaration#defineSyntheticField(IClass.IField) */
- public void
- defineSyntheticField(IClass.IField iField) throws CompileException {
- if (!(this instanceof InnerClassDeclaration)) throw new JaninoRuntimeException();
-
- IClass.IField if2 = (IClass.IField) this.syntheticFields.get(iField.getName());
- if (if2 != null) {
- if (iField.getType() != if2.getType()) throw new JaninoRuntimeException();
- return;
- }
- this.syntheticFields.put(iField.getName(), iField);
- }
-
- /** @return The declared constructors, or the default constructor */
- ConstructorDeclarator[]
- getConstructors() {
- if (this.constructors.isEmpty()) {
- ConstructorDeclarator defaultConstructor = new ConstructorDeclarator(
- this.getLocation(), // location
- null, // optionalDocComment
- new Java.Modifiers(Mod.PUBLIC), // modifiers
- new FormalParameters(), // formalParameters
- new Type[0], // thrownExceptions
- null, // optionalExplicitConstructorInvocation
- Collections.EMPTY_LIST // optionalStatements
- );
- defaultConstructor.setDeclaringType(this);
- return new ConstructorDeclarator[] { defaultConstructor };
- }
-
- return (ConstructorDeclarator[]) this.constructors.toArray(
- new ConstructorDeclarator[this.constructors.size()]
- );
- }
-
- /** All field names start with "this$" or "val$". */
- final SortedMap syntheticFields = new TreeMap();
- }
-
- /** Representation of a JLS7 15.9.5 'anonymous class declaration'. */
- public static final
- class AnonymousClassDeclaration extends ClassDeclaration implements InnerClassDeclaration {
-
- /** Base class or interface. */
- public final Type baseType;
-
- public
- AnonymousClassDeclaration(Location location, Type baseType) {
- super(
- location, // location
- new Modifiers((short) (Mod.PRIVATE | Mod.FINAL)) // modifiers
- );
- (this.baseType = baseType).setEnclosingScope(new EnclosingScopeOfTypeDeclaration(this));
- }
-
- @Override public void
- accept(Visitor.TypeDeclarationVisitor visitor) { visitor.visitAnonymousClassDeclaration(this); }
-
- // Implement TypeDeclaration.
-
- @Override public String
- getClassName() {
- if (this.myName == null) {
- Scope s = this.getEnclosingScope();
- for (; !(s instanceof TypeDeclaration); s = s.getEnclosingScope());
- this.myName = ((TypeDeclaration) s).createAnonymousClassName();
- }
- return this.myName;
- }
- private String myName;
-
- @Override public String
- toString() { return this.getClassName(); }
- }
-
- /** Base for the various named class declarations. */
- public abstract static
- class NamedClassDeclaration extends ClassDeclaration implements NamedTypeDeclaration, DocCommentable {
-
- private final String optionalDocComment;
-
- /** The simple name of this class. */
- public final String name;
-
- /** The optional type parameters of this interface. */
- public final TypeParameter[] optionalTypeParameters;
-
- /** The type of the extended class. */
- public final Type optionalExtendedType;
-
- /** The types of the implemented interfaces. */
- public final Type[] implementedTypes;
-
- public
- NamedClassDeclaration(
- Location location,
- String optionalDocComment,
- Modifiers modifiers,
- String name,
- TypeParameter[] optionalTypeParameters,
- Type optionalExtendedType,
- Type[] implementedTypes
- ) {
- super(location, modifiers);
- this.optionalDocComment = optionalDocComment;
- this.name = name;
- this.optionalTypeParameters = optionalTypeParameters;
- this.optionalExtendedType = optionalExtendedType;
- if (optionalExtendedType != null) {
- optionalExtendedType.setEnclosingScope(new EnclosingScopeOfTypeDeclaration(this));
- }
- this.implementedTypes = implementedTypes;
- for (Type implementedType : implementedTypes) {
- implementedType.setEnclosingScope(new EnclosingScopeOfTypeDeclaration(this));
- }
- }
-
- @Override public String
- toString() { return this.name; }
-
- // Implement NamedTypeDeclaration.
-
- @Override public String
- getName() { return this.name; }
-
- @Override public TypeParameter[]
- getOptionalTypeParameters() { return this.optionalTypeParameters; }
-
- // Implement DocCommentable.
-
- @Override public String
- getDocComment() { return this.optionalDocComment; }
-
- @Override public boolean
- hasDeprecatedDocTag() {
- return this.optionalDocComment != null && this.optionalDocComment.indexOf("@deprecated") != -1;
- }
- }
-
- /** Lazily determines and returns the enclosing {@link Java.Scope} of the given {@link Java.TypeDeclaration}. */
- public static final
- class EnclosingScopeOfTypeDeclaration implements Scope {
-
- /** The specific type declaration. */
- public final TypeDeclaration typeDeclaration;
-
- public
- EnclosingScopeOfTypeDeclaration(TypeDeclaration typeDeclaration) { this.typeDeclaration = typeDeclaration; }
-
- @Override public Scope
- getEnclosingScope() { return this.typeDeclaration.getEnclosingScope(); }
- }
-
- /**
- * Representation of a 'member class declaration', i.e. a class declaration that appears inside another class
- * declaration.
- */
- public static final
- class MemberClassDeclaration extends NamedClassDeclaration implements MemberTypeDeclaration, InnerClassDeclaration {
- public
- MemberClassDeclaration(
- Location location,
- String optionalDocComment,
- Modifiers modifiers,
- String name,
- TypeParameter[] optionalTypeParameters,
- Type optionalExtendedType,
- Type[] implementedTypes
- ) {
- super(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- name, // name
- optionalTypeParameters, // optionalTypeParameters
- optionalExtendedType, // optionalExtendedType
- implementedTypes // implementedTypes
- );
- }
-
- // Implement TypeBodyDeclaration.
-
- @Override public void
- setDeclaringType(TypeDeclaration declaringType) { this.setEnclosingScope(declaringType); }
-
- @Override public TypeDeclaration
- getDeclaringType() { return (TypeDeclaration) this.getEnclosingScope(); }
-
- @Override public boolean
- isStatic() { return Mod.isStatic(this.getModifierFlags()); }
-
- // Implement TypeDeclaration.
-
- @Override public String
- getClassName() { return this.getDeclaringType().getClassName() + '$' + this.getName(); }
-
- @Override public void
- accept(Visitor.TypeDeclarationVisitor visitor) { visitor.visitMemberClassDeclaration(this); }
-
- @Override public void
- accept(Visitor.TypeBodyDeclarationVisitor visitor) { visitor.visitMemberClassDeclaration(this); }
- }
-
- /** Representation of a 'local class declaration' i.e. a class declaration that appears inside a method body. */
- public static final
- class LocalClassDeclaration extends NamedClassDeclaration implements InnerClassDeclaration {
-
- public
- LocalClassDeclaration(
- Location location,
- String optionalDocComment,
- Modifiers modifiers,
- String name,
- TypeParameter[] optionalTypeParameters,
- Type optionalExtendedType,
- Type[] implementedTypes
- ) {
- super(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- name, // name
- optionalTypeParameters, // optionalTypeParameters
- optionalExtendedType, // optionalExtendedType
- implementedTypes // implementedTypes
- );
- }
-
- // Implement TypeDeclaration.
-
- @Override public String
- getClassName() {
- for (Scope s = this.getEnclosingScope();; s = s.getEnclosingScope()) {
- if (s instanceof Java.TypeDeclaration) {
- return ((Java.TypeDeclaration) s).getClassName() + '$' + this.name;
- }
- }
- }
-
- @Override public void
- accept(Visitor.TypeDeclarationVisitor visitor) { visitor.visitLocalClassDeclaration(this); }
- }
-
- /** Implementation of a 'package member class declaration', a.k.a. 'top-level class declaration'. */
- public static final
- class PackageMemberClassDeclaration extends NamedClassDeclaration implements PackageMemberTypeDeclaration {
-
- public
- PackageMemberClassDeclaration(
- Location location,
- String optionalDocComment,
- Modifiers modifiers,
- String name,
- TypeParameter[] optionalTypeParameters,
- Type optionalExtendedType,
- Type[] implementedTypes
- ) throws CompileException {
- super(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- name, // name
- optionalTypeParameters, // optionalTypeParameters
- optionalExtendedType, // optionalExtendedType
- implementedTypes // implementedTypes
- );
-
- // Check for forbidden modifiers (JLS7 7.6).
- if ((modifiers.flags & (Mod.PROTECTED | Mod.PRIVATE | Mod.STATIC)) != 0) {
- this.throwCompileException(
- "Modifiers \"protected\", \"private\" and \"static\" not allowed in package member class "
- + "declaration"
- );
- }
- }
-
- // Implement PackageMemberTypeDeclaration.
-
- @Override public void
- setDeclaringCompilationUnit(CompilationUnit declaringCompilationUnit) {
- this.setEnclosingScope(declaringCompilationUnit);
- }
-
- @Override public CompilationUnit
- getDeclaringCompilationUnit() { return (CompilationUnit) this.getEnclosingScope(); }
-
- // Implement TypeDeclaration.
-
- @Override public String
- getClassName() {
- String className = this.getName();
-
- CompilationUnit compilationUnit = (CompilationUnit) this.getEnclosingScope();
- if (compilationUnit.optionalPackageDeclaration != null) {
- className = compilationUnit.optionalPackageDeclaration.packageName + '.' + className;
- }
-
- return className;
- }
-
- @Override public void
- accept(Visitor.TypeDeclarationVisitor visitor) { visitor.visitPackageMemberClassDeclaration(this); }
- }
-
- /** Base for the various interface declaration kinds. */
- public abstract static
- class InterfaceDeclaration extends AbstractTypeDeclaration implements NamedTypeDeclaration, DocCommentable {
-
- private final String optionalDocComment;
-
- /** The simple name of the interface. */
- public final String name;
-
- /** The optional type parameters of this interface. */
- public final TypeParameter[] optionalTypeParameters;
-
- protected
- InterfaceDeclaration(
- Location location,
- String optionalDocComment,
- Modifiers modifiers,
- String name,
- TypeParameter[] optionalTypeParameters,
- Type[] extendedTypes
- ) {
- super(location, modifiers);
- this.optionalDocComment = optionalDocComment;
- this.name = name;
- this.optionalTypeParameters = optionalTypeParameters;
- this.extendedTypes = extendedTypes;
- for (Type extendedType : extendedTypes) {
- extendedType.setEnclosingScope(new EnclosingScopeOfTypeDeclaration(this));
- }
- }
-
- @Override public String
- toString() { return this.name; }
-
- /** Adds one constant declaration to this interface declaration. */
- public void
- addConstantDeclaration(FieldDeclaration fd) {
- this.constantDeclarations.add(fd);
- fd.setDeclaringType(this);
-
- // Clear resolved type cache.
- if (this.resolvedType != null) this.resolvedType.clearIFieldCaches();
- }
-
- /** The types of the interfaces that this interface extends. */
- public final Type[] extendedTypes;
-
- /** The constants that this interface declares. */
- public final List constantDeclarations = new ArrayList();
-
- /** Set during "compile()". */
- IClass[] interfaces;
-
- // Implement NamedTypeDeclaration.
-
- @Override public String
- getName() { return this.name; }
-
- @Override public TypeParameter[]
- getOptionalTypeParameters() { return this.optionalTypeParameters; }
-
- // Implement DocCommentable.
-
- @Override public String
- getDocComment() { return this.optionalDocComment; }
-
- @Override public boolean
- hasDeprecatedDocTag() {
- return this.optionalDocComment != null && this.optionalDocComment.indexOf("@deprecated") != -1;
- }
- }
-
- /**
- * Representation of a 'member interface declaration', i.e. an interface declaration that appears inside another
- * class or interface declaration.
- */
- public static final
- class MemberInterfaceDeclaration extends InterfaceDeclaration implements MemberTypeDeclaration {
-
- public
- MemberInterfaceDeclaration(
- Location location,
- String optionalDocComment,
- Modifiers modifiers,
- String name,
- TypeParameter[] optionalTypeParameters,
- Type[] extendedTypes
- ) {
- super(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- name, // name
- optionalTypeParameters, // optionalTypeParameters
- extendedTypes // extendedTypes
- );
- }
-
- // Implement TypeDeclaration.
-
- @Override public String
- getClassName() {
- NamedTypeDeclaration declaringType = (NamedTypeDeclaration) this.getEnclosingScope();
- return (
- declaringType.getClassName()
- + '$'
- + this.getName()
- );
- }
-
- // Implement TypeBodyDeclaration.
-
- @Override public void
- setDeclaringType(TypeDeclaration declaringType) { this.setEnclosingScope(declaringType); }
-
- @Override public TypeDeclaration
- getDeclaringType() { return (TypeDeclaration) this.getEnclosingScope(); }
-
- @Override public boolean
- isStatic() { return Mod.isStatic(this.getModifierFlags()); }
-
- @Override public void
- accept(Visitor.TypeDeclarationVisitor visitor) { visitor.visitMemberInterfaceDeclaration(this); }
-
- @Override public void
- accept(Visitor.TypeBodyDeclarationVisitor visitor) { visitor.visitMemberInterfaceDeclaration(this); }
- }
-
- /** Representation of a 'package member interface declaration', a.k.a. 'top-level interface declaration'. */
- public static final
- class PackageMemberInterfaceDeclaration extends InterfaceDeclaration implements PackageMemberTypeDeclaration {
-
- public
- PackageMemberInterfaceDeclaration(
- Location location,
- String optionalDocComment,
- Modifiers modifiers,
- String name,
- TypeParameter[] optionalTypeParameters,
- Type[] extendedTypes
- ) throws CompileException {
- super(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- name, // name
- optionalTypeParameters, // optionalTypeParameters
- extendedTypes // extendedTypes
- );
-
- // Check for forbidden modifiers (JLS7 7.6).
- if ((modifiers.flags & (Mod.PROTECTED | Mod.PRIVATE | Mod.STATIC)) != 0) {
- this.throwCompileException(
- "Modifiers \"protected\", \"private\" and \"static\" not allowed in package member interface "
- + "declaration"
- );
- }
- }
-
- // Implement PackageMemberTypeDeclaration.
-
- @Override public void
- setDeclaringCompilationUnit(CompilationUnit declaringCompilationUnit) {
- this.setEnclosingScope(declaringCompilationUnit);
- }
-
- @Override public CompilationUnit
- getDeclaringCompilationUnit() { return (CompilationUnit) this.getEnclosingScope(); }
-
- // Implement TypeDeclaration.
-
- @Override public String
- getClassName() {
- String className = this.getName();
-
- CompilationUnit compilationUnit = (CompilationUnit) this.getEnclosingScope();
- if (compilationUnit.optionalPackageDeclaration != null) {
- className = compilationUnit.optionalPackageDeclaration.packageName + '.' + className;
- }
-
- return className;
- }
-
- @Override public void
- accept(Visitor.TypeDeclarationVisitor visitor) { visitor.visitPackageMemberInterfaceDeclaration(this); }
- }
-
- /** Representation of a type parameter (which declares a type variable). */
- public static
- class TypeParameter {
-
- /** The name of the type variable. */
- public final String name;
-
- /** The optional bound of the type parameter. */
- public final ReferenceType[] optionalBound;
-
- public
- TypeParameter(String name, ReferenceType[] optionalBound) {
- assert name != null;
- this.name = name;
- this.optionalBound = optionalBound;
- }
-
- @Override public String
- toString() {
- return (
- this.optionalBound == null
- ? this.name
- : this.name + " extends " + Java.join(this.optionalBound, " & ")
- );
- }
- }
-
- /**
- * Representation of a "ClassBodyDeclaration" or an "InterfaceMemberDeclaration". These are:
- *
- * Field declarators
- * Method declarators
- * Static and non-static initializers
- * Member type declarations
- *
- */
- public
- interface TypeBodyDeclaration extends Locatable, Scope {
-
- /** Sets the type declaration that this declaration belongs to. */
- void setDeclaringType(TypeDeclaration declaringType);
-
- /** @return The type declaration that this declaration belongs to. */
- TypeDeclaration getDeclaringType();
-
- /** @return Whether this declaration has the STATIC modifier */
- boolean isStatic();
-
- /**
- * Invokes the '{@code visit...()}' method of {@link Visitor.TypeBodyDeclarationVisitor} for the concrete
- * {@link TypeBodyDeclaration} type.
- */
- void accept(Visitor.TypeBodyDeclarationVisitor visitor);
- }
-
- /** Abstract implementation of {@link TypeBodyDeclaration}. */
- public abstract static
- class AbstractTypeBodyDeclaration extends Located implements TypeBodyDeclaration {
-
- private TypeDeclaration declaringType;
-
- /** Whether this declaration has the STATIC modifier */
- public final boolean statiC;
-
- protected
- AbstractTypeBodyDeclaration(Location location, boolean statiC) {
- super(location);
- this.statiC = statiC;
- }
-
- // Implement TypeBodyDeclaration.
-
- @Override public void
- setDeclaringType(TypeDeclaration declaringType) {
- if (this.declaringType != null && declaringType != null) {
- throw new JaninoRuntimeException(
- "Declaring type for type body declaration \""
- + this.toString()
- + "\"at "
- + this.getLocation()
- + " is already set"
- );
- }
- this.declaringType = declaringType;
- }
-
- @Override public TypeDeclaration
- getDeclaringType() { return this.declaringType; }
-
- @Override public boolean
- isStatic() { return this.statiC; }
-
- /** Forward-implements {@link BlockStatement#setEnclosingScope(Java.Scope)}. */
- public void
- setEnclosingScope(Scope enclosingScope) { this.declaringType = (TypeDeclaration) enclosingScope; }
-
- // Implement 'Scope'.
-
- @Override public Scope
- getEnclosingScope() { return this.declaringType; }
- }
-
- /** Representation of an 'instance initializer' (JLS7 8.6) or 'static initializer' (JLS7 8.7). */
- public static final
- class Initializer extends AbstractTypeBodyDeclaration implements BlockStatement {
-
- /** The block that poses the initializer. */
- public final Block block;
-
- public
- Initializer(Location location, boolean statiC, Block block) {
- super(location, statiC);
- (this.block = block).setEnclosingScope(this);
- }
-
- @Override public String
- toString() { return this.statiC ? "static " + this.block : this.block.toString(); }
-
- // Implement BlockStatement.
-
- @Override public void
- accept(Visitor.TypeBodyDeclarationVisitor visitor) { visitor.visitInitializer(this); }
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitInitializer(this); }
-
- @Override public Java.LocalVariable
- findLocalVariable(String name) { return this.block.findLocalVariable(name); }
- }
-
- /** Abstract base class for {@link Java.ConstructorDeclarator} and {@link Java.MethodDeclarator}. */
- public abstract static
- class FunctionDeclarator extends AbstractTypeBodyDeclaration implements DocCommentable {
-
- private final String optionalDocComment;
-
- /** The {@link Modifiers} of this declarator. */
- public final Modifiers modifiers;
-
- /** The return type of the function (VOID for constructors). */
- public final Type type;
-
- /** The name of the function ("" for constructors. */
- public final String name;
-
- /** The parameters of the function. */
- public final FormalParameters formalParameters;
-
- /** The types of the declared exceptions. */
- public final Type[] thrownExceptions;
-
- /** The statements that comprise the function; {@code null} for abstract method declarations. */
- public final List extends BlockStatement> optionalStatements;
-
- public
- FunctionDeclarator(
- Location location,
- String optionalDocComment,
- Modifiers modifiers,
- Type type,
- String name,
- FormalParameters parameters,
- Type[] thrownExceptions,
- List extends BlockStatement> optionalStatements
- ) {
- super(location, Mod.isStatic(modifiers.flags));
- this.optionalDocComment = optionalDocComment;
- this.modifiers = parameters.variableArity ? modifiers.add(Mod.VARARGS) : modifiers;
- this.type = type;
- this.name = name;
- this.formalParameters = parameters;
- this.thrownExceptions = thrownExceptions;
- this.optionalStatements = optionalStatements;
-
- this.type.setEnclosingScope(this);
- for (FormalParameter fp : parameters.parameters) fp.type.setEnclosingScope(this);
- for (Type te : thrownExceptions) te.setEnclosingScope(this);
- if (optionalStatements != null) {
- for (Java.BlockStatement bs : optionalStatements) {
-
- // Catch 22: In the initializers, some statement have their enclosing already
- // set!
- if (("".equals(name) || "".equals(name)) && bs.getEnclosingScope() != null) continue;
-
- bs.setEnclosingScope(this);
- }
- }
- }
-
- /** @return The annotations of this function */
- public Annotation[]
- getAnnotations() { return this.modifiers.annotations; }
-
- // Implement "FunctionDeclarator".
-
- /**
- * Invokes the '{@code visit...()}' method of {@link Visitor.FunctionDeclaratorVisitor} for the concrete
- * {@link FunctionDeclarator} type.
- */
- public abstract void
- accept(Visitor.FunctionDeclaratorVisitor visitor);
-
- // Override "AbstractTypeBodyDeclaration"
-
- @Override public void
- setDeclaringType(TypeDeclaration declaringType) {
- super.setDeclaringType(declaringType);
- for (Annotation a : this.modifiers.annotations) a.setEnclosingScope(declaringType);
- }
-
- // Implement "Scope".
-
- @Override public Scope
- getEnclosingScope() { return this.getDeclaringType(); }
-
- /** Set by "compile()". */
- IClass returnType;
-
- // Implement DocCommentable.
-
- @Override public String
- getDocComment() { return this.optionalDocComment; }
-
- @Override public boolean
- hasDeprecatedDocTag() {
- return this.optionalDocComment != null && this.optionalDocComment.indexOf("@deprecated") != -1;
- }
-
- /** Representation of the (formal) function parameters. */
- public static final
- class FormalParameters extends Located {
-
- /** The parameters of this function, but not the {@link #variableArity}. */
- public final FormalParameter[] parameters;
-
- /**
- * Whether this method has 'variable arity', i.e. its last parameter has an ellipsis ('...') after the
- * type.
- */
- public final boolean variableArity;
-
- public
- FormalParameters() { this(null, new FormalParameter[0], false); }
-
- public
- FormalParameters(Location location, FormalParameter[] parameters, boolean variableArity) {
- super(location);
- this.parameters = parameters;
- this.variableArity = variableArity;
- }
-
- @Override public String
- toString() {
- if (this.parameters.length == 0) return "()";
- StringBuilder sb = new StringBuilder("(");
- for (int i = 0; i < this.parameters.length; i++) {
- if (i > 0) sb.append(", ");
- sb.append(this.parameters[i].toString(i == this.parameters.length - 1 && this.variableArity));
- }
- return sb.append(')').toString();
- }
- }
-
- /** Representation of a (formal) function parameter. */
- public static final
- class FormalParameter extends Located {
-
- /** Whether the parameter is declared FINAL. */
- public final boolean finaL;
-
- /** The type of the parameter. */
- public final Type type;
-
- /** The name of the parameter. */
- public final String name;
-
- public
- FormalParameter(Location location, boolean finaL, Type type, String name) {
- super(location);
- this.finaL = finaL;
- this.type = type;
- this.name = name;
- }
-
- /**
- * @param hasEllipsis Whether this is the last function parameter and has an ellipsis ('...') after the
- * type
- */
- public String
- toString(boolean hasEllipsis) { return this.type.toString() + (hasEllipsis ? "... " : " ") + this.name; }
-
- @Override public String
- toString() { return this.toString(false); }
-
- // Compile time members.
-
-
- /** The local variable associated with this parameter. */
- public Java.LocalVariable localVariable;
- }
-
- // Compile time members
-
- /** Mapping of variable names to {@link LocalVariable}s. */
- public Map localVariables;
- }
-
- /** Representation of a constructor declarator. */
- public static final
- class ConstructorDeclarator extends FunctionDeclarator {
-
- /** The resolved {@link IClass.IConstructor}. */
- IClass.IConstructor iConstructor;
-
- /** The {@link AlternateConstructorInvocation} or {@link SuperConstructorInvocation}, if any. */
- public final ConstructorInvocation optionalConstructorInvocation;
-
- public
- ConstructorDeclarator(
- Location location,
- String optionalDocComment,
- Modifiers modifiers,
- FormalParameters parameters,
- Type[] thrownExceptions,
- ConstructorInvocation optionalConstructorInvocation,
- List statements
- ) {
- super(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- new BasicType(location, BasicType.VOID), // type
- "", // name
- parameters, // parameters
- thrownExceptions, // thrownExceptions
- statements // optionalStatements
- );
- this.optionalConstructorInvocation = optionalConstructorInvocation;
- if (optionalConstructorInvocation != null) optionalConstructorInvocation.setEnclosingScope(this);
- }
-
- /** @return The {@link ClassDeclaration} where this {@link ConstructorDeclarator} appears */
- public ClassDeclaration
- getDeclaringClass() { return (ClassDeclaration) this.getEnclosingScope(); }
-
- // Compile time members.
-
- /** Synthetic parameter name to {@link Java.LocalVariable} mapping. */
- final Map syntheticParameters = new HashMap();
-
- // Implement "FunctionDeclarator":
-
- @Override public String
- toString() {
- StringBuilder sb = new StringBuilder(this.getDeclaringClass().getClassName()).append('(');
-
- FormalParameter[] fps = this.formalParameters.parameters;
- for (int i = 0; i < fps.length; ++i) {
- if (i > 0) sb.append(", ");
- sb.append(fps[i].toString(i == fps.length - 1 && this.formalParameters.variableArity));
- }
- sb.append(')');
- return sb.toString();
- }
-
- @Override public void
- accept(Visitor.TypeBodyDeclarationVisitor visitor) { visitor.visitConstructorDeclarator(this); }
-
- @Override public void
- accept(Visitor.FunctionDeclaratorVisitor visitor) { visitor.visitConstructorDeclarator(this); }
- }
-
- /** Representation of a method declarator. */
- public static final
- class MethodDeclarator extends FunctionDeclarator {
- public
- MethodDeclarator(
- Location location,
- String optionalDocComment,
- Java.Modifiers modifiers,
- Type type,
- String name,
- FormalParameters parameters,
- Type[] thrownExceptions,
- List extends BlockStatement> optionalStatements
- ) {
- super(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- type, // type
- name, // name
- parameters, // parameters
- thrownExceptions, // thrownExceptions
- optionalStatements // optionalStatements
- );
- }
-
- @Override public String
- toString() {
- StringBuilder sb = new StringBuilder(this.name).append('(');
- FormalParameter[] fps = this.formalParameters.parameters;
- for (int i = 0; i < fps.length; ++i) {
- if (i > 0) sb.append(", ");
- sb.append(fps[i].toString(i == fps.length - 1 && this.formalParameters.variableArity));
- }
- sb.append(')');
- return sb.toString();
- }
-
- @Override public void
- accept(Visitor.TypeBodyDeclarationVisitor visitor) { visitor.visitMethodDeclarator(this); }
-
- @Override public void
- accept(Visitor.FunctionDeclaratorVisitor visitor) { visitor.visitMethodDeclarator(this); }
-
- /** The resolved {@link IMethod}. */
- IClass.IMethod iMethod;
- }
-
- /**
- * This class is derived from "Statement", because it provides for the
- * initialization of the field. In other words, "compile()" generates the
- * code that initializes the field.
- */
- public static final
- class FieldDeclaration extends Statement implements TypeBodyDeclaration, DocCommentable {
-
- private final String optionalDocComment;
-
- /** The modifiers of this field declaration. */
- public final Modifiers modifiers;
-
- /** The type of this field. */
- public final Type type;
-
- /** The declarators of this field declaration, e.g. 'int a, b;'. */
- public final VariableDeclarator[] variableDeclarators;
-
- public
- FieldDeclaration(
- Location location,
- String optionalDocComment,
- Modifiers modifiers,
- Type type,
- VariableDeclarator[] variableDeclarators
- ) {
- super(location);
- this.optionalDocComment = optionalDocComment;
- this.modifiers = modifiers;
- this.type = type;
- this.variableDeclarators = variableDeclarators;
-
- this.type.setEnclosingScope(this);
- for (VariableDeclarator vd : variableDeclarators) {
- if (vd.optionalInitializer != null) Java.setEnclosingBlockStatement(vd.optionalInitializer, this);
- }
- }
-
- /** @return The annotations of this field */
- public Annotation[]
- getAnnotations() { return this.modifiers.annotations; }
-
- // Implement TypeBodyDeclaration.
-
- @Override public void
- setDeclaringType(TypeDeclaration declaringType) { this.setEnclosingScope(declaringType); }
-
- @Override public TypeDeclaration
- getDeclaringType() { return (TypeDeclaration) this.getEnclosingScope(); }
-
- @Override public boolean
- isStatic() { return Mod.isStatic(this.modifiers.flags); }
-
- @Override public String
- toString() {
- StringBuilder sb = new StringBuilder();
- sb.append(Mod.shortToString(this.modifiers.flags)).append(' ').append(this.type);
- sb.append(' ').append(this.variableDeclarators[0]);
- for (int i = 1; i < this.variableDeclarators.length; ++i) {
- sb.append(", ").append(this.variableDeclarators[i]);
- }
- return sb.toString();
- }
-
- @Override public void
- accept(Visitor.TypeBodyDeclarationVisitor visitor) { visitor.visitFieldDeclaration(this); }
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitFieldDeclaration(this); }
-
- // Implement DocCommentable.
-
- @Override public String
- getDocComment() { return this.optionalDocComment; }
-
- @Override public boolean
- hasDeprecatedDocTag() {
- return this.optionalDocComment != null && this.optionalDocComment.indexOf("@deprecated") != -1;
- }
- }
- private static void
- setEnclosingBlockStatement(ArrayInitializerOrRvalue aiorv, BlockStatement enclosingBlockStatement) {
- if (aiorv instanceof Rvalue) {
- ((Rvalue) aiorv).setEnclosingBlockStatement(enclosingBlockStatement);
- } else
- if (aiorv instanceof ArrayInitializer) {
- for (ArrayInitializerOrRvalue v : ((ArrayInitializer) aiorv).values) {
- Java.setEnclosingBlockStatement(v, enclosingBlockStatement);
- }
- } else
- {
- throw new JaninoRuntimeException("Unexpected array or initializer class " + aiorv.getClass().getName());
- }
- }
-
- /** Used by FieldDeclaration and LocalVariableDeclarationStatement. */
- public static final
- class VariableDeclarator extends Located {
-
- /** The name of this field or local variable. */
- public final String name;
-
- /** The number of '[]'s after the name. */
- public final int brackets;
-
- /** The initializer for the variable, if any. */
- public final ArrayInitializerOrRvalue optionalInitializer;
-
- public
- VariableDeclarator(Location location, String name, int brackets, ArrayInitializerOrRvalue optionalInitializer) {
- super(location);
- this.name = name;
- this.brackets = brackets;
- this.optionalInitializer = optionalInitializer;
-
- // Used both by field declarations an local variable declarations, so naming conventions checking (JLS7
- // 6.4.2) cannot be done here.
- }
-
- @Override public String
- toString() {
- StringBuilder sb = new StringBuilder(this.name);
- for (int i = 0; i < this.brackets; ++i) sb.append("[]");
- if (this.optionalInitializer != null) sb.append(" = ").append(this.optionalInitializer);
- return sb.toString();
- }
-
- // Compile time members.
-
- /** Used only if the variable declarator declares a local variable. */
- public LocalVariable localVariable;
- }
-
- /**
- * Everything that can be compiled to code, e.g. the statements occurring in the body of a method or in a block,
- * explicit constructor invocations and instance/static initializers.
- */
- public
- interface BlockStatement extends Locatable, Scope {
-
- /** Sets the enclosing scope of this {@link BlockStatement}. */
- void setEnclosingScope(Scope enclosingScope);
-
- // Implement Scope.
-
- @Override Scope getEnclosingScope();
-
- /**
- * Invokes the '{@code visit...()}' method of {@link Visitor.BlockStatementVisitor} for the concrete
- * {@link BlockStatement} type.
- */
- void accept(Visitor.BlockStatementVisitor visitor);
-
- /** @return The local variable with the given {@code name} */
- Java.LocalVariable findLocalVariable(String name);
- }
-
- /**
- * Everything that can occur in the body of a method or in a block. Particularly, explicit constructor invocations
- * and initializers are not statements in this sense.
- *
- * This class is mis-named; according to JLS7 8.8.7 and 14.2, its name should be 'BlockStatement'.
- */
- public abstract static
- class Statement extends Located implements BlockStatement {
- private Scope enclosingScope;
-
- protected
- Statement(Location location) { super(location); }
-
- // Implement "BlockStatement".
-
- @Override public void
- setEnclosingScope(Scope enclosingScope) {
- if (this.enclosingScope != null && enclosingScope != this.enclosingScope) {
- throw new JaninoRuntimeException(
- "Enclosing scope is already set for statement \""
- + this.toString()
- + "\" at "
- + this.getLocation()
- );
- }
- this.enclosingScope = enclosingScope;
- }
-
- @Override public Scope
- getEnclosingScope() { return this.enclosingScope; }
-
- // Compile time members
-
- /** The map of currently visible local variables. */
- public Map localVariables;
-
- @Override public Java.LocalVariable
- findLocalVariable(String name) {
- if (this.localVariables == null) { return null; }
- return (LocalVariable) this.localVariables.get(name);
- }
- }
-
- /** Representation of a JLS7 14.7 'labeled statement'. */
- public static final
- class LabeledStatement extends BreakableStatement {
-
- /** The lael of this labeled statement. */
- public final String label;
-
- /** The labeled block. */
- public final Statement body;
-
- public
- LabeledStatement(Location location, String label, Statement body) {
- super(location);
- this.label = label;
- (this.body = body).setEnclosingScope(this);
- }
-
- @Override public String
- toString() { return this.label + ": " + this.body; }
-
- // Compile time members:
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitLabeledStatement(this); }
- }
-
- /**
- * Representation of a Java™ "block" (JLS7 14.2).
- *
- * The statements that the block defines are executed in sequence.
- */
- public static final
- class Block extends Statement {
-
- /** The list of statements that comprise the body of the block. */
- public final List statements = new ArrayList();
-
- public
- Block(Location location) { super(location); }
-
- /** Adds one statement to the end of the block. */
- public void
- addStatement(BlockStatement statement) {
- this.statements.add(statement);
- statement.setEnclosingScope(this);
- }
-
- /** Adds a list of statements to the end of the block. */
- public void
- addStatements(List statements) {
- this.statements.addAll(statements);
- for (BlockStatement bs : statements) bs.setEnclosingScope(this);
- }
-
- /** @return A copy of the list of statements that comprise the body of the block */
- public BlockStatement[]
- getStatements() {
- return (BlockStatement[]) this.statements.toArray(new BlockStatement[this.statements.size()]);
- }
-
- // Compile time members.
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitBlock(this); }
-
- @Override public String
- toString() { return "{ ... }"; }
- }
-
- /**
- * Base class for statements that can be terminated abnormally with a "break" statement.
- *
- * According JLS7 14.15, statements that can be terminated abnormally with a "break" statement are
- *
- * {@link ContinuableStatement}s ("for", "do" and "while")
- * Labeled statements
- * "switch" statements
- *
- */
- public abstract static
- class BreakableStatement extends Statement {
-
- protected
- BreakableStatement(Location location) { super(location); }
-
- /**
- * This one's filled in by the first BREAK statement, and is {@link Offset#set()} by this breakable statement.
- */
- CodeContext.Offset whereToBreak;
- }
-
- /**
- * Base class for statements that support the 'continue' statement.
- *
- * According to the JLS7 14.16, these are "for", "do" and "while".
- */
- public abstract static
- class ContinuableStatement extends BreakableStatement {
- protected
- ContinuableStatement(Location location, BlockStatement body) {
- super(location);
- (this.body = body).setEnclosingScope(this);
- }
-
- /**
- * This one's filled in by the first CONTINUE statement, and is {@link Offset#set()} by this continuable
- * statement.
- */
- protected CodeContext.Offset whereToContinue;
- /** The body of this continuable statement. */
- public final BlockStatement body;
- }
-
- /** Representation of the JLS7 14.8 'expression statement'. */
- public static final
- class ExpressionStatement extends Statement {
-
- /** The rvalue that is evaluated when the statement is executed. */
- public final Rvalue rvalue;
-
- public
- ExpressionStatement(Rvalue rvalue) throws CompileException {
- super(rvalue.getLocation());
- if (!(
- rvalue instanceof Java.Assignment
- || rvalue instanceof Java.Crement
- || rvalue instanceof Java.MethodInvocation
- || rvalue instanceof Java.SuperclassMethodInvocation
- || rvalue instanceof Java.NewClassInstance
- || rvalue instanceof Java.NewAnonymousClassInstance
- )) {
- String expressionType = rvalue.getClass().getName();
- expressionType = expressionType.substring(expressionType.lastIndexOf('.') + 1);
- this.throwCompileException(
- expressionType
- + " is not allowed as an expression statement. "
- + "Expressions statements must be one of assignments, method invocations, or object allocations."
- );
- }
- (this.rvalue = rvalue).setEnclosingBlockStatement(this);
- }
-
- @Override public String
- toString() { return this.rvalue.toString() + ';'; }
-
- // Compile time members:
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitExpressionStatement(this); }
- }
-
- /** Representation of the JLS7 14.3 'local class declaration statement'. */
- public static final
- class LocalClassDeclarationStatement extends Statement {
-
- /** The class declaration that poses the body of the statement. */
- public final LocalClassDeclaration lcd;
-
- public
- LocalClassDeclarationStatement(Java.LocalClassDeclaration lcd) {
- super(lcd.getLocation());
- (this.lcd = lcd).setEnclosingScope(this);
- }
-
- @Override public String
- toString() { return this.lcd.toString(); }
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitLocalClassDeclarationStatement(this); }
- }
-
- /** Representation of a JLS7 14.9 IF statement. */
- public static final
- class IfStatement extends Statement {
-
- /** The condition of the IF statement. */
- public final Rvalue condition;
-
- /** The 'then statement', which is executed iff the condition evaluates to TRUE. */
- public final BlockStatement thenStatement;
-
- /** The optional ELSE statement, which is executed iff the condition evaluates to FALSE. */
- public final BlockStatement optionalElseStatement;
-
- /**
- * Notice that the elseStatement
is mandatory; for an if statement without
- * an "else" clause, a dummy {@link Java.EmptyStatement} should be passed.
- */
- public
- IfStatement(
- Location location,
- Rvalue condition,
- BlockStatement thenStatement,
- BlockStatement optionalElseStatement
- ) {
- super(location);
- (this.condition = condition).setEnclosingBlockStatement(this);
- (this.thenStatement = thenStatement).setEnclosingScope(this);
- this.optionalElseStatement = optionalElseStatement;
- if (optionalElseStatement != null) optionalElseStatement.setEnclosingScope(this);
- }
-
- @Override public String
- toString() { return this.optionalElseStatement == null ? "if" : "if ... else"; }
-
- // Compile time members:
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitIfStatement(this); }
- }
-
- /** Representation of a JLS7 14.14.1 'basic FOR statement'. */
- public static final
- class ForStatement extends ContinuableStatement {
-
- /** The optional 'init' part of the 'basic FOR statement'. */
- public final BlockStatement optionalInit;
-
- /** The optional 'condition' part of the 'basic FOR statement'. */
- public final Rvalue optionalCondition;
-
- /** The optional 'update' part of the 'basic FOR statement'. */
- public final Rvalue[] optionalUpdate;
-
- public
- ForStatement(
- Location location,
- BlockStatement optionalInit,
- Rvalue optionalCondition,
- Rvalue[] optionalUpdate,
- BlockStatement body
- ) {
- super(location, body);
- this.optionalInit = optionalInit;
- if (optionalInit != null) optionalInit.setEnclosingScope(this);
- this.optionalCondition = optionalCondition;
- if (optionalCondition != null) optionalCondition.setEnclosingBlockStatement(this);
- this.optionalUpdate = optionalUpdate;
- if (optionalUpdate != null) for (Rvalue rv : optionalUpdate) rv.setEnclosingBlockStatement(this);
- }
-
- @Override public String
- toString() { return "for (...; ...; ...) ..."; }
-
- // Compile time members:
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitForStatement(this); }
- }
-
- /** Representation of a JLS7 14.14.2 'enhanced FOR statement'. */
- public static final
- class ForEachStatement extends ContinuableStatement {
-
- /** The 'current element local variable declaration' part of the 'enhanced FOR statement'. */
- public final FormalParameter currentElement;
-
- /** The 'expression' part of the 'enhanced FOR statement'. */
- public final Rvalue expression;
-
- public
- ForEachStatement(Location location, FormalParameter currentElement, Rvalue expression, BlockStatement body) {
- super(location, body);
- (this.currentElement = currentElement).type.setEnclosingScope(this);
- (this.expression = expression).setEnclosingBlockStatement(this);
- }
-
- @Override public String
- toString() { return "for (... : ...) ..."; }
-
- // Compile time members:
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitForEachStatement(this); }
- }
-
- /** Representation of the JLS7 14.2 WHILE statement. */
- public static final
- class WhileStatement extends ContinuableStatement {
-
- /** The 'condition' of the WHILE statement. */
- public final Rvalue condition;
-
- public
- WhileStatement(Location location, Rvalue condition, BlockStatement body) {
- super(location, body);
- (this.condition = condition).setEnclosingBlockStatement(this);
- }
-
- @Override public String
- toString() { return "while (" + this.condition + ") " + this.body + ';'; }
-
- // Compile time members:
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitWhileStatement(this); }
- }
-
- /** Representation of a JLS7 14.20 TRY statement. */
- public static final
- class TryStatement extends Statement {
-
- /** The body of the TRY statement. */
- public final BlockStatement body;
-
- /** The list of catch clauses (including the 'default' clause) of the TRY statement. */
- public final List catchClauses;
-
- /** The optional 'finally' block of the TRY statement. */
- public final Block optionalFinally;
-
- public
- TryStatement(
- Location location,
- BlockStatement body,
- List catchClauses,
- Block optionalFinally
- ) {
- super(location);
- (this.body = body).setEnclosingScope(this);
- for (CatchClause cc : (this.catchClauses = catchClauses)) cc.setEnclosingTryStatement(this);
- this.optionalFinally = optionalFinally;
- if (optionalFinally != null) optionalFinally.setEnclosingScope(this);
- }
-
- @Override public String
- toString() {
- return (
- "try ... "
- + this.catchClauses.size()
- + (this.optionalFinally == null ? " catches" : " catches ... finally")
- );
- }
-
- // Compile time members:
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitTryStatement(this); }
-
- /**
- * This one's created iff the TRY statement has a FINALLY clause when the compilation of the TRY statement
- * begins.
- */
- CodeContext.Offset finallyOffset;
- }
-
- /** Representation of a JLS7 14.20.1 CATCH clause. */
- public static
- class CatchClause extends Located implements Scope {
-
- /** Container for the type and the name of the caught exception. */
- public final FormalParameter caughtException;
-
- /** Body of the CATCH clause. */
- public final Block body;
-
- /** Link to the enclosing TRY statement. */
- private TryStatement enclosingTryStatement;
-
- // Compile time fields.
-
- /** Flag for catch clause reachability analysis. */
- public boolean reachable;
-
- public
- CatchClause(Location location, FormalParameter caughtException, Block body) {
- super(location);
- (this.caughtException = caughtException).type.setEnclosingScope(this);
- (this.body = body).setEnclosingScope(this);
- }
-
- /** Links this CATCH clause to the enclosing TRY statement. */
- public void
- setEnclosingTryStatement(TryStatement enclosingTryStatement) {
- if (this.enclosingTryStatement != null && enclosingTryStatement != this.enclosingTryStatement) {
- throw new JaninoRuntimeException(
- "Enclosing TRY statement already set for catch clause "
- + this.toString()
- + " at "
- + this.getLocation()
- );
- }
- this.enclosingTryStatement = enclosingTryStatement;
- }
-
- @Override public Scope
- getEnclosingScope() { return this.enclosingTryStatement; }
-
- @Override public String
- toString() { return "catch (" + this.caughtException + ") " + this.body; }
- }
-
- /** The JLS7 14.10 "switch" Statement. */
- public static final
- class SwitchStatement extends BreakableStatement {
-
- /** The rvalue that is evaluated and matched with the CASE clauses. */
- public final Rvalue condition;
-
- /** The list of 'switch block statement groups' that pose the body of the SWITCH statement. */
- public final List sbsgs;
-
- public
- SwitchStatement(Location location, Rvalue condition, List sbsgs) {
- super(location);
- (this.condition = condition).setEnclosingBlockStatement(this);
- for (SwitchBlockStatementGroup sbsg : (this.sbsgs = sbsgs)) {
- for (Rvalue cl : sbsg.caseLabels) cl.setEnclosingBlockStatement(this);
- for (BlockStatement bs : sbsg.blockStatements) bs.setEnclosingScope(this);
- }
- }
-
- @Override public String
- toString() { return "switch (" + this.condition + ") { (" + this.sbsgs.size() + " statement groups) }"; }
-
- /** Representation of a 'switch block statement group' as defined in JLS7 14.11. */
- public static
- class SwitchBlockStatementGroup extends Java.Located {
-
- /** The CASE labels at the top of the 'switch block statement group'. */
- public final List caseLabels;
-
- /** Whether this 'switch block statement group' includes the DEFAULT label. */
- public final boolean hasDefaultLabel;
-
- /** The statements following the CASE labels. */
- public final List blockStatements;
-
- public
- SwitchBlockStatementGroup(
- Location location,
- List caseLabels,
- boolean hasDefaultLabel,
- List blockStatements
- ) {
- super(location);
- this.caseLabels = caseLabels;
- this.hasDefaultLabel = hasDefaultLabel;
- this.blockStatements = blockStatements;
- }
-
- @Override public String
- toString() {
- return (
- this.caseLabels.size()
- + (this.hasDefaultLabel ? " case label(s) plus DEFAULT" : " case label(s)")
- );
- }
- }
-
- // Compile time members:
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitSwitchStatement(this); }
- }
- static
- class Padder extends CodeContext.Inserter implements CodeContext.FixUp {
-
- public
- Padder(CodeContext codeContext) { codeContext.super(); }
-
- @Override public void
- fixUp() {
- int x = this.offset % 4;
- if (x != 0) {
- CodeContext ca = this.getCodeContext();
- ca.pushInserter(this);
- ca.makeSpace((short) -1, 4 - x);
- ca.popInserter();
- }
- }
- }
-
- /** Representation of a JLS7 14.9 SYNCHRONIZED statement. */
- public static final
- class SynchronizedStatement extends Statement {
-
- /** The object reference on which the statement synchronizes. */
- public final Rvalue expression;
-
- /** The body of this SYNCHRONIZED statement. */
- public final BlockStatement body;
-
- public
- SynchronizedStatement(Location location, Rvalue expression, BlockStatement body) {
- super(location);
- (this.expression = expression).setEnclosingBlockStatement(this);
- (this.body = body).setEnclosingScope(this);
- }
-
- @Override public String
- toString() { return "synchronized(" + this.expression + ") " + this.body; }
-
- // Compile time members:
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitSynchronizedStatement(this); }
-
- /** The index of the local variable for the monitor object. */
- short monitorLvIndex = -1;
- }
-
- /** Representation of a JLS7 14.13 DO statement. */
- public static final
- class DoStatement extends ContinuableStatement {
-
- /** The condition in the WHILE clause of this DO statement. */
- public final Rvalue condition;
-
- public
- DoStatement(Location location, BlockStatement body, Rvalue condition) {
- super(location, body);
- (this.condition = condition).setEnclosingBlockStatement(this);
- }
-
- @Override public String
- toString() { return "do " + this.body + " while(" + this.condition + ");"; }
-
- // Compile time members:
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitDoStatement(this); }
- }
-
- /** Representation of a JLS7 14.4 'local variable declaration statement'. */
- public static final
- class LocalVariableDeclarationStatement extends Statement {
-
- /** The local variable modifiers (annotations and/or flags like FINAL). */
- public final Modifiers modifiers;
-
- /** The declared type of the local variable. */
- public final Type type;
-
- /** The (one or more) 'variable declarators' that follow the type. */
- public final VariableDeclarator[] variableDeclarators;
-
- /** @param modifiers Only "final" allowed */
- public
- LocalVariableDeclarationStatement(
- Location location,
- Modifiers modifiers,
- Type type,
- VariableDeclarator[] variableDeclarators
- ) {
- super(location);
- this.modifiers = modifiers;
- this.type = type;
- this.variableDeclarators = variableDeclarators;
-
- this.type.setEnclosingScope(this);
- for (VariableDeclarator vd : variableDeclarators) {
- if (vd.optionalInitializer != null) Java.setEnclosingBlockStatement(vd.optionalInitializer, this);
- }
- }
-
- // Compile time members:
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitLocalVariableDeclarationStatement(this); }
-
- @Override public String
- toString() {
- StringBuilder sb = new StringBuilder();
- if (this.modifiers.flags != Mod.NONE) {
- sb.append(Mod.shortToString(this.modifiers.flags)).append(' ');
- }
- sb.append(this.type).append(' ').append(this.variableDeclarators[0].toString());
- for (int i = 1; i < this.variableDeclarators.length; ++i) {
- sb.append(", ").append(this.variableDeclarators[i].toString());
- }
- return sb.append(';').toString();
- }
- }
-
- /** Representation of the JLS7 14.17 RETURN statement. */
- public static final
- class ReturnStatement extends Statement {
-
- /** The optional rvalue that is returned. */
- public final Rvalue optionalReturnValue;
-
- public
- ReturnStatement(Location location, Rvalue optionalReturnValue) {
- super(location);
- this.optionalReturnValue = optionalReturnValue;
- if (optionalReturnValue != null) optionalReturnValue.setEnclosingBlockStatement(this);
- }
-
- @Override public String
- toString() { return this.optionalReturnValue == null ? "return;" : "return " + this.optionalReturnValue + ';'; }
-
- // Compile time members:
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitReturnStatement(this); }
- }
-
- /** Representation of a JLS7 14.18 THROW statement. */
- public static final
- class ThrowStatement extends Statement {
-
- /** The rvalue (of type {@link Throwable}) thrown by this THROW statement. */
- public final Rvalue expression;
-
- public
- ThrowStatement(Location location, Rvalue expression) {
- super(location);
- (this.expression = expression).setEnclosingBlockStatement(this);
- }
-
- @Override public String
- toString() { return "throw " + this.expression + ';'; }
-
- // Compile time members:
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitThrowStatement(this); }
- }
-
- /** Representation of the JLS7 14.15 BREAK statement. */
- public static final
- class BreakStatement extends Statement {
-
- /** The optional label that this BREAK statement refers to. */
- public final String optionalLabel;
-
- public
- BreakStatement(Location location, String optionalLabel) {
- super(location);
- this.optionalLabel = optionalLabel;
- }
-
- @Override public String
- toString() { return this.optionalLabel == null ? "break;" : "break " + this.optionalLabel + ';'; }
-
- // Compile time members:
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitBreakStatement(this); }
- }
-
- /** Representation of the JLS7 14.16 CONTINUE statement. */
- public static final
- class ContinueStatement extends Statement {
-
- /** The optional label that this CONTINUE statement refers to. */
- public final String optionalLabel;
-
- public
- ContinueStatement(Location location, String optionalLabel) {
- super(location);
- this.optionalLabel = optionalLabel;
- }
-
- @Override public String
- toString() { return this.optionalLabel == null ? "continue;" : "continue " + this.optionalLabel + ';'; }
-
- // Compile time members:
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitContinueStatement(this); }
- }
-
- /** Representation of the JLS7 14.10 ASSERT statement. */
- public static final
- class AssertStatement extends Statement {
-
- /** The left-hand-side expression of this ASSERT statement. */
- public final Rvalue expression1;
-
- /** The optional right-hand-side expression of this ASSERT statement. */
- public final Rvalue optionalExpression2;
-
- public
- AssertStatement(Location location, Rvalue expression1, Rvalue optionalExpression2) {
- super(location);
- this.expression1 = expression1;
- this.optionalExpression2 = optionalExpression2;
-
- this.expression1.setEnclosingBlockStatement(this);
- if (this.optionalExpression2 != null) this.optionalExpression2.setEnclosingBlockStatement(this);
- }
-
- @Override public String
- toString() {
- return (
- this.optionalExpression2 == null
- ? "assert " + this.expression1 + ';'
- : "assert " + this.expression1 + " : " + this.optionalExpression2 + ';'
- );
- }
-
- @Override public void accept(BlockStatementVisitor visitor) { visitor.visitAssertStatement(this); }
- }
-
- /** Representation of the "empty statement", i.e. the blank semicolon. */
- public static final
- class EmptyStatement extends Statement {
-
- public
- EmptyStatement(Location location) { super(location); }
-
- @Override public String
- toString() { return ";"; }
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitEmptyStatement(this); }
- }
-
- /** Abstract base class for {@link Java.Type}, {@link Java.Rvalue} and {@link Java.Lvalue}. */
- public abstract static
- class Atom extends Located {
-
- public
- Atom(Location location) { super(location); }
-
- /** @return This atom, converted to {@link Type}, or {@code null} if this atom is not a type */
- public Type toType() { return null; }
-
- /** @return This atom, converted to {@link Rvalue}, or {@code null} if this atom is not an rvalue */
- public Rvalue toRvalue() { return null; }
-
- /** @return This atom, converted to {@link Lvalue}, or {@code null} if this atom is not an lvalue */
- public Lvalue toLvalue() { return null; }
-
- @Override public abstract String
- toString();
-
- // Parse time members:
-
- /**
- * @return This atom, converted to {@link Type}
- * @throws CompileException This atom is not a {@link Type}
- */
- public final Type
- toTypeOrCompileException() throws CompileException {
- Type result = this.toType();
- if (result == null) this.throwCompileException("Expression \"" + this.toString() + "\" is not a type");
- return result;
- }
-
- /**
- * @return This atom, converted to an {@link Rvalue}
- * @throws CompileException This atom is not an {@link Rvalue}
- */
- public final Rvalue
- toRvalueOrCompileException() throws CompileException {
- Rvalue result = this.toRvalue();
- if (result == null) this.throwCompileException("Expression \"" + this.toString() + "\" is not an rvalue");
- return result;
- }
-
- /**
- * @return This atom, converted to an {@link Lvalue}
- * @throws CompileException This atom is not a {@link Lvalue}
- */
- public final Lvalue
- toLvalueOrCompileException() throws CompileException {
- Lvalue result = this.toLvalue();
- if (result == null) this.throwCompileException("Expression \"" + this.toString() + "\" is not an lvalue");
- return result;
- }
-
- /**
- * Invokes the '{@code visit...()}' method of {@link Visitor.AtomVisitor} for the concrete {@link Atom} type.
- */
- public abstract void
- accept(Visitor.AtomVisitor visitor);
- }
-
- /** Representation of a Java™ type. */
- public abstract static
- class Type extends Atom {
- private Scope enclosingScope;
-
- protected
- Type(Location location) { super(location); }
-
- /**
- * Sets the enclosing scope for this object and all subordinate {@link org.codehaus.janino.Java.Type} objects.
- */
- public void
- setEnclosingScope(final Scope enclosingScope) {
- if (this.enclosingScope != null && enclosingScope != this.enclosingScope) {
- throw new JaninoRuntimeException(
- "Enclosing scope already set for type \""
- + this.toString()
- + "\" at "
- + this.getLocation()
- );
- }
- this.enclosingScope = enclosingScope;
- }
-
- /** @return The enclosing scope (as previously set by {@link #setEnclosingScope(Java.Scope)}) */
- public Scope
- getEnclosingScope() { return this.enclosingScope; }
-
- @Override public Type
- toType() { return this; }
-
- /**
- * Invokes the '{@code visit...()}' method of {@link Visitor.TypeVisitor} for the concrete {@link Type} type.
- */
- public abstract void
- accept(Visitor.TypeVisitor visitor);
- }
-
- /** This class is not used when code is parsed; it is intended for "programmatic" types. */
- public static final
- class SimpleType extends Type {
-
- /** The {@link IClass} represented by this {@link Type}. */
- public final IClass iClass;
-
- public
- SimpleType(Location location, IClass iClass) {
- super(location);
- this.iClass = iClass;
- }
-
- @Override public String
- toString() { return this.iClass.toString(); }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitSimpleType(this); }
-
- @Override public void
- accept(Visitor.TypeVisitor visitor) { visitor.visitSimpleType(this); }
- }
-
- /** Representation of a JLS7 18 "basic type" (obviously equivalent to a JLS7 4.2 "primitive type"). */
- public static final
- class BasicType extends Type {
-
- /** One of {@link #VOID}, {@link #BYTE} and consorts. */
- public final int index;
-
- public
- BasicType(Location location, int index) {
- super(location);
- this.index = index;
- }
-
- @Override public String
- toString() {
- switch (this.index) {
- case BasicType.VOID:
- return "void";
- case BasicType.BYTE:
- return "byte";
- case BasicType.SHORT:
- return "short";
- case BasicType.CHAR:
- return "char";
- case BasicType.INT:
- return "int";
- case BasicType.LONG:
- return "long";
- case BasicType.FLOAT:
- return "float";
- case BasicType.DOUBLE:
- return "double";
- case BasicType.BOOLEAN:
- return "boolean";
- default:
- throw new JaninoRuntimeException("Invalid index " + this.index);
- }
- }
-
- @Override public void
- accept(Visitor.TypeVisitor visitor) { visitor.visitBasicType(this); }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitBasicType(this); }
-
- /** Value representing the VOID type. */
- public static final int VOID = 0;
-
- /** Value representing the BYTE type. */
- public static final int BYTE = 1;
-
- /** Value representing the SHORT type. */
- public static final int SHORT = 2;
-
- /** Value representing the CHAR type. */
- public static final int CHAR = 3;
-
- /** Value representing the INT type. */
- public static final int INT = 4;
-
- /** Value representing the LONG type. */
- public static final int LONG = 5;
-
- /** Value representing the FLOAT type. */
- public static final int FLOAT = 6;
-
- /** Value representing the DOUBLE type. */
- public static final int DOUBLE = 7;
-
- /** Value representing the BOOLEAN type. */
- public static final int BOOLEAN = 8;
- }
-
- /** representation of a JLS7 4.3 reference type. */
- public static final
- class ReferenceType extends Type implements TypeArgument {
-
- /** The list of (dot-separated) identifiers that pose the reference type, e.g. "java", "util", "Map". */
- public final String[] identifiers;
-
- /** The optional type arguments of the reference type. */
- public final TypeArgument[] optionalTypeArguments;
-
- public
- ReferenceType(Location location, String[] identifiers, TypeArgument[] optionalTypeArguments) {
- super(location);
- assert identifiers != null;
- this.identifiers = identifiers;
- this.optionalTypeArguments = optionalTypeArguments;
- }
-
- @Override public String
- toString() {
- String s = Java.join(this.identifiers, ".");
- if (this.optionalTypeArguments != null) s += '<' + Java.join(this.optionalTypeArguments, ", ") + ">";
- return s;
- }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitReferenceType(this); }
-
- @Override public void
- accept(Visitor.TypeVisitor visitor) { visitor.visitReferenceType(this); }
-
- @Override public void
- accept(TypeArgumentVisitor visitor) { visitor.visitReferenceType(this); }
- }
-
- /** Representation of a JLS7 4.5.1 type argument. */
- public
- interface TypeArgument {
-
- /**
- * Invokes the '{@code visit...()}' method of {@link Visitor.TypeArgumentVisitor} for the concrete {@link
- * TypeArgument} type.
- */
- void accept(Visitor.TypeArgumentVisitor visitor);
- }
-
- /**
- * Representation of the first part of a JLS7 15.9 'Qualified class instance creation expression': The 'a.new
- * MyClass' part of 'a.new MyClass(...)'.
- */
- public static final
- class RvalueMemberType extends Type {
-
- /** The expression that represents the outer instance required for the instantiation of the inner type. */
- public final Rvalue rvalue;
-
- /** The simple name of the inner type being instantiated. */
- public final String identifier;
-
- /** Notice: The {@code rvalue} is not a subordinate object! */
- public
- RvalueMemberType(Location location, Rvalue rvalue, String identifier) {
- super(location);
- this.rvalue = rvalue;
- this.identifier = identifier;
- }
-
- @Override public String
- toString() { return this.identifier; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitRvalueMemberType(this); }
-
- @Override public void
- accept(Visitor.TypeVisitor visitor) { visitor.visitRvalueMemberType(this); }
- }
-
- /** Representation of a JLS7 10.1 'array type'. */
- public static final
- class ArrayType extends Type implements TypeArgument {
-
- /** The (declared) type of the array's components. */
- public final Type componentType;
-
- public
- ArrayType(Type componentType) {
- super(componentType.getLocation());
- this.componentType = componentType;
- }
-
- @Override public void
- setEnclosingScope(final Scope enclosingScope) {
- super.setEnclosingScope(enclosingScope);
- this.componentType.setEnclosingScope(enclosingScope);
- }
-
- @Override public String
- toString() { return this.componentType.toString() + "[]"; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitArrayType(this); }
-
- @Override public void
- accept(Visitor.TypeVisitor visitor) { visitor.visitArrayType(this); }
-
- @Override public void
- accept(TypeArgumentVisitor visitor) { visitor.visitArrayType(this); }
- }
-
- /**
- * Representation of an "rvalue", i.e. an expression that has a type and
- * a value, but cannot be assigned to: An expression that can be the
- * right-hand-side of an assignment.
- */
- public abstract static
- class Rvalue extends Atom implements ArrayInitializerOrRvalue, ElementValue {
- private Java.BlockStatement enclosingBlockStatement;
-
- protected
- Rvalue(Location location) { super(location); }
-
- /** Sets enclosing block statement for this object and all subordinate {@link Java.Rvalue} objects. */
- public final void
- setEnclosingBlockStatement(final Java.BlockStatement enclosingBlockStatement) {
- this.accept((Visitor.RvalueVisitor) new Traverser() {
-
- @Override public void
- traverseRvalue(Java.Rvalue rv) {
- if (rv.enclosingBlockStatement != null && enclosingBlockStatement != rv.enclosingBlockStatement) {
- throw new JaninoRuntimeException(
- "Enclosing block statement for rvalue \""
- + rv
- + "\" at "
- + rv.getLocation()
- + " is already set"
- );
- }
- rv.enclosingBlockStatement = enclosingBlockStatement;
- super.traverseRvalue(rv);
- }
- @Override public void
- traverseAnonymousClassDeclaration(Java.AnonymousClassDeclaration acd) {
- acd.setEnclosingScope(enclosingBlockStatement);
- ;
- }
- @Override public void
- traverseType(Java.Type t) {
- if (t.enclosingScope != null && enclosingBlockStatement != t.enclosingScope) {
- throw new JaninoRuntimeException(
- "Enclosing scope already set for type \""
- + this.toString()
- + "\" at "
- + t.getLocation()
- );
- }
- t.enclosingScope = enclosingBlockStatement;
-// t.setEnclosingScope(enclosingBlockStatement);
- super.traverseType(t);
- }
- }.comprehensiveVisitor());
- }
-
- /**
- * @return The enclosing block statement, as set with {@link #setEnclosingBlockStatement(Java.BlockStatement)}
- */
- public Java.BlockStatement
- getEnclosingBlockStatement() { return this.enclosingBlockStatement; }
-
- @Override public Rvalue
- toRvalue() { return this; }
-
- /**
- * The special value for the {@link #constantValue} field indicating that this rvalue does not have a
- * constant value.
- */
- static final Object CONSTANT_VALUE_UNKNOWN = new Object() {
-
- @Override public String
- toString() { return "CONSTANT_VALUE_UNKNOWN"; }
- };
-
- /**
- * The constant value of this rvalue, or {@link #CONSTANT_VALUE_UNKNOWN} iff this rvalue does not have a
- * constant value.
- */
- Object constantValue = Java.Rvalue.CONSTANT_VALUE_UNKNOWN;
-
- /**
- * Invokes the '{@code visit...()}' method of {@link Visitor.RvalueVisitor} for the concrete {@link Rvalue}
- * type.
- */
- public abstract void accept(Visitor.RvalueVisitor rvv);
- }
-
- /** Base class for {@link Java.Rvalue}s that compile better as conditional branches. */
- public abstract static
- class BooleanRvalue extends Rvalue {
- protected BooleanRvalue(Location location) { super(location); }
- }
-
- /**
- * Representation of an "lvalue", i.e. an expression that has a type and
- * a value, and can be assigned to: An expression that can be the
- * left-hand-side of an assignment.
- */
- public abstract static
- class Lvalue extends Rvalue {
- protected Lvalue(Location location) { super(location); }
-
- @Override public Lvalue
- toLvalue() { return this; }
-
- /**
- * Invokes the '{@code visit...()}' method of {@link Visitor.LvalueVisitor} for the concrete {@link Lvalue}
- * type.
- */
- public abstract void
- accept(Visitor.LvalueVisitor lvv);
- }
-
- /**
- * Representation of a JLS7 6.5.2 'ambiguous name'.
- *
- * This class is special: It does not extend/implement the {@link Atom} subclasses, but overrides {@link Atom}'s
- * "{@code to...()}" methods.
- */
- public static final
- class AmbiguousName extends Lvalue {
-
- /** The first {@link #n} of these identifiers comprise this ambiguous name. */
- public final String[] identifiers;
-
- /** @see #identifiers */
- public final int n;
-
- public
- AmbiguousName(Location location, String[] identifiers) {
- this(location, identifiers, identifiers.length);
- }
- public
- AmbiguousName(Location location, String[] identifiers, int n) {
- super(location);
- this.identifiers = identifiers;
- this.n = n;
- }
-
- // Override "Atom.toType()".
- private Type type;
-
- @Override public Type
- toType() {
- if (this.type == null) {
- String[] is = new String[this.n];
- System.arraycopy(this.identifiers, 0, is, 0, this.n);
- this.type = new ReferenceType(this.getLocation(), is, null);
- this.type.setEnclosingScope(this.getEnclosingBlockStatement());
- }
- return this.type;
- }
-
- // Compile time members.
-
- @Override public String
- toString() { return Java.join(this.identifiers, ".", 0, this.n); }
-
- @Override public Lvalue
- toLvalue() {
- if (this.reclassified != null) { return this.reclassified.toLvalue(); }
- return this;
- }
-
- @Override public Rvalue
- toRvalue() {
- if (this.reclassified != null) { return this.reclassified.toRvalue(); }
- return this;
- }
-
- /** The result of 'ambiguous name resolution' furing compilation. */
- Atom reclassified;
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitAmbiguousName(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitAmbiguousName(this); }
-
- @Override public void
- accept(Visitor.LvalueVisitor visitor) { visitor.visitAmbiguousName(this); }
-
- @Override public void
- accept(Visitor.ElementValueVisitor visitor) { visitor.visitAmbiguousName(this); }
- }
-
- /** Representation of a JLS7 6.5.2.1.5 'package name'. */
- public static final
- class Package extends Atom {
-
- /** The complete name of a package, e.g. 'java' or 'java.util'. */
- public final String name;
-
- public
- Package(Location location, String name) {
- super(location);
- this.name = name;
- }
-
- @Override public String
- toString() { return this.name; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitPackage(this); }
- }
-
- /** Representation of a local variable access -- used during compilation. */
- public static final
- class LocalVariableAccess extends Lvalue {
-
- /** The local variable that is accessed. */
- public final LocalVariable localVariable;
-
- public
- LocalVariableAccess(Location location, LocalVariable localVariable) {
- super(location);
- this.localVariable = localVariable;
- }
-
- // Compile time members.
-
- @Override public String
- toString() { return this.localVariable.toString(); }
-
- @Override public void
- accept(Visitor.LvalueVisitor visitor) { visitor.visitLocalVariableAccess(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitLocalVariableAccess(this); }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitLocalVariableAccess(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitLocalVariableAccess(this); }
- }
-
- /**
- * Representation of an access to a field of a class or an interface. (Does not implement the {@link ArrayLength},
- * e.g. "myArray.length".)
- */
- public static final
- class FieldAccess extends Lvalue {
-
- /**
- * The left-hand-side of the field access - either a type or an rvalue (which includes all
- * lvalues).
- */
- public final Atom lhs;
-
- /** The field within the class or instance identified by the {@link #lhs}. */
- public final IClass.IField field;
-
- public
- FieldAccess(Location location, Atom lhs, IClass.IField field) {
- super(location);
- this.lhs = lhs;
- this.field = field;
- }
-
- // Compile time members.
-
- // Implement "Atom".
-
- @Override public String
- toString() { return this.lhs.toString() + '.' + this.field.getName(); }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitFieldAccess(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitFieldAccess(this); }
-
- @Override public void
- accept(Visitor.LvalueVisitor visitor) { visitor.visitFieldAccess(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitFieldAccess(this); }
- }
-
- /** Representation of the JLS7 10.7 array type 'length' pseudo-member. */
- public static final
- class ArrayLength extends Rvalue {
-
- /** The rvalue identifying the array to determine the length of. */
- public final Rvalue lhs;
-
- public
- ArrayLength(Location location, Rvalue lhs) {
- super(location);
- this.lhs = lhs;
- }
-
- // Compile time members.
-
- // Implement "Atom".
-
- @Override public String
- toString() { return this.lhs.toString() + ".length"; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitArrayLength(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitArrayLength(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitArrayLength(this); }
- }
-
- /** Representation of an JLS7 15.8.3 access to the innermost enclosing instance. */
- public static final
- class ThisReference extends Rvalue {
-
- public
- ThisReference(Location location) { super(location); }
-
- // Compile time members.
-
- /** A cache for the type of the instance that 'this' refers to. */
- IClass iClass;
-
- // Implement "Atom".
-
- @Override public String
- toString() { return "this"; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitThisReference(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitThisReference(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitThisReference(this); }
- }
-
- /** Representation of an JLS7 15.8.4 access to the current object or an enclosing instance. */
- public static final
- class QualifiedThisReference extends Rvalue {
-
- /** The qualification left from the 'this' keyword. */
- public final Type qualification;
-
- public
- QualifiedThisReference(Location location, Type qualification) {
- super(location);
-
- if (qualification == null) throw new NullPointerException();
- this.qualification = qualification;
- }
-
- // Compile time members.
-
- /** The innermost enclosing class declaration. */
- ClassDeclaration declaringClass;
-
- /**
- * The innermost 'type body declaration' enclosing this 'qualified this reference', i.e. the method,
- * type initializer or field initializer.
- */
- TypeBodyDeclaration declaringTypeBodyDeclaration;
-
- /** The resolved {@link #qualification}. */
- IClass targetIClass;
-
- // Implement "Atom".
-
- @Override public String
- toString() { return this.qualification.toString() + ".this"; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitQualifiedThisReference(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitQualifiedThisReference(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitQualifiedThisReference(this); }
- }
-
- /** Representation of a JLS7 15.8.2 'class literal'. */
- public static final
- class ClassLiteral extends Rvalue {
-
- /** The type left of the '.class' suffix. */
- public final Type type;
-
- public
- ClassLiteral(Location location, Type type) {
- super(location);
- this.type = type;
- }
-
- // Implement "Atom".
-
- @Override public String
- toString() { return this.type.toString() + ".class"; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitClassLiteral(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitClassLiteral(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitClassLiteral(this); }
- }
-
- /** Representation of all JLS7 15.26 assignments. */
- public static final
- class Assignment extends Rvalue {
-
- /** The lvalue to assign to. */
- public final Lvalue lhs;
-
- /**
- * The assignment operator; either the 'simple assignment operator ('=', JLS7 15.26.1) or one of the 'compound
- * assignment operators (JLS7 15.26.2).
- */
- public final String operator;
-
- /** The rvalue that is assigned. */
- public final Rvalue rhs;
-
- public
- Assignment(Location location, Lvalue lhs, String operator, Rvalue rhs) {
- super(location);
- this.lhs = lhs;
- this.operator = operator;
- this.rhs = rhs;
- }
-
- // Compile time members.
-
- // Implement "Atom".
-
- @Override public String
- toString() { return this.lhs.toString() + ' ' + this.operator + ' ' + this.rhs.toString(); }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitAssignment(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitAssignment(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitAssignment(this); }
- }
-
- /** Representation of a JLS7 15.25 'conditional operation'. */
- public static final
- class ConditionalExpression extends Rvalue {
-
- /** Left-hand side of this conditional operation. */
- public final Rvalue lhs;
-
- /** Middle-hand side of this conditional operation. */
- public final Rvalue mhs;
-
- /** Right-hand side of this conditional operation. */
- public final Rvalue rhs;
-
- public
- ConditionalExpression(Location location, Rvalue lhs, Rvalue mhs, Rvalue rhs) {
- super(location);
- this.lhs = lhs;
- this.mhs = mhs;
- this.rhs = rhs;
- }
-
- // Implement "Atom".
-
- @Override public String
- toString() { return this.lhs.toString() + " ? " + this.mhs.toString() + " : " + this.rhs.toString(); }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitConditionalExpression(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitConditionalExpression(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitConditionalExpression(this); }
- }
-
- /**
- * Representation of a JLS7 15.14.2 'postfix increment operation', a JLS7 15.14.3 'postfix decrement operation', a
- * JLS7 15.15.1 'prefix increment operation' or a JLS7 15.15.2 'prefix decrement operation'.
- */
- public static final
- class Crement extends Rvalue {
-
- /** Whether this operation is 'pre' (TRUE) or 'post' (FALSE). */
- public final boolean pre;
-
- /** The operator; either "++" or "--". */
- public final String operator;
-
- /** The lvalue to operate upon. */
- public final Lvalue operand;
-
- public
- Crement(Location location, String operator, Lvalue operand) {
- super(location);
- this.pre = true;
- this.operator = operator;
- this.operand = operand;
- }
- public
- Crement(Location location, Lvalue operand, String operator) {
- super(location);
- this.pre = false;
- this.operator = operator;
- this.operand = operand;
- }
-
- // Compile time members.
-
- // Implement "Atom".
-
- @Override public String
- toString() { return this.pre ? this.operator + this.operand : this.operand + this.operator; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitCrement(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitCrement(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitCrement(this); }
- }
-
- /** Representation of a JLS7 15.13 'array access expression'. */
- public static final
- class ArrayAccessExpression extends Lvalue {
-
- /** The array to access (must be an {@link Lvalue} if the access is modifying). */
- public final Rvalue lhs;
-
- /** The index value to use. */
- public final Rvalue index;
-
- public
- ArrayAccessExpression(Location location, Rvalue lhs, Rvalue index) {
- super(location);
- this.lhs = lhs;
- this.index = index;
- }
-
- // Compile time members:
-
- // Implement "Atom".
-
- @Override public String
- toString() { return this.lhs.toString() + '[' + this.index + ']'; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitArrayAccessExpression(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitArrayAccessExpression(this); }
-
- @Override public void
- accept(Visitor.LvalueVisitor visitor) { visitor.visitArrayAccessExpression(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitArrayAccessExpression(this); }
- }
-
- /** Representation of a JLS7 15.11 'field access expression', including the "array length" pseudo field access. */
- public static final
- class FieldAccessExpression extends Lvalue {
-
- /** {@link Type}, {@link Rvalue} or {@link Lvalue} to operate upon. */
- public final Atom lhs;
-
- /** Name of the field within the {@link #lhs} to access. */
- public final String fieldName;
-
- public
- FieldAccessExpression(Location location, Atom lhs, String fieldName) {
- super(location);
- this.lhs = lhs;
- this.fieldName = fieldName;
- }
-
- // Compile time members:
-
- // Implement "Atom".
-
- @Override public String
- toString() { return this.lhs.toString() + '.' + this.fieldName; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitFieldAccessExpression(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitFieldAccessExpression(this); }
-
- @Override public void
- accept(Visitor.LvalueVisitor visitor) { visitor.visitFieldAccessExpression(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitFieldAccessExpression(this); }
-
- /** The {@link ArrayLength} or {@link FieldAccess} resulting from this 'field access expression'. */
- Rvalue value;
- }
-
- /** Representation of an JLS7 'superclass field access expression', e.g. "super.fld" and "Type.super.fld". */
- public static final
- class SuperclassFieldAccessExpression extends Lvalue {
-
- /** The optional qualification before '.super.fld'. */
- public final Type optionalQualification;
-
- /** The name of the field to access. */
- public final String fieldName;
-
- public
- SuperclassFieldAccessExpression(Location location, Type optionalQualification, String fieldName) {
- super(location);
- this.optionalQualification = optionalQualification;
- this.fieldName = fieldName;
- }
-
- // Compile time members.
-
- // Implement "Atom".
-
- @Override public String
- toString() {
- return (
- this.optionalQualification == null
- ? "super."
- : this.optionalQualification.toString() + ".super."
- ) + this.fieldName;
- }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitSuperclassFieldAccessExpression(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitSuperclassFieldAccessExpression(this); }
-
- @Override public void
- accept(Visitor.LvalueVisitor visitor) { visitor.visitSuperclassFieldAccessExpression(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitSuperclassFieldAccessExpression(this); }
-
- /** The {@link FieldAccess} that implements this {@link FieldAccessExpression}. */
- Rvalue value;
- }
-
- /**
- * Representation of a JLS7 15.15.3 'unary plus operator', a JLS7 15.15.4 'unary minus operator', a JLS7 15.15.5
- * 'bitwise complement operator' or a JLS7 15.15.6 'logical complement operator'.
- */
- public static final
- class UnaryOperation extends BooleanRvalue {
-
- /** The operator (either "+", "-", "~" or "!"). */
- public final String operator;
-
- /** The rvalue to operate upon. */
- public final Rvalue operand;
-
- public
- UnaryOperation(Location location, String operator, Rvalue operand) {
- super(location);
- this.operator = operator;
- this.operand = operand;
- }
-
- // Implement "Atom".
-
- @Override public String
- toString() { return this.operator + this.operand.toString(); }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitUnaryOperation(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitUnaryOperation(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitUnaryOperation(this); }
- }
-
- /** Representation of a JLS7 15.20.2 'type comparison operation'. */
- public static final
- class Instanceof extends Rvalue {
-
- /** The rvalue who's type is to be compared. */
- public final Rvalue lhs;
-
- /** The type that the {@link #lhs} is checked against. */
- public final Type rhs;
-
- public
- Instanceof(Location location, Rvalue lhs, Type rhs) {
- super(location);
- this.lhs = lhs;
- this.rhs = rhs;
- }
-
- // Compile time members.
-
- // Implement "Atom".
-
- @Override public String
- toString() { return this.lhs.toString() + " instanceof " + this.rhs.toString(); }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitInstanceof(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitInstanceof(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitInstanceof(this); }
- }
-
- /**
- * Representation of all non-operand-modifying binary operations.
- *
- * Operations with boolean result:
- *
- * ||
- * JLS7 15.24 'conditional or operation'
- * &&
- * JLS7 15.23 'conditional and operation'
- * ==
- * JLS7 15.21 'equality operation'
- * !=
- * JLS7 15.22 'non-equality operation'
- * < > <= >=
- * JLS7 15.20.1 'numerical comparison operations'
- *
- * Operations with non-boolean result:
- *
- * |
- * JLS7 15.22.1 'integer bitwise OR operation' and JLS7 15.22.2 'boolean logical OR operation'
- * ^
- * JLS7 15.22.1 'integer bitwise XOR operation' and JLS7 15.22.2 'boolean logical XOR operation'
- * &
- * JLS7 15.22.1 'integer bitwise AND operation' and JLS7 15.22.2 'boolean logical AND operation'
- * * / %
- * JLS7 15.17 'multiplicative operations'
- * + -
- * JLS7 15.18 'additive operations'
- * << >> >>>
- * JLS7 15.19 'shift operations'
- *
- */
- public static final
- class BinaryOperation extends BooleanRvalue {
-
- /** The left hand side operand. */
- public final Rvalue lhs;
-
- /** The operator; one of thos described in {@link BinaryOperation}. */
- public final String op;
-
- /** The right hand side operand. */
- public final Rvalue rhs;
-
- public
- BinaryOperation(Location location, Rvalue lhs, String op, Rvalue rhs) {
- super(location);
- this.lhs = lhs;
- this.op = op;
- this.rhs = rhs;
- }
-
- // Compile time members.
-
- // Implement "Atom".
-
- @Override public String
- toString() { return this.lhs.toString() + ' ' + this.op + ' ' + this.rhs.toString(); }
-
- /** Returns an {@link Iterator} over a left-to-right sequence of {@link Java.Rvalue}s. */
- public Iterator
- unrollLeftAssociation() {
- List operands = new ArrayList();
- BinaryOperation bo = this;
- for (;;) {
- operands.add(bo.rhs);
- Rvalue lhs = bo.lhs;
- if (lhs instanceof BinaryOperation && ((BinaryOperation) lhs).op == this.op) {
- bo = (BinaryOperation) lhs;
- } else {
- operands.add(lhs);
- break;
- }
- }
- return new ReverseListIterator(operands.listIterator(operands.size()));
- }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitBinaryOperation(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitBinaryOperation(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitBinaryOperation(this); }
- }
-
- /** Representation of a JLS7 15.16 'cast expression'. */
- public static final
- class Cast extends Rvalue {
-
- /** The type to convert to. */
- public final Type targetType;
-
- /** The rvalue to convert. */
- public final Rvalue value;
-
- public
- Cast(Location location, Type targetType, Rvalue value) {
- super(location);
- this.targetType = targetType;
- this.value = value;
- }
-
- // Compile time members.
-
- // Implement "Atom".
-
- @Override public String
- toString() { return '(' + this.targetType.toString() + ") " + this.value.toString(); }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitCast(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitCast(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitCast(this); }
- }
-
- /** Representation of a JLS7 15.8.5 'parenthesized expression'. */
- public static final
- class ParenthesizedExpression extends Lvalue {
-
- /** The rvalue in parentheses. */
- public final Rvalue value;
-
- public
- ParenthesizedExpression(Location location, Rvalue value) {
- super(location);
- this.value = value;
- }
-
- // Implement 'Atom'.
-
- @Override public String
- toString() { return '(' + this.value.toString() + ')'; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitParenthesizedExpression(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitParenthesizedExpression(this); }
-
- @Override public void
- accept(Visitor.LvalueVisitor visitor) { visitor.visitParenthesizedExpression(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitParenthesizedExpression(this); }
- }
-
- /** Abstract bas class for {@link SuperConstructorInvocation} and {@link AlternateConstructorInvocation}. */
- public abstract static
- class ConstructorInvocation extends Atom implements BlockStatement {
-
- /** The arguments to pass to the constructor. */
- public final Rvalue[] arguments;
-
- private Scope enclosingScope;
-
- protected
- ConstructorInvocation(Location location, Rvalue[] arguments) {
- super(location);
- this.arguments = arguments;
- for (Rvalue a : arguments) a.setEnclosingBlockStatement(this);
- }
-
- // Implement BlockStatement
-
- @Override public void
- setEnclosingScope(Scope enclosingScope) {
- if (this.enclosingScope != null && enclosingScope != null) {
- throw new JaninoRuntimeException(
- "Enclosing scope is already set for statement \""
- + this.toString()
- + "\" at "
- + this.getLocation()
- );
- }
- this.enclosingScope = enclosingScope;
- }
-
- @Override public Scope
- getEnclosingScope() { return this.enclosingScope; }
-
- /** The local variables that are accessible during the compilation of the constructor invocation. */
- public Map localVariables;
-
- @Override public Java.LocalVariable
- findLocalVariable(String name) {
- if (this.localVariables == null) { return null; }
- return (LocalVariable) this.localVariables.get(name);
- }
- }
-
- /** Representation of a JLS7 8.8.7.1. 'alternate constructor invocation'. */
- public static final
- class AlternateConstructorInvocation extends ConstructorInvocation {
-
- public
- AlternateConstructorInvocation(Location location, Rvalue[] arguments) { super(location, arguments); }
-
- // Implement Atom.
-
- @Override public String
- toString() { return "this()"; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) {
- ((Visitor.BlockStatementVisitor) visitor).visitAlternateConstructorInvocation(this);
- }
-
- // Implement BlockStatement.
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitAlternateConstructorInvocation(this); }
- }
-
- /** Representation of a JLS7 8.8.7.1. 'superclass constructor invocation'. */
- public static final
- class SuperConstructorInvocation extends ConstructorInvocation {
-
- /**
- * The qualification for this 'qualified superclass constructor invocation', or {@code null} iff this is an
- * 'unqualified superclass constructor invocation'.
- */
- public final Rvalue optionalQualification;
-
- public
- SuperConstructorInvocation(Location location, Rvalue optionalQualification, Rvalue[] arguments) {
- super(location, arguments);
- this.optionalQualification = optionalQualification;
- if (optionalQualification != null) optionalQualification.setEnclosingBlockStatement(this);
- }
-
- // Implement Atom.
-
- @Override public String
- toString() { return "super()"; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) {
- ((Visitor.BlockStatementVisitor) visitor).visitSuperConstructorInvocation(this);
- }
-
- // Implement BlockStatement.
-
- @Override public void
- accept(Visitor.BlockStatementVisitor visitor) { visitor.visitSuperConstructorInvocation(this); }
- }
-
- /** Representation of a JLS7 15.12 'method invocation expression'. */
- public static final
- class MethodInvocation extends Invocation {
-
- /** The optional type or rvalue that qualifies this method invocation. */
- public final Atom optionalTarget;
-
- public
- MethodInvocation(Location location, Atom optionalTarget, String methodName, Rvalue[] arguments) {
- super(location, methodName, arguments);
- this.optionalTarget = optionalTarget;
- }
-
- // Implement "Atom".
-
- /** The resolved {@link IMethod}. */
- IClass.IMethod iMethod;
-
- @Override public String
- toString() {
- StringBuilder sb = new StringBuilder();
- if (this.optionalTarget != null) sb.append(this.optionalTarget.toString()).append('.');
- sb.append(this.methodName).append('(');
- for (int i = 0; i < this.arguments.length; ++i) {
- if (i > 0) sb.append(", ");
- sb.append(this.arguments[i].toString());
- }
- sb.append(')');
- return sb.toString();
- }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitMethodInvocation(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitMethodInvocation(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitMethodInvocation(this); }
- }
-
- /** Representation of a JLS7 15.12.1.1.3 'superclass method invocation'. */
- public static final
- class SuperclassMethodInvocation extends Invocation {
-
- public
- SuperclassMethodInvocation(Location location, String methodName, Rvalue[] arguments) {
- super(location, methodName, arguments);
- }
-
- // Implement "Atom".
-
- @Override public String
- toString() { return "super." + this.methodName + "()"; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitSuperclassMethodInvocation(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitSuperclassMethodInvocation(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitSuperclassMethodInvocation(this); }
- }
-
- /** Abstract base class for {@link MethodInvocation} and {@link SuperclassMethodInvocation}. */
- public abstract static
- class Invocation extends Rvalue {
-
- /** name of the invoked method. */
- public final String methodName;
-
- /** Arguments to pass to the method. */
- public final Rvalue[] arguments;
-
- protected
- Invocation(Location location, String methodName, Rvalue[] arguments) {
- super(location);
- this.methodName = methodName;
- this.arguments = arguments;
- }
- }
-
- /** Representation of a JLS7 'class instance creation expression'. */
- public static final
- class NewClassInstance extends Rvalue {
-
- /** The qualification of this 'qualified class instance creation expression'. */
- public final Rvalue optionalQualification;
-
- /** The type to instantiate. */
- public final Type type;
-
- /** The arguments to pass to the constructor. */
- public final Rvalue[] arguments;
-
- public
- NewClassInstance(Location location, Rvalue optionalQualification, Type type, Rvalue[] arguments) {
- super(location);
- this.optionalQualification = optionalQualification;
- this.type = type;
- this.arguments = arguments;
- }
-
- // Compile time members.
-
- /** The resolved {@link #type}. */
- protected IClass iClass;
-
- public
- NewClassInstance(Location location, Rvalue optionalQualification, IClass iClass, Rvalue[] arguments) {
- super(location);
- this.optionalQualification = optionalQualification;
- this.type = null;
- this.arguments = arguments;
- this.iClass = iClass;
- }
-
- // Implement "Atom".
-
- @Override public String
- toString() {
- StringBuilder sb = new StringBuilder();
- if (this.optionalQualification != null) sb.append(this.optionalQualification.toString()).append('.');
- sb.append("new ");
- if (this.type != null) {
- sb.append(this.type.toString());
- } else
- if (this.iClass != null) {
- sb.append(this.iClass.toString());
- } else {
- sb.append("???");
- }
- sb.append('(');
- for (int i = 0; i < this.arguments.length; ++i) {
- if (i > 0) sb.append(", ");
- sb.append(this.arguments[i].toString());
- }
- sb.append(')');
- return sb.toString();
- }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitNewClassInstance(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitNewClassInstance(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitNewClassInstance(this); }
- }
-
- /** Representation of a JLS7 15.9 'anonymous class instance creation expression'. */
- public static final
- class NewAnonymousClassInstance extends Rvalue {
-
- /** The qualification iff this a 'qualified anonymous class instance creation expression'. */
- public final Rvalue optionalQualification;
-
- /** The declaration of the anonymous class to instantiate. */
- public final AnonymousClassDeclaration anonymousClassDeclaration;
-
- /** The arguments to pass to the constructor. */
- public final Rvalue[] arguments;
-
- public
- NewAnonymousClassInstance(
- Location location,
- Rvalue optionalQualification,
- AnonymousClassDeclaration anonymousClassDeclaration,
- Rvalue[] arguments
- ) {
- super(location);
- this.optionalQualification = optionalQualification;
- this.anonymousClassDeclaration = anonymousClassDeclaration;
- this.arguments = arguments;
- }
-
- // Implement "Atom".
-
- @Override public String
- toString() {
- StringBuilder sb = new StringBuilder();
- if (this.optionalQualification != null) sb.append(this.optionalQualification.toString()).append('.');
- sb.append("new ").append(this.anonymousClassDeclaration.baseType.toString()).append("() { ... }");
- return sb.toString();
- }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitNewAnonymousClassInstance(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitNewAnonymousClassInstance(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitNewAnonymousClassInstance(this); }
- }
-
- /** 'Artificial' operation for accessing the parameters of the synthetic constructor of an anonymous class. */
- public static final
- class ParameterAccess extends Rvalue {
-
- /** The parameter to access. */
- public final FormalParameter formalParameter;
-
- public
- ParameterAccess(Location location, FormalParameter formalParameter) {
- super(location);
- this.formalParameter = formalParameter;
- }
-
- // Implement Atom
-
- @Override public String
- toString() { return this.formalParameter.name; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitParameterAccess(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitParameterAccess(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitParameterAccess(this); }
- }
-
- /** Representation of a JLS7 15.10 'array creation expression'. */
- public static final
- class NewArray extends Rvalue {
-
- /**
- * The component type of the ({@link #dimExprs}{@code .length + }{@link #dims})-dimensional array to
- * instantiate.
- */
- public final Type type;
-
- /** The sizes of the first dimensions to instantiate. */
- public final Rvalue[] dimExprs;
-
- /** The count of additional dimensions that the array should have. */
- public final int dims;
-
- /**
- * Create a new array with dimension dimExprs.length + dims
- *
- * e.g. byte[12][][] is created with
- *
- * new NewArray(
- * null,
- * Java.BasicType(NULL, Java.BasicType.BYTE),
- * new Rvalue[] { new Java.Literal(null, Integer.valueOf(12) },
- * 2
- * )
- *
- *
- * @param location the location of this element
- * @param type the base type of the array
- * @param dimExprs sizes for dimensions being allocated with specific sizes
- * @param dims the number of dimensions that are not yet allocated
- */
- public
- NewArray(Location location, Type type, Rvalue[] dimExprs, int dims) {
- super(location);
- this.type = type;
- this.dimExprs = dimExprs;
- this.dims = dims;
- }
-
- // Implement "Atom".
-
- @Override public String
- toString() { return "new " + this.type.toString() + "[]..."; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitNewArray(this); }
-
- // Implement "Rvalue".
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitNewArray(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitNewArray(this); }
- }
-
- /** Representation of a JLS7 15.10 'array creation expression'. */
- public static final
- class NewInitializedArray extends Rvalue {
-
- /** The array type to be instantiated. */
- public final ArrayType arrayType;
-
- /** The (mandatory) initializer for the array. */
- public final ArrayInitializer arrayInitializer;
-
- /** The resolved {@link #arrayType}. */
- public final IClass arrayIClass;
-
- public
- NewInitializedArray(Location location, ArrayType arrayType, ArrayInitializer arrayInitializer) {
- super(location);
- this.arrayType = arrayType;
- this.arrayInitializer = arrayInitializer;
- this.arrayIClass = null;
- }
-
- NewInitializedArray(Location location, IClass arrayIClass, ArrayInitializer arrayInitializer) {
- super(location);
- this.arrayType = null;
- this.arrayInitializer = arrayInitializer;
- this.arrayIClass = arrayIClass;
- }
-
- // Implement "Atom".
-
- @Override public String
- toString() { return "new " + this.arrayType.toString() + " { ... }"; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitNewInitializedArray(this); }
-
- // Implement "Rvalue".
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitNewInitializedArray(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitNewInitializedArray(this); }
- }
-
- /**
- * Representation of a JLS7 10.6 'array initializer'.
- *
- * Allocates an array and initializes its members with (not necessarily
- * constant) values.
- */
- public static final
- class ArrayInitializer extends Located implements ArrayInitializerOrRvalue {
-
- /** The values to assign to the array elements. */
- public final ArrayInitializerOrRvalue[] values;
-
- public
- ArrayInitializer(Location location, ArrayInitializerOrRvalue[] values) {
- super(location);
- this.values = values;
- }
-
- @Override public String
- toString() { return " { (" + this.values.length + " values) }"; }
- }
-
- /** The union of {@link ArrayInitializer} and {@link Rvalue}. */
- public
- interface ArrayInitializerOrRvalue extends Locatable {
- }
-
- /** Abstract base class for the various Java™ literals; see JLS7 3.10. */
- public abstract static
- class Literal extends Rvalue {
-
- /** The text of the literal token, as in the source code. */
- public final String value;
-
- /** @param value The text of the literal token, as in the source code */
- public Literal(Location location, String value) { super(location); this.value = value; }
-
- // Implement "Atom".
-
- @Override public String
- toString() { return this.value; }
- }
-
- /** Representation of an "integer literal" (JLS7 3.10.1) (types {@code int} and {@code long}). */
- public static final
- class IntegerLiteral extends Literal {
- public IntegerLiteral(Location location, String value) { super(location, value); }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitIntegerLiteral(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitIntegerLiteral(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitIntegerLiteral(this); }
- }
-
- /** Representation of a "floating-point literal" (JLS7 3.10.2) (types {@code float} and {@code double}). */
- public static final
- class FloatingPointLiteral extends Literal {
- public FloatingPointLiteral(Location location, String value) { super(location, value); }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitFloatingPointLiteral(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitFloatingPointLiteral(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitFloatingPointLiteral(this); }
- }
-
- /** Representation of a "boolean literal" (JLS7 3.10.3) (type {@code boolean}). */
- public static final
- class BooleanLiteral extends Literal {
- public BooleanLiteral(Location location, String value) { super(location, value); }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitBooleanLiteral(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitBooleanLiteral(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitBooleanLiteral(this); }
- }
-
- /** Representation of a "character literal" (JLS7 3.10.4) (type {@code char}). */
- public static final
- class CharacterLiteral extends Literal {
- public CharacterLiteral(Location location, String value) { super(location, value); }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitCharacterLiteral(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitCharacterLiteral(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitCharacterLiteral(this); }
- }
-
- /** Representation of a "string literal" (JLS7 3.10.5) (type {@link String}). */
- public static final
- class StringLiteral extends Literal {
- public StringLiteral(Location location, String value) { super(location, value); }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitStringLiteral(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitStringLiteral(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitStringLiteral(this); }
- }
-
- /** Representation of a "null literal" (JLS7 3.10.7). */
- public static final
- class NullLiteral extends Literal {
- public NullLiteral(Location location, String value) { super(location, value); }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitNullLiteral(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitNullLiteral(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitNullLiteral(this); }
- }
-
- /** This class is not used when code is parsed; it is intended for "programmatic" literals. */
- public static final
- class SimpleConstant extends Rvalue {
-
- /**
- * The value represented by this constant; either {@code null} (representing the {@code null} literal), a
- * {@link Byte}, {@link Short}, {@link Integer}, {@link Long}, {@link Float}, {@link Double}, {@link
- * Character}, {@link Boolean} or {@link String}.
- *
- * @see #SimpleConstant(Location)
- * @see #SimpleConstant(Location,byte)
- * @see #SimpleConstant(Location,short)
- * @see #SimpleConstant(Location,int)
- * @see #SimpleConstant(Location,long)
- * @see #SimpleConstant(Location,float)
- * @see #SimpleConstant(Location,double)
- * @see #SimpleConstant(Location,char)
- * @see #SimpleConstant(Location,boolean)
- * @see #SimpleConstant(Location,String)
- */
- final Object value;
-
- /** Equivalent of the {@code null} literal. */
- public SimpleConstant(Location location) { super(location); this.value = null; }
-
- /** Equivalent of an literal, casted to {@code byte}. */
- public SimpleConstant(Location location, byte value) { super(location); this.value = value; }
-
- /** Equivalent of an literal, casted to {@code short}. */
- public SimpleConstant(Location location, short value) { super(location); this.value = value; }
-
- /** Equivalent of an {@link IntegerLiteral} with type {@code int}. */
- public SimpleConstant(Location location, int value) { super(location); this.value = value; }
-
- /** Equivalent of an {@link IntegerLiteral} with type {@code long}. */
- public SimpleConstant(Location location, long value) { super(location); this.value = value; }
-
- /**
- * Equivalent of a {@link FloatingPointLiteral} with type {@code float}.
- * Notice that this class supports the special values {@link Float#NaN}, {@link Float#NEGATIVE_INFINITY} and
- * {@link Float#POSITIVE_INFINITY}, which can not be represented with a {@link FloatingPointLiteral}.
- */
- public SimpleConstant(Location location, float value) { super(location); this.value = value; }
-
- /**
- * Equivalent of a {@link FloatingPointLiteral} with type {@code double}.
- * Notice that this class supports the special values {@link Double#NaN}, {@link Double#NEGATIVE_INFINITY} and
- * {@link Double#POSITIVE_INFINITY}, which can not be represented with a {@link FloatingPointLiteral}.
- */
- public SimpleConstant(Location location, double value) { super(location); this.value = value; }
-
- /** Equivalent of a {@link CharacterLiteral}. */
- public SimpleConstant(Location location, char value) { super(location); this.value = value; }
-
- /** Equivalent of a {@link BooleanLiteral}. */
- public SimpleConstant(Location location, boolean value) { super(location); this.value = value; }
-
- /**
- * Equivalent of a {@link StringLiteral}, or, if {@code value} is null, the equivalent of a {@link
- * NullLiteral}.
- */
- public SimpleConstant(Location location, String value) { super(location); this.value = value; }
-
- @Override public void
- accept(Visitor.AtomVisitor visitor) { visitor.visitSimpleConstant(this); }
-
- @Override public void
- accept(Visitor.RvalueVisitor visitor) { visitor.visitSimpleConstant(this); }
-
- @Override public void
- accept(ElementValueVisitor visitor) { visitor.visitSimpleConstant(this); }
-
- @Override public String
- toString() { return "[" + this.value + ']'; }
- }
-
- /**
- * All local variables have a slot number; local variables that get written into the 'localvariabletable'
- * also have a start and end offset that defines the variable's extent in the bytecode. If the name is null,
- * or variable debugging is not on, then the variable won't be written into the localvariabletable and the
- * offsets can be ignored.
- */
- public static
- class LocalVariableSlot {
-
- private short slotIndex = -1;
- private String name;
- private final IClass type;
- private Offset start, end;
-
- public
- LocalVariableSlot(String name, short slotNumber, IClass type) {
- this.name = name;
- this.slotIndex = slotNumber;
- this.type = type;
- }
-
- @Override public String
- toString() {
- StringBuilder buf = new StringBuilder("local var(").append(this.name).append(", ").append(this.slotIndex);
- if (this.name != null) {
- buf.append(", ").append(this.type);
- buf.append(", ").append(this.start.offset);
- buf.append(", ").append(this.end.offset);
- }
- buf.append(")");
-
- return buf.toString();
- }
-
- /** @return The 'local variable index' associated with this local variable */
- public short getSlotIndex() { return this.slotIndex; }
- /** @param slotIndex The 'local variable index' to associate with this local variable */
- public void setSlotIndex(short slotIndex) { this.slotIndex = slotIndex; }
-
- /** @return The name of this local variable */
- public String getName() { return this.name; }
- /** @param name The name of this local variable */
- public void setName(String name) { this.name = name; }
-
- /** @return The {@link Offset} from which this local variable is visible */
- public Offset getStart() { return this.start; }
- /** @param start The {@link Offset} from which this local variable is visible */
- public void setStart(Offset start) { this.start = start; }
-
- /** @return The {@link Offset} up to which this local variable is visible */
- public Offset getEnd() { return this.end; }
- /** @param end The {@link Offset} up to which this local variable is visible */
- public void setEnd(Offset end) { this.end = end; }
-
- /** @return the resolved type of this local variable */
- public IClass getType() { return this.type; }
- }
-
- /** Representation of a local variable while it is in scope during compilation. */
- public static
- class LocalVariable {
-
- /** Whether this local variable has the FINAL modifier flag. */
- public final boolean finaL;
-
- /** The type of this local variable. */
- public final IClass type;
-
- /** The slot reserved for this local variable. */
- public LocalVariableSlot slot;
-
- public
- LocalVariable(boolean finaL, IClass type) {
- this.finaL = finaL;
- this.type = type;
- }
-
- @Override public String
- toString() {
- StringBuilder sb = new StringBuilder();
-
- if (this.finaL) sb.append("final ");
- sb.append(this.type).append(" ");
-
- return sb.toString();
- }
-
- /** @param slot The slot to reserve for this local variable */
- public void setSlot(LocalVariableSlot slot) { this.slot = slot; }
-
- /** @return The slot reserved for this local variable */
- public short
- getSlotIndex() {
- if (this.slot == null) return -1;
- return this.slot.getSlotIndex();
- }
- }
-
- /** Representation of a JLS7 4.5.1 'wildcard'. */
- public static
- class Wildcard implements TypeArgument {
-
- /**
- * Value for {@link #bounds} indicating that this wildcard has no bounds; {@link #referenceType} is irrelevant
- * in this case.
- */
- public static final int BOUNDS_NONE = 0;
-
- /** Value for {@link #bounds} indicating that this wildcard has 'extends' bounds. */
- public static final int BOUNDS_EXTENDS = 1;
-
- /** Value for {@link #bounds} indicating that this wildcard has 'super' bounds. */
- public static final int BOUNDS_SUPER = 2;
-
- /**
- * The kind of bounds that this wildcard has.
- *
- * @see #BOUNDS_NONE
- * @see #BOUNDS_EXTENDS
- * @see #BOUNDS_SUPER
- */
- public final int bounds;
-
- /** The reference type of this wildcard's EXTENDS or SUPER bounds. */
- public final ReferenceType referenceType;
-
- public
- Wildcard() {
- this.bounds = Wildcard.BOUNDS_NONE;
- this.referenceType = null;
- }
-
- public
- Wildcard(int bounds, ReferenceType referenceType) {
- assert bounds == Wildcard.BOUNDS_EXTENDS || bounds == Wildcard.BOUNDS_SUPER;
- this.bounds = bounds;
- assert referenceType != null;
- this.referenceType = referenceType;
- }
-
- @Override public void
- accept(TypeArgumentVisitor visitor) { visitor.visitWildcard(this); }
-
- @Override public String
- toString() {
- return (
- this.bounds == Wildcard.BOUNDS_EXTENDS ? "? extends " + this.referenceType :
- this.bounds == Wildcard.BOUNDS_SUPER ? "? super " + this.referenceType :
- "?"
- );
- }
- }
-
- /**
- * @return {@code null} iff {@code a == null}, or "" iff {@code a.length == 0}, or the elements of {@code a},
- * converted to strings concatenated and separated with the {@code separator}
- */
- public static String
- join(Object[] a, String separator) {
- return Java.join(a, separator, 0, a.length);
- }
-
- /**
- * @return {@code null} iff {@code a == null}, or "" iff {@code off >= len}, or element {@code off ... len-1} of
- * {@code a}, converted to strings concatenated and separated with the {@code separator}
- */
- public static String
- join(Object[] a, String separator, int off, int len) {
- if (a == null) return ("(null)");
- if (off >= len) return "";
- StringBuilder sb = new StringBuilder(a[off].toString());
- for (++off; off < len; ++off) {
- sb.append(separator);
- sb.append(a[off]);
- }
- return sb.toString();
- }
-}
diff --git a/src/org/codehaus/janino/JavaSourceClassLoader.java b/src/org/codehaus/janino/JavaSourceClassLoader.java
deleted file mode 100644
index 606d160f..00000000
--- a/src/org/codehaus/janino/JavaSourceClassLoader.java
+++ /dev/null
@@ -1,256 +0,0 @@
-
-/*
- * 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.
- *
- * 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 (null
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}.
- *
- * 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 (null
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 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 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 null
if no source code could be found
- * @throws ClassNotFoundException on compilation problems
- */
- protected Map
- generateBytecodes(String name) throws ClassNotFoundException {
- if (this.iClassLoader.loadIClass(Descriptor.fromClassName(name)) == null) return null;
-
- Map bytecodes = new HashMap();
- Set 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;
-}
diff --git a/src/org/codehaus/janino/JavaSourceIClassLoader.java b/src/org/codehaus/janino/JavaSourceIClassLoader.java
deleted file mode 100644
index 6251f1c9..00000000
--- a/src/org/codehaus/janino/JavaSourceIClassLoader.java
+++ /dev/null
@@ -1,208 +0,0 @@
-
-/*
- * 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.
- *
- * 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 unitCompilers = new HashSet();
-
- 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
- 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) {}
- }
- }
-}
diff --git a/src/org/codehaus/janino/MethodDescriptor.java b/src/org/codehaus/janino/MethodDescriptor.java
deleted file mode 100644
index f7a28e30..00000000
--- a/src/org/codehaus/janino/MethodDescriptor.java
+++ /dev/null
@@ -1,86 +0,0 @@
-
-/*
- * 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 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); }
-}
diff --git a/src/org/codehaus/janino/Mod.java b/src/org/codehaus/janino/Mod.java
deleted file mode 100644
index 92a7e3e8..00000000
--- a/src/org/codehaus/janino/Mod.java
+++ /dev/null
@@ -1,270 +0,0 @@
-
-/*
- * 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.
- *
- * Notice: This class should be named IClass.IModifier
, 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' -- no 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:
- *
- * Value zero is mapped to "".
- * Non-zero values are mapped to a sequence of words, separated with blanks.
- * {@link #VARARGS} is mapped to "transient", because the two flags have the same value
- * {@link #SUPER} is mapped to "synchronized", because the two flags have the same value
- * {@link #BRIDGE} is mapped to "volatile", because the two flags have the same value
- *
- */
- 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),
- };
-}
-
diff --git a/src/org/codehaus/janino/Opcode.java b/src/org/codehaus/janino/Opcode.java
deleted file mode 100644
index ffc201bc..00000000
--- a/src/org/codehaus/janino/Opcode.java
+++ /dev/null
@@ -1,614 +0,0 @@
-
-/*
- * 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;
- }
-}
diff --git a/src/org/codehaus/janino/Parser.java b/src/org/codehaus/janino/Parser.java
deleted file mode 100644
index d411c73c..00000000
--- a/src/org/codehaus/janino/Parser.java
+++ /dev/null
@@ -1,3138 +0,0 @@
-
-/*
- * 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.util.ArrayList;
-import java.util.List;
-
-import org.codehaus.commons.compiler.CompileException;
-import org.codehaus.commons.compiler.Location;
-import org.codehaus.commons.compiler.WarningHandler;
-import org.codehaus.janino.Java.AlternateConstructorInvocation;
-import org.codehaus.janino.Java.AmbiguousName;
-import org.codehaus.janino.Java.Annotation;
-import org.codehaus.janino.Java.AnonymousClassDeclaration;
-import org.codehaus.janino.Java.ArrayAccessExpression;
-import org.codehaus.janino.Java.ArrayInitializer;
-import org.codehaus.janino.Java.ArrayInitializerOrRvalue;
-import org.codehaus.janino.Java.ArrayType;
-import org.codehaus.janino.Java.AssertStatement;
-import org.codehaus.janino.Java.Assignment;
-import org.codehaus.janino.Java.Atom;
-import org.codehaus.janino.Java.BasicType;
-import org.codehaus.janino.Java.BinaryOperation;
-import org.codehaus.janino.Java.Block;
-import org.codehaus.janino.Java.BlockStatement;
-import org.codehaus.janino.Java.BooleanLiteral;
-import org.codehaus.janino.Java.BreakStatement;
-import org.codehaus.janino.Java.Cast;
-import org.codehaus.janino.Java.CatchClause;
-import org.codehaus.janino.Java.CharacterLiteral;
-import org.codehaus.janino.Java.ClassDeclaration;
-import org.codehaus.janino.Java.ClassLiteral;
-import org.codehaus.janino.Java.CompilationUnit;
-import org.codehaus.janino.Java.CompilationUnit.ImportDeclaration;
-import org.codehaus.janino.Java.ConditionalExpression;
-import org.codehaus.janino.Java.ConstructorDeclarator;
-import org.codehaus.janino.Java.ConstructorInvocation;
-import org.codehaus.janino.Java.ContinueStatement;
-import org.codehaus.janino.Java.Crement;
-import org.codehaus.janino.Java.DoStatement;
-import org.codehaus.janino.Java.ElementValue;
-import org.codehaus.janino.Java.ElementValuePair;
-import org.codehaus.janino.Java.EmptyStatement;
-import org.codehaus.janino.Java.ExpressionStatement;
-import org.codehaus.janino.Java.FieldAccessExpression;
-import org.codehaus.janino.Java.FieldDeclaration;
-import org.codehaus.janino.Java.FloatingPointLiteral;
-import org.codehaus.janino.Java.ForEachStatement;
-import org.codehaus.janino.Java.ForStatement;
-import org.codehaus.janino.Java.FunctionDeclarator.FormalParameter;
-import org.codehaus.janino.Java.FunctionDeclarator.FormalParameters;
-import org.codehaus.janino.Java.IfStatement;
-import org.codehaus.janino.Java.Initializer;
-import org.codehaus.janino.Java.Instanceof;
-import org.codehaus.janino.Java.IntegerLiteral;
-import org.codehaus.janino.Java.InterfaceDeclaration;
-import org.codehaus.janino.Java.LabeledStatement;
-import org.codehaus.janino.Java.LocalClassDeclaration;
-import org.codehaus.janino.Java.LocalClassDeclarationStatement;
-import org.codehaus.janino.Java.LocalVariableDeclarationStatement;
-import org.codehaus.janino.Java.Lvalue;
-import org.codehaus.janino.Java.MemberClassDeclaration;
-import org.codehaus.janino.Java.MemberInterfaceDeclaration;
-import org.codehaus.janino.Java.MemberTypeDeclaration;
-import org.codehaus.janino.Java.MethodDeclarator;
-import org.codehaus.janino.Java.MethodInvocation;
-import org.codehaus.janino.Java.Modifiers;
-import org.codehaus.janino.Java.NamedClassDeclaration;
-import org.codehaus.janino.Java.NewAnonymousClassInstance;
-import org.codehaus.janino.Java.NewArray;
-import org.codehaus.janino.Java.NewClassInstance;
-import org.codehaus.janino.Java.NewInitializedArray;
-import org.codehaus.janino.Java.NullLiteral;
-import org.codehaus.janino.Java.PackageDeclaration;
-import org.codehaus.janino.Java.PackageMemberClassDeclaration;
-import org.codehaus.janino.Java.PackageMemberInterfaceDeclaration;
-import org.codehaus.janino.Java.PackageMemberTypeDeclaration;
-import org.codehaus.janino.Java.ParenthesizedExpression;
-import org.codehaus.janino.Java.QualifiedThisReference;
-import org.codehaus.janino.Java.ReferenceType;
-import org.codehaus.janino.Java.ReturnStatement;
-import org.codehaus.janino.Java.Rvalue;
-import org.codehaus.janino.Java.RvalueMemberType;
-import org.codehaus.janino.Java.Statement;
-import org.codehaus.janino.Java.StringLiteral;
-import org.codehaus.janino.Java.SuperConstructorInvocation;
-import org.codehaus.janino.Java.SuperclassFieldAccessExpression;
-import org.codehaus.janino.Java.SuperclassMethodInvocation;
-import org.codehaus.janino.Java.SwitchStatement;
-import org.codehaus.janino.Java.SynchronizedStatement;
-import org.codehaus.janino.Java.ThisReference;
-import org.codehaus.janino.Java.ThrowStatement;
-import org.codehaus.janino.Java.TryStatement;
-import org.codehaus.janino.Java.Type;
-import org.codehaus.janino.Java.TypeArgument;
-import org.codehaus.janino.Java.TypeParameter;
-import org.codehaus.janino.Java.UnaryOperation;
-import org.codehaus.janino.Java.VariableDeclarator;
-import org.codehaus.janino.Java.WhileStatement;
-import org.codehaus.janino.Java.Wildcard;
-import org.codehaus.janino.Scanner.Token;
-import org.codehaus.janino.util.enumerator.Enumerator;
-
-/**
- * A parser for the Java™ programming language.
- *
- * 'JLS7' refers to the Java Language Specification, Java SE 7
- * Edition .
- */
-@SuppressWarnings({ "rawtypes", "unchecked" }) public
-class Parser {
- private final Scanner scanner;
-
- public
- Parser(Scanner scanner) { this.scanner = scanner; }
-
- /** @return The scanner that produces the tokens for this parser. */
- public Scanner
- getScanner() { return this.scanner; }
-
- /**
- *
- * CompilationUnit := [ PackageDeclaration ]
- * { ImportDeclaration }
- * { TypeDeclaration }
- *
- */
- public CompilationUnit
- parseCompilationUnit() throws CompileException, IOException {
- CompilationUnit compilationUnit = new CompilationUnit(this.location().getFileName());
-
- if (this.peek("package")) {
- compilationUnit.setPackageDeclaration(this.parsePackageDeclaration());
- }
-
- while (this.peek("import")) {
- compilationUnit.addImportDeclaration(this.parseImportDeclaration());
- }
-
- while (!this.peekEof()) {
- if (this.peekRead(";")) continue;
-
- compilationUnit.addPackageMemberTypeDeclaration(this.parsePackageMemberTypeDeclaration());
- }
-
- return compilationUnit;
- }
-
- /**
- *
- * PackageDeclaration := 'package' QualifiedIdentifier ';'
- *
- */
- public PackageDeclaration
- parsePackageDeclaration() throws CompileException, IOException {
- this.read("package");
- Location loc = this.location();
- String packageName = Parser.join(this.parseQualifiedIdentifier(), ".");
- this.read(";");
- this.verifyStringIsConventionalPackageName(packageName, loc);
- return new PackageDeclaration(loc, packageName);
- }
-
- /**
- *
- * ImportDeclaration := 'import' ImportDeclarationBody ';'
- *
- */
- public CompilationUnit.ImportDeclaration
- parseImportDeclaration() throws CompileException, IOException {
- this.read("import");
- CompilationUnit.ImportDeclaration importDeclaration = this.parseImportDeclarationBody();
- this.read(";");
- return importDeclaration;
- }
-
- /**
- *
- * ImportDeclarationBody := [ 'static' ] Identifier { '.' Identifier } [ '.' '*' ]
- *
- */
- public CompilationUnit.ImportDeclaration
- parseImportDeclarationBody() throws CompileException, IOException {
- final Location loc = this.location();
-
- boolean isStatic = this.peekRead("static");
-
- List l = new ArrayList();
- l.add(this.readIdentifier());
- for (;;) {
- if (!this.peek(".")) {
- String[] identifiers = (String[]) l.toArray(new String[l.size()]);
- return (
- isStatic
- ? (ImportDeclaration) new CompilationUnit.SingleStaticImportDeclaration(loc, identifiers)
- : (ImportDeclaration) new CompilationUnit.SingleTypeImportDeclaration(loc, identifiers)
- );
- }
- this.read(".");
- if (this.peekRead("*")) {
- String[] identifiers = (String[]) l.toArray(new String[l.size()]);
- return (
- isStatic
- ? (ImportDeclaration) new CompilationUnit.StaticImportOnDemandDeclaration(loc, identifiers)
- : (ImportDeclaration) new CompilationUnit.TypeImportOnDemandDeclaration(loc, identifiers)
- );
- }
- l.add(this.readIdentifier());
- }
- }
-
- /**
- *
- * QualifiedIdentifier := Identifier { '.' Identifier }
- *
- */
- public String[]
- parseQualifiedIdentifier() throws CompileException, IOException {
- List l = new ArrayList();
- l.add(this.readIdentifier());
- while (this.peek(".") && this.peekNextButOne().type == Token.IDENTIFIER) {
- this.read();
- l.add(this.readIdentifier());
- }
- return (String[]) l.toArray(new String[l.size()]);
- }
-
- /**
- *
- * PackageMemberTypeDeclaration :=
- * ModifiersOpt 'class' ClassDeclarationRest |
- * ModifiersOpt 'interface' InterfaceDeclarationRest
- *
- */
- public PackageMemberTypeDeclaration
- parsePackageMemberTypeDeclaration() throws CompileException, IOException {
- String optionalDocComment = this.scanner.doc();
-
- Modifiers modifiers = this.parseModifiers();
-
- switch (this.read(new String[] { "class", "interface" })) {
- case 0:
- if (optionalDocComment == null) this.warning("CDCM", "Class doc comment missing", this.location());
- return (PackageMemberClassDeclaration) this.parseClassDeclarationRest(
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- ClassDeclarationContext.COMPILATION_UNIT // context
- );
- case 1:
- if (optionalDocComment == null) this.warning("IDCM", "Interface doc comment missing", this.location());
- return (PackageMemberInterfaceDeclaration) this.parseInterfaceDeclarationRest(
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- InterfaceDeclarationContext.COMPILATION_UNIT // context
- );
- default:
- throw new IllegalStateException();
- }
- }
-
- /**
- *
- * ModifiersAndAnnotations := { 'public' | 'protected' | 'private' | 'static' | 'abstract' | 'final' | 'native'
- * | 'synchronized' | 'transient' | 'volatile' | 'strictfp' | Annotation }
- *
- */
- public Java.Modifiers
- parseModifiers() throws CompileException, IOException {
- short mod = 0;
- List as = new ArrayList();
- for (;;) {
- if (this.peek("@")) {
- as.add(this.parseAnnotation());
- continue;
- }
-
- int idx = this.peekRead(Parser.MODIFIER_NAMES);
- if (idx == -1) break;
- String kw = Parser.MODIFIER_NAMES[idx];
- short x = Parser.MODIFIER_CODES[idx];
-
- if ((mod & x) != 0) throw this.compileException("Duplicate modifier \"" + kw + "\"");
- for (short m : Parser.MUTUALLY_EXCLUSIVE_MODIFIER_CODES) {
- if ((x & m) != 0 && (mod & m) != 0) {
- throw this.compileException("Only one of '" + Mod.shortToString(m) + "' allowed");
- }
- }
- mod |= x;
- }
-
- return new Modifiers(mod, (Annotation[]) as.toArray(new Java.Annotation[as.size()]));
- }
- private static final String[] MODIFIER_NAMES = {
- "public", "protected", "private", "static", "abstract", "final", "native", "synchronized",
- "transient", "volatile", "strictfp"
- };
- private static final short[] MODIFIER_CODES = {
- Mod.PUBLIC, Mod.PROTECTED, Mod.PRIVATE, Mod.STATIC, Mod.ABSTRACT, Mod.FINAL, Mod.NATIVE, Mod.SYNCHRONIZED,
- Mod.TRANSIENT, Mod.VOLATILE, Mod.STRICTFP
- };
- private static final short[] MUTUALLY_EXCLUSIVE_MODIFIER_CODES = {
- Mod.PUBLIC | Mod.PROTECTED | Mod.PRIVATE,
- Mod.ABSTRACT | Mod.FINAL,
- };
-
- /**
- *
- * Annotation :=
- * MarkerAnnotation // JLS7 9.7.2
- * | SingleElementAnnotation // JLS7 9.7.3
- * | NormalAnnotation // JLS7 9.7.1
- *
- * MarkerAnnotation := '@' Identifier
- *
- * SingleElementAnnotation := '@' Identifier '(' ElementValue ')'
- *
- * NormalAnnotation := '@' TypeName '(' ElementValuePairsOpt ')'
- *
- * ElementValuePairsOpt := [ ElementValuePair { ',' ElementValuePair } ]
- *
- */
- private Java.Annotation
- parseAnnotation() throws CompileException, IOException {
- this.read("@");
- ReferenceType type = this.parseReferenceType();
-
- if (!this.peekRead("(")) return new Java.MarkerAnnotation(type);
-
- if (this.peekIdentifier() == null || !this.peekNextButOne("=")) {
- Java.ElementValue elementValue = this.parseElementValue();
- this.read(")");
- return new Java.SingleElementAnnotation(type, elementValue);
- }
-
- List evps = new ArrayList();
- while (!this.peekRead(")")) evps.add(this.parseElementValuePair());
-
- return new Java.NormalAnnotation(
- type,
- (ElementValuePair[]) evps.toArray(new Java.ElementValuePair[evps.size()])
- );
- }
-
- /**
- *
- * ElementValuePair := Identifier '=' ElementValue
- *
- */
- private Java.ElementValuePair
- parseElementValuePair() throws CompileException, IOException {
- String identifier = this.readIdentifier();
- this.read("=");
- return new Java.ElementValuePair(identifier, this.parseElementValue());
- }
-
- /**
- *
- * ElementValue :=
- * ConditionalExpression
- * | Annotation
- * | ElementValueArrayInitializer
- *
- */
- private Java.ElementValue
- parseElementValue() throws CompileException, IOException {
- if (this.peek("@")) return this.parseAnnotation();
- if (this.peek("{")) return this.parseElementValueArrayInitializer();
- return this.parseConditionalAndExpression().toRvalueOrCompileException();
- }
-
- /**
- *
- * ElementValueArrayInitializer := '{' { ElementValue | ',' } '}'
- *
- */
- private ElementValue
- parseElementValueArrayInitializer() throws CompileException, IOException {
- this.read("{");
- List evs = new ArrayList();
- while (!this.peekRead("}")) {
- if (this.peekRead(",")) continue;
- evs.add(this.parseElementValue());
- }
- return new Java.ElementValueArrayInitializer((ElementValue[]) evs.toArray(new Java.ElementValue[evs.size()]));
- }
-
- /**
- *
- * ClassDeclarationRest :=
- * Identifier [ typeParameters ]
- * [ 'extends' ReferenceType ]
- * [ 'implements' ReferenceTypeList ]
- * ClassBody
- *
- */
- public NamedClassDeclaration
- parseClassDeclarationRest(
- String optionalDocComment,
- Modifiers modifiers,
- ClassDeclarationContext context
- ) throws CompileException, IOException {
- Location location = this.location();
- String className = this.readIdentifier();
- this.verifyIdentifierIsConventionalClassOrInterfaceName(className, location);
-
- TypeParameter[] optionalTypeParameters = this.parseTypeParametersOpt();
-
- ReferenceType optionalExtendedType = null;
- if (this.peekRead("extends")) {
- optionalExtendedType = this.parseReferenceType();
- }
-
- ReferenceType[] implementedTypes = new ReferenceType[0];
- if (this.peekRead("implements")) {
- implementedTypes = this.parseReferenceTypeList();
- }
-
- NamedClassDeclaration namedClassDeclaration;
- if (context == ClassDeclarationContext.COMPILATION_UNIT) {
- namedClassDeclaration = new PackageMemberClassDeclaration(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- className, // name
- optionalTypeParameters, // optionalTypeParameters
- optionalExtendedType, // optinalExtendedType
- implementedTypes // implementedTypes
- );
- } else
- if (context == ClassDeclarationContext.TYPE_DECLARATION) {
- namedClassDeclaration = new MemberClassDeclaration(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- className, // name
- optionalTypeParameters, // optionalTypeParameters
- optionalExtendedType, // optionalExtendedType
- implementedTypes // implementedTypes
- );
- } else
- if (context == ClassDeclarationContext.BLOCK) {
- namedClassDeclaration = new LocalClassDeclaration(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- className, // name
- optionalTypeParameters, // optionalTypeParameters
- optionalExtendedType, // optionalExtendedType
- implementedTypes // implementedTypes
- );
- } else
- {
- throw new JaninoRuntimeException("SNO: Class declaration in unexpected context " + context);
- }
-
- this.parseClassBody(namedClassDeclaration);
- return namedClassDeclaration;
- }
-
- /** Enumerator for the kinds of context where a class declaration can occur. */
- public static final
- class ClassDeclarationContext extends Enumerator {
-
- /** Enumerator for the kinds of context where a class declaration can occur. */
- /** The class declaration appears inside a 'block'. */
- /** The class declaration appears inside a 'block'. */
- public static final ClassDeclarationContext BLOCK = new ClassDeclarationContext("block");
-
- /** The class declaration appears (directly) inside a type declaration. */
- public static final ClassDeclarationContext TYPE_DECLARATION = new ClassDeclarationContext("type_declaration");
-
- /** The class declaration appears on the top level. */
- public static final ClassDeclarationContext COMPILATION_UNIT = new ClassDeclarationContext("compilation_unit");
-
- private ClassDeclarationContext(String name) { super(name); }
- }
-
- /**
- *
- * ClassBody := '{' { ClassBodyDeclaration } '}'
- *
- */
- public void
- parseClassBody(ClassDeclaration classDeclaration) throws CompileException, IOException {
- this.read("{");
-
- for (;;) {
- if (this.peekRead("}")) return;
-
- this.parseClassBodyDeclaration(classDeclaration);
- }
- }
-
- /**
- *
- * ClassBodyDeclaration :=
- * ';' |
- * ModifiersOpt (
- * Block | // Instance (JLS7 8.6) or static initializer (JLS7 8.7)
- * 'void' Identifier MethodDeclarationRest |
- * 'class' ClassDeclarationRest |
- * 'interface' InterfaceDeclarationRest |
- * ConstructorDeclarator |
- * Type Identifier (
- * MethodDeclarationRest |
- * FieldDeclarationRest ';'
- * )
- * )
- *
- *
- */
- public void
- parseClassBodyDeclaration(ClassDeclaration classDeclaration) throws CompileException, IOException {
- if (this.peekRead(";")) return;
-
- String optionalDocComment = this.scanner.doc();
- Modifiers modifiers = this.parseModifiers();
-
- // Initializer?
- if (this.peek("{")) {
- if ((modifiers.flags & ~Mod.STATIC) != 0) {
- throw this.compileException("Only modifier \"static\" allowed on initializer");
- }
-
- Initializer initializer = new Initializer(
- this.location(), // location
- Mod.isStatic(modifiers.flags), // statiC
- this.parseBlock() // block
- );
-
- classDeclaration.addInitializer(initializer);
- return;
- }
-
- // "void" method declaration.
- if (this.peekRead("void")) {
- Location location = this.location();
- if (optionalDocComment == null) this.warning("MDCM", "Method doc comment missing", location);
- String name = this.readIdentifier();
- classDeclaration.addDeclaredMethod(this.parseMethodDeclarationRest(
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- new BasicType(location, BasicType.VOID), // type
- name // name
- ));
- return;
- }
-
- // Member class.
- if (this.peekRead("class")) {
- if (optionalDocComment == null) this.warning("MCDCM", "Member class doc comment missing", this.location());
- classDeclaration.addMemberTypeDeclaration((MemberTypeDeclaration) this.parseClassDeclarationRest(
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- ClassDeclarationContext.TYPE_DECLARATION // context
- ));
- return;
- }
-
- // Member interface.
- if (this.peekRead("interface")) {
- if (optionalDocComment == null) {
- this.warning("MIDCM", "Member interface doc comment missing", this.location());
- }
- classDeclaration.addMemberTypeDeclaration((MemberTypeDeclaration) this.parseInterfaceDeclarationRest(
- optionalDocComment, // optionalDocComment
- modifiers.add(Mod.STATIC), // modifiers
- InterfaceDeclarationContext.NAMED_TYPE_DECLARATION // context
- ));
- return;
- }
-
- // Constructor.
- if (
- classDeclaration instanceof NamedClassDeclaration
- && this.peek().value.equals(((NamedClassDeclaration) classDeclaration).getName())
- && this.peekNextButOne("(")
- ) {
- if (optionalDocComment == null) this.warning("CDCM", "Constructor doc comment missing", this.location());
- classDeclaration.addConstructor(this.parseConstructorDeclarator(
- optionalDocComment, // declaringClass
- modifiers // modifiers
- ));
- return;
- }
-
- // Member method or field.
- Type memberType = this.parseType();
- Location location = this.location();
- String memberName = this.readIdentifier();
-
- // Method declarator.
- if (this.peek("(")) {
- if (optionalDocComment == null) this.warning("MDCM", "Method doc comment missing", this.location());
- classDeclaration.addDeclaredMethod(this.parseMethodDeclarationRest(
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- memberType, // type
- memberName // name
- ));
- return;
- }
-
- // Field declarator.
- if (optionalDocComment == null) this.warning("FDCM", "Field doc comment missing", this.location());
- FieldDeclaration fd = new FieldDeclaration(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- memberType, // type
- this.parseFieldDeclarationRest(memberName) // variableDeclarators
- );
- this.read(";");
- classDeclaration.addFieldDeclaration(fd);
- }
-
- /**
- *
- * InterfaceDeclarationRest :=
- * Identifier [ typeParameters ]
- * [ 'extends' ReferenceTypeList ]
- * InterfaceBody
- *
- */
- public InterfaceDeclaration
- parseInterfaceDeclarationRest(
- String optionalDocComment,
- Modifiers modifiers,
- InterfaceDeclarationContext context
- ) throws CompileException, IOException {
- Location location = this.location();
- String interfaceName = this.readIdentifier();
- this.verifyIdentifierIsConventionalClassOrInterfaceName(interfaceName, location);
-
- TypeParameter[] optionalTypeParameters = this.parseTypeParametersOpt();
-
- ReferenceType[] extendedTypes = new ReferenceType[0];
- if (this.peekRead("extends")) {
- extendedTypes = this.parseReferenceTypeList();
- }
-
- InterfaceDeclaration interfaceDeclaration;
- if (context == InterfaceDeclarationContext.COMPILATION_UNIT) {
- interfaceDeclaration = new PackageMemberInterfaceDeclaration(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- interfaceName, // name
- optionalTypeParameters, // optionalTypeParameters
- extendedTypes // extendedTypes
- );
- } else
- if (context == InterfaceDeclarationContext.NAMED_TYPE_DECLARATION) {
- interfaceDeclaration = new MemberInterfaceDeclaration(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- interfaceName, // name
- optionalTypeParameters, // optionalTypeParameters
- extendedTypes // extendedTypes
- );
- } else
- {
- throw new JaninoRuntimeException("SNO: Interface declaration in unexpected context " + context);
- }
-
- this.parseInterfaceBody(interfaceDeclaration);
- return interfaceDeclaration;
- }
-
- /** Enumerator for the kinds of context where an interface declaration can occur. */
- public static final
- class InterfaceDeclarationContext extends Enumerator {
-
- /** The interface declaration appears (directly) inside a 'named type declaration'. */
- public static final InterfaceDeclarationContext
- NAMED_TYPE_DECLARATION = new InterfaceDeclarationContext("named_type_declaration");
-
- /** The interface declaration appears at the top level. */
- public static final InterfaceDeclarationContext
- COMPILATION_UNIT = new InterfaceDeclarationContext("compilation_unit");
-
- private InterfaceDeclarationContext(String name) { super(name); }
- }
-
- /**
- *
- * InterfaceBody := '{' {
- * ';' |
- * ModifiersOpt (
- * 'void' Identifier MethodDeclarationRest |
- * 'class' ClassDeclarationRest |
- * 'interface' InterfaceDeclarationRest |
- * Type Identifier (
- * MethodDeclarationRest |
- * FieldDeclarationRest
- * )
- * )
- * } '}'
- *
- */
- public void
- parseInterfaceBody(InterfaceDeclaration interfaceDeclaration) throws CompileException, IOException {
- this.read("{");
-
- while (!this.peekRead("}")) {
-
- if (this.peekRead(";")) continue;
-
- String optionalDocComment = this.scanner.doc();
- Modifiers modifiers = this.parseModifiers();
-
- // "void" method declaration.
- if (this.peekRead("void")) {
- if (optionalDocComment == null) this.warning("MDCM", "Method doc comment missing", this.location());
- Location location = this.location();
- String name = this.readIdentifier();
- interfaceDeclaration.addDeclaredMethod(this.parseMethodDeclarationRest(
- optionalDocComment, // optionalDocComment
- modifiers.add(Mod.ABSTRACT | Mod.PUBLIC), // modifiers
- new BasicType(location, BasicType.VOID), // type
- name // name
- ));
- } else
-
- // Member class.
- if (this.peekRead("class")) {
- if (optionalDocComment == null) {
- this.warning("MCDCM", "Member class doc comment missing", this.location());
- }
- interfaceDeclaration.addMemberTypeDeclaration(
- (MemberTypeDeclaration) this.parseClassDeclarationRest(
- optionalDocComment, // optionalDocComment
- modifiers.add(Mod.STATIC | Mod.PUBLIC), // ModifiersAndAnnotations
- ClassDeclarationContext.TYPE_DECLARATION // context
- )
- );
- } else
-
- // Member interface.
- if (this.peekRead("interface")) {
- if (optionalDocComment == null) {
- this.warning("MIDCM", "Member interface doc comment missing", this.location());
- }
- interfaceDeclaration.addMemberTypeDeclaration(
- (MemberTypeDeclaration) this.parseInterfaceDeclarationRest(
- optionalDocComment, // optionalDocComment
- modifiers.add(Mod.STATIC | Mod.PUBLIC), // ModifiersAndAnnotations
- InterfaceDeclarationContext.NAMED_TYPE_DECLARATION // context
- )
- );
- } else
-
- // Member method or field.
- {
- this.parseTypeArgumentsOpt();
-
- Type memberType = this.parseType();
- String memberName = this.readIdentifier();
- Location location = this.location();
-
- // Method declarator.
- if (this.peek("(")) {
- if (optionalDocComment == null) this.warning("MDCM", "Method doc comment missing", this.location());
- interfaceDeclaration.addDeclaredMethod(this.parseMethodDeclarationRest(
- optionalDocComment, // optionalDocComment
- modifiers.add(Mod.ABSTRACT | Mod.PUBLIC), // modifiers
- memberType, // type
- memberName // name
- ));
- } else
-
- // Field declarator.
- {
- if (optionalDocComment == null) this.warning("FDCM", "Field doc comment missing", this.location());
- FieldDeclaration fd = new FieldDeclaration(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers.add(Mod.PUBLIC | Mod.STATIC | Mod.FINAL), // modifiers
- memberType, // type
- this.parseFieldDeclarationRest(memberName) // variableDeclarators
- );
- interfaceDeclaration.addConstantDeclaration(fd);
- }
- }
- }
- }
-
- /**
- *
- * ConstructorDeclarator :=
- * Identifier
- * FormalParameters
- * [ 'throws' ReferenceTypeList ]
- * '{'
- * [ 'this' Arguments ';' | 'super' Arguments ';' | Primary '.' 'super' Arguments ';' ]
- * BlockStatements
- * '}'
- *
- */
- public ConstructorDeclarator
- parseConstructorDeclarator(String optionalDocComment, Modifiers modifiers)
- throws CompileException, IOException {
- this.readIdentifier(); // Class name
-
- // Parse formal parameters.
- final FormalParameters formalParameters = this.parseFormalParameters();
-
- // Parse "throws" clause.
- ReferenceType[] thrownExceptions;
- if (this.peekRead("throws")) {
- thrownExceptions = this.parseReferenceTypeList();
- } else {
- thrownExceptions = new ReferenceType[0];
- }
-
- // Parse constructor body.
- final Location location = this.location();
- this.read("{");
-
- // Special treatment for the first statement of the constructor body: If this is surely an
- // expression statement, and if it could be a "ConstructorInvocation", then parse the
- // expression and check if it IS a ConstructorInvocation.
- ConstructorInvocation optionalConstructorInvocation = null;
- List statements = new ArrayList();
- if (
- this.peek(new String[] {
- "this", "super", "new", "void",
- "byte", "char", "short", "int", "long", "float", "double", "boolean",
- }) != -1
- || this.peekLiteral()
- || this.peekIdentifier() != null
- ) {
- Atom a = this.parseExpression();
- if (a instanceof ConstructorInvocation) {
- this.read(";");
- optionalConstructorInvocation = (ConstructorInvocation) a;
- } else {
- Statement s;
- if (this.peekIdentifier() != null) {
- Type variableType = a.toTypeOrCompileException();
- s = new LocalVariableDeclarationStatement(
- a.getLocation(), // location
- new Java.Modifiers(Mod.NONE), // modifiers
- variableType, // type
- this.parseVariableDeclarators() // variableDeclarators
- );
- this.read(";");
- } else {
- s = new ExpressionStatement(a.toRvalueOrCompileException());
- this.read(";");
- }
- statements.add(s);
- }
- }
- statements.addAll(this.parseBlockStatements());
-
- this.read("}");
-
- return new ConstructorDeclarator(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- formalParameters, // formalParameters
- thrownExceptions, // thrownExceptions
- optionalConstructorInvocation, // optionalConstructorInvocationStatement
- statements // statements
- );
- }
-
- /**
- *
- * MethodDeclarationRest :=
- * FormalParameters
- * { '[' ']' }
- * [ 'throws' ReferenceTypeList ]
- * ( ';' | MethodBody )
- *
- */
- public MethodDeclarator
- parseMethodDeclarationRest(
- String optionalDocComment,
- Modifiers modifiers,
- Type type,
- String name
- ) throws CompileException, IOException {
- Location location = this.location();
-
- this.verifyIdentifierIsConventionalMethodName(name, location);
-
- final FormalParameters formalParameters = this.parseFormalParameters();
-
- for (int i = this.parseBracketsOpt(); i > 0; --i) type = new ArrayType(type);
-
- ReferenceType[] thrownExceptions;
- if (this.peekRead("throws")) {
- thrownExceptions = this.parseReferenceTypeList();
- } else {
- thrownExceptions = new ReferenceType[0];
- }
-
- List optionalStatements;
- if (this.peekRead(";")) {
- if (!Mod.isAbstract(modifiers.flags) && !Mod.isNative(modifiers.flags)) {
- throw this.compileException("Non-abstract, non-native method must have a body");
- }
- optionalStatements = null;
- } else {
- if (Mod.isAbstract(modifiers.flags) || Mod.isNative(modifiers.flags)) {
- throw this.compileException("Abstract or native method must not have a body");
- }
- this.read("{");
- optionalStatements = this.parseBlockStatements();
- this.read("}");
- }
- return new MethodDeclarator(
- location, // location
- optionalDocComment, // optionalDocComment
- modifiers, // modifiers
- type, // type
- name, // name
- formalParameters, // formalParameters
- thrownExceptions, // thrownExceptions
- optionalStatements // optionalStatements
- );
- }
-
- /**
- *
- * VariableInitializer :=
- * ArrayInitializer |
- * Expression
- *
- */
- public ArrayInitializerOrRvalue
- parseVariableInitializer() throws CompileException, IOException {
- if (this.peek("{")) {
- return this.parseArrayInitializer();
- } else
- {
- return this.parseExpression().toRvalueOrCompileException();
- }
- }
-
- /**
- *
- * ArrayInitializer :=
- * '{' [ VariableInitializer { ',' VariableInitializer } [ ',' ] '}'
- *
- */
- public ArrayInitializer
- parseArrayInitializer() throws CompileException, IOException {
- final Location location = this.location();
- this.read("{");
- List l = new ArrayList();
- while (!this.peekRead("}")) {
- l.add(this.parseVariableInitializer());
- if (this.peekRead("}")) break;
- this.read(",");
- }
- return new ArrayInitializer(
- location,
- (ArrayInitializerOrRvalue[]) l.toArray(new ArrayInitializerOrRvalue[l.size()])
- );
- }
-
- /**
- *
- * FormalParameters := '(' [ FormalParameter { ',' FormalParameter } ] ')'
- *
- */
- public FormalParameters
- parseFormalParameters() throws CompileException, IOException {
- this.read("(");
- if (this.peekRead(")")) return new FormalParameters();
-
- List l = new ArrayList();
- boolean[] hasEllipsis = new boolean[1];
- do {
- if (hasEllipsis[0]) throw this.compileException("Only the last parameter may have an ellipsis");
- l.add(this.parseFormalParameter(hasEllipsis));
- } while (this.read(new String[] { ",", ")" }) == 0);
- return new FormalParameters(
- this.location(), // location
- (FormalParameter[]) l.toArray(new FormalParameter[l.size()]), // parameters
- hasEllipsis[0] // variableArity
- );
- }
-
- /**
- *
- * FormalParameter := [ 'final' ] Type [ '.' '.' '.' ] Identifier BracketsOpt
- *
- */
- public FormalParameter
- parseFormalParameter(boolean[] hasEllipsis) throws CompileException, IOException {
- final boolean finaL = this.peekRead("final");
-
- Type type = this.parseType(); // SUPPRESS CHECKSTYLE UsageDistance
-
- if (this.peekRead(".")) {
- this.read(".");
- this.read(".");
- hasEllipsis[0] = true;
- }
- Location location = this.location();
- String name = this.readIdentifier();
- this.verifyIdentifierIsConventionalLocalVariableOrParameterName(name, location);
-
- for (int i = this.parseBracketsOpt(); i > 0; --i) type = new ArrayType(type);
- return new FormalParameter(location, finaL, type, name);
- }
-
- /**
- *
- * BracketsOpt := { '[' ']' }
- *
- */
- int
- parseBracketsOpt() throws CompileException, IOException {
- int res = 0;
- while (this.peek("[") && this.peekNextButOne("]")) {
- this.read();
- this.read();
- ++res;
- }
- return res;
- }
-
- /**
- *
- * MethodBody := Block
- *
- */
- public Block
- parseMethodBody() throws CompileException, IOException { return this.parseBlock(); }
-
- /**
- *
- * '{' BlockStatements '}'
- *
- */
- public Block
- parseBlock() throws CompileException, IOException {
- Block block = new Block(this.location());
- this.read("{");
- block.addStatements(this.parseBlockStatements());
- this.read("}");
- return block;
- }
-
- /**
- *
- * BlockStatements := { BlockStatement }
- *
- */
- public List
- parseBlockStatements() throws CompileException, IOException {
- List l = new ArrayList();
- while (!this.peek("}") && !this.peek("case") && !this.peek("default")) l.add(this.parseBlockStatement());
- return l;
- }
-
- /**
- *
- * BlockStatement := { Identifier ':' } (
- * ( Modifiers Type | ModifiersOpt BasicType ) VariableDeclarators ';' |
- * 'class' ... |
- * Statement |
- * 'final' Type VariableDeclarators ';' |
- * Expression ';' |
- * Expression VariableDeclarators ';' (1)
- * )
- *
- *
- * (1) "Expression" must pose a type, and has optional trailing brackets.
- */
- public BlockStatement
- parseBlockStatement() throws CompileException, IOException {
-
- // Statement?
- if (
- (
- this.peekIdentifier() != null
- && this.peekNextButOne(":")
- )
- || this.peek(new String[] {
- "if", "for", "while", "do", "try", "switch", "synchronized",
- "return", "throw", "break", "continue", "assert"
- }) != -1
- || this.peek(new String[] { "{", ";" }) != -1
- ) return this.parseStatement();
-
- // Local class declaration?
- if (this.peekRead("class")) {
- // JAVADOC[TM] ignores doc comments for local classes, but we
- // don't...
- String optionalDocComment = this.scanner.doc();
- if (optionalDocComment == null) this.warning("LCDCM", "Local class doc comment missing", this.location());
-
- final LocalClassDeclaration lcd = (LocalClassDeclaration) this.parseClassDeclarationRest(
- optionalDocComment, // optionalDocComment
- new Modifiers(), // modifiers
- ClassDeclarationContext.BLOCK // context
- );
- return new LocalClassDeclarationStatement(lcd);
- }
-
- // Modifiers Type VariableDeclarators ';'
- if (this.peek(new String[] { "final", "@" }) != -1) {
- LocalVariableDeclarationStatement lvds = new LocalVariableDeclarationStatement(
- this.location(), // location
- this.parseModifiers(), // modifiers
- this.parseType(), // type
- this.parseVariableDeclarators() // variableDeclarators
- );
- this.read(";");
- return lvds;
- }
-
- // It's either a non-final local variable declaration or an expression statement. We can
- // only tell after parsing an expression.
-
- Atom a = this.parseExpression();
-
- // Expression ';'
- if (this.peekRead(";")) {
- return new ExpressionStatement(a.toRvalueOrCompileException());
- }
-
- // Expression VariableDeclarators ';'
- Type variableType = a.toTypeOrCompileException();
- LocalVariableDeclarationStatement lvds = new LocalVariableDeclarationStatement(
- a.getLocation(), // location
- new Java.Modifiers(Mod.NONE), // modifiers
- variableType, // type
- this.parseVariableDeclarators() // variableDeclarators
- );
- this.read(";");
- return lvds;
- }
-
- /**
- *
- * VariableDeclarators := VariableDeclarator { ',' VariableDeclarator }
- *
- */
- public VariableDeclarator[]
- parseVariableDeclarators() throws CompileException, IOException {
- List l = new ArrayList();
- do {
- VariableDeclarator vd = this.parseVariableDeclarator();
- this.verifyIdentifierIsConventionalLocalVariableOrParameterName(vd.name, vd.getLocation());
- l.add(vd);
- } while (this.peekRead(","));
- return (VariableDeclarator[]) l.toArray(new VariableDeclarator[l.size()]);
- }
-
- /**
- *
- * FieldDeclarationRest :=
- * VariableDeclaratorRest
- * { ',' VariableDeclarator }
- *
- */
- public VariableDeclarator[]
- parseFieldDeclarationRest(String name) throws CompileException, IOException {
- List l = new ArrayList();
-
- VariableDeclarator vd = this.parseVariableDeclaratorRest(name);
- this.verifyIdentifierIsConventionalFieldName(vd.name, vd.getLocation());
- l.add(vd);
-
- while (this.peekRead(",")) {
-
- vd = this.parseVariableDeclarator();
- this.verifyIdentifierIsConventionalFieldName(vd.name, vd.getLocation());
- l.add(vd);
- }
- return (VariableDeclarator[]) l.toArray(new VariableDeclarator[l.size()]);
- }
-
- /**
- *
- * VariableDeclarator := Identifier VariableDeclaratorRest
- *
- */
- public VariableDeclarator
- parseVariableDeclarator() throws CompileException, IOException {
- return this.parseVariableDeclaratorRest(this.readIdentifier());
- }
-
- /**
- *
- * VariableDeclaratorRest := { '[' ']' } [ '=' VariableInitializer ]
- *
- * Used by field declarations and local variable declarations.
- */
- public VariableDeclarator
- parseVariableDeclaratorRest(String name) throws CompileException, IOException {
- Location loc = this.location();
- int brackets = this.parseBracketsOpt();
- ArrayInitializerOrRvalue initializer = null;
-
- if (this.peekRead("=")) initializer = this.parseVariableInitializer();
-
- return new VariableDeclarator(loc, name, brackets, initializer);
- }
-
- /**
- *
- * Statement :=
- * LabeledStatement |
- * Block |
- * IfStatement |
- * ForStatement |
- * WhileStatement |
- * DoStatement |
- * TryStatement |
- * 'switch' ... |
- * 'synchronized' ... |
- * ReturnStatement |
- * ThrowStatement |
- * BreakStatement |
- * ContinueStatement |
- * EmptyStatement |
- * ExpressionStatement
- *
- */
- public Statement
- parseStatement() throws CompileException, IOException {
- if (this.peekIdentifier() != null && this.peekNextButOne(":")) {
- return this.parseLabeledStatement();
- }
-
- Statement stmt = (
- this.peek("{") ? this.parseBlock() :
- this.peek("if") ? this.parseIfStatement() :
- this.peek("for") ? this.parseForStatement() :
- this.peek("while") ? this.parseWhileStatement() :
- this.peek("do") ? this.parseDoStatement() :
- this.peek("try") ? this.parseTryStatement() :
- this.peek("switch") ? this.parseSwitchStatement() :
- this.peek("synchronized") ? this.parseSynchronizedStatement() :
- this.peek("return") ? this.parseReturnStatement() :
- this.peek("throw") ? this.parseThrowStatement() :
- this.peek("break") ? this.parseBreakStatement() :
- this.peek("continue") ? this.parseContinueStatement() :
- this.peek("assert") ? this.parseAssertStatement() :
- this.peek(";") ? this.parseEmptyStatement() :
- this.parseExpressionStatement()
- );
- if (stmt == null) throw this.compileException("'" + this.peek().value + "' NYI");
-
- return stmt;
- }
-
- /**
- *
- * LabeledStatement := Identifier ':' Statement
- *
- */
- public Statement
- parseLabeledStatement() throws CompileException, IOException {
- String label = this.readIdentifier();
- this.read(":");
- return new LabeledStatement(
- this.location(), // location
- label, // label
- this.parseStatement() // body
- );
- }
-
- /**
- *
- * IfStatement := 'if' '(' Expression ')' Statement [ 'else' Statement ]
- *
- */
- public Statement
- parseIfStatement() throws CompileException, IOException {
- final Location location = this.location();
- this.read("if");
- this.read("(");
- final Rvalue condition = this.parseExpression().toRvalueOrCompileException();
- this.read(")");
-
- Statement thenStatement = this.parseStatement();
-
- Statement optionalElseStatement = null;
- if (this.peekRead("else")) {
- optionalElseStatement = this.parseStatement();
- }
-
- return new IfStatement(
- location, // location
- condition, // condition
- thenStatement, // thenStatement
- optionalElseStatement // optionalElseStatement
- );
- }
-
- /**
- *
- * ForStatement :=
- * 'for' '(' [ ForInit ] ';' [ Expression ] ';' [ ExpressionList ] ')' Statement
- * | 'for' '(' FormalParameter ':' Expression ')' Statement
- *
- * ForInit :=
- * Modifiers Type VariableDeclarators
- * | ModifiersOpt BasicType VariableDeclarators
- * | Expression VariableDeclarators (1)
- * | Expression { ',' Expression }
- *
- * (1) "Expression" must pose a type.
- */
- public Statement
- parseForStatement() throws CompileException, IOException {
- this.read("for");
- Location forLocation = this.location();
-
- this.read("(");
-
- BlockStatement optionalInit = null;
- INIT:
- if (!this.peek(";")) {
-
- // 'for' '(' Modifiers Type VariableDeclarators
- // 'for' '(' [ Modifiers ] BasicType VariableDeclarators
- if (this.peek(new String[] {
- "final", "@", "byte", "short", "char", "int", "long", "float", "double", "boolean"
- }) != -1) {
- Modifiers modifiers = this.parseModifiers();
- Type type = this.parseType();
- if (this.peekIdentifier() != null && this.peekNextButOne(":")) {
-
- // 'for' '(' [ Modifiers ] Type identifier ':' Expression ')' Statement
- final String name = this.readIdentifier();
- final Location nameLocation = this.location();
- this.read(":");
- Rvalue expression = this.parseExpression().toRvalue();
- this.read(")");
- return new ForEachStatement(
- forLocation, // location
- new FormalParameter( // currentElement
- nameLocation,
- Mod.isFinal(modifiers.flags),
- type,
- name
- ),
- expression, // expression
- this.parseStatement() // body
- );
- }
-
- // 'for' '(' [ Modifiers ] Type VariableDeclarators
- optionalInit = new LocalVariableDeclarationStatement(
- this.location(), // location
- modifiers, // modifiers
- type, // type
- this.parseVariableDeclarators() // variableDeclarators
- );
- break INIT;
- }
-
- Atom a = this.parseExpression();
-
- if (this.peekIdentifier() != null) {
- if (this.peekNextButOne(":")) {
-
- // 'for' '(' Expression identifier ':' Expression ')' Statement
- final String name = this.readIdentifier();
- final Location nameLocation = this.location();
- this.read(":");
- Rvalue expression = this.parseExpression().toRvalue();
- this.read(")");
- return new ForEachStatement(
- forLocation, // location
- new FormalParameter( // currentElement
- nameLocation,
- false,
- a.toTypeOrCompileException(),
- name
- ),
- expression, // expression
- this.parseStatement() // body
- );
- }
-
- // 'for' '(' Expression VariableDeclarators
- optionalInit = new LocalVariableDeclarationStatement(
- this.location(), // location
- new Java.Modifiers(Mod.NONE), // modifiers
- a.toTypeOrCompileException(), // type
- this.parseVariableDeclarators() // variableDeclarators
- );
- break INIT;
- }
-
- if (!this.peekRead(",")) {
-
- // 'for' '(' Expression
- optionalInit = new ExpressionStatement(a.toRvalueOrCompileException());
- break INIT;
- }
-
- // 'for' '(' Expression { ',' Expression }
- {
- List l = new ArrayList();
- l.add(new ExpressionStatement(a.toRvalueOrCompileException()));
- do {
- l.add(new ExpressionStatement(this.parseExpression().toRvalueOrCompileException()));
- } while (this.peekRead(","));
-
- Block b = new Block(a.getLocation());
- b.addStatements(l);
- optionalInit = b;
- }
- }
-
- this.read(";");
-
- Rvalue optionalCondition = null;
- if (!this.peek(";")) optionalCondition = this.parseExpression().toRvalueOrCompileException();
-
- this.read(";");
-
- Rvalue[] optionalUpdate = null;
- if (!this.peek(")")) optionalUpdate = this.parseExpressionList();
-
- this.read(")");
-
- return new ForStatement(
- forLocation, // location
- optionalInit, // optionalInit
- optionalCondition, // optionalCondition
- optionalUpdate, // optionalUpdate
- this.parseStatement() // body
- );
- }
-
- /**
- *
- * WhileStatement := 'while' '(' Expression ')' Statement
- *
- */
- public Statement
- parseWhileStatement() throws CompileException, IOException {
- final Location location = this.location();
- this.read("while");
-
- this.read("(");
- Rvalue condition = this.parseExpression().toRvalueOrCompileException();
- this.read(")");
-
- return new WhileStatement(
- location, // location
- condition, // condition
- this.parseStatement() // body
- );
- }
-
- /**
- *
- * DoStatement := 'do' Statement 'while' '(' Expression ')' ';'
- *
- */
- public Statement
- parseDoStatement() throws CompileException, IOException {
- final Location location = this.location();
- this.read("do");
-
- final Statement body = this.parseStatement();
-
- this.read("while");
- this.read("(");
- final Rvalue condition = this.parseExpression().toRvalueOrCompileException();
- this.read(")");
- this.read(";");
-
- return new DoStatement(
- location, // location
- body, // body
- condition // condition
- );
- }
-
- /**
- *
- * TryStatement :=
- * 'try' Block Catches [ Finally ] |
- * 'try' Block Finally
- *
- * Catches := CatchClause { CatchClause }
- *
- * CatchClause := 'catch' '(' FormalParameter ')' Block
- *
- * Finally := 'finally' Block
- *
- */
- public Statement
- parseTryStatement() throws CompileException, IOException {
- Location location = this.location();
- this.read("try");
-
- final Block body = this.parseBlock();
-
- // { CatchClause }
- List ccs = new ArrayList();
- while (this.peekRead("catch")) {
- final Location loc = this.location();
- this.read("(");
- boolean[] hasEllipsis = new boolean[1];
- final FormalParameter caughtException = this.parseFormalParameter(hasEllipsis);
- if (hasEllipsis[0]) throw this.compileException("Catch clause parameter must not have an ellipsis");
- this.read(")");
- ccs.add(new CatchClause(
- loc, // location
- caughtException, // caughtException
- this.parseBlock() // body
- ));
- }
- Block optionalFinally = null;
- if (this.peekRead("finally")) {
- optionalFinally = this.parseBlock();
- }
- if (ccs.size() == 0 && optionalFinally == null) {
- throw this.compileException(
- "\"try\" statement must have at least one \"catch\" clause or a \"finally\" clause"
- );
- }
-
- return new TryStatement(
- location, // location
- body, // body
- ccs, // catchClauses
- optionalFinally // optionalFinally
- );
- }
-
- /**
- *
- * SwitchStatement :=
- * 'switch' '(' Expression ')' '{' { SwitchLabels BlockStatements } '}'
- *
- * SwitchLabels := SwitchLabels { SwitchLabels }
- *
- * SwitchLabel := 'case' Expression ':' | 'default' ':'
- *
- */
- public Statement
- parseSwitchStatement() throws CompileException, IOException {
- final Location location = this.location();
- this.read("switch");
-
- this.read("(");
- final Rvalue condition = this.parseExpression().toRvalueOrCompileException();
- this.read(")");
-
- this.read("{");
- List sbsgs = new ArrayList();
- while (!this.peekRead("}")) {
- Location location2 = this.location();
- boolean hasDefaultLabel = false;
- List caseLabels = new ArrayList();
- do {
- if (this.peekRead("case")) {
- caseLabels.add(this.parseExpression().toRvalueOrCompileException());
- } else
- if (this.peekRead("default")) {
- if (hasDefaultLabel) throw this.compileException("Duplicate \"default\" label");
- hasDefaultLabel = true;
- } else {
- throw this.compileException("\"case\" or \"default\" expected");
- }
- this.read(":");
- } while (this.peek(new String[] { "case", "default" }) != -1);
-
- SwitchStatement.SwitchBlockStatementGroup sbsg = new SwitchStatement.SwitchBlockStatementGroup(
- location2, // location
- caseLabels, // caseLabels
- hasDefaultLabel, // hasDefaultLabel
- this.parseBlockStatements() // blockStatements
- );
- sbsgs.add(sbsg);
- }
- return new SwitchStatement(
- location, // location
- condition, // condition
- sbsgs // sbsgs
- );
- }
-
- /**
- *
- * SynchronizedStatement :=
- * 'synchronized' '(' expression ')' Block
- *
- */
- public Statement
- parseSynchronizedStatement() throws CompileException, IOException {
- final Location location = this.location();
- this.read("synchronized");
- this.read("(");
- Rvalue expression = this.parseExpression().toRvalueOrCompileException();
- this.read(")");
- return new SynchronizedStatement(
- location, // location
- expression, // expression
- this.parseBlock() // body
- );
- }
-
- /**
- *
- * ReturnStatement := 'return' [ Expression ] ';'
- *
- */
- public Statement
- parseReturnStatement() throws CompileException, IOException {
- final Location location = this.location();
- this.read("return");
- Rvalue returnValue = this.peek(";") ? null : this.parseExpression().toRvalueOrCompileException();
- this.read(";");
- return new ReturnStatement(location, returnValue);
- }
-
- /**
- *
- * ThrowStatement := 'throw' Expression ';'
- *
- */
- public Statement
- parseThrowStatement() throws CompileException, IOException {
- final Location location = this.location();
- this.read("throw");
- final Rvalue expression = this.parseExpression().toRvalueOrCompileException();
- this.read(";");
-
- return new ThrowStatement(location, expression);
- }
-
- /**
- *
- * BreakStatement := 'break' [ Identifier ] ';'
- *
- */
- public Statement
- parseBreakStatement() throws CompileException, IOException {
- final Location location = this.location();
- this.read("break");
- String optionalLabel = null;
- if (this.peekIdentifier() != null) optionalLabel = this.readIdentifier();
- this.read(";");
- return new BreakStatement(location, optionalLabel);
- }
-
- /**
- *
- * ContinueStatement := 'continue' [ Identifier ] ';'
- *
- */
- public Statement
- parseContinueStatement() throws CompileException, IOException {
- final Location location = this.location();
- this.read("continue");
- String optionalLabel = null;
- if (this.peekIdentifier() != null) optionalLabel = this.readIdentifier();
- this.read(";");
- return new ContinueStatement(location, optionalLabel);
- }
-
- /**
- *
- * AssertStatement := 'assert' Expression [ ':' Expression ] ';'
- *
- */
- public Statement
- parseAssertStatement() throws CompileException, IOException {
- this.read("assert");
- Location loc = this.location();
-
- Rvalue expression1 = this.parseExpression().toRvalueOrCompileException();
- Rvalue optionalExpression2 = this.peekRead(":") ? this.parseExpression().toRvalueOrCompileException() : null;
- this.read(";");
-
- return new AssertStatement(loc, expression1, optionalExpression2);
- }
-
- /**
- *
- * EmptyStatement := ';'
- *
- */
- public Statement
- parseEmptyStatement() throws CompileException, IOException {
- Location location = this.location();
- this.read(";");
- return new EmptyStatement(location);
- }
-
- /**
- *
- * ExpressionList := Expression { ',' Expression }
- *
- */
- public Rvalue[]
- parseExpressionList() throws CompileException, IOException {
- List l = new ArrayList();
- do {
- l.add(this.parseExpression().toRvalueOrCompileException());
- } while (this.peekRead(","));
- return (Rvalue[]) l.toArray(new Rvalue[l.size()]);
- }
-
- /**
- *
- * Type := (
- * 'byte' | 'short' | 'char' | 'int' | 'long' |
- * 'float' | 'double' | 'boolean' |
- * ReferenceType
- * ) { '[' ']' }
- *
- */
- public Type
- parseType() throws CompileException, IOException {
- int idx = this.peekRead(Parser.BASIC_TYPE_NAMES);
- Type res = (
- idx != -1
- ? (Type) new BasicType(this.location(), Parser.BASIC_TYPE_CODES[idx])
- : this.parseReferenceType()
- );
- for (int i = this.parseBracketsOpt(); i > 0; --i) res = new ArrayType(res);
- return res;
- }
- private static final String[] BASIC_TYPE_NAMES = {
- "byte", "short", "char", "int", "long", "float",
- "double", "boolean"
- };
- private static final int[] BASIC_TYPE_CODES = {
- BasicType.BYTE, BasicType.SHORT, BasicType.CHAR, BasicType.INT, BasicType.LONG, BasicType.FLOAT,
- BasicType.DOUBLE, BasicType.BOOLEAN
- };
-
- /**
- *
- * ReferenceType := QualifiedIdentifier [ TypeArguments ]
- *
- */
- public ReferenceType
- parseReferenceType() throws CompileException, IOException {
- return new ReferenceType(this.location(), this.parseQualifiedIdentifier(), this.parseTypeArgumentsOpt());
- }
-
- /**
- *
- * TypeParameters := '<' TypeParameter { ',' TypeParameter } '>'
- *
- */
- private TypeParameter[]
- parseTypeParametersOpt() throws CompileException, IOException {
- if (!this.peekRead("<")) return null;
- List l = new ArrayList();
- l.add(this.parseTypeParameter());
- while (this.read(new String[] { ",", ">" }) == 0) {
- l.add(this.parseTypeParameter());
- }
- return (TypeParameter[]) l.toArray(new TypeParameter[l.size()]);
- }
-
- /**
- *
- * TypeParameter := identifier [ 'extends' ( identifier | ReferenceType { '&' ReferenceType }
- *
- */
- private TypeParameter
- parseTypeParameter() throws CompileException, IOException {
- String name = this.readIdentifier();
- if (this.peekRead("extends")) {
- List bound = new ArrayList();
- bound.add(this.parseReferenceType());
- while (this.peekRead("&")) this.parseReferenceType();
- return new TypeParameter(name, (ReferenceType[]) bound.toArray(new ReferenceType[bound.size()]));
- }
- return new TypeParameter(name, null);
- }
-
- /**
- *
- * TypeArguments := '<' TypeArgument { ',' TypeArgument } '>'
- *
- */
- private TypeArgument[]
- parseTypeArgumentsOpt() throws CompileException, IOException {
- if (!this.peekRead("<")) return null;
-
- // Temporarily switch the scanner into 'expect greater' mode, where it doesn't recognize operators starting
- // with '>>'.
- boolean orig = this.scanner.setExpectGreater(true);
- try {
-
- List typeArguments = new ArrayList();
- typeArguments.add(this.parseTypeArgument());
- while (this.read(new String[] { ">", "," }) == 1) {
- typeArguments.add(this.parseTypeArgument());
- }
- return (TypeArgument[]) typeArguments.toArray(new TypeArgument[typeArguments.size()]);
- } finally {
- this.scanner.setExpectGreater(orig);
- }
- }
-
- /**
- *
- * TypeArgument :=
- * ReferenceType { '[' ']' } <= The optional brackets are mising in JLS7, section 18!?
- * | BasicType '[' ']' { '[' ']' }
- * | '?' extends ReferenceType
- * | '?' super ReferenceType
- *
- */
- private TypeArgument
- parseTypeArgument() throws CompileException, IOException {
- if (this.peekRead("?")) {
- return (
- this.peekRead("extends") ? new Wildcard(Wildcard.BOUNDS_EXTENDS, this.parseReferenceType()) :
- this.peekRead("super") ? new Wildcard(Wildcard.BOUNDS_SUPER, this.parseReferenceType()) :
- new Wildcard()
- );
- }
-
- Type t = this.parseType();
-
- int i = this.parseBracketsOpt();
- for (; i > 0; i--) t = new ArrayType(t);
- if (!(t instanceof TypeArgument)) throw this.compileException("'" + t + "' is not a valid type argument");
- return (TypeArgument) t;
- }
-
- /**
- *
- * ReferenceTypeList := ReferenceType { ',' ReferenceType }
- *
- */
- public ReferenceType[]
- parseReferenceTypeList() throws CompileException, IOException {
- List l = new ArrayList();
- l.add(this.parseReferenceType());
- while (this.peekRead(",")) {
- l.add(this.parseReferenceType());
- }
- return (ReferenceType[]) l.toArray(new ReferenceType[l.size()]);
- }
-
- /**
- *
- * Expression := AssignmentExpression
- *
- */
- public Atom
- parseExpression() throws CompileException, IOException {
- return this.parseAssignmentExpression();
- }
-
- /**
- *
- * AssignmentExpression :=
- * ConditionalExpression [ AssignmentOperator AssignmentExpression ]
- *
- * AssignmentOperator :=
- * '=' | '*=' | '/=' | '%=' | '+=' | '-=' | '<<=' |
- * '>>=' | '>>>=' | '&=' | '^=' | '|='
- *
- */
- public Atom
- parseAssignmentExpression() throws CompileException, IOException {
- Atom a = this.parseConditionalExpression();
- if (this.peek(
- new String[] { "=", "+=", "-=", "*=", "/=", "&=", "|=", "^=", "%=", "<<=", ">>=", ">>>=" }
- ) != -1) {
- final Lvalue lhs = a.toLvalueOrCompileException();
- Location location = this.location();
- String operator = this.readOperator();
- final Rvalue rhs = this.parseAssignmentExpression().toRvalueOrCompileException();
- return new Assignment(location, lhs, operator, rhs);
- }
- return a;
- }
-
- /**
- *
- * ConditionalExpression :=
- * ConditionalOrExpression [ '?' Expression ':' ConditionalExpression ]
- *
- */
- public Atom
- parseConditionalExpression() throws CompileException, IOException {
- Atom a = this.parseConditionalOrExpression();
- if (!this.peekRead("?")) return a;
- Location location = this.location();
-
- Rvalue lhs = a.toRvalueOrCompileException();
- Rvalue mhs = this.parseExpression().toRvalueOrCompileException();
- this.read(":");
- Rvalue rhs = this.parseConditionalExpression().toRvalueOrCompileException();
- return new ConditionalExpression(location, lhs, mhs, rhs);
- }
-
- /**
- *
- * ConditionalOrExpression :=
- * ConditionalAndExpression { '||' ConditionalAndExpression ]
- *
- */
- public Atom
- parseConditionalOrExpression() throws CompileException, IOException {
- Atom a = this.parseConditionalAndExpression();
- while (this.peekRead("||")) {
- Location location = this.location();
- a = new BinaryOperation(
- location,
- a.toRvalueOrCompileException(),
- "||",
- this.parseConditionalAndExpression().toRvalueOrCompileException()
- );
- }
- return a;
- }
-
- /**
- *
- * ConditionalAndExpression :=
- * InclusiveOrExpression { '&&' InclusiveOrExpression }
- *
- */
- public Atom
- parseConditionalAndExpression() throws CompileException, IOException {
- Atom a = this.parseInclusiveOrExpression();
- while (this.peekRead("&&")) {
- Location location = this.location();
- a = new BinaryOperation(
- location,
- a.toRvalueOrCompileException(),
- "&&",
- this.parseInclusiveOrExpression().toRvalueOrCompileException()
- );
- }
- return a;
- }
-
- /**
- *
- * InclusiveOrExpression :=
- * ExclusiveOrExpression { '|' ExclusiveOrExpression }
- *
- */
- public Atom
- parseInclusiveOrExpression() throws CompileException, IOException {
- Atom a = this.parseExclusiveOrExpression();
- while (this.peekRead("|")) {
- Location location = this.location();
- a = new BinaryOperation(
- location,
- a.toRvalueOrCompileException(),
- "|",
- this.parseExclusiveOrExpression().toRvalueOrCompileException()
- );
- }
- return a;
- }
-
- /**
- *
- * ExclusiveOrExpression :=
- * AndExpression { '^' AndExpression }
- *
- */
- public Atom
- parseExclusiveOrExpression() throws CompileException, IOException {
- Atom a = this.parseAndExpression();
- while (this.peekRead("^")) {
- Location location = this.location();
- a = new BinaryOperation(
- location,
- a.toRvalueOrCompileException(),
- "^",
- this.parseAndExpression().toRvalueOrCompileException()
- );
- }
- return a;
- }
-
- /**
- *
- * AndExpression :=
- * EqualityExpression { '&' EqualityExpression }
- *
- */
- public Atom
- parseAndExpression() throws CompileException, IOException {
- Atom a = this.parseEqualityExpression();
- while (this.peekRead("&")) {
- Location location = this.location();
- a = new BinaryOperation(
- location,
- a.toRvalueOrCompileException(),
- "&",
- this.parseEqualityExpression().toRvalueOrCompileException()
- );
- }
- return a;
- }
-
- /**
- *
- * EqualityExpression :=
- * RelationalExpression { ( '==' | '!=' ) RelationalExpression }
- *
- */
- public Atom
- parseEqualityExpression() throws CompileException, IOException {
- Atom a = this.parseRelationalExpression();
-
- while (this.peek(new String[] { "==", "!=" }) != -1) {
- a = new BinaryOperation(
- this.location(), // location
- a.toRvalueOrCompileException(), // lhs
- this.read().value, // op
- this.parseRelationalExpression().toRvalueOrCompileException() // rhs
- );
- }
- return a;
- }
-
- /**
- *
- * RelationalExpression :=
- * ShiftExpression {
- * 'instanceof' ReferenceType
- * | '<' ShiftExpression [ { ',' TypeArgument } '>' ]
- * | '<' TypeArgument [ { ',' TypeArgument } '>' ]
- * | ( '>' | '<=' | '>=' ) ShiftExpression
- * }
- *
- */
- public Atom
- parseRelationalExpression() throws CompileException, IOException {
- Atom a = this.parseShiftExpression();
-
- for (;;) {
- if (this.peekRead("instanceof")) {
- Location location = this.location();
- a = new Instanceof(
- location,
- a.toRvalueOrCompileException(),
- this.parseType()
- );
- } else
- if (this.peek(new String[] { "<", ">", "<=", ">=" }) != -1) {
- String op = this.read().value;
-
- if ("<".equals(op) && a instanceof Java.AmbiguousName && this.peek("?")) {
- final String[] identifiers = ((Java.AmbiguousName) a).identifiers;
-
- // Temporarily switch the scanner into 'expect greater' mode, where it doesn't recognize operators
- // starting with '>>'.
- boolean orig = this.scanner.setExpectGreater(true);
- try {
-
- // '<' TypeArgument [ { ',' TypeArgument } '>' ]
- List typeArguments = new ArrayList();
- typeArguments.add(this.parseTypeArgument());
- while (this.read(new String[] { ">", "," }) == 1) typeArguments.add(this.parseTypeArgument());
-
- return new ReferenceType(
- this.location(),
- identifiers,
- (TypeArgument[]) typeArguments.toArray(new TypeArgument[typeArguments.size()])
- );
- } finally {
- this.scanner.setExpectGreater(orig);
- }
- }
-
- Atom rhs = this.parseShiftExpression();
-
- if ("<".equals(op) && a instanceof Java.AmbiguousName) {
-
- // Temporarily switch the scanner into 'expect greater' mode, where it doesn't recognize operators
- // starting with '>>'.
- boolean orig = this.scanner.setExpectGreater(true);
- try {
-
- if (this.peek(new String[] { "<", ">", "," }) != -1) {
- final String[] identifiers = ((Java.AmbiguousName) a).identifiers;
-
- // '<' ShiftExpression [ TypeArguments ] { ',' TypeArgument } '>'
- this.parseTypeArgumentsOpt();
- Type t = rhs.toTypeOrCompileException();
-
- TypeArgument ta;
- if (t instanceof ArrayType) { ta = (ArrayType) t; } else
- if (t instanceof ReferenceType) { ta = (ReferenceType) t; } else
- {
- throw this.compileException("'" + t + "' is not a valid type argument");
- }
-
- List typeArguments = new ArrayList();
- typeArguments.add(ta);
- while (this.read(new String[] { ">", "," }) == 1) {
- typeArguments.add(this.parseTypeArgument());
- }
-
- return new ReferenceType(
- this.location(),
- identifiers,
- (TypeArgument[]) typeArguments.toArray(new TypeArgument[typeArguments.size()])
- );
- }
- } finally {
- this.scanner.setExpectGreater(orig);
- }
- }
-
- a = new BinaryOperation(
- this.location(), // location
- a.toRvalueOrCompileException(), // lhs
- op, // op
- rhs.toRvalueOrCompileException() // rhs
- );
- } else {
- return a;
- }
- }
- }
-
- /**
- *
- * ShiftExpression :=
- * AdditiveExpression { ( '<<' | '>>' | '>>>' ) AdditiveExpression }
- *
- */
- public Atom
- parseShiftExpression() throws CompileException, IOException {
- Atom a = this.parseAdditiveExpression();
-
- while (this.peek(new String[] { "<<", ">>", ">>>" }) != -1) {
- a = new BinaryOperation(
- this.location(), // location
- a.toRvalueOrCompileException(), // lhs
- this.read().value, // op
- this.parseAdditiveExpression().toRvalueOrCompileException() // rhs
- );
- }
- return a;
- }
-
- /**
- *
- * AdditiveExpression :=
- * MultiplicativeExpression { ( '+' | '-' ) MultiplicativeExpression }
- *
- */
- public Atom
- parseAdditiveExpression() throws CompileException, IOException {
- Atom a = this.parseMultiplicativeExpression();
-
- while (this.peek(new String[] { "+", "-" }) != -1) {
- a = new BinaryOperation(
- this.location(), // location
- a.toRvalueOrCompileException(), // lhs
- this.read().value, // op
- this.parseMultiplicativeExpression().toRvalueOrCompileException() // rhs
- );
- }
- return a;
- }
-
- /**
- *
- * MultiplicativeExpression :=
- * UnaryExpression { ( '*' | '/' | '%' ) UnaryExpression }
- *
- */
- public Atom
- parseMultiplicativeExpression() throws CompileException, IOException {
- Atom a = this.parseUnaryExpression();
-
- while (this.peek(new String[] { "*", "/", "%" }) != -1) {
- a = new BinaryOperation(
- this.location(), // location
- a.toRvalueOrCompileException(), // lhs
- this.read().value, // op
- this.parseUnaryExpression().toRvalueOrCompileException() // rhs
- );
- }
- return a;
- }
-
- /**
- *
- * UnaryExpression :=
- * { PrefixOperator } Primary { Selector } { PostfixOperator }
- *
- * PrefixOperator := '++' | '--' | '+' | '-' | '~' | '!'
- *
- * PostfixOperator := '++' | '--'
- *
- */
- public Atom
- parseUnaryExpression() throws CompileException, IOException {
- if (this.peek(new String[] { "++", "--" }) != -1) {
- return new Crement(
- this.location(), // location
- this.read().value, // operator
- this.parseUnaryExpression().toLvalueOrCompileException() // operand
- );
- }
-
- if (this.peek(new String[] { "+", "-", "~", "!" }) != -1) {
- return new UnaryOperation(
- this.location(), // location
- this.read().value, // operator
- this.parseUnaryExpression().toRvalueOrCompileException() // operand
- );
- }
-
- Atom a = this.parsePrimary();
-
- while (this.peek(new String[] { ".", "[" }) != -1) {
- a = this.parseSelector(a);
- }
-
- while (this.peek(new String[] { "++", "--" }) != -1) {
- a = new Crement(
- this.location(), // location
- a.toLvalueOrCompileException(), // operand
- this.read().value // operator
- );
- }
-
- return a;
- }
-
- /**
- *
- * Primary :=
- * CastExpression | // CastExpression 15.16
- * '(' Expression ')' | // ParenthesizedExpression 15.8.5
- * Literal | // Literal 15.8.1
- * Name | // AmbiguousName
- * Name Arguments | // MethodInvocation
- * Name '[]' { '[]' } | // ArrayType 10.1
- * Name '[]' { '[]' } '.' 'class' | // ClassLiteral 15.8.2
- * 'this' | // This 15.8.3
- * 'this' Arguments | // Alternate constructor invocation 8.8.5.1
- * 'super' Arguments | // Unqualified superclass constructor invocation 8.8.5.1
- * 'super' '.' Identifier | // SuperclassFieldAccess 15.11.2
- * 'super' '.' Identifier Arguments | // SuperclassMethodInvocation 15.12.4.9
- * NewClassInstance |
- * NewAnonymousClassInstance | // ClassInstanceCreationExpression 15.9
- * NewArray | // ArrayCreationExpression 15.10
- * NewInitializedArray | // ArrayInitializer 10.6
- * BasicType { '[]' } | // Type
- * BasicType { '[]' } '.' 'class' | // ClassLiteral 15.8.2
- * 'void' '.' 'class' // ClassLiteral 15.8.2
- *
- * CastExpression :=
- * '(' PrimitiveType { '[]' } ')' UnaryExpression |
- * '(' Expression ')' UnaryExpression
- *
- * NewClassInstance := 'new' ReferenceType Arguments
- *
- * NewAnonymousClassInstance := 'new' ReferenceType Arguments [ ClassBody ]
- *
- * NewArray := 'new' Type DimExprs { '[]' }
- *
- * NewInitializedArray := 'new' ArrayType ArrayInitializer
- *
- */
- public Atom
- parsePrimary() throws CompileException, IOException {
- if (this.peekRead("(")) {
- if (
- this.peek(new String[] { "boolean", "char", "byte", "short", "int", "long", "float", "double", }) != -1
- ) {
- // '(' PrimitiveType { '[]' } ')' UnaryExpression
- Type type = this.parseType();
- int brackets = this.parseBracketsOpt();
- this.read(")");
- for (int i = 0; i < brackets; ++i) type = new ArrayType(type);
- return new Cast(
- this.location(), // location
- type, // targetType
- this.parseUnaryExpression().toRvalueOrCompileException() // value
- );
- }
- Atom a = this.parseExpression();
- this.read(")");
-
- if (
- this.peekLiteral()
- || this.peekIdentifier() != null
- || this.peek(new String[] { "(", "~", "!", }) != -1
- || this.peek(new String[] { "this", "super", "new", }) != -1
- ) {
- // '(' Expression ')' UnaryExpression
- return new Cast(
- this.location(), // location
- a.toTypeOrCompileException(), // targetType
- this.parseUnaryExpression().toRvalueOrCompileException() // value
- );
- }
-
- // '(' Expression ')'
- return new ParenthesizedExpression(a.getLocation(), a.toRvalueOrCompileException());
- }
-
- if (this.peekLiteral()) {
-
- // Literal
- return this.parseLiteral();
- }
-
- if (this.peekIdentifier() != null) {
- Location location = this.location();
- String[] qi = this.parseQualifiedIdentifier();
- if (this.peek("(")) {
- // Name Arguments
- return new MethodInvocation(
- this.location(), // location
- qi.length == 1 ? null : new AmbiguousName( // optionalTarget
- location, // location
- qi, // identifiers
- qi.length - 1 // n
- ),
- qi[qi.length - 1], // methodName
- this.parseArguments() // arguments
- );
- }
- if (this.peek("[") && this.peekNextButOne("]")) {
- // Name '[]' { '[]' }
- // Name '[]' { '[]' } '.' 'class'
- Type res = new ReferenceType(
- location, // location
- qi, // identifiers
- null // optionalTypeArguments
- );
- int brackets = this.parseBracketsOpt();
- for (int i = 0; i < brackets; ++i) res = new ArrayType(res);
- if (this.peek(".") && this.peekNextButOne("class")) {
- this.read();
- Location location2 = this.location();
- this.read();
- return new ClassLiteral(location2, res);
- } else {
- return res;
- }
- }
- // Name
- return new AmbiguousName(
- location, // location
- qi // identifiers
- );
- }
-
- if (this.peekRead("this")) {
- Location location = this.location();
- if (this.peek("(")) {
-
- // 'this' Arguments
- // Alternate constructor invocation (JLS7 8.8.7.1).
- return new AlternateConstructorInvocation(
- location, // location
- this.parseArguments() // arguments
- );
- } else
- {
-
- // 'this'
- return new ThisReference(location);
- }
- }
-
- if (this.peekRead("super")) {
- if (this.peek("(")) {
-
- // 'super' Arguments
- // Unqualified superclass constructor invocation (JLS7 8.8.7.1).
- return new SuperConstructorInvocation(
- this.location(), // location
- (Rvalue) null, // optionalQualification
- this.parseArguments() // arguments
- );
- }
- this.read(".");
- String name = this.readIdentifier();
- if (this.peek("(")) {
-
- // 'super' '.' Identifier Arguments
- return new SuperclassMethodInvocation(
- this.location(), // location
- name, // methodName
- this.parseArguments() // arguments
- );
- } else {
-
- // 'super' '.' Identifier
- return new SuperclassFieldAccessExpression(
- this.location(), // location
- (Type) null, // optionalQualification
- name // fieldName
- );
- }
- }
-
- // 'new'
- if (this.peekRead("new")) {
- Location location = this.location();
- Type type = this.parseType();
- if (type instanceof ArrayType) {
- // 'new' ArrayType ArrayInitializer
- return new NewInitializedArray(location, (ArrayType) type, this.parseArrayInitializer());
- }
- if (type instanceof ReferenceType && this.peek("(")) {
- // 'new' ReferenceType Arguments [ ClassBody ]
- Rvalue[] arguments = this.parseArguments();
- if (this.peek("{")) {
- // 'new' ReferenceType Arguments ClassBody
- final AnonymousClassDeclaration anonymousClassDeclaration = new AnonymousClassDeclaration(
- this.location(), // location
- type // baseType
- );
- this.parseClassBody(anonymousClassDeclaration);
- return new NewAnonymousClassInstance(
- location, // location
- (Rvalue) null, // optionalQualification
- anonymousClassDeclaration, // anonymousClassDeclaration
- arguments // arguments
- );
- } else {
- // 'new' ReferenceType Arguments
- return new NewClassInstance(
- location, // location
- (Rvalue) null, // optionalQualification
- type, // type
- arguments // arguments
- );
- }
- }
- // 'new' Type DimExprs { '[]' }
- return new NewArray(
- location, // location
- type, // type
- this.parseDimExprs(), // dimExprs
- this.parseBracketsOpt() // dims
- );
- }
-
- // BasicType
- if (this.peek(new String[] { "boolean", "char", "byte", "short", "int", "long", "float", "double" }) != -1) {
- Type res = this.parseType();
- int brackets = this.parseBracketsOpt();
- for (int i = 0; i < brackets; ++i) res = new ArrayType(res);
- if (this.peek(".") && this.peekNextButOne("class")) {
- // BasicType { '[]' } '.' 'class'
- this.read();
- Location location = this.location();
- this.read();
- return new ClassLiteral(location, res);
- }
- // BasicType { '[]' }
- return res;
- }
-
- // 'void'
- if (this.peekRead("void")) {
- if (this.peek(".") && this.peekNextButOne("class")) {
- // 'void' '.' 'class'
- this.read();
- Location location = this.location();
- this.read();
- return new ClassLiteral(location, new BasicType(location, BasicType.VOID));
- }
- throw this.compileException("\"void\" encountered in wrong context");
- }
-
- throw this.compileException("Unexpected token \"" + this.peek().value + "\" in primary");
- }
-
- /**
- *
- * Selector :=
- * '.' Identifier | // FieldAccess 15.11.1
- * '.' Identifier Arguments | // MethodInvocation
- * '.' 'this' // QualifiedThis 15.8.4
- * '.' 'super' Arguments // Qualified superclass constructor invocation (JLS7 8.8.7.1)
- * '.' 'super' '.' Identifier | // SuperclassFieldReference (JLS7 15.11.2)
- * '.' 'super' '.' Identifier Arguments | // SuperclassMethodInvocation (JLS7 15.12.3)
- * '.' 'new' Identifier Arguments [ ClassBody ] | // QualifiedClassInstanceCreationExpression 15.9
- * '.' 'class'
- * '[' Expression ']' // ArrayAccessExpression 15.13
- *
- */
- public Atom
- parseSelector(Atom atom) throws CompileException, IOException {
- if (this.peekRead(".")) {
- if (this.peek().type == Token.IDENTIFIER) {
- String identifier = this.readIdentifier();
- if (this.peek("(")) {
- // '.' Identifier Arguments
- return new MethodInvocation(
- this.location(), // location
- atom.toRvalueOrCompileException(), // optionalTarget
- identifier, // methodName
- this.parseArguments() // arguments
- );
- }
- // '.' Identifier
- return new FieldAccessExpression(
- this.location(), // location
- atom.toRvalueOrCompileException(), // lhs
- identifier // fieldName
- );
- }
- if (this.peekRead("this")) {
- // '.' 'this'
- Location location = this.location();
- return new QualifiedThisReference(
- location, // location
- atom.toTypeOrCompileException() // qualification
- );
- }
- if (this.peekRead("super")) {
- Location location = this.location();
- if (this.peek("(")) {
-
- // '.' 'super' Arguments
- // Qualified superclass constructor invocation (JLS7 8.7.1.2.2) (LHS is an Rvalue)
- return new SuperConstructorInvocation(
- location, // location
- atom.toRvalueOrCompileException(), // optionalQualification
- this.parseArguments() // arguments
- );
- }
- this.read(".");
- String identifier = this.readIdentifier();
-
- if (this.peek("(")) {
-
- // '.' 'super' '.' Identifier Arguments
- // Qualified superclass method invocation (JLS7 15.12.1.1.4) (LHS is a ClassName).
- // TODO: Qualified superclass method invocation
- throw this.compileException("Qualified superclass method invocation NYI");
- } else {
-
- // '.' 'super' '.' Identifier
- // Qualified superclass field access (JLS7 15.11.2) (LHS is an Rvalue).
- return new SuperclassFieldAccessExpression(
- location, // location
- atom.toTypeOrCompileException(), // optionalQualification
- identifier // fieldName
- );
- }
- }
- if (this.peekRead("new")) {
- // '.' 'new' Identifier Arguments [ ClassBody ]
- Rvalue lhs = atom.toRvalue();
- Location location = this.location();
- String identifier = this.readIdentifier();
- Type type = new RvalueMemberType(
- location, // location
- lhs, // rValue
- identifier // identifier
- );
- Rvalue[] arguments = this.parseArguments();
- if (this.peek("{")) {
- // '.' 'new' Identifier Arguments ClassBody (LHS is an Rvalue)
- final AnonymousClassDeclaration anonymousClassDeclaration = new AnonymousClassDeclaration(
- this.location(), // location
- type // baseType
- );
- this.parseClassBody(anonymousClassDeclaration);
- return new NewAnonymousClassInstance(
- location, // location
- lhs, // optionalQualification
- anonymousClassDeclaration, // anonymousClassDeclaration
- arguments // arguments
- );
- } else {
- // '.' 'new' Identifier Arguments (LHS is an Rvalue)
- return new NewClassInstance(
- location, // location
- lhs, // optionalQualification
- type, // referenceType
- arguments // arguments
- );
- }
- }
- if (this.peekRead("class")) {
- // '.' 'class'
- Location location = this.location();
- return new ClassLiteral(location, atom.toTypeOrCompileException());
- }
- throw this.compileException("Unexpected selector '" + this.peek().value + "' after \".\"");
- }
- if (this.peekRead("[")) {
- // '[' Expression ']'
- Location location = this.location();
- Rvalue index = this.parseExpression().toRvalueOrCompileException();
- this.read("]");
- return new ArrayAccessExpression(
- location, // location
- atom.toRvalueOrCompileException(), // lhs
- index // index
- );
- }
- throw this.compileException("Unexpected token '" + this.peek().value + "' in selector");
- }
-
- /**
- *
- * DimExprs := DimExpr { DimExpr }
- *
- */
- public Rvalue[]
- parseDimExprs() throws CompileException, IOException {
- List l = new ArrayList();
- l.add(this.parseDimExpr());
- while (this.peek("[") && !this.peekNextButOne("]")) {
- l.add(this.parseDimExpr());
- }
- return (Rvalue[]) l.toArray(new Rvalue[l.size()]);
- }
-
- /**
- *
- * DimExpr := '[' Expression ']'
- *
- */
- public Rvalue
- parseDimExpr() throws CompileException, IOException {
- this.read("[");
- Rvalue res = this.parseExpression().toRvalueOrCompileException();
- this.read("]");
- return res;
- }
-
- /**
- *
- * Arguments := '(' [ ArgumentList ] ')'
- *
- */
- public Rvalue[]
- parseArguments() throws CompileException, IOException {
- this.read("(");
- if (this.peekRead(")")) return new Rvalue[0];
- Rvalue[] arguments = this.parseArgumentList();
- this.read(")");
- return arguments;
- }
-
- /**
- *
- * ArgumentList := Expression { ',' Expression }
- *
- */
- public Rvalue[]
- parseArgumentList() throws CompileException, IOException {
- List l = new ArrayList();
- do {
- l.add(this.parseExpression().toRvalueOrCompileException());
- } while (this.peekRead(","));
- return (Rvalue[]) l.toArray(new Rvalue[l.size()]);
- }
-
- /**
- *
- * Literal :=
- * IntegerLiteral
- * | FloatingPointLiteral
- * | BooleanLiteral
- * | CharacterLiteral
- * | StringLiteral
- * | NullLiteral
- *
- */
- public Rvalue
- parseLiteral() throws CompileException, IOException {
- Token t = this.read();
- switch (t.type) {
- case Token.INTEGER_LITERAL: return new IntegerLiteral(t.getLocation(), t.value);
- case Token.FLOATING_POINT_LITERAL: return new FloatingPointLiteral(t.getLocation(), t.value);
- case Token.BOOLEAN_LITERAL: return new BooleanLiteral(t.getLocation(), t.value);
- case Token.CHARACTER_LITERAL: return new CharacterLiteral(t.getLocation(), t.value);
- case Token.STRING_LITERAL: return new StringLiteral(t.getLocation(), t.value);
- case Token.NULL_LITERAL: return new NullLiteral(t.getLocation(), t.value);
- default:
- throw this.compileException("Literal expected");
- }
- }
-
- /**
- *
- * ExpressionStatement := Expression ';'
- *
- */
- public Statement
- parseExpressionStatement() throws CompileException, IOException {
- Rvalue rv = this.parseExpression().toRvalueOrCompileException();
- this.read(";");
-
- return new ExpressionStatement(rv);
- }
-
- /** @return The location of the first character of the previously {@link #peek()}ed or {@link #read()} token */
- public Location
- location() { return this.scanner.location(); }
-
- private Token nextToken, nextButOneToken;
-
- // Token-level methods.
-
- /** @return The next token, but does not consume it */
- public Token
- peek() throws CompileException, IOException {
- if (this.nextToken == null) this.nextToken = this.scanner.produce();
- return this.nextToken;
- }
-
- /** @return The next-but-one token, but consumes neither the next nor the next-but-one token */
- public Token
- peekNextButOne() throws CompileException, IOException {
- if (this.nextToken == null) this.nextToken = this.scanner.produce();
- if (this.nextButOneToken == null) this.nextButOneToken = this.scanner.produce();
- return this.nextButOneToken;
- }
-
- /** @return The next and also consumes it, or {@code null} iff the scanner is at end-of-input */
- public Token
- read() throws CompileException, IOException {
- if (this.nextToken == null) return this.scanner.produce();
- final Token result = this.nextToken;
- this.nextToken = this.nextButOneToken;
- this.nextButOneToken = null;
- return result;
- }
-
- // Peek/read/peekRead convenience methods.
-
- /** @return Whether the value of the next token equals {@code suspected}; does not consume the next token */
- public boolean
- peek(String suspected) throws CompileException, IOException {
- return this.peek().value.equals(suspected);
- }
-
- /**
- * Checks whether the value of the next token equals any of the {@code suspected}; does not consume the next
- * token.
- *
- * @return The index of the first of the {@code suspected} that equals the value of the next token, or -1 if the
- * value of the next token equals none of the {@code suspected}
- */
- public int
- peek(String[] suspected) throws CompileException, IOException {
- return Parser.indexOf(suspected, this.peek().value);
- }
-
- /**
- * Checks whether the type of the next token is any of the {@code suspected}; does not consume the next token.
- *
- * @return The index of the first of the {@code suspected} types that is the next token's type, or -1 if the type
- * of the next token is none of the {@code suspected} types
- */
- public int
- peek(int[] suspected) throws CompileException, IOException {
- return Parser.indexOf(suspected, this.peek().type);
- }
-
- /**
- * @return Whether the value of the next-but-one token equals the {@code suspected}; consumes neither the next
- * nor the next-but-one token
- */
- public boolean
- peekNextButOne(String suspected) throws CompileException, IOException {
- return this.peekNextButOne().value.equals(suspected);
- }
-
- /**
- * Verifies that the value of the next token equals {@code expected}, and consumes the token.
- *
- * @throws CompileException The value of the next token does not equal {@code expected} (this includes the case
- * that the scanner is at end-of-input)
- */
- public void
- read(String expected) throws CompileException, IOException {
- String s = this.read().value;
- if (!s.equals(expected)) throw this.compileException("'" + expected + "' expected instead of '" + s + "'");
- }
-
- /**
- * Verifies that the value of the next token equals one of the {@code expected}, and consumes the token.
- *
- * @return The index of the consumed token within {@code expected}
- * @throws CompileException The value of the next token does not equal any of the {@code expected} (this includes
- * the case where the scanner is at end-of-input)
- */
- public int
- read(String[] expected) throws CompileException, IOException {
-
- String s = this.read().value;
-
- int idx = Parser.indexOf(expected, s);
- if (idx == -1) {
- throw this.compileException("One of '" + Parser.join(expected, " ") + "' expected instead of '" + s + "'");
- }
- return idx;
- }
-
- /**
- * @return Whether the value of the next token equals the {@code suspected}; if so, it consumes the next token
- * @throws CompileException
- * @throws IOException
- */
- public boolean
- peekRead(String suspected) throws CompileException, IOException {
- if (this.nextToken == null) {
- Token t = this.scanner.produce();
- if (t.value.equals(suspected)) return true;
- this.nextToken = t;
- return false;
- }
- if (!this.nextToken.value.equals(suspected)) return false;
- this.nextToken = this.nextButOneToken;
- this.nextButOneToken = null;
- return true;
- }
-
- /** @return -1 iff the next token is none of values
*/
- public int
- peekRead(String[] values) throws CompileException, IOException {
- if (this.nextToken == null) {
- Token t = this.scanner.produce();
- int idx = Parser.indexOf(values, t.value);
- if (idx != -1) return idx;
- this.nextToken = t;
- return -1;
- }
- int idx = Parser.indexOf(values, this.nextToken.value);
- if (idx == -1) return -1;
- this.nextToken = this.nextButOneToken;
- this.nextButOneToken = null;
- return idx;
- }
-
- /** @return Whether the scanner is at end-of-input */
- public boolean
- peekEof() throws CompileException, IOException {
- return this.peek().type == Token.EOF;
- }
-
- /** @return {@code null} iff the next token is not an identifier, otherwise the value of the identifier token */
- public String
- peekIdentifier() throws CompileException, IOException {
- Token t = this.peek();
- return t.type == Token.IDENTIFIER ? t.value : null;
- }
-
- /** @return Whether the next token is a literal */
- public boolean
- peekLiteral() throws CompileException, IOException {
- return this.peek(new int[] {
- Token.INTEGER_LITERAL, Token.FLOATING_POINT_LITERAL, Token.BOOLEAN_LITERAL, Token.CHARACTER_LITERAL,
- Token.STRING_LITERAL, Token.NULL_LITERAL,
- }) != -1;
- }
-
- /**
- * @return The value of the next token, which is an indentifier
- * @throws CompileException The next token is not an identifier
- */
- public String
- readIdentifier() throws CompileException, IOException {
- Token t = this.read();
- if (t.type != Token.IDENTIFIER) throw this.compileException("Identifier expected instead of '" + t.value + "'");
- return t.value;
- }
-
- /**
- * @return The value of the next token, which is an operator
- * @throws CompileException The next token is not an operator
- */
- public String
- readOperator() throws CompileException, IOException {
- Token t = this.read();
- if (t.type != Token.OPERATOR) throw this.compileException("Operator expected instead of '" + t.value + "'");
- return t.value;
- }
-
- private static int
- indexOf(String[] strings, String subject) {
- for (int i = 0; i < strings.length; ++i) {
- if (strings[i].equals(subject)) return i;
- }
- return -1;
- }
-
- private static int
- indexOf(int[] values, int subject) {
- for (int i = 0; i < values.length; ++i) {
- if (values[i] == subject) return i;
- }
- return -1;
- }
-
- /** Issue a warning if the given string does not comply with the package naming conventions. */
- private void
- verifyStringIsConventionalPackageName(String s, Location loc) throws CompileException {
- if (!Character.isLowerCase(s.charAt(0))) {
- this.warning(
- "UPN",
- "Package name \"" + s + "\" does not begin with a lower-case letter (see JLS7 6.8.1)",
- loc
- );
- return;
- }
-
- for (int i = 0; i < s.length(); ++i) {
- char c = s.charAt(i);
- if (!Character.isLowerCase(c) && c != '_' && c != '.') {
- this.warning("PPN", "Poorly chosen package name \"" + s + "\" contains bad character '" + c + "'", loc);
- return;
- }
- }
- }
-
- /**
- * Issue a warning if the given identifier does not comply with the class and interface type naming conventions
- * (JLS7 6.8.2).
- */
- private void
- verifyIdentifierIsConventionalClassOrInterfaceName(String id, Location loc) throws CompileException {
- if (!Character.isUpperCase(id.charAt(0))) {
- this.warning(
- "UCOIN1",
- "Class or interface name \"" + id + "\" does not begin with an upper-case letter (see JLS7 6.8.2)",
- loc
- );
- return;
- }
- for (int i = 0; i < id.length(); ++i) {
- char c = id.charAt(i);
- if (!Character.isLetter(c) && !Character.isDigit(c)) {
- this.warning("UCOIN", (
- "Class or interface name \""
- + id
- + "\" contains unconventional character \""
- + c
- + "\" (see JLS7 6.8.2)"
- ), loc);
- return;
- }
- }
- }
-
- /** Issue a warning if the given identifier does not comply with the method naming conventions (JLS7 6.8.3). */
- private void
- verifyIdentifierIsConventionalMethodName(String id, Location loc) throws CompileException {
- if (!Character.isLowerCase(id.charAt(0))) {
- this.warning(
- "UMN1",
- "Method name \"" + id + "\" does not begin with a lower-case letter (see JLS7 6.8.3)",
- loc
- );
- return;
- }
- for (int i = 0; i < id.length(); ++i) {
- char c = id.charAt(i);
- if (!Character.isLetter(c) && !Character.isDigit(c)) {
- this.warning(
- "UMN",
- "Method name \"" + id + "\" contains unconventional character \"" + c + "\" (see JLS7 6.8.3)",
- loc
- );
- return;
- }
- }
- }
-
- /**
- * Issue a warning if the given identifier does not comply with the field naming conventions (JLS7 6.8.4) and
- * constant naming conventions (JLS7 6.8.5).
- */
- private void
- verifyIdentifierIsConventionalFieldName(String id, Location loc) throws CompileException {
-
- // In practice, a field is not always a constant iff it is static-final. So let's
- // always tolerate both field and constant names.
-
- if (Character.isUpperCase(id.charAt(0))) {
- for (int i = 0; i < id.length(); ++i) {
- char c = id.charAt(i);
- if (!Character.isUpperCase(c) && !Character.isDigit(c) && c != '_') {
- this.warning(
- "UCN",
- "Constant name \"" + id + "\" contains unconventional character \"" + c + "\" (see JLS7 6.8.5)",
- loc
- );
- return;
- }
- }
- } else
- if (Character.isLowerCase(id.charAt(0))) {
- for (int i = 0; i < id.length(); ++i) {
- char c = id.charAt(i);
- if (!Character.isLetter(c) && !Character.isDigit(c)) {
- this.warning(
- "UFN",
- "Field name \"" + id + "\" contains unconventional character \"" + c + "\" (see JLS7 6.8.4)",
- loc
- );
- return;
- }
- }
- } else {
- this.warning("UFN1", (
- "\""
- + id
- + "\" is neither a conventional field name (JLS7 6.8.4) nor a conventional constant name (JLS7 6.8.5)"
- ), loc);
- }
- }
-
- /**
- * Issue a warning if the given identifier does not comply with the local variable and parameter naming conventions
- * (JLS7 6.8.6).
- */
- private void
- verifyIdentifierIsConventionalLocalVariableOrParameterName(String id, Location loc) throws CompileException {
- if (!Character.isLowerCase(id.charAt(0))) {
- this.warning(
- "ULVN1",
- "Local variable name \"" + id + "\" does not begin with a lower-case letter (see JLS7 6.8.6)",
- loc
- );
- return;
- }
- for (int i = 0; i < id.length(); ++i) {
- char c = id.charAt(i);
- if (!Character.isLetter(c) && !Character.isDigit(c)) {
- this.warning("ULVN", (
- "Local variable name \""
- + id
- + "\" contains unconventional character \""
- + c
- + "\" (see JLS7 6.8.6)"
- ), loc);
- return;
- }
- }
- }
-
- /**
- * By default, warnings are discarded, but an application my install a {@link WarningHandler}.
- *
- * Notice that there is no Parser.setErrorHandler()
method, but parse errors always throw a {@link
- * CompileException}. The reason being is that there is no reasonable way to recover from parse errors and continue
- * parsing, so there is no need to install a custom parse error handler.
- *
- * @param optionalWarningHandler null
to indicate that no warnings be issued
- */
- public void
- setWarningHandler(WarningHandler optionalWarningHandler) {
- this.optionalWarningHandler = optionalWarningHandler;
- }
-
- // Used for elaborate warning handling.
- private WarningHandler optionalWarningHandler;
-
- /**
- * Issues a warning with the given message and location and returns. This is done through
- * a {@link WarningHandler} that was installed through
- * {@link #setWarningHandler(WarningHandler)}.
- *
- * The handle
argument qulifies the warning and is typically used by
- * the {@link WarningHandler} to suppress individual warnings.
- *
- * @throws CompileException The optionally installed {@link WarningHandler} decided to throw a {@link
- * CompileException}
- */
- private void
- warning(String handle, String message, Location optionalLocation) throws CompileException {
- if (this.optionalWarningHandler != null) {
- this.optionalWarningHandler.handleWarning(handle, message, optionalLocation);
- }
- }
-
- /** Convenience method for throwing a {@link CompileException}. */
- protected final CompileException
- compileException(String message) {
- return new CompileException(message, this.location());
- }
-
- private static String
- join(String[] sa, String separator) {
- if (sa == null) return ("(null)");
- if (sa.length == 0) return ("(zero length array)");
- StringBuilder sb = new StringBuilder(sa[0]);
- for (int i = 1; i < sa.length; ++i) {
- sb.append(separator).append(sa[i]);
- }
- return sb.toString();
- }
-}
diff --git a/src/org/codehaus/janino/ReflectionIClass.java b/src/org/codehaus/janino/ReflectionIClass.java
deleted file mode 100644
index dd92daf7..00000000
--- a/src/org/codehaus/janino/ReflectionIClass.java
+++ /dev/null
@@ -1,384 +0,0 @@
-
-/*
- * 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:
- *
- *
- * It treats non-static fields as non-constant
- *
- * Even fields with a non-constant 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}.)
- *
- */
- @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
- );
- }
-}
diff --git a/src/org/codehaus/janino/ResourceFinderIClassLoader.java b/src/org/codehaus/janino/ResourceFinderIClassLoader.java
deleted file mode 100644
index cad7c25b..00000000
--- a/src/org/codehaus/janino/ResourceFinderIClassLoader.java
+++ /dev/null
@@ -1,82 +0,0 @@
-
-/*
- * 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;
- }
-}
diff --git a/src/org/codehaus/janino/Scanner.java b/src/org/codehaus/janino/Scanner.java
deleted file mode 100644
index 5e8b8a3e..00000000
--- a/src/org/codehaus/janino/Scanner.java
+++ /dev/null
@@ -1,1026 +0,0 @@
-
-/*
- * 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.FileInputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.codehaus.commons.compiler.CompileException;
-import org.codehaus.commons.compiler.ICookable;
-import org.codehaus.commons.compiler.Location;
-import org.codehaus.commons.compiler.WarningHandler;
-import org.codehaus.janino.util.TeeReader;
-
-/**
- * Splits up a character stream into tokens and returns them as
- * {@link java.lang.String String} objects.
- *
- * The optionalFileName
parameter passed to many
- * constructors should point
- */
-@SuppressWarnings({ "rawtypes", "unchecked" }) public
-class Scanner {
-
- // Public Scanners that read from a file.
-
- /**
- * Set up a scanner that reads tokens from the given file in the default charset.
- *
- * This method is deprecated because it leaves the input file open.
- *
- * @deprecated // SUPPRESS CHECKSTYLE MissingDeprecated
- */
- @Deprecated public
- Scanner(String fileName) throws CompileException, IOException {
- this(
- fileName, // optionalFileName
- new FileInputStream(fileName) // is
- );
- }
-
- /**
- * Set up a scanner that reads tokens from the given file in the given encoding.
- *
- * This method is deprecated because it leaves the input file open.
- *
- * @deprecated // SUPPRESS CHECKSTYLE MissingDeprecated
- */
- @Deprecated public
- Scanner(String fileName, String encoding) throws CompileException, IOException {
- this(
- fileName, // optionalFileName
- new FileInputStream(fileName), // is
- encoding // optionalEncoding
- );
- }
-
- /**
- * Set up a scanner that reads tokens from the given file in the platform
- * default encoding.
- *
- * This method is deprecated because it leaves the input file open.
- *
- * @deprecated // SUPPRESS CHECKSTYLE MissingDeprecated
- */
- @Deprecated public
- Scanner(File file) throws CompileException, IOException {
- this(
- file.getAbsolutePath(), // optionalFileName
- new FileInputStream(file), // is
- null // optionalEncoding
- );
- }
-
- /**
- * Set up a scanner that reads tokens from the given file in the given encoding.
- *
- * This method is deprecated because it leaves the input file open.
- *
- * @deprecated // SUPPRESS CHECKSTYLE MissingDeprecated
- */
- @Deprecated public
- Scanner(File file, String optionalEncoding) throws CompileException, IOException {
- this(
- file.getAbsolutePath(), // optionalFileName
- new FileInputStream(file), // is
- optionalEncoding // optionalEncoding
- );
- }
-
- // Public Scanners that read from an InputStream
-
- /**
- * Set up a scanner that reads tokens from the given
- * {@link InputStream} in the platform default encoding.
- *
- * The fileName
is solely used for reporting in thrown
- * exceptions.
- */
- public
- Scanner(String optionalFileName, InputStream is) throws CompileException, IOException {
- this(
- optionalFileName,
- new InputStreamReader(is), // in
- (short) 1, // initialLineNumber
- (short) 0 // initialColumnNumber
- );
- }
-
- /**
- * Set up a scanner that reads tokens from the given
- * {@link InputStream} with the given optionalEncoding
- * (null
means platform default encoding).
- *
- * The optionalFileName
is used for reporting errors during
- * compilation and for source level debugging, and should name an existing
- * file. If null
is passed, and the system property
- * org.codehaus.janino.source_debugging.enable
is set to "true", then
- * a temporary file in org.codehaus.janino.source_debugging.dir
or the
- * system's default temp dir is created in order to make the source code
- * available to a debugger.
- */
- public
- Scanner(String optionalFileName, InputStream is, String optionalEncoding) throws CompileException, IOException {
- this(
- optionalFileName, // optionalFileName
- ( // in
- optionalEncoding == null
- ? new InputStreamReader(is)
- : new InputStreamReader(is, optionalEncoding)
- ),
- (short) 1, // initialLineNumber
- (short) 0 // initialColumnNumber
- );
- }
-
- // Public Scanners that read from a Reader.
-
- /**
- * Set up a scanner that reads tokens from the given
- * {@link Reader}.
- *
- * The optionalFileName
is used for reporting errors during
- * compilation and for source level debugging, and should name an existing
- * file. If null
is passed, and the system property
- * org.codehaus.janino.source_debugging.enable
is set to "true", then
- * a temporary file in org.codehaus.janino.source_debugging.dir
or the
- * system's default temp dir is created in order to make the source code
- * available to a debugger.
- */
- public
- Scanner(String optionalFileName, Reader in) throws CompileException, IOException {
- this(
- optionalFileName, // optionalFileName
- in, // in
- (short) 1, // initialLineNumber
- (short) 0 // initialColumnNumber
- );
- }
-
- /** Creates a {@link Scanner} that counts lines and columns from non-default initial values. */
- public
- Scanner(
- String optionalFileName,
- Reader in,
- short initialLineNumber, // "1" is a good idea
- short initialColumnNumber // "0" is a good idea
- ) throws CompileException, IOException {
-
- // Debugging on source code level is only possible if the code comes from
- // a "real" Java source file which the debugger can read. If this is not the
- // case, and we absolutely want source code level debugging, then we write
- // a verbatim copy of the source code into a temporary file in the system
- // temp directory.
- // This behavior is controlled by the two system properties
- // org.codehaus.janino.source_debugging.enable
- // org.codehaus.janino.source_debugging.dir
- // JANINO is designed to compile in memory to save the overhead of disk
- // I/O, so writing this file is only recommended for source code level
- // debugging purposes.
- if (optionalFileName == null && Boolean.getBoolean(ICookable.SYSTEM_PROPERTY_SOURCE_DEBUGGING_ENABLE)) {
- String dirName = System.getProperty(ICookable.SYSTEM_PROPERTY_SOURCE_DEBUGGING_DIR);
- File dir = dirName == null ? null : new File(dirName);
- File temporaryFile = File.createTempFile("janino", ".java", dir);
- temporaryFile.deleteOnExit();
- in = new TeeReader(
- in, // in
- new FileWriter(temporaryFile), // out
- true // closeWriterOnEOF
- );
- optionalFileName = temporaryFile.getAbsolutePath();
- }
-
- this.optionalFileName = optionalFileName;
- this.in = new UnicodeUnescapeReader(in);
- this.nextCharLineNumber = initialLineNumber;
- this.nextCharColumnNumber = initialColumnNumber;
-
- this.readNextChar();
- }
-
- /** @return The file name optionally passed to the constructor */
- public String
- getFileName() { return this.optionalFileName; }
-
- /**
- * Closes the character source (file, {@link InputStream}, {@link Reader}) associated with this object. The results
- * of future calls to {@link #produce()} are undefined.
- *
- * @deprecated This method is deprecated, because the concept described above is confusing. An application should
- * close the underlying {@link InputStream} or {@link Reader} itself.
- */
- @Deprecated public void
- close() throws IOException { this.in.close(); }
-
- /**
- * Get the text of the doc comment (a.k.a. "JAVADOC comment") preceeding
- * the next token.
- * @return null
if the next token is not preceeded by a doc comment
- */
- public String
- doc() {
- String s = this.docComment;
- this.docComment = null;
- return s;
- }
-
- /** @return The {@link Location} of the next character */
- public Location
- location() {
- return new Location(this.optionalFileName, this.nextCharLineNumber, this.nextCharColumnNumber);
- }
-
- /** Representation of a Java™ token. */
- public final
- class Token {
- private final String optionalFileName;
- private final short lineNumber;
- private final short columnNumber;
- private Location location;
-
- /** The type of this token; legal values are the various public constant declared in this class. */
- public final int type;
-
- /** Indication of the 'end-of-input' condition. */
- public static final int EOF = 0;
-
- /** The token represents an identifier. */
- public static final int IDENTIFIER = 1;
-
- /** The token represents a keyword. */
- public static final int KEYWORD = 2;
-
- /**
- * The token represents an integer literal; its {@link #value} is the text of the integer literal exactly as it
- * appears in the source code.
- */
- public static final int INTEGER_LITERAL = 3;
-
- /**
- * The token represents a floating-point literal; its {@link #value} is the text of the floating-point literal
- * exactly as it appears in the source code.
- */
- public static final int FLOATING_POINT_LITERAL = 4;
-
- /** The token represents a boolean literal; its {@link #value} is either 'true' or 'false'. */
- public static final int BOOLEAN_LITERAL = 5;
-
- /**
- * The token represents a character literal; its {@link #value} is the text of the character literal exactly as
- * it appears in the source code (including the single quotes around it).
- */
- public static final int CHARACTER_LITERAL = 6;
-
- /**
- * The token represents a string literal; its {@link #value} is the text of the string literal exactly as it
- * appears in the source code (including the double quotes around it).
- */
- public static final int STRING_LITERAL = 7;
-
- /** The token represents the {@code null} literal; its {@link #value} is 'null'. */
- public static final int NULL_LITERAL = 8;
-
- /** The token represents an operator; its {@link #value} is exactly the particular operator (e.g. "<<<="). */
- public static final int OPERATOR = 9;
-
- /** The text of the token exactly as it appears in the source code. */
- public final String value;
-
- private
- Token(int type, String value) {
- this.optionalFileName = Scanner.this.optionalFileName;
- this.lineNumber = Scanner.this.tokenLineNumber;
- this.columnNumber = Scanner.this.tokenColumnNumber;
- this.type = type;
- this.value = value;
- }
-
- /** @return The location of the first character of this token */
- public Location
- getLocation() {
- if (this.location == null) {
- this.location = new Location(this.optionalFileName, this.lineNumber, this.columnNumber);
- }
- return this.location;
- }
-
- @Override public String
- toString() { return this.value; }
- }
-
- /**
- * Preduces and returns the next token. Notice that end-of-input is not signalized with a {@code null}
- * product, but by the special {@link Token#EOF} token.
- */
- public Token
- produce() throws CompileException, IOException {
- if (this.docComment != null) {
- this.warning("MDC", "Misplaced doc comment", this.location());
- this.docComment = null;
- }
-
- // Skip whitespace and process comments.
- int state = 0;
- StringBuilder dcsb = null; // For doc comment
-
- PROCESS_COMMENTS:
- for (;;) {
- switch (state) {
-
- case 0: // Outside any comment
- if (this.nextChar == -1) {
- return new Token(Token.EOF, "EOF");
- } else
- if (Character.isWhitespace((char) this.nextChar)) {
- ;
- } else
- if (this.nextChar == '/') {
- state = 1;
- } else
- {
- break PROCESS_COMMENTS;
- }
- break;
-
- case 1: // After "/"
- if (this.nextChar == -1) {
- return new Token(Token.OPERATOR, "/");
- } else
- if (this.nextChar == '=') {
- this.readNextChar();
- return new Token(Token.OPERATOR, "/=");
- } else
- if (this.nextChar == '/') {
- state = 2;
- } else
- if (this.nextChar == '*') {
- state = 3;
- } else
- {
- return new Token(Token.OPERATOR, "/");
- }
- break;
-
- case 2: // After "//..."
- if (this.nextChar == -1) {
- return new Token(Token.EOF, "EOF");
- } else
- if (this.nextChar == '\r' || this.nextChar == '\n') {
- state = 0;
- } else
- {
- ;
- }
- break;
-
- case 3: // After "/*"
- if (this.nextChar == -1) {
- throw new CompileException("EOF in traditional comment", this.location());
- } else
- if (this.nextChar == '*') {
- state = 4;
- } else
- {
- state = 9;
- }
- break;
-
- case 4: // After "/**"
- if (this.nextChar == -1) {
- throw new CompileException("EOF in doc comment", this.location());
- } else
- if (this.nextChar == '/') {
- state = 0;
- } else
- {
- if (this.docComment != null) {
- this.warning(
- "MDC",
- "Multiple doc comments",
- new Location(this.optionalFileName, this.nextCharLineNumber, this.nextCharColumnNumber)
- );
- }
- dcsb = new StringBuilder().append((char) this.nextChar);
- state = (
- (this.nextChar == '\r' || this.nextChar == '\n') ? 6
- : this.nextChar == '*' ? 8
- : 5
- );
- }
- break;
-
- case 5: // After "/**..."
- if (this.nextChar == -1) {
- throw new CompileException("EOF in doc comment", this.location());
- } else
- if (this.nextChar == '*') {
- state = 8;
- } else
- if (this.nextChar == '\r' || this.nextChar == '\n') {
- dcsb.append((char) this.nextChar);
- state = 6;
- } else
- {
- dcsb.append((char) this.nextChar);
- }
- break;
-
- case 6: // After "/**...\n"
- if (this.nextChar == -1) {
- throw new CompileException("EOF in doc comment", this.location());
- } else
- if (this.nextChar == '*') {
- state = 7;
- } else
- if (this.nextChar == '\r' || this.nextChar == '\n') {
- dcsb.append((char) this.nextChar);
- } else
- if (this.nextChar == ' ' || this.nextChar == '\t') {
- ;
- } else
- {
- dcsb.append((char) this.nextChar);
- state = 5;
- }
- break;
-
- case 7: // After "/**...\n *"
- if (this.nextChar == -1) {
- throw new CompileException("EOF in doc comment", this.location());
- } else
- if (this.nextChar == '*') {
- ;
- } else
- if (this.nextChar == '/') {
- this.docComment = dcsb.toString();
- state = 0;
- } else
- {
- dcsb.append((char) this.nextChar);
- state = 5;
- }
- break;
-
- case 8: // After "/**...*"
- if (this.nextChar == -1) {
- throw new CompileException("EOF in doc comment", this.location());
- } else
- if (this.nextChar == '/') {
- this.docComment = dcsb.toString();
- state = 0;
- } else
- if (this.nextChar == '*') {
- dcsb.append('*');
- } else
- {
- dcsb.append('*');
- dcsb.append((char) this.nextChar);
- state = 5;
- }
- break;
-
- case 9: // After "/*..."
- if (this.nextChar == -1) {
- throw new CompileException("EOF in traditional comment", this.location());
- } else
- if (this.nextChar == '*') {
- state = 10;
- } else
- {
- ;
- }
- break;
-
- case 10: // After "/*...*"
- if (this.nextChar == -1) {
- throw new CompileException("EOF in traditional comment", this.location());
- } else
- if (this.nextChar == '/') {
- state = 0;
- } else
- if (this.nextChar == '*') {
- ;
- } else
- {
- state = 9;
- }
- break;
-
- default:
- throw new JaninoRuntimeException(Integer.toString(state));
- }
- this.readNextChar();
- }
-
- /*
- * Whitespace and comments are now skipped; "nextChar" is definitely
- * the first character of the token.
- */
- this.tokenLineNumber = this.nextCharLineNumber;
- this.tokenColumnNumber = this.nextCharColumnNumber;
-
- // Scan identifier.
- if (Character.isJavaIdentifierStart((char) this.nextChar)) {
- StringBuilder sb = new StringBuilder();
- sb.append((char) this.nextChar);
- for (;;) {
- this.readNextChar();
- if (this.nextChar == -1 || !Character.isJavaIdentifierPart((char) this.nextChar)) break;
- sb.append((char) this.nextChar);
- }
- String s = sb.toString();
- if ("true".equals(s)) return new Token(Token.BOOLEAN_LITERAL, "true");
- if ("false".equals(s)) return new Token(Token.BOOLEAN_LITERAL, "false");
- if ("null".equals(s)) return new Token(Token.NULL_LITERAL, "null");
- {
- String v = (String) Scanner.JAVA_KEYWORDS.get(s);
- if (v != null) return new Token(Token.KEYWORD, v);
- }
- return new Token(Token.IDENTIFIER, s);
- }
-
- // Scan numeric literal.
- if (Character.isDigit((char) this.nextChar)) {
- return this.scanNumericLiteral(false);
- }
-
- // A "." is special: Could either be a floating-point constant like ".001", or the "."
- // operator.
- if (this.nextChar == '.') {
- this.readNextChar();
- if (Character.isDigit((char) this.nextChar)) {
- return this.scanNumericLiteral(true);
- } else {
- return new Token(Token.OPERATOR, ".");
- }
- }
-
- // Scan string literal.
- if (this.nextChar == '"') {
- StringBuilder sb = new StringBuilder("\"");
- this.readNextChar();
- while (this.nextChar != '"') {
- this.scanLiteralCharacter(sb);
- }
- this.readNextChar();
- return new Token(Token.STRING_LITERAL, sb.append('"').toString());
- }
-
- // Scan character literal.
- if (this.nextChar == '\'') {
- this.readNextChar();
- if (this.nextChar == '\'') {
- throw new CompileException(
- "Single quote must be backslash-escaped in character literal",
- this.location()
- );
- }
-
- StringBuilder sb = new StringBuilder("'");
- this.scanLiteralCharacter(sb);
- if (this.nextChar != '\'') throw new CompileException("Closing single quote missing", this.location());
- this.readNextChar();
-
- return new Token(Token.CHARACTER_LITERAL, sb.append('\'').toString());
- }
-
- // Scan separator / operator.
- {
- String v = (String) Scanner.JAVA_OPERATORS.get(new String(new char[] { (char) this.nextChar }));
- if (v != null) {
- for (;;) {
- this.readNextChar();
- String v2 = (String) (
- this.expectGreater
- ? Scanner.JAVA_OPERATORS_EXPECT_GREATER
- : Scanner.JAVA_OPERATORS
- ).get(v + (char) this.nextChar);
- if (v2 == null) return new Token(Token.OPERATOR, v);
- v = v2;
- }
- }
- }
-
- throw new CompileException(
- "Invalid character input \"" + (char) this.nextChar + "\" (character code " + this.nextChar + ")",
- this.location()
- );
- }
-
- /** @return Whether the scanner is currently in 'expect greater' mode */
- public boolean
- getExpectGreater() { return this.expectGreater; }
-
- /**
- * Sets or resets the 'expect greater' mode.
- *
- * @return Whether the 'expect greater' mode was previously active
- */
- public boolean
- setExpectGreater(boolean value) {
- boolean tmp = this.expectGreater;
- this.expectGreater = value;
- return tmp;
- }
-
- private Token
- scanNumericLiteral(boolean hadDecimalPoint) throws CompileException, IOException {
- StringBuilder sb = hadDecimalPoint ? new StringBuilder(".") : new StringBuilder();
- int state = hadDecimalPoint ? 2 : 0;
- for (;;) {
- switch (state) {
-
- case 0: // First character.
- if (this.nextChar == '0') {
- sb.append('0');
- state = 6;
- } else
- if (Character.isDigit((char) this.nextChar)) {
- sb.append((char) this.nextChar);
- state = 1;
- } else
- {
- throw new CompileException(
- "Numeric literal begins with invalid character '" + (char) this.nextChar + "'",
- this.location()
- );
- }
- break;
-
- case 1: // Decimal digits.
- if (Character.isDigit((char) this.nextChar)) {
- sb.append((char) this.nextChar);
- } else
- if (this.nextChar == 'l' || this.nextChar == 'L') {
- sb.append((char) this.nextChar);
- this.readNextChar();
- return new Token(Token.INTEGER_LITERAL, sb.toString());
- } else
- if (this.nextChar == 'f' || this.nextChar == 'F' || this.nextChar == 'd' || this.nextChar == 'D') {
- sb.append((char) this.nextChar);
- this.readNextChar();
- return new Token(Token.FLOATING_POINT_LITERAL, sb.toString());
- } else
- if (this.nextChar == '.') {
- sb.append('.');
- state = 2;
- } else
- if (this.nextChar == 'E' || this.nextChar == 'e') {
- sb.append('E');
- state = 3;
- } else
- {
- return new Token(Token.INTEGER_LITERAL, sb.toString());
- }
- break;
-
- case 2: // After decimal point.
- if (Character.isDigit((char) this.nextChar)) {
- sb.append((char) this.nextChar);
- } else
- if (this.nextChar == 'e' || this.nextChar == 'E') {
- sb.append('E');
- state = 3;
- } else
- if (this.nextChar == 'f' || this.nextChar == 'F' || this.nextChar == 'd' || this.nextChar == 'D') {
- sb.append((char) this.nextChar);
- this.readNextChar();
- return new Token(Token.FLOATING_POINT_LITERAL, sb.toString());
- } else
- {
- return new Token(Token.FLOATING_POINT_LITERAL, sb.toString());
- }
- break;
-
- case 3: // Read exponent.
- if (Character.isDigit((char) this.nextChar)) {
- sb.append((char) this.nextChar);
- state = 5;
- } else
- if (this.nextChar == '-' || this.nextChar == '+') {
- sb.append((char) this.nextChar);
- state = 4;
- } else
- {
- throw new CompileException("Exponent missing after \"E\"", this.location());
- }
- break;
-
- case 4: // After exponent sign.
- if (Character.isDigit((char) this.nextChar)) {
- sb.append((char) this.nextChar);
- state = 5;
- } else
- {
- throw new CompileException("Exponent missing after 'E' and sign", this.location());
- }
- break;
-
- case 5: // After first exponent digit.
- if (Character.isDigit((char) this.nextChar)) {
- sb.append((char) this.nextChar);
- } else
- if (this.nextChar == 'f' || this.nextChar == 'F' || this.nextChar == 'd' || this.nextChar == 'D') {
- sb.append((char) this.nextChar);
- this.readNextChar();
- return new Token(Token.FLOATING_POINT_LITERAL, sb.toString());
- } else
- {
- return new Token(Token.FLOATING_POINT_LITERAL, sb.toString());
- }
- break;
-
- case 6: // After leading zero
- if ("01234567".indexOf(this.nextChar) != -1) {
- sb.append((char) this.nextChar);
- state = 7;
- } else
- if (this.nextChar == 'l' || this.nextChar == 'L') {
- sb.append((char) this.nextChar);
- this.readNextChar();
- return new Token(Token.INTEGER_LITERAL, sb.toString());
- } else
- if (this.nextChar == 'f' || this.nextChar == 'F' || this.nextChar == 'd' || this.nextChar == 'D') {
- sb.append((char) this.nextChar);
- this.readNextChar();
- return new Token(Token.FLOATING_POINT_LITERAL, sb.toString());
- } else
- if (this.nextChar == '.') {
- sb.append('.');
- state = 2;
- } else
- if (this.nextChar == 'E' || this.nextChar == 'e') {
- sb.append((char) this.nextChar);
- state = 3;
- } else
- if (this.nextChar == 'x' || this.nextChar == 'X') {
- sb.append((char) this.nextChar);
- state = 8;
- } else
- {
- return new Token(Token.INTEGER_LITERAL, "0");
- }
- break;
-
- case 7: // In octal literal.
- if ("01234567".indexOf(this.nextChar) != -1) {
- sb.append((char) this.nextChar);
- } else
- if (this.nextChar == '8' || this.nextChar == '9') {
- throw new CompileException(
- "Digit '" + (char) this.nextChar + "' not allowed in octal literal",
- this.location()
- );
- } else
- if (this.nextChar == 'l' || this.nextChar == 'L') {
- // Octal long literal.
- sb.append((char) this.nextChar);
- this.readNextChar();
- return new Token(Token.INTEGER_LITERAL, sb.toString());
- } else
- {
- // Octal int literal
- return new Token(Token.INTEGER_LITERAL, sb.toString());
- }
- break;
-
- case 8: // After '0x'.
- if (Character.digit((char) this.nextChar, 16) != -1) {
- sb.append((char) this.nextChar);
- state = 9;
- } else
- {
- throw new CompileException("Hex digit expected after \"0x\"", this.location());
- }
- break;
-
- case 9: // After first hex digit.
- if (Character.digit((char) this.nextChar, 16) != -1) {
- sb.append((char) this.nextChar);
- } else
- if (this.nextChar == 'l' || this.nextChar == 'L') {
- // Hex long literal
- sb.append((char) this.nextChar);
- this.readNextChar();
- return new Token(Token.INTEGER_LITERAL, sb.toString());
- } else
- {
- // Hex int literal
- return new Token(Token.INTEGER_LITERAL, sb.toString());
- }
- break;
-
- default:
- throw new JaninoRuntimeException(Integer.toString(state));
- }
- this.readNextChar();
- }
- }
-
- /** Scans the next literal character into a {@link StringBuilder}. */
- private void
- scanLiteralCharacter(StringBuilder sb) throws CompileException, IOException {
- if (this.nextChar == -1) throw new CompileException("EOF in literal", this.location());
-
- if (this.nextChar == '\r' || this.nextChar == '\n') {
- throw new CompileException("Line break in literal not allowed", this.location());
- }
-
- if (this.nextChar != '\\') {
-
- // Not an escape sequence.
- sb.append((char) this.nextChar);
- this.readNextChar();
- return;
- }
-
- // JLS7 3.10.6: Escape sequences for character and string literals.
- sb.append('\\');
- this.readNextChar();
-
- {
- int idx = "btnfr\"'\\".indexOf(this.nextChar);
- if (idx != -1) {
-
- // "\t" and friends.
- sb.append((char) this.nextChar);
- this.readNextChar();
- return;
- }
- }
-
- {
- int idx = "01234567".indexOf(this.nextChar);
- if (idx != -1) {
-
- // Octal escapes: "\0" through "\3ff".
- char firstChar = (char) this.nextChar;
- sb.append(firstChar);
- this.readNextChar();
-
- idx = "01234567".indexOf(this.nextChar);
- if (idx == -1) return;
- sb.append((char) this.nextChar);
- this.readNextChar();
-
- idx = "01234567".indexOf(this.nextChar);
- if (idx == -1) return;
- if ("0123".indexOf(firstChar) == -1) {
- throw new CompileException("Invalid octal escape", this.location());
- }
- sb.append((char) this.nextChar);
- this.readNextChar();
- return;
- }
- }
-
- throw new CompileException("Invalid escape sequence", this.location());
- }
-
- // Read one character and store in "nextChar".
- private void
- readNextChar() throws IOException, CompileException {
- try {
- this.nextChar = this.in.read();
- } catch (UnicodeUnescapeException ex) {
- throw new CompileException(ex.getMessage(), this.location(), ex);
- }
- if (this.nextChar == '\r') {
- ++this.nextCharLineNumber;
- this.nextCharColumnNumber = 0;
- this.crLfPending = true;
- } else
- if (this.nextChar == '\n') {
- if (this.crLfPending) {
- this.crLfPending = false;
- } else {
- ++this.nextCharLineNumber;
- this.nextCharColumnNumber = 0;
- }
- } else
- {
- ++this.nextCharColumnNumber;
- }
-//System.out.println("'" + (char) nextChar + "' = " + (int) nextChar);
- }
-
- private final String optionalFileName;
- private final Reader in;
- private int nextChar = -1; // Always valid (one character read-ahead).
- private boolean crLfPending;
- private short nextCharLineNumber;
- private short nextCharColumnNumber;
-
- /** Line number of the previously produced token (typically starting at one). */
- private short tokenLineNumber;
-
- /**
- * Column number of the first character of the previously produced token (1 if token is immediately preceded by a
- * line break).
- */
- private short tokenColumnNumber;
-
- /** The optional JAVADOC comment preceding the {@link #nextToken}. */
- private String docComment;
-
- /**
- * Whether the scanner is in 'expect greater' mode: If so, it parses character sequences like ">>>=" as
- * ">", ">", ">", "=".
- */
- private boolean expectGreater;
-
- private static final Map JAVA_KEYWORDS = new HashMap();
- static {
- String[] ks = {
- "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue",
- "default", "do", "double", "else", "extends", "final", "finally", "float", "for", "goto", "if",
- "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "package", "private",
- "protected", "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this",
- "throw", "throws", "transient", "try", "void", "volatile", "while",
- };
- for (int i = 0; i < ks.length; ++i) Scanner.JAVA_KEYWORDS.put(ks[i], ks[i]);
- }
- private static final Map JAVA_OPERATORS = new HashMap();
- private static final Map JAVA_OPERATORS_EXPECT_GREATER = new HashMap();
- static {
- String[] ops = {
- // Separators:
- "(", ")", "{", "}", "[", "]", ";", ",", ".", "@",
- // Operators:
- "=", ">", "<", "!", "~", "?", ":",
- "==", "<=", ">=", "!=", "&&", "||", "++", "--",
- "+", "-", "*", "/", "&", "|", "^", "%", "<<", ">>", ">>>",
- "+=", "-=", "*=", "/=", "&=", "|=", "^=", "%=", "<<=", ">>=", ">>>=",
- };
- for (String op : ops) {
- Scanner.JAVA_OPERATORS.put(op, op);
- if (!op.startsWith(">>")) Scanner.JAVA_OPERATORS_EXPECT_GREATER.put(op, op);
- }
- }
-
- /**
- * By default, warnings are discarded, but an application my install a
- * {@link WarningHandler}.
- *
- * Notice that there is no Scanner.setErrorHandler()
method, but scan errors
- * always throw a {@link CompileException}. The reason being is that there is no reasonable
- * way to recover from scan errors and continue scanning, so there is no need to install
- * a custom scan error handler.
- *
- * @param optionalWarningHandler null
to indicate that no warnings be issued
- */
- public void
- setWarningHandler(WarningHandler optionalWarningHandler) {
- this.optionalWarningHandler = optionalWarningHandler;
- }
-
- // Used for elaborate warning handling.
- private WarningHandler optionalWarningHandler;
-
- /**
- * Issues a warning with the given message and location and returns. This is done through
- * a {@link WarningHandler} that was installed through
- * {@link #setWarningHandler(WarningHandler)}.
- *
- * The handle
argument qulifies the warning and is typically used by
- * the {@link WarningHandler} to suppress individual warnings.
- * @throws CompileException
- */
- private void
- warning(String handle, String message, Location optionalLocation) throws CompileException {
- if (this.optionalWarningHandler != null) {
- this.optionalWarningHandler.handleWarning(handle, message, optionalLocation);
- }
- }
-}
diff --git a/src/org/codehaus/janino/ScriptEvaluator.java b/src/org/codehaus/janino/ScriptEvaluator.java
deleted file mode 100644
index 9a05ebbb..00000000
--- a/src/org/codehaus/janino/ScriptEvaluator.java
+++ /dev/null
@@ -1,993 +0,0 @@
-
-/*
- * 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
- * ScriptEvaluator se = new ScriptEvaluator();
- * se.cook(script);
- *
- * @see #ScriptEvaluator()
- * @see Cookable#cook(String)
- */
- public
- ScriptEvaluator(String script) throws CompileException {
- this.cook(script);
- }
-
- /**
- * Equivalent to
- * ScriptEvaluator se = new ScriptEvaluator();
- * se.setReturnType(returnType);
- * se.cook(script);
- *
- * @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
- * ScriptEvaluator se = new ScriptEvaluator();
- * se.setReturnType(returnType);
- * se.setParameters(parameterNames, parameterTypes);
- * se.cook(script);
- *
- * @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
- * ScriptEvaluator se = new ScriptEvaluator();
- * se.setReturnType(returnType);
- * se.setParameters(parameterNames, parameterTypes);
- * se.setThrownExceptions(thrownExceptions);
- * se.cook(script);
- *
- * @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
- * ScriptEvaluator se = new ScriptEvaluator();
- * se.setReturnType(returnType);
- * se.setParameters(parameterNames, parameterTypes);
- * se.setThrownExceptions(thrownExceptions);
- * se.setParentClassLoader(optionalParentClassLoader);
- * se.cook(optionalFileName, is);
- *
- * @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
- * ScriptEvaluator se = new ScriptEvaluator();
- * se.setReturnType(returnType);
- * se.setParameters(parameterNames, parameterTypes);
- * se.setThrownExceptions(thrownExceptions);
- * se.setParentClassLoader(optionalParentClassLoader);
- * se.cook(reader);
- *
- * @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
- * ScriptEvaluator se = new ScriptEvaluator();
- * se.setReturnType(returnType);
- * se.setParameters(parameterNames, parameterTypes);
- * se.setThrownExceptions(thrownExceptions);
- * se.setParentClassLoader(optionalParentClassLoader);
- * se.cook(scanner);
- *
- * @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
- * 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);
- *
- * @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
- * 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);
- *
- * @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 set of scripts into one class. Notice that
- * if any of the scripts causes trouble, the entire compilation will fail. If you
- * need to report which of the scripts causes the exception, you may want to use the
- * optionalFileName
argument of {@link Scanner#Scanner(String, Reader)} to
- * distinguish between the individual token sources.
- *
- * On a 2 GHz Intel Pentium Core Duo under Windows XP with an IBM 1.4.2 JDK, compiling
- * 10000 expressions "a + b" (integer) takes about 4 seconds and 56 MB of main memory.
- * The generated class file is 639203 bytes large.
- *
- * The number and the complexity of the scripts is restricted by the
- * Limitations
- * of the Java Virtual Machine , where the most limiting factor is the 64K entries limit
- * of the constant pool. Since every method with a distinct name requires one entry there,
- * you can define at best 32K (very simple) scripts.
- *
- * If and only if the number of scanners is one, then that single script may contain leading
- * IMPORT directives.
- *
- * @throws IllegalStateException Any of the preceeding set...()
had an array size different from that
- * of scanners
- */
- 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 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 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.
- *
- * The number and the complexity of the scripts is restricted by the
- * Limitations
- * of the Java Virtual Machine , where the most limiting factor is the 64K entries limit
- * of the constant pool. Since every method with a distinct name requires one entry there,
- * you can define at best 32K (very simple) scripts.
- */
- @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 block
by parsing statements until EOF and adding them to the block. */
- protected List
- makeStatements(int idx, Parser parser) throws CompileException, IOException {
- List statements = new ArrayList();
- while (!parser.peekEof()) {
- statements.add(parser.parseBlockStatement());
- }
-
- return statements;
- }
-
- /**
- * To the given {@link Java.ClassDeclaration}, add
- *
- * A public method declaration with the given return type, name, parameter
- * names and values and thrown exceptions
- * A block
- *
- *
- * @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 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);
- }
-
- /**
- *
- * {@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);
- *
- *
- * @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 this
- * implementation of org.codehaus.commons.compiler
. 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.
- *
- * If any component starts with an upper-case letter, then ambiguous name is assumed to
- * be a type name.
- * 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.)
- * Otherwise, the first component of the ambiguous name is assumed to be a parameter name.
- *
- *
- * @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 localVariableNames = new HashSet();
- final Set 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];
- }
-}
diff --git a/src/org/codehaus/janino/SimpleCompiler.java b/src/org/codehaus/janino/SimpleCompiler.java
deleted file mode 100644
index 9f8be147..00000000
--- a/src/org/codehaus/janino/SimpleCompiler.java
+++ /dev/null
@@ -1,425 +0,0 @@
-
-/*
- * 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 { }");
- System.out.println("Reads a compilation unit from the given and invokes method");
- System.out.println("\"public static void main(String[])\" of class , passing the");
- System.out.println("given 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
- * SimpleCompiler sc = new SimpleCompiler();
- * sc.cook(optionalFileName, in);
- *
- * @see #SimpleCompiler()
- * @see Cookable#cook(String, Reader)
- */
- public
- SimpleCompiler(String optionalFileName, Reader in) throws IOException, CompileException {
- this.cook(optionalFileName, in);
- }
-
- /**
- * Equivalent to
- * SimpleCompiler sc = new SimpleCompiler();
- * sc.cook(optionalFileName, is);
- *
- * @see #SimpleCompiler()
- * @see Cookable#cook(String, InputStream)
- */
- public
- SimpleCompiler(String optionalFileName, InputStream is) throws IOException, CompileException {
- this.cook(optionalFileName, is);
- }
-
- /**
- * Equivalent to
- * SimpleCompiler sc = new SimpleCompiler();
- * sc.cook(fileName);
- *
- * @see #SimpleCompiler()
- * @see Cookable#cookFile(String)
- */
- public
- SimpleCompiler(String fileName) throws IOException, CompileException {
- this.cookFile(fileName);
- }
-
- /**
- * Equivalent to
- * SimpleCompiler sc = new SimpleCompiler();
- * sc.setParentClassLoader(optionalParentClassLoader);
- * sc.cook(scanner);
- *
- * @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
- *
- * Both are objects of the same class (e.g. both are {@link ScriptEvaluator}s)
- * Both generated functionally equal classes as seen by {@link ByteArrayClassLoader#equals(Object)}
- *
- */
- @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 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 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");
- }
-}
diff --git a/src/org/codehaus/janino/TODO.txt b/src/org/codehaus/janino/TODO.txt
deleted file mode 100644
index da2d8c05..00000000
--- a/src/org/codehaus/janino/TODO.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-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 l;')
-* Implement type parameters ('class MyClass { ... }')
-* Enhanced FOR loop
-
-Recently implemented:
-* ASSERT (simplified, ASSERTions are ALWAYS enabled, as if '-ea' were set)
diff --git a/src/org/codehaus/janino/UnicodeUnescapeException.java b/src/org/codehaus/janino/UnicodeUnescapeException.java
deleted file mode 100644
index a8c3798c..00000000
--- a/src/org/codehaus/janino/UnicodeUnescapeException.java
+++ /dev/null
@@ -1,43 +0,0 @@
-
-/*
- * 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); }
-}
diff --git a/src/org/codehaus/janino/UnicodeUnescapeReader.java b/src/org/codehaus/janino/UnicodeUnescapeReader.java
deleted file mode 100644
index b987f4e8..00000000
--- a/src/org/codehaus/janino/UnicodeUnescapeReader.java
+++ /dev/null
@@ -1,110 +0,0 @@
-
-/*
- * 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.
- *
- * 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;
-}
diff --git a/src/org/codehaus/janino/UnitCompiler.java b/src/org/codehaus/janino/UnitCompiler.java
deleted file mode 100644
index f38ec2df..00000000
--- a/src/org/codehaus/janino/UnitCompiler.java
+++ /dev/null
@@ -1,10542 +0,0 @@
-
-/*
- * Janino - An embedded Java[TM] compiler
- *
- * Copyright (c) 2001-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.
- */
-
-package org.codehaus.janino;
-
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.TreeMap;
-
-import org.codehaus.commons.compiler.CompileException;
-import org.codehaus.commons.compiler.ErrorHandler;
-import org.codehaus.commons.compiler.Location;
-import org.codehaus.commons.compiler.UncheckedCompileException;
-import org.codehaus.commons.compiler.WarningHandler;
-import org.codehaus.janino.CodeContext.Inserter;
-import org.codehaus.janino.CodeContext.Offset;
-import org.codehaus.janino.IClass.IConstructor;
-import org.codehaus.janino.IClass.IField;
-import org.codehaus.janino.IClass.IInvocable;
-import org.codehaus.janino.IClass.IMethod;
-import org.codehaus.janino.Java.AbstractTypeDeclaration;
-import org.codehaus.janino.Java.AlternateConstructorInvocation;
-import org.codehaus.janino.Java.AmbiguousName;
-import org.codehaus.janino.Java.Annotation;
-import org.codehaus.janino.Java.AnonymousClassDeclaration;
-import org.codehaus.janino.Java.ArrayAccessExpression;
-import org.codehaus.janino.Java.ArrayInitializer;
-import org.codehaus.janino.Java.ArrayInitializerOrRvalue;
-import org.codehaus.janino.Java.ArrayLength;
-import org.codehaus.janino.Java.ArrayType;
-import org.codehaus.janino.Java.AssertStatement;
-import org.codehaus.janino.Java.Assignment;
-import org.codehaus.janino.Java.Atom;
-import org.codehaus.janino.Java.BasicType;
-import org.codehaus.janino.Java.BinaryOperation;
-import org.codehaus.janino.Java.Block;
-import org.codehaus.janino.Java.BlockStatement;
-import org.codehaus.janino.Java.BooleanLiteral;
-import org.codehaus.janino.Java.BooleanRvalue;
-import org.codehaus.janino.Java.BreakStatement;
-import org.codehaus.janino.Java.BreakableStatement;
-import org.codehaus.janino.Java.Cast;
-import org.codehaus.janino.Java.CatchClause;
-import org.codehaus.janino.Java.CharacterLiteral;
-import org.codehaus.janino.Java.ClassDeclaration;
-import org.codehaus.janino.Java.ClassLiteral;
-import org.codehaus.janino.Java.CompilationUnit;
-import org.codehaus.janino.Java.CompilationUnit.ImportDeclaration;
-import org.codehaus.janino.Java.CompilationUnit.SingleStaticImportDeclaration;
-import org.codehaus.janino.Java.CompilationUnit.SingleTypeImportDeclaration;
-import org.codehaus.janino.Java.CompilationUnit.StaticImportOnDemandDeclaration;
-import org.codehaus.janino.Java.CompilationUnit.TypeImportOnDemandDeclaration;
-import org.codehaus.janino.Java.ConditionalExpression;
-import org.codehaus.janino.Java.ConstructorDeclarator;
-import org.codehaus.janino.Java.ConstructorInvocation;
-import org.codehaus.janino.Java.ContinuableStatement;
-import org.codehaus.janino.Java.ContinueStatement;
-import org.codehaus.janino.Java.Crement;
-import org.codehaus.janino.Java.DoStatement;
-import org.codehaus.janino.Java.DocCommentable;
-import org.codehaus.janino.Java.EmptyStatement;
-import org.codehaus.janino.Java.EnclosingScopeOfTypeDeclaration;
-import org.codehaus.janino.Java.ExpressionStatement;
-import org.codehaus.janino.Java.FieldAccess;
-import org.codehaus.janino.Java.FieldAccessExpression;
-import org.codehaus.janino.Java.FieldDeclaration;
-import org.codehaus.janino.Java.FloatingPointLiteral;
-import org.codehaus.janino.Java.ForEachStatement;
-import org.codehaus.janino.Java.ForStatement;
-import org.codehaus.janino.Java.FunctionDeclarator;
-import org.codehaus.janino.Java.FunctionDeclarator.FormalParameter;
-import org.codehaus.janino.Java.FunctionDeclarator.FormalParameters;
-import org.codehaus.janino.Java.IfStatement;
-import org.codehaus.janino.Java.Initializer;
-import org.codehaus.janino.Java.InnerClassDeclaration;
-import org.codehaus.janino.Java.Instanceof;
-import org.codehaus.janino.Java.IntegerLiteral;
-import org.codehaus.janino.Java.InterfaceDeclaration;
-import org.codehaus.janino.Java.Invocation;
-import org.codehaus.janino.Java.LabeledStatement;
-import org.codehaus.janino.Java.Literal;
-import org.codehaus.janino.Java.LocalClassDeclaration;
-import org.codehaus.janino.Java.LocalClassDeclarationStatement;
-import org.codehaus.janino.Java.LocalVariable;
-import org.codehaus.janino.Java.LocalVariableAccess;
-import org.codehaus.janino.Java.LocalVariableDeclarationStatement;
-import org.codehaus.janino.Java.LocalVariableSlot;
-import org.codehaus.janino.Java.Locatable;
-import org.codehaus.janino.Java.Located;
-import org.codehaus.janino.Java.Lvalue;
-import org.codehaus.janino.Java.MemberClassDeclaration;
-import org.codehaus.janino.Java.MemberInterfaceDeclaration;
-import org.codehaus.janino.Java.MemberTypeDeclaration;
-import org.codehaus.janino.Java.MethodDeclarator;
-import org.codehaus.janino.Java.MethodInvocation;
-import org.codehaus.janino.Java.Modifiers;
-import org.codehaus.janino.Java.NamedClassDeclaration;
-import org.codehaus.janino.Java.NamedTypeDeclaration;
-import org.codehaus.janino.Java.NewAnonymousClassInstance;
-import org.codehaus.janino.Java.NewArray;
-import org.codehaus.janino.Java.NewClassInstance;
-import org.codehaus.janino.Java.NewInitializedArray;
-import org.codehaus.janino.Java.NullLiteral;
-import org.codehaus.janino.Java.Package;
-import org.codehaus.janino.Java.PackageMemberClassDeclaration;
-import org.codehaus.janino.Java.PackageMemberInterfaceDeclaration;
-import org.codehaus.janino.Java.PackageMemberTypeDeclaration;
-import org.codehaus.janino.Java.Padder;
-import org.codehaus.janino.Java.ParameterAccess;
-import org.codehaus.janino.Java.ParenthesizedExpression;
-import org.codehaus.janino.Java.QualifiedThisReference;
-import org.codehaus.janino.Java.ReferenceType;
-import org.codehaus.janino.Java.ReturnStatement;
-import org.codehaus.janino.Java.Rvalue;
-import org.codehaus.janino.Java.RvalueMemberType;
-import org.codehaus.janino.Java.Scope;
-import org.codehaus.janino.Java.SimpleConstant;
-import org.codehaus.janino.Java.SimpleType;
-import org.codehaus.janino.Java.Statement;
-import org.codehaus.janino.Java.StringLiteral;
-import org.codehaus.janino.Java.SuperConstructorInvocation;
-import org.codehaus.janino.Java.SuperclassFieldAccessExpression;
-import org.codehaus.janino.Java.SuperclassMethodInvocation;
-import org.codehaus.janino.Java.SwitchStatement;
-import org.codehaus.janino.Java.SynchronizedStatement;
-import org.codehaus.janino.Java.ThisReference;
-import org.codehaus.janino.Java.ThrowStatement;
-import org.codehaus.janino.Java.TryStatement;
-import org.codehaus.janino.Java.Type;
-import org.codehaus.janino.Java.TypeBodyDeclaration;
-import org.codehaus.janino.Java.TypeDeclaration;
-import org.codehaus.janino.Java.TypeParameter;
-import org.codehaus.janino.Java.UnaryOperation;
-import org.codehaus.janino.Java.VariableDeclarator;
-import org.codehaus.janino.Java.WhileStatement;
-import org.codehaus.janino.Visitor.AtomVisitor;
-import org.codehaus.janino.Visitor.BlockStatementVisitor;
-import org.codehaus.janino.Visitor.ElementValueVisitor;
-import org.codehaus.janino.Visitor.ImportVisitor;
-import org.codehaus.janino.Visitor.LvalueVisitor;
-import org.codehaus.janino.Visitor.RvalueVisitor;
-import org.codehaus.janino.Visitor.TypeDeclarationVisitor;
-import org.codehaus.janino.util.ClassFile;
-
-/**
- * This class actually implements the Java™ compiler. It is associated with exactly one compilation unit which it
- * compiles.
- */
-@SuppressWarnings({ "rawtypes", "unchecked" }) public
-class UnitCompiler {
- private static final boolean DEBUG = false;
-
- /**
- * This constant determines the number of operands up to which the
- *
- * a.concat(b).concat(c)
- *
- * strategy is used to implement string concatenation. For more operands, the
- *
- * new StringBuilder(a).append(b).append(c).append(d).toString()
- *
- * strategy is chosen.
- *
- * A very good article from Tom
- * Gibara analyzes the impact of this decision and recommends a value of three.
- */
- private static final int STRING_CONCAT_LIMIT = 3;
-
- /**
- * Special value for the {@code orientation} parameter of the {@link #compileBoolean(Java.Rvalue,
- * CodeContext.Offset, boolean)} methods, indicating that the code should be generated such that execution branches
- * if the value on top of the operand stack is TRUE.
- */
- public static final boolean JUMP_IF_TRUE = true;
-
- /**
- * Special value for the {@code orientation} parameter of the {@link #compileBoolean(Java.Rvalue,
- * CodeContext.Offset, boolean)} methods, indicating that the code should be generated such that execution branches
- * if the value on top of the operand stack is FALSE.
- */
- public static final boolean JUMP_IF_FALSE = false;
-
- public
- UnitCompiler(CompilationUnit compilationUnit, IClassLoader iClassLoader) {
- this.compilationUnit = compilationUnit;
- this.iClassLoader = iClassLoader;
- }
-
- /** @return The {@link CompilationUnit} that this {@link UnitCompiler} compiles */
- public CompilationUnit
- getCompilationUnit() { return this.compilationUnit; }
-
- private void
- import2(SingleStaticImportDeclaration ssid) throws CompileException {
- String name = UnitCompiler.last(ssid.identifiers);
-
- List
- importedObjects = (List ) this.singleStaticImports.get(name);
- if (importedObjects == null) {
- importedObjects = new ArrayList();
- this.singleStaticImports.put(name, importedObjects);
- }
-
- // Type?
- {
- IClass iClass = this.findTypeByFullyQualifiedName(ssid.getLocation(), ssid.identifiers);
- if (iClass != null) {
- importedObjects.add(iClass);
- return;
- }
- }
-
- String[] typeName = UnitCompiler.allButLast(ssid.identifiers);
- IClass iClass = this.findTypeByFullyQualifiedName(ssid.getLocation(), typeName);
- if (iClass == null) {
- this.compileError("Could not load \"" + Java.join(typeName, ".") + "\"", ssid.getLocation());
- return;
- }
-
- // Static field?
- IField iField = iClass.getDeclaredIField(name);
- if (iField != null) {
- if (!iField.isStatic()) {
- this.compileError(
- "Field \"" + name + "\" of \"" + Java.join(typeName, ".") + "\" must be static",
- ssid.getLocation()
- );
- }
- importedObjects.add(iField);
- return;
- }
-
- // Static method?
- IMethod[] ms = iClass.getDeclaredIMethods(name);
- if (ms.length > 0) {
- importedObjects.addAll(Arrays.asList(ms));
- return;
- }
-
- // Give up.
- this.compileError(
- "\"" + Java.join(typeName, ".") + "\" has no static member \"" + name + "\"",
- ssid.getLocation()
- );
- }
- private void
- import2(StaticImportOnDemandDeclaration siodd) throws CompileException {
- IClass iClass = this.findTypeByFullyQualifiedName(siodd.getLocation(), siodd.identifiers);
- if (iClass == null) {
- this.compileError("Could not load \"" + Java.join(siodd.identifiers, ".") + "\"", siodd.getLocation());
- return;
- }
- this.staticImportsOnDemand.add(iClass);
- }
-
- /**
- * Generates an array of {@link ClassFile} objects which represent the classes and interfaces declared in the
- * compilation unit.
- */
- public ClassFile[]
- compileUnit(boolean debugSource, boolean debugLines, boolean debugVars) throws CompileException {
- this.debugSource = debugSource;
- this.debugLines = debugLines;
- this.debugVars = debugVars;
-
- // Compile static import declarations.
- // Notice: The single-type and on-demand imports are needed BEFORE the unit is compiled, thus they are
- // processed in 'getSingleTypeImport()' and 'importOnDemand()'.
- for (ImportDeclaration id : this.compilationUnit.importDeclarations) {
- try {
- id.accept(new ImportVisitor() {
- // CHECKSTYLE LineLengthCheck:OFF
- @Override public void visitSingleTypeImportDeclaration(SingleTypeImportDeclaration stid) {}
- @Override public void visitTypeImportOnDemandDeclaration(TypeImportOnDemandDeclaration tiodd) {}
- @Override public void visitSingleStaticImportDeclaration(SingleStaticImportDeclaration ssid) { try { UnitCompiler.this.import2(ssid); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitStaticImportOnDemandDeclaration(StaticImportOnDemandDeclaration siodd) { try { UnitCompiler.this.import2(siodd); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- // CHECKSTYLE LineLengthCheck:ON
- });
- } catch (UncheckedCompileException uce) {
- throw uce.compileException; // SUPPRESS CHECKSTYLE AvoidHidingCause
- }
- }
-
- this.generatedClassFiles = new ArrayList();
-
- for (PackageMemberTypeDeclaration pmtd : this.compilationUnit.packageMemberTypeDeclarations) {
- this.compile(pmtd);
- }
-
- if (this.compileErrorCount > 0) {
- throw new CompileException((
- this.compileErrorCount
- + " error(s) while compiling unit \""
- + this.compilationUnit.optionalFileName
- + "\""
- ), null);
- }
-
- List l = this.generatedClassFiles;
- return (ClassFile[]) l.toArray(new ClassFile[l.size()]);
- }
-
- // ------------ TypeDeclaration.compile() -------------
-
- private void
- compile(TypeDeclaration td) throws CompileException {
-
- TypeDeclarationVisitor tdv = new TypeDeclarationVisitor() {
- // CHECKSTYLE LineLengthCheck:OFF
- @Override public void visitAnonymousClassDeclaration(AnonymousClassDeclaration acd) { try { UnitCompiler.this.compile2(acd); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitLocalClassDeclaration(LocalClassDeclaration lcd) { try { UnitCompiler.this.compile2(lcd); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitPackageMemberClassDeclaration(PackageMemberClassDeclaration pmcd) { try { UnitCompiler.this.compile2((PackageMemberTypeDeclaration) pmcd); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitMemberInterfaceDeclaration(MemberInterfaceDeclaration mid) { try { UnitCompiler.this.compile2(mid); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitPackageMemberInterfaceDeclaration(PackageMemberInterfaceDeclaration pmid) { try { UnitCompiler.this.compile2((PackageMemberTypeDeclaration) pmid); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitMemberClassDeclaration(MemberClassDeclaration mcd) { try { UnitCompiler.this.compile2(mcd); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- // CHECKSTYLE LineLengthCheck:ON
- };
- try {
- td.accept(tdv);
- } catch (UncheckedCompileException uce) {
- throw uce.compileException; // SUPPRESS CHECKSTYLE AvoidHidingCause
- }
- }
- private void
- compile2(PackageMemberTypeDeclaration pmtd) throws CompileException {
- CompilationUnit declaringCompilationUnit = pmtd.getDeclaringCompilationUnit();
-
- // Check for conflict with single-type-import (7.6).
- {
- String[] ss = this.getSingleTypeImport(pmtd.getName(), pmtd.getLocation());
- if (ss != null) {
- this.compileError((
- "Package member type declaration \""
- + pmtd.getName()
- + "\" conflicts with single-type-import \""
- + Java.join(ss, ".")
- + "\""
- ), pmtd.getLocation());
- }
- }
-
- // Check for redefinition within compilation unit (7.6).
- {
- PackageMemberTypeDeclaration otherPmtd = declaringCompilationUnit.getPackageMemberTypeDeclaration(
- pmtd.getName()
- );
- if (otherPmtd != pmtd) {
- this.compileError((
- "Redeclaration of type \""
- + pmtd.getName()
- + "\", previously declared in "
- + otherPmtd.getLocation()
- ), pmtd.getLocation());
- }
- }
-
- if (pmtd instanceof NamedClassDeclaration) {
- this.compile2((NamedClassDeclaration) pmtd);
- } else
- if (pmtd instanceof InterfaceDeclaration) {
- this.compile2((InterfaceDeclaration) pmtd);
- } else
- {
- throw new JaninoRuntimeException("PMTD of unexpected type " + pmtd.getClass().getName());
- }
- }
-
- private void
- compile2(ClassDeclaration cd) throws CompileException {
- IClass iClass = this.resolve(cd);
-
- // Check that all methods of the non-abstract class are implemented.
- if (!Mod.isAbstract(cd.getModifierFlags())) {
- IMethod[] ms = iClass.getIMethods();
- for (IMethod base : ms) {
- if (base.isAbstract()) {
- IMethod override = iClass.findIMethod(base.getName(), base.getParameterTypes());
- if (
- override == null // It wasn't overridden
- || override.isAbstract() // It was overridden with an abstract method
- // The override does not provide a covariant return type
- || !base.getReturnType().isAssignableFrom(override.getReturnType())
- ) {
- this.compileError(
- "Non-abstract class \"" + iClass + "\" must implement method \"" + base + "\"",
- cd.getLocation()
- );
- }
- }
- }
- }
-
- // Create "ClassFile" object.
- ClassFile cf = new ClassFile(
- (short) (cd.getModifierFlags() | Mod.SUPER), // accessFlags
- iClass.getDescriptor(), // thisClassFD
- iClass.getSuperclass().getDescriptor(), // superclassFD
- IClass.getDescriptors(iClass.getInterfaces()) // interfaceFDs
- );
-
- // TODO: Add annotations with retention != SOURCE.
-
-// for (Annotation a : cd.getAnnotations()) {
-// assert false : "Class '" + iClass + "' has annotation '" + a + "'";
-// }
-
- // Add InnerClasses attribute entry for this class declaration.
- if (cd.getEnclosingScope() instanceof CompilationUnit) {
- ;
- } else
- if (cd.getEnclosingScope() instanceof Block) {
- short innerClassInfoIndex = cf.addConstantClassInfo(iClass.getDescriptor());
- short innerNameIndex = (
- this instanceof NamedTypeDeclaration
- ? cf.addConstantUtf8Info(((NamedTypeDeclaration) this).getName())
- : (short) 0
- );
- assert cd.getAnnotations().length == 0 : "NYI";
- cf.addInnerClassesAttributeEntry(new ClassFile.InnerClassesAttribute.Entry(
- innerClassInfoIndex, // innerClassInfoIndex
- (short) 0, // outerClassInfoIndex
- innerNameIndex, // innerNameIndex
- cd.getModifierFlags() // innerClassAccessFlags
- ));
- } else
- if (cd.getEnclosingScope() instanceof TypeDeclaration) {
- short innerClassInfoIndex = cf.addConstantClassInfo(iClass.getDescriptor());
- short outerClassInfoIndex = cf.addConstantClassInfo(
- this.resolve(((TypeDeclaration) cd.getEnclosingScope())).getDescriptor()
- );
- short innerNameIndex = cf.addConstantUtf8Info(((MemberTypeDeclaration) cd).getName());
- assert cd.getAnnotations().length == 0 : "NYI";
- cf.addInnerClassesAttributeEntry(new ClassFile.InnerClassesAttribute.Entry(
- innerClassInfoIndex, // innerClassInfoIndex
- outerClassInfoIndex, // outerClassInfoIndex
- innerNameIndex, // innerNameIndex
- cd.getModifierFlags() // innerClassAccessFlags
- ));
- }
-
- // Set "SourceFile" attribute.
- if (this.debugSource) {
- String sourceFileName;
- {
- String s = cd.getLocation().getFileName();
- if (s != null) {
- sourceFileName = new File(s).getName();
- } else if (cd instanceof NamedTypeDeclaration) {
- sourceFileName = ((NamedTypeDeclaration) cd).getName() + ".java";
- } else {
- sourceFileName = "ANONYMOUS.java";
- }
- }
- cf.addSourceFileAttribute(sourceFileName);
- }
-
- // Add "Deprecated" attribute (JVMS 4.7.10).
- if (cd instanceof DocCommentable) {
- if (((DocCommentable) cd).hasDeprecatedDocTag()) cf.addDeprecatedAttribute();
- }
-
- // Optional: Generate and compile class initialization method.
- {
- List statements = new ArrayList();
- for (BlockStatement vdoi : cd.variableDeclaratorsAndInitializers) {
- if (((TypeBodyDeclaration) vdoi).isStatic()) statements.add(vdoi);
- }
-
- this.maybeCreateInitMethod(cd, cf, statements);
- }
-
- this.compileDeclaredMethods(cd, cf);
-
- // Compile declared constructors.
- // As a side effect of compiling methods and constructors, synthetic "class-dollar" methods (which implement
- // class literals) are generated on-the fly. We need to note how many we have here so we can compile the
- // extras.
- final int declaredMethodCount = cd.getMethodDeclarations().size();
- {
- int syntheticFieldCount = cd.syntheticFields.size();
- ConstructorDeclarator[] ctords = cd.getConstructors();
- for (ConstructorDeclarator ctord : ctords) {
- this.compile(ctord, cf);
- if (syntheticFieldCount != cd.syntheticFields.size()) {
- throw new JaninoRuntimeException(
- "SNO: Compilation of constructor \""
- + ctord
- + "\" ("
- + ctord.getLocation()
- + ") added synthetic fields!?"
- );
- }
- }
- }
-
- // A side effect of this call may create synthetic functions to access protected parent variables.
- this.compileDeclaredMemberTypes(cd, cf);
-
- // Compile the aforementioned extras.
- this.compileDeclaredMethods(cd, cf, declaredMethodCount);
-
- {
- // for every method look for bridge methods that need to be supplied this is used to correctly dispatch
- // into covariant return types from existing code.
- IMethod[] ms = iClass.getIMethods();
- for (IMethod base : ms) {
- if (!base.isStatic()) {
- IMethod override = iClass.findIMethod(base.getName(), base.getParameterTypes());
-
- // If we overrode the method but with a DIFFERENT return type.
- if (
- override != null
- && !base.getReturnType().equals(override.getReturnType())
- ) {
- this.compileBridgeMethod(cf, base, override);
- }
- }
- }
- }
-
- // Class and instance variables.
- for (BlockStatement vdoi : cd.variableDeclaratorsAndInitializers) {
- if (vdoi instanceof FieldDeclaration) this.addFields((FieldDeclaration) vdoi, cf);
- }
-
- // Synthetic fields.
- for (IField f : cd.syntheticFields.values()) {
- cf.addFieldInfo(
- new Modifiers(Mod.PACKAGE), // modifiers
- f.getName(), // fieldName
- f.getType().getDescriptor(), // fieldTypeFD
- null // optionalConstantValue
- );
- }
-
-
- // Add the generated class file to a thread-local store.
- this.generatedClassFiles.add(cf);
- }
-
- /** Creates {@link ClassFile.FieldInfo}s for all fields declared by the given {@link FieldDeclaration}. */
- private void
- addFields(FieldDeclaration fd, ClassFile cf) throws CompileException {
- for (VariableDeclarator vd : fd.variableDeclarators) {
-
- Type type = fd.type;
- for (int i = 0; i < vd.brackets; ++i) type = new ArrayType(type);
-
- Object ocv = UnitCompiler.NOT_CONSTANT;
- if (Mod.isFinal(fd.modifiers.flags) && vd.optionalInitializer instanceof Rvalue) {
- ocv = this.getConstantValue((Rvalue) vd.optionalInitializer);
- }
-
- ClassFile.FieldInfo fi;
- if (Mod.isPrivateAccess(fd.modifiers.flags)) {
-
- // To make the private field accessible for enclosing types, enclosed types and types enclosed by the
- // same type, it is modified as follows:
- // + Access is changed from PRIVATE to PACKAGE
- assert fd.modifiers.annotations.length == 0 : "NYI";
- fi = cf.addFieldInfo(
- fd.modifiers.changeAccess(Mod.PACKAGE), // modifiers
- vd.name, // fieldName
- this.getType(type).getDescriptor(), // fieldTypeFD
- ocv == UnitCompiler.NOT_CONSTANT ? null : ocv // optionalConstantValue
- );
- } else
- {
- assert fd.modifiers.annotations.length == 0 : "NYI";
- fi = cf.addFieldInfo(
- fd.modifiers, // modifiers
- vd.name, // fieldName
- this.getType(type).getDescriptor(), // fieldTypeFD
- ocv == UnitCompiler.NOT_CONSTANT ? null : ocv // optionalConstantValue
- );
- }
-
- // Add "Deprecated" attribute (JVMS 4.7.10).
- if (fd.hasDeprecatedDocTag()) {
- fi.addAttribute(new ClassFile.DeprecatedAttribute(cf.addConstantUtf8Info("Deprecated")));
- }
- }
- }
-
- private void
- compile2(AnonymousClassDeclaration acd) throws CompileException {
- this.compile2((InnerClassDeclaration) acd);
- }
-
- private void
- compile2(LocalClassDeclaration lcd) throws CompileException {
- this.compile2((InnerClassDeclaration) lcd);
- }
-
- private void
- compile2(InnerClassDeclaration icd) throws CompileException {
-
- // Define a synthetic "this$..." field if there is an enclosing instance.
- {
- List ocs = UnitCompiler.getOuterClasses(icd);
- final int nesting = ocs.size();
- if (nesting >= 2) {
- icd.defineSyntheticField(new SimpleIField(
- this.resolve(icd),
- "this$" + (nesting - 2),
- this.resolve((TypeDeclaration) ocs.get(1))
- ));
- }
- }
-
- // For classes that enclose surrounding scopes, trawl their field initializers looking for synthetic fields.
- if (icd instanceof AnonymousClassDeclaration || icd instanceof LocalClassDeclaration) {
- ClassDeclaration cd = (ClassDeclaration) icd;
-
- // Compilation of field declarations can create synthetic variables, so we must not use an iterator.
- List vdais = cd.variableDeclaratorsAndInitializers;
- for (int i = 0; i < vdais.size(); i++) {
- BlockStatement vdoi = (BlockStatement) vdais.get(i);
- this.fakeCompile(vdoi);
- }
- }
-
- this.compile2((ClassDeclaration) icd);
- }
-
- private void
- compile2(final MemberClassDeclaration mcd) throws CompileException { this.compile2((InnerClassDeclaration) mcd); }
-
- private void
- compile2(InterfaceDeclaration id) throws CompileException {
- final IClass iClass = this.resolve(id);
-
- // Determine extended interfaces.
- id.interfaces = new IClass[id.extendedTypes.length];
- String[] interfaceDescriptors = new String[id.interfaces.length];
- for (int i = 0; i < id.extendedTypes.length; ++i) {
- id.interfaces[i] = this.getType(id.extendedTypes[i]);
- interfaceDescriptors[i] = id.interfaces[i].getDescriptor();
- }
-
- // Create "ClassFile" object.
- ClassFile cf = new ClassFile(
- (short) (id.getModifierFlags() | Mod.SUPER | Mod.INTERFACE | Mod.ABSTRACT), // accessFlags
- iClass.getDescriptor(), // thisClassFD
- Descriptor.JAVA_LANG_OBJECT, // superclassFD
- interfaceDescriptors // interfaceFDs
- );
-
- // TODO: Add annotations with retention != SOURCE.
-
-// for (Annotation a : id.getAnnotations()) {
-// assert false : "Interface '" + iClass + "' has annotation '" + a + "'";
-// }
-
- // Set "SourceFile" attribute.
- if (this.debugSource) {
- String sourceFileName;
- {
- String s = id.getLocation().getFileName();
- if (s != null) {
- sourceFileName = new File(s).getName();
- } else {
- sourceFileName = id.getName() + ".java";
- }
- }
- cf.addSourceFileAttribute(sourceFileName);
- }
-
- // Add "Deprecated" attribute (JVMS 4.7.10).
- if (id.hasDeprecatedDocTag()) cf.addDeprecatedAttribute();
-
- // Interface initialization method.
- if (!id.constantDeclarations.isEmpty()) {
- List statements = new ArrayList();
- statements.addAll(id.constantDeclarations);
-
- this.maybeCreateInitMethod(id, cf, statements);
- }
-
- this.compileDeclaredMethods(id, cf);
-
- // Class variables.
- for (FieldDeclaration constantDeclaration : id.constantDeclarations) this.addFields(constantDeclaration, cf);
-
- this.compileDeclaredMemberTypes(id, cf);
-
- // Add the generated class file to a thread-local store.
- this.generatedClassFiles.add(cf);
- }
-
- /**
- * Create class initialization method iff there is any initialization code.
- *
- * @param decl The type declaration
- * @param cf The class file into which to put the method
- * @param b The block for the method (possibly empty)
- * @throws CompileException
- */
- private void
- maybeCreateInitMethod(
- AbstractTypeDeclaration decl,
- ClassFile cf,
- List statements
- ) throws CompileException {
-
- // Create interface initialization method iff there is any initialization code.
- if (this.generatesCode2(statements)) {
- MethodDeclarator md = new MethodDeclarator(
- decl.getLocation(), // location
- null, // optionalDocComment
- new Modifiers((short) (Mod.STATIC | Mod.PUBLIC)), // modifiers
- new BasicType( // type
- decl.getLocation(),
- BasicType.VOID
- ),
- "", // name
- new FormalParameters(), // formalParameters
- new ReferenceType[0], // thrownExceptions
- statements // optionalStatements
- );
- md.setDeclaringType(decl);
- this.compile(md, cf);
- }
- }
-
- /**
- * Compile all of the types for this declaration
- *
- * NB: as a side effect this will fill in the synthetic field map
- */
- private void
- compileDeclaredMemberTypes(TypeDeclaration decl, ClassFile cf) throws CompileException {
- for (MemberTypeDeclaration mtd : decl.getMemberTypeDeclarations()) {
- this.compile(mtd);
-
- // Add InnerClasses attribute entry for member type declaration.
- short innerClassInfoIndex = cf.addConstantClassInfo(this.resolve(mtd).getDescriptor());
- short outerClassInfoIndex = cf.addConstantClassInfo(this.resolve(decl).getDescriptor());
- short innerNameIndex = cf.addConstantUtf8Info(mtd.getName());
- assert mtd.getAnnotations().length == 0;
- cf.addInnerClassesAttributeEntry(new ClassFile.InnerClassesAttribute.Entry(
- innerClassInfoIndex, // innerClassInfoIndex
- outerClassInfoIndex, // outerClassInfoIndex
- innerNameIndex, // innerNameIndex
- mtd.getModifierFlags() // innerClassAccessFlags
- ));
- }
- }
-
- /**
- * Compile all of the methods for this declaration
- *
- * NB: as a side effect this will fill in the synthetic field map
- *
- * @throws CompileException
- */
- private void
- compileDeclaredMethods(AbstractTypeDeclaration typeDeclaration, ClassFile cf) throws CompileException {
- this.compileDeclaredMethods(typeDeclaration, cf, 0);
- }
-
- /**
- * Compile methods for this declaration starting at {@code startPos}.
- *
- * @param startPos Starting parameter to fill in
- * @throws CompileException
- */
- private void
- compileDeclaredMethods(TypeDeclaration typeDeclaration, ClassFile cf, int startPos) throws CompileException {
-
- // Notice that as a side effect of compiling methods, synthetic "class-dollar" methods (which implement class
- // literals) are generated on-the fly. Hence, we must not use an Iterator here.
-
- for (int i = startPos; i < typeDeclaration.getMethodDeclarations().size(); ++i) {
- MethodDeclarator md = (MethodDeclarator) typeDeclaration.getMethodDeclarations().get(i);
-
- IMethod m = this.toIMethod(md);
- boolean overrides = this.overridesMethodFromSupertype(m, this.resolve(md.getDeclaringType()));
- boolean hasOverrideAnnotation = this.hasAnnotation(md, this.iClassLoader.ANNO_java_lang_Override);
- if (overrides && !hasOverrideAnnotation && !(typeDeclaration instanceof InterfaceDeclaration)) {
- this.warning("MO", "Missing @Override", md.getLocation());
- } else
- if (!overrides && hasOverrideAnnotation) {
- this.compileError("Method does not override a method declared in a supertype", md.getLocation());
- }
-
- this.compile(md, cf);
- }
- }
-
- private boolean
- hasAnnotation(FunctionDeclarator fd, IClass methodAnnotation) throws CompileException {
- Annotation[] methodAnnotations = fd.modifiers.annotations;
- for (Annotation ma : methodAnnotations) {
- if (this.getType(ma.getType()) == methodAnnotation) return true;
- }
- return false;
- }
-
- private boolean
- overridesMethodFromSupertype(IMethod m, IClass type) throws CompileException {
-
- // Check whether it overrides a method declared in the superclass (or any of its supertypes).
- {
- IClass superclass = type.getSuperclass();
- if (superclass != null && this.overridesMethod(m, superclass)) return true;
- }
-
- // Check whether it overrides a method declared in an interface (or any of its superinterfaces).
- IClass[] ifs = type.getInterfaces();
- for (IClass i : ifs) {
- if (this.overridesMethod(m, i)) return true;
- }
-
- // Special handling for interfaces that don't extend other interfaces: JLS7 dictates that these stem from
- // 'Object', but 'getSuperclass()' returns NULL for interfaces.
- if (ifs.length == 0 && type.isInterface()) {
- return this.overridesMethod(m, this.iClassLoader.TYPE_java_lang_Object);
- }
-
- return false;
- }
-
- /** @return Whether {@code method} overrides a method of {@code type} or any of its supertypes */
- private boolean
- overridesMethod(IMethod method, IClass type) throws CompileException {
-
- // Check whether it overrides a method declared in THIS type.
- IMethod[] ms = type.getDeclaredIMethods(method.getName());
- for (IMethod m : ms) {
- if (Arrays.equals(method.getParameterTypes(), m.getParameterTypes())) return true;
- }
-
- // Check whether it overrides a method declared in a supertype.
- return this.overridesMethodFromSupertype(method, type);
- }
-
- /** Compiles a bridge method which will add a method of the signature of base that delegates to override. */
- private void
- compileBridgeMethod(ClassFile cf, IMethod base, IMethod override) throws CompileException {
- ClassFile.MethodInfo mi = cf.addMethodInfo(
- new Modifiers((short) (Mod.PUBLIC | Mod.SYNTHETIC)),
- base.getName(),
- base.getDescriptor()
- );
-
- // Add "Exceptions" attribute (JVMS 4.7.4).
- IClass[] thrownExceptions = base.getThrownExceptions();
- if (thrownExceptions.length > 0) {
- final short eani = cf.addConstantUtf8Info("Exceptions");
- short[] tecciis = new short[thrownExceptions.length];
- for (int i = 0; i < thrownExceptions.length; ++i) {
- tecciis[i] = cf.addConstantClassInfo(thrownExceptions[i].getDescriptor());
- }
- mi.addAttribute(new ClassFile.ExceptionsAttribute(eani, tecciis));
- }
-
- final CodeContext codeContext = new CodeContext(mi.getClassFile(), base.toString());
- final CodeContext savedCodeContext = this.replaceCodeContext(codeContext);
-
- // Allocate all our local variables.
- codeContext.saveLocalVariables();
- codeContext.allocateLocalVariable((short) 1, "this", override.getDeclaringIClass());
- IClass[] paramTypes = override.getParameterTypes();
- LocalVariableSlot[] locals = new LocalVariableSlot[paramTypes.length];
- for (int i = 0; i < paramTypes.length; ++i) {
- locals[i] = codeContext.allocateLocalVariable(
- Descriptor.size(paramTypes[i].getDescriptor()),
- "param" + i,
- paramTypes[i]
- );
- }
-
- this.writeOpcode(Located.NOWHERE, Opcode.ALOAD_0);
- for (LocalVariableSlot l : locals) this.load(Located.NOWHERE, l.getType(), l.getSlotIndex());
- this.invoke(Located.NOWHERE, override);
- this.writeOpcode(Located.NOWHERE, Opcode.ARETURN);
- this.replaceCodeContext(savedCodeContext);
- codeContext.flowAnalysis(override.getName());
-
- // Add the code context as a code attribute to the MethodInfo.
- mi.addAttribute(new ClassFile.AttributeInfo(cf.addConstantUtf8Info("Code")) {
-
- @Override protected void
- storeBody(DataOutputStream dos) throws IOException {
- codeContext.storeCodeAttributeBody(dos, (short) 0, (short) 0);
- }
- });
- }
-
- /** @return Whether this statement can complete normally (JLS7 14.1) */
- private boolean
- compile(BlockStatement bs) throws CompileException {
- final boolean[] res = new boolean[1];
- BlockStatementVisitor bsv = new BlockStatementVisitor() {
- // CHECKSTYLE LineLengthCheck:OFF
- @Override public void visitInitializer(Initializer i) { try { res[0] = UnitCompiler.this.compile2(i); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldDeclaration(FieldDeclaration fd) { try { res[0] = UnitCompiler.this.compile2(fd); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitLabeledStatement(LabeledStatement ls) { try { res[0] = UnitCompiler.this.compile2(ls); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitBlock(Block b) { try { res[0] = UnitCompiler.this.compile2(b); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitExpressionStatement(ExpressionStatement es) { try { res[0] = UnitCompiler.this.compile2(es); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitIfStatement(IfStatement is) { try { res[0] = UnitCompiler.this.compile2(is); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitForStatement(ForStatement fs) { try { res[0] = UnitCompiler.this.compile2(fs); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitForEachStatement(ForEachStatement fes) { try { res[0] = UnitCompiler.this.compile2(fes); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitWhileStatement(WhileStatement ws) { try { res[0] = UnitCompiler.this.compile2(ws); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitTryStatement(TryStatement ts) { try { res[0] = UnitCompiler.this.compile2(ts); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSwitchStatement(SwitchStatement ss) { try { res[0] = UnitCompiler.this.compile2(ss); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSynchronizedStatement(SynchronizedStatement ss) { try { res[0] = UnitCompiler.this.compile2(ss); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitDoStatement(DoStatement ds) { try { res[0] = UnitCompiler.this.compile2(ds); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitLocalVariableDeclarationStatement(LocalVariableDeclarationStatement lvds) { try { res[0] = UnitCompiler.this.compile2(lvds); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitReturnStatement(ReturnStatement rs) { try { res[0] = UnitCompiler.this.compile2(rs); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitThrowStatement(ThrowStatement ts) { try { res[0] = UnitCompiler.this.compile2(ts); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitBreakStatement(BreakStatement bs) { try { res[0] = UnitCompiler.this.compile2(bs); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitContinueStatement(ContinueStatement cs) { try { res[0] = UnitCompiler.this.compile2(cs); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitAssertStatement(AssertStatement as) { try { res[0] = UnitCompiler.this.compile2(as); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitEmptyStatement(EmptyStatement es) { res[0] = UnitCompiler.this.compile2(es); }
- @Override public void visitLocalClassDeclarationStatement(LocalClassDeclarationStatement lcds) { try { res[0] = UnitCompiler.this.compile2(lcds); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitAlternateConstructorInvocation(AlternateConstructorInvocation aci) { try { res[0] = UnitCompiler.this.compile2(aci); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSuperConstructorInvocation(SuperConstructorInvocation sci) { try { res[0] = UnitCompiler.this.compile2(sci); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- // CHECKSTYLE LineLengthCheck:ON
- };
- try {
- bs.accept(bsv);
- return res[0];
- } catch (UncheckedCompileException uce) {
- throw uce.compileException; // SUPPRESS CHECKSTYLE AvoidHidingCause
- }
- }
-
- /**
- * Called to check whether the given {@link Rvalue} compiles or not.
- *
- * @return Whether the block statement can complete normally
- */
- private boolean
- fakeCompile(BlockStatement bs) throws CompileException {
-
- Offset from = this.codeContext.newOffset();
-
- boolean ccn = this.compile(bs);
-
- Offset to = this.codeContext.newOffset();
-
- this.codeContext.removeCode(from, to);
-
- return ccn;
- }
-
- private boolean
- compile2(Initializer i) throws CompileException {
- return this.compile(i.block);
- }
-
- private boolean
- compile2(Block b) throws CompileException {
- this.codeContext.saveLocalVariables();
- try {
- return this.compileStatements(b.statements);
- } finally {
- this.codeContext.restoreLocalVariables();
- }
- }
-
- private boolean
- compileStatements(List extends BlockStatement> statements) throws CompileException {
- boolean previousStatementCanCompleteNormally = true;
- for (BlockStatement bs : statements) {
- if (!previousStatementCanCompleteNormally && this.generatesCode(bs)) {
- this.compileError("Statement is unreachable", bs.getLocation());
- break;
- }
- previousStatementCanCompleteNormally = this.compile(bs);
- }
- return previousStatementCanCompleteNormally;
- }
-
- private boolean
- compile2(DoStatement ds) throws CompileException {
- Object cvc = this.getConstantValue(ds.condition);
- if (cvc != UnitCompiler.NOT_CONSTANT) {
- if (Boolean.TRUE.equals(cvc)) {
- this.warning("DSTC", (
- "Condition of DO statement is always TRUE; "
- + "the proper way of declaring an unconditional loop is \"for (;;)\""
- ), ds.getLocation());
- return this.compileUnconditionalLoop(ds, ds.body, null);
- } else
- {
- this.warning("DSNR", "DO statement never repeats", ds.getLocation());
- }
- }
-
- final CodeContext.Offset bodyOffset = this.codeContext.newOffset();
-
- // Compile body.
- ds.whereToContinue = null;
- if (!this.compile(ds.body) && ds.whereToContinue == null) {
- this.warning("DSNTC", "\"do\" statement never tests its condition", ds.getLocation());
- if (ds.whereToBreak == null) return false;
- ds.whereToBreak.set();
- ds.whereToBreak = null;
- return true;
- }
- if (ds.whereToContinue != null) {
- ds.whereToContinue.set();
- ds.whereToContinue = null;
- }
-
- // Compile condition.
- this.compileBoolean(ds.condition, bodyOffset, UnitCompiler.JUMP_IF_TRUE);
-
- if (ds.whereToBreak != null) {
- ds.whereToBreak.set();
- ds.whereToBreak = null;
- }
-
- return true;
- }
-
- private boolean
- compile2(ForStatement fs) throws CompileException {
- this.codeContext.saveLocalVariables();
- try {
-
- // Compile initializer.
- if (fs.optionalInit != null) this.compile(fs.optionalInit);
-
- if (fs.optionalCondition == null) {
- return this.compileUnconditionalLoop(fs, fs.body, fs.optionalUpdate);
- } else
- {
- Object cvc = this.getConstantValue(fs.optionalCondition);
- if (cvc != UnitCompiler.NOT_CONSTANT) {
- if (Boolean.TRUE.equals(cvc)) {
- this.warning("FSTC", (
- "Condition of FOR statement is always TRUE; "
- + "the proper way of declaring an unconditional loop is \"for (;;)\""
- ), fs.getLocation());
- return this.compileUnconditionalLoop(fs, fs.body, fs.optionalUpdate);
- } else
- {
- this.warning("FSNR", "FOR statement never repeats", fs.getLocation());
- }
- }
- }
-
- CodeContext.Offset toCondition = this.codeContext.new Offset();
- this.writeBranch(fs, Opcode.GOTO, toCondition);
-
- // Compile body.
- fs.whereToContinue = null;
- final CodeContext.Offset bodyOffset = this.codeContext.newOffset();
- boolean bodyCcn = this.compile(fs.body);
- if (fs.whereToContinue != null) fs.whereToContinue.set();
-
- // Compile update.
- if (fs.optionalUpdate != null) {
- if (!bodyCcn && fs.whereToContinue == null) {
- this.warning("FUUR", "For update is unreachable", fs.getLocation());
- } else
- {
- for (Rvalue rv : fs.optionalUpdate) this.compile(rv);
- }
- }
- fs.whereToContinue = null;
-
- // Compile condition.
- toCondition.set();
- this.compileBoolean(fs.optionalCondition, bodyOffset, UnitCompiler.JUMP_IF_TRUE);
- } finally {
- this.codeContext.restoreLocalVariables();
- }
-
- if (fs.whereToBreak != null) {
- fs.whereToBreak.set();
- fs.whereToBreak = null;
- }
-
- return true;
- }
-
- private boolean
- compile2(ForEachStatement fes) throws CompileException {
- IClass expressionType = this.getType(fes.expression);
- if (expressionType.isArray()) {
- this.codeContext.saveLocalVariables();
- try {
-
- // Allocate the local variable for the current element.
- LocalVariable elementLv = this.getLocalVariable(fes.currentElement, false);
- elementLv.setSlot(this.codeContext.allocateLocalVariable(
- Descriptor.size(elementLv.type.getDescriptor()),
- fes.currentElement.name,
- elementLv.type
- ));
-
- // Compile initializer.
- this.compileGetValue(fes.expression);
- short expressionLv = this.codeContext.allocateLocalVariable((short) 1);
- this.store(fes.expression, expressionType, expressionLv);
-
- this.pushConstant(fes, 0);
- LocalVariable indexLv = new LocalVariable(false, IClass.INT);
- indexLv.setSlot(this.codeContext.allocateLocalVariable((short) 1, null, indexLv.type));
- this.store(fes, indexLv);
-
- CodeContext.Offset toCondition = this.codeContext.new Offset();
- this.writeBranch(fes, Opcode.GOTO, toCondition);
-
- // Compile the body.
- fes.whereToContinue = null;
- final CodeContext.Offset bodyOffset = this.codeContext.newOffset();
-
- this.load(fes, expressionType, expressionLv);
- this.load(fes, indexLv);
- this.writeOpcode(fes, Opcode.IALOAD + UnitCompiler.ilfdabcs(expressionType.getComponentType()));
- this.assignmentConversion(fes.currentElement, expressionType.getComponentType(), elementLv.type, null);
- this.store(fes, elementLv);
-
- boolean bodyCcn = this.compile(fes.body);
- if (fes.whereToContinue != null) fes.whereToContinue.set();
-
- // Compile update.
- if (!bodyCcn && fes.whereToContinue == null) {
- this.warning("FUUR", "For update is unreachable", fes.getLocation());
- } else {
- this.crement(fes, indexLv, "++");
- }
- fes.whereToContinue = null;
-
- // Compile condition.
- toCondition.set();
- this.load(fes, indexLv);
- this.load(fes, expressionType, expressionLv);
- this.writeOpcode(fes, Opcode.ARRAYLENGTH);
- this.writeBranch(fes, Opcode.IF_ICMPLT, bodyOffset);
- } finally {
- this.codeContext.restoreLocalVariables();
- }
-
- if (fes.whereToBreak != null) {
- fes.whereToBreak.set();
- fes.whereToBreak = null;
- }
- } else
- if (this.iClassLoader.TYPE_java_lang_Iterable.isAssignableFrom(expressionType)) {
- this.codeContext.saveLocalVariables();
- try {
-
- // Allocate the local variable for the current element.
- LocalVariable elementLv = this.getLocalVariable(fes.currentElement, false);
- elementLv.setSlot(this.codeContext.allocateLocalVariable(
- (short) 1,
- fes.currentElement.name,
- elementLv.type
- ));
-
- // Compile initializer.
- this.compileGetValue(fes.expression);
- this.invoke(fes.expression, this.iClassLoader.METH_java_lang_Iterable__iterator);
- LocalVariable iteratorLv = new LocalVariable(false, this.iClassLoader.TYPE_java_util_Iterator);
- iteratorLv.setSlot(this.codeContext.allocateLocalVariable((short) 1, null, iteratorLv.type));
- this.store(fes, iteratorLv);
-
- CodeContext.Offset toCondition = this.codeContext.new Offset();
- this.writeBranch(fes, Opcode.GOTO, toCondition);
-
- // Compile the body.
- fes.whereToContinue = null;
- final CodeContext.Offset bodyOffset = this.codeContext.newOffset();
-
- this.load(fes, iteratorLv);
- this.invoke(fes.expression, this.iClassLoader.METH_java_util_Iterator__next);
- if (
- !this.tryAssignmentConversion(
- fes.currentElement,
- this.iClassLoader.TYPE_java_lang_Object,
- elementLv.type,
- null
- )
- && !this.tryNarrowingReferenceConversion(
- fes.currentElement,
- this.iClassLoader.TYPE_java_lang_Object,
- elementLv.type
- )
- ) throw new AssertionError();
- this.store(fes, elementLv);
-
- boolean bodyCcn = this.compile(fes.body);
- if (fes.whereToContinue != null) fes.whereToContinue.set();
-
- // Compile update.
- if (!bodyCcn && fes.whereToContinue == null) {
- this.warning("FUUR", "For update is unreachable", fes.getLocation());
- }
- fes.whereToContinue = null;
-
- // Compile condition.
- toCondition.set();
- this.load(fes, iteratorLv);
- this.invoke(fes.expression, this.iClassLoader.METH_java_util_Iterator__hasNext);
- this.writeBranch(fes, Opcode.IFNE, bodyOffset);
- } finally {
- this.codeContext.restoreLocalVariables();
- }
-
- if (fes.whereToBreak != null) {
- fes.whereToBreak.set();
- fes.whereToBreak = null;
- }
- } else
- {
- this.compileError("Cannot iterate over '" + expressionType + "'");
- }
- return true;
- }
-
- private boolean
- compile2(WhileStatement ws) throws CompileException {
- Object cvc = this.getConstantValue(ws.condition);
- if (cvc != UnitCompiler.NOT_CONSTANT) {
- if (Boolean.TRUE.equals(cvc)) {
- this.warning("WSTC", (
- "Condition of WHILE statement is always TRUE; "
- + "the proper way of declaring an unconditional loop is \"for (;;)\""
- ), ws.getLocation());
- return this.compileUnconditionalLoop(ws, ws.body, null);
- } else
- {
- this.warning("WSNR", "WHILE statement never repeats", ws.getLocation());
- }
- }
-
- // Compile body.
- ws.whereToContinue = this.codeContext.new Offset();
- this.writeBranch(ws, Opcode.GOTO, ws.whereToContinue);
- final CodeContext.Offset bodyOffset = this.codeContext.newOffset();
- this.compile(ws.body); // Return value (CCN) is ignored.
- ws.whereToContinue.set();
- ws.whereToContinue = null;
-
- // Compile condition.
- this.compileBoolean(ws.condition, bodyOffset, UnitCompiler.JUMP_IF_TRUE);
-
- if (ws.whereToBreak != null) {
- ws.whereToBreak.set();
- ws.whereToBreak = null;
- }
- return true;
- }
-
- private boolean
- compileUnconditionalLoop(ContinuableStatement cs, BlockStatement body, Rvalue[] optionalUpdate)
- throws CompileException {
- if (optionalUpdate != null) return this.compileUnconditionalLoopWithUpdate(cs, body, optionalUpdate);
-
- // Compile body.
- cs.whereToContinue = this.codeContext.newOffset();
- if (this.compile(body)) this.writeBranch(cs, Opcode.GOTO, cs.whereToContinue);
- cs.whereToContinue = null;
-
- if (cs.whereToBreak == null) return false;
- cs.whereToBreak.set();
- cs.whereToBreak = null;
- return true;
- }
- private boolean
- compileUnconditionalLoopWithUpdate(ContinuableStatement cs, BlockStatement body, Rvalue[] update)
- throws CompileException {
-
- // Compile body.
- cs.whereToContinue = null;
- final CodeContext.Offset bodyOffset = this.codeContext.newOffset();
- boolean bodyCcn = this.compile(body);
-
- // Compile the "update".
- if (cs.whereToContinue != null) cs.whereToContinue.set();
- if (!bodyCcn && cs.whereToContinue == null) {
- this.warning("LUUR", "Loop update is unreachable", update[0].getLocation());
- } else
- {
- for (Rvalue rv : update) this.compile(rv);
- this.writeBranch(cs, Opcode.GOTO, bodyOffset);
- }
- cs.whereToContinue = null;
-
- if (cs.whereToBreak == null) return false;
- cs.whereToBreak.set();
- cs.whereToBreak = null;
- return true;
- }
-
- private boolean
- compile2(LabeledStatement ls) throws CompileException {
- boolean canCompleteNormally = this.compile(ls.body);
-
- if (ls.whereToBreak == null) return canCompleteNormally;
-
- ls.whereToBreak.set();
- ls.whereToBreak = null;
- return true;
- }
-
- private boolean
- compile2(SwitchStatement ss) throws CompileException {
-
- // Compute condition.
- IClass switchExpressionType = this.compileGetValue(ss.condition);
- this.assignmentConversion(
- ss, // locatable
- switchExpressionType, // sourceType
- IClass.INT, // targetType
- null // optionalConstantValue
- );
-
- // Prepare the map of case labels to code offsets.
- TreeMap caseLabelMap = new TreeMap();
- CodeContext.Offset defaultLabelOffset = null;
- CodeContext.Offset[] sbsgOffsets = new CodeContext.Offset[ss.sbsgs.size()];
- for (int i = 0; i < ss.sbsgs.size(); ++i) {
- SwitchStatement.SwitchBlockStatementGroup sbsg = (SwitchStatement.SwitchBlockStatementGroup) (
- ss.sbsgs.get(i)
- );
- sbsgOffsets[i] = this.codeContext.new Offset();
- for (Rvalue caseLabel : sbsg.caseLabels) {
-
- // Verify that case label value is a constant.
- Object cv = this.getConstantValue(caseLabel);
- if (cv == UnitCompiler.NOT_CONSTANT) {
- this.compileError("Value of 'case' label does not pose a constant value", caseLabel.getLocation());
- cv = new Integer(99);
- }
-
- // Verify that case label is assignable to the type of the switch expression.
- IClass rvType = this.getType(caseLabel);
- this.assignmentConversion(
- ss, // locatable
- rvType, // sourceType
- switchExpressionType, // targetType
- cv // optionalConstantValue
- );
-
- // Convert char, byte, short, int to "Integer".
- Integer civ;
- if (cv instanceof Integer) {
- civ = (Integer) cv;
- } else
- if (cv instanceof Number) {
- civ = new Integer(((Number) cv).intValue());
- } else
- if (cv instanceof Character) {
- civ = new Integer(((Character) cv).charValue());
- } else {
- this.compileError(
- "Value of case label must be a char, byte, short or int constant",
- caseLabel.getLocation()
- );
- civ = new Integer(99);
- }
-
- // Store in case label map.
- if (caseLabelMap.containsKey(civ)) {
- this.compileError("Duplicate \"case\" switch label value", caseLabel.getLocation());
- }
- caseLabelMap.put(civ, sbsgOffsets[i]);
- }
- if (sbsg.hasDefaultLabel) {
- if (defaultLabelOffset != null) {
- this.compileError("Duplicate \"default\" switch label", sbsg.getLocation());
- }
- defaultLabelOffset = sbsgOffsets[i];
- }
- }
- if (defaultLabelOffset == null) defaultLabelOffset = this.getWhereToBreak(ss);
-
- // Generate TABLESWITCH or LOOKUPSWITCH instruction.
- CodeContext.Offset switchOffset = this.codeContext.newOffset();
- if (caseLabelMap.isEmpty()) {
- // Special case: SWITCH statement without CASE labels (but maybe a DEFAULT label).
- ;
- } else
- if (
- (Integer) caseLabelMap.firstKey() + caseLabelMap.size() // Beware of INT overflow!
- >= (Integer) caseLabelMap.lastKey() - caseLabelMap.size()
- ) {
-
- // The case label values are strictly consecutity or almost consecutive (at most 50% 'gaps'), so
- // let's use a TABLESWITCH.
- final int low = (Integer) caseLabelMap.firstKey();
- final int high = (Integer) caseLabelMap.lastKey();
-
- this.writeOpcode(ss, Opcode.TABLESWITCH);
- new Padder(this.codeContext).set();
- this.writeOffset(switchOffset, defaultLabelOffset);
- this.writeInt(low);
- this.writeInt(high);
- int cur = low;
- for (Map.Entry me : caseLabelMap.entrySet()) {
- int caseLabelValue = (Integer) me.getKey();
- CodeContext.Offset caseLabelOffset = (CodeContext.Offset) me.getValue();
-
- while (cur < caseLabelValue) {
- this.writeOffset(switchOffset, defaultLabelOffset);
- ++cur;
- }
- this.writeOffset(switchOffset, caseLabelOffset);
- ++cur;
- }
- } else
- {
-
- // The case label values are not 'consecutive enough', so use a LOOKUPSWOTCH.
- this.writeOpcode(ss, Opcode.LOOKUPSWITCH);
- new Padder(this.codeContext).set();
- this.writeOffset(switchOffset, defaultLabelOffset);
- this.writeInt(caseLabelMap.size());
- for (Map.Entry me : caseLabelMap.entrySet()) {
- this.writeInt((Integer) me.getKey());
- this.writeOffset(switchOffset, (CodeContext.Offset) me.getValue());
- }
- }
-
- // Compile statement groups.
- boolean canCompleteNormally = true;
- for (int i = 0; i < ss.sbsgs.size(); ++i) {
- SwitchStatement.SwitchBlockStatementGroup sbsg = (
- (SwitchStatement.SwitchBlockStatementGroup) ss.sbsgs.get(i)
- );
- sbsgOffsets[i].set();
- canCompleteNormally = true;
- for (BlockStatement bs : sbsg.blockStatements) {
- if (!canCompleteNormally) {
- this.compileError("Statement is unreachable", bs.getLocation());
- break;
- }
- canCompleteNormally = this.compile(bs);
- }
- }
- if (ss.whereToBreak == null) return canCompleteNormally;
-
- ss.whereToBreak.set();
- ss.whereToBreak = null;
- return true;
- }
-
- private boolean
- compile2(BreakStatement bs) throws CompileException {
-
- // Find the broken statement.
- BreakableStatement brokenStatement = null;
- if (bs.optionalLabel == null) {
- for (
- Scope s = bs.getEnclosingScope();
- s instanceof Statement || s instanceof CatchClause;
- s = s.getEnclosingScope()
- ) {
- if (s instanceof BreakableStatement) {
- brokenStatement = (BreakableStatement) s;
- break;
- }
- }
- if (brokenStatement == null) {
- this.compileError("\"break\" statement is not enclosed by a breakable statement", bs.getLocation());
- return false;
- }
- } else {
- for (
- Scope s = bs.getEnclosingScope();
- s instanceof Statement || s instanceof CatchClause;
- s = s.getEnclosingScope()
- ) {
- if (s instanceof LabeledStatement) {
- LabeledStatement ls = (LabeledStatement) s;
- if (ls.label.equals(bs.optionalLabel)) {
- brokenStatement = ls;
- break;
- }
- }
- }
- if (brokenStatement == null) {
- this.compileError((
- "Statement \"break "
- + bs.optionalLabel
- + "\" is not enclosed by a breakable statement with label \""
- + bs.optionalLabel
- + "\""
- ), bs.getLocation());
- return false;
- }
- }
-
- this.leaveStatements(
- bs.getEnclosingScope(), // from
- brokenStatement.getEnclosingScope(), // to
- null // optionalStackValueType
- );
- this.writeBranch(bs, Opcode.GOTO, this.getWhereToBreak(brokenStatement));
- return false;
- }
-
- private boolean
- compile2(ContinueStatement cs) throws CompileException {
-
- // Find the continued statement.
- ContinuableStatement continuedStatement = null;
- if (cs.optionalLabel == null) {
- for (
- Scope s = cs.getEnclosingScope();
- s instanceof Statement || s instanceof CatchClause;
- s = s.getEnclosingScope()
- ) {
- if (s instanceof ContinuableStatement) {
- continuedStatement = (ContinuableStatement) s;
- break;
- }
- }
- if (continuedStatement == null) {
- this.compileError(
- "\"continue\" statement is not enclosed by a continuable statement",
- cs.getLocation()
- );
- return false;
- }
- } else {
- for (
- Scope s = cs.getEnclosingScope();
- s instanceof Statement || s instanceof CatchClause;
- s = s.getEnclosingScope()
- ) {
- if (s instanceof LabeledStatement) {
- LabeledStatement ls = (LabeledStatement) s;
- if (ls.label.equals(cs.optionalLabel)) {
- Statement st = ls.body;
- while (st instanceof LabeledStatement) st = ((LabeledStatement) st).body;
- if (!(st instanceof ContinuableStatement)) {
- this.compileError("Labeled statement is not continuable", st.getLocation());
- return false;
- }
- continuedStatement = (ContinuableStatement) st;
- break;
- }
- }
- }
- if (continuedStatement == null) {
- this.compileError((
- "Statement \"continue "
- + cs.optionalLabel
- + "\" is not enclosed by a continuable statement with label \""
- + cs.optionalLabel
- + "\""
- ), cs.getLocation());
- return false;
- }
- }
-
- if (continuedStatement.whereToContinue == null) {
- continuedStatement.whereToContinue = this.codeContext.new Offset();
- }
-
- this.leaveStatements(
- cs.getEnclosingScope(), // from
- continuedStatement.getEnclosingScope(), // to
- null // optionalStackValueType
- );
- this.writeBranch(cs, Opcode.GOTO, continuedStatement.whereToContinue);
- return false;
- }
-
- private boolean
- compile2(AssertStatement as) throws CompileException {
-
- // assert expression1;
- // if (!expression1) throw new AssertionError();
- // assert expression1 : expression2;
- // if (!expression1) throw new AssertionError(expression2);
- CodeContext.Offset end = this.codeContext.new Offset();
- try {
- this.compileBoolean(as.expression1, end, UnitCompiler.JUMP_IF_TRUE);
-
- this.writeOpcode(as, Opcode.NEW);
- this.writeConstantClassInfo(Descriptor.JAVA_LANG_ASSERTIONERROR);
- this.writeOpcode(as, Opcode.DUP);
-
- Rvalue[] arguments = (
- as.optionalExpression2 == null
- ? new Rvalue[0]
- : new Rvalue[] { as.optionalExpression2 }
- );
- this.invokeConstructor(
- as, // locatable
- as, // scope
- null, // optionalEnclosingInstance
- this.iClassLoader.TYPE_java_lang_AssertionError, // targetClass
- arguments // arguments
- );
- this.writeOpcode(as, Opcode.ATHROW);
- } finally {
- end.set();
- }
- return true;
- }
-
- @SuppressWarnings("static-method") private boolean
- compile2(EmptyStatement es) { return true; }
-
- private boolean
- compile2(ExpressionStatement ee) throws CompileException {
- this.compile(ee.rvalue);
- return true;
- }
-
- private boolean
- compile2(FieldDeclaration fd) throws CompileException {
- for (VariableDeclarator vd : fd.variableDeclarators) {
-
- ArrayInitializerOrRvalue initializer = this.getNonConstantFinalInitializer(fd, vd);
- if (initializer == null) continue;
-
- assert fd.modifiers.annotations.length == 0;
- if (!Mod.isStatic(fd.modifiers.flags)) this.writeOpcode(fd, Opcode.ALOAD_0);
- IClass fieldType = this.getType(fd.type);
- if (initializer instanceof Rvalue) {
- Rvalue rvalue = (Rvalue) initializer;
- IClass initializerType = this.compileGetValue(rvalue);
- fieldType = fieldType.getArrayIClass(vd.brackets, this.iClassLoader.TYPE_java_lang_Object);
- this.assignmentConversion(
- fd, // locatable
- initializerType, // sourceType
- fieldType, // targetType
- this.getConstantValue(rvalue) // optionalConstantValue
- );
- } else
- if (initializer instanceof ArrayInitializer) {
- this.compileGetValue((ArrayInitializer) initializer, fieldType);
- } else
- {
- throw new JaninoRuntimeException(
- "Unexpected array initializer or rvalue class "
- + initializer.getClass().getName()
- );
- }
-
- // No need to check accessibility here.
- ;
-
- assert fd.modifiers.annotations.length == 0;
- this.putfield(fd, this.resolve(fd.getDeclaringType()).getDeclaredIField(vd.name));
- }
- return true;
- }
-
- private boolean
- compile2(IfStatement is) throws CompileException {
- Object cv = this.getConstantValue(is.condition);
- BlockStatement es = (
- is.optionalElseStatement != null
- ? is.optionalElseStatement
- : new EmptyStatement(is.thenStatement.getLocation())
- );
- if (cv instanceof Boolean) {
-
- // Constant condition.
- this.fakeCompile(is.condition);
- BlockStatement seeingStatement, blindStatement;
- if (((Boolean) cv).booleanValue()) {
- seeingStatement = is.thenStatement;
- blindStatement = es;
- } else {
- seeingStatement = es;
- blindStatement = is.thenStatement;
- }
-
- // Compile the seeing statement.
- final CodeContext.Inserter ins = this.codeContext.newInserter();
- boolean ssccn = this.compile(seeingStatement);
- boolean bsccn = this.fakeCompile(blindStatement);
- if (ssccn) return true;
- if (!bsccn) return false;
-
- // Hm... the "seeing statement" cannot complete normally, but the "blind statement" can. Things are getting
- // complicated here! The robust solution is to compile the constant-condition-IF statement as a
- // non-constant-condition-IF statement. As an optimization, iff the IF-statement is enclosed ONLY by blocks,
- // then the remaining bytecode can be written to a "fake" code context, i.e. be thrown away.
-
- // Compile constant-condition-IF statement as non-constant-condition-IF statement.
- CodeContext.Offset off = this.codeContext.newOffset();
-
- this.codeContext.pushInserter(ins);
- try {
- this.pushConstant(is, Boolean.FALSE);
- this.writeBranch(is, Opcode.IFNE, off);
- } finally {
- this.codeContext.popInserter();
- }
-
- return true;
- }
-
- // Non-constant condition.
- if (this.generatesCode(is.thenStatement)) {
- if (this.generatesCode(es)) {
-
- // if (expression) statement else statement
- CodeContext.Offset eso = this.codeContext.new Offset();
- CodeContext.Offset end = this.codeContext.new Offset();
- this.compileBoolean(is.condition, eso, UnitCompiler.JUMP_IF_FALSE);
- boolean tsccn = this.compile(is.thenStatement);
- if (tsccn) this.writeBranch(is, Opcode.GOTO, end);
- eso.set();
- boolean esccn = this.compile(es);
- end.set();
- return tsccn || esccn;
- } else {
-
- // if (expression) statement else ;
- CodeContext.Offset end = this.codeContext.new Offset();
- this.compileBoolean(is.condition, end, UnitCompiler.JUMP_IF_FALSE);
- this.compile(is.thenStatement);
- end.set();
- return true;
- }
- } else {
- if (this.generatesCode(es)) {
-
- // if (expression) ; else statement
- CodeContext.Offset end = this.codeContext.new Offset();
- this.compileBoolean(is.condition, end, UnitCompiler.JUMP_IF_TRUE);
- this.compile(es);
- end.set();
- return true;
- } else {
-
- // if (expression) ; else ;
- IClass conditionType = this.compileGetValue(is.condition);
- if (conditionType != IClass.BOOLEAN) this.compileError("Not a boolean expression", is.getLocation());
- this.pop(is, conditionType);
- return true;
- }
- }
- }
-
- private boolean
- compile2(LocalClassDeclarationStatement lcds) throws CompileException {
-
- // Check for redefinition.
- LocalClassDeclaration otherLcd = UnitCompiler.findLocalClassDeclaration(lcds, lcds.lcd.name);
- if (otherLcd != lcds.lcd) {
- this.compileError(
- "Redeclaration of local class \""
- + lcds.lcd.name
- + "\"; previously declared in "
- + otherLcd.getLocation()
- );
- }
-
- this.compile(lcds.lcd);
- return true;
- }
-
- /** Finds a local class declared in any block enclosing the given block statement. */
- private static LocalClassDeclaration
- findLocalClassDeclaration(Scope s, String name) {
- if (s instanceof CompilationUnit) return null;
- for (;;) {
- Scope es = s.getEnclosingScope();
- if (es instanceof CompilationUnit) break;
- if (
- s instanceof BlockStatement
- && (es instanceof Block || es instanceof FunctionDeclarator)
- ) {
- BlockStatement bs = (BlockStatement) s;
- List extends BlockStatement> statements = (
- es instanceof BlockStatement
- ? ((Block) es).statements
- : ((FunctionDeclarator) es).optionalStatements
- );
- for (BlockStatement bs2 : statements) {
- if (bs2 instanceof LocalClassDeclarationStatement) {
- LocalClassDeclarationStatement lcds = ((LocalClassDeclarationStatement) bs2);
- if (lcds.lcd.name.equals(name)) return lcds.lcd;
- }
- if (bs2 == bs) break;
- }
- }
- s = es;
- }
- return null;
- }
-
- private boolean
- compile2(LocalVariableDeclarationStatement lvds) throws CompileException {
- assert lvds.modifiers.annotations.length == 0;
- if ((lvds.modifiers.flags & ~Mod.FINAL) != 0) {
- this.compileError(
- "The only allowed modifier in local variable declarations is \"final\"",
- lvds.getLocation()
- );
- }
-
- for (VariableDeclarator vd : lvds.variableDeclarators) {
-
- LocalVariable lv = this.getLocalVariable(lvds, vd);
- lv.setSlot(
- this.codeContext.allocateLocalVariable(Descriptor.size(lv.type.getDescriptor()), vd.name, lv.type)
- );
-
- if (vd.optionalInitializer != null) {
- if (vd.optionalInitializer instanceof Rvalue) {
- Rvalue rhs = (Rvalue) vd.optionalInitializer;
- this.assignmentConversion(
- lvds, // locatable
- this.compileGetValue(rhs), // sourceType
- lv.type, // targetType
- this.getConstantValue(rhs) // optionalConstantValue
- );
- } else
- if (vd.optionalInitializer instanceof ArrayInitializer) {
- this.compileGetValue((ArrayInitializer) vd.optionalInitializer, lv.type);
- } else
- {
- throw new JaninoRuntimeException(
- "Unexpected rvalue or array initialized class "
- + vd.optionalInitializer.getClass().getName()
- );
- }
- this.store(lvds, lv);
- }
- }
- return true;
- }
-
- /** @return The {@link LocalVariable} corresponding with the local variable declaration/declarator */
- public LocalVariable
- getLocalVariable(LocalVariableDeclarationStatement lvds, VariableDeclarator vd) throws CompileException {
- if (vd.localVariable == null) {
-
- // Determine variable type.
- Type variableType = lvds.type;
- for (int k = 0; k < vd.brackets; ++k) variableType = new ArrayType(variableType);
-
- assert lvds.modifiers.annotations.length == 0;
- vd.localVariable = new LocalVariable(
- Mod.isFinal(lvds.modifiers.flags), // finaL
- this.getType(variableType) // type
- );
- }
- return vd.localVariable;
- }
-
- private boolean
- compile2(ReturnStatement rs) throws CompileException {
-
- // Determine enclosing block, function and compilation Unit.
- FunctionDeclarator enclosingFunction = null;
- {
- Scope s = rs.getEnclosingScope();
- while (s instanceof Statement || s instanceof CatchClause) s = s.getEnclosingScope();
- enclosingFunction = (FunctionDeclarator) s;
- }
-
- IClass returnType = this.getReturnType(enclosingFunction);
- if (returnType == IClass.VOID) {
- if (rs.optionalReturnValue != null) this.compileError("Method must not return a value", rs.getLocation());
- this.leaveStatements(
- rs.getEnclosingScope(), // from
- enclosingFunction, // to
- null // optionalStackValueType
- );
- this.writeOpcode(rs, Opcode.RETURN);
- return false;
- }
- if (rs.optionalReturnValue == null) {
- this.compileError("Method must return a value", rs.getLocation());
- return false;
- }
- IClass type = this.compileGetValue(rs.optionalReturnValue);
- this.assignmentConversion(
- rs, // locatable
- type, // sourceType
- returnType, // targetType
- this.getConstantValue(rs.optionalReturnValue) // optionalConstantValue
- );
-
- this.leaveStatements(
- rs.getEnclosingScope(), // from
- enclosingFunction, // to
- returnType // optionalStackValueType
- );
- this.writeOpcode(rs, Opcode.IRETURN + UnitCompiler.ilfda(returnType));
- return false;
- }
-
- private boolean
- compile2(SynchronizedStatement ss) throws CompileException {
-
- // Evaluate monitor object expression.
- if (!this.iClassLoader.TYPE_java_lang_Object.isAssignableFrom(this.compileGetValue(ss.expression))) {
- this.compileError(
- "Monitor object of \"synchronized\" statement is not a subclass of \"Object\"",
- ss.getLocation()
- );
- }
-
- this.codeContext.saveLocalVariables();
- boolean canCompleteNormally = false;
- try {
-
- // Allocate a local variable for the monitor object.
- ss.monitorLvIndex = this.codeContext.allocateLocalVariable((short) 1);
-
- // Store the monitor object.
- this.writeOpcode(ss, Opcode.DUP);
- this.store(ss, this.iClassLoader.TYPE_java_lang_Object, ss.monitorLvIndex);
-
- // Create lock on the monitor object.
- this.writeOpcode(ss, Opcode.MONITORENTER);
-
- // Compile the statement body.
- final CodeContext.Offset monitorExitOffset = this.codeContext.new Offset();
- final CodeContext.Offset beginningOfBody = this.codeContext.newOffset();
- canCompleteNormally = this.compile(ss.body);
- if (canCompleteNormally) {
- this.writeBranch(ss, Opcode.GOTO, monitorExitOffset);
- }
-
- // Generate the exception handler.
- CodeContext.Offset here = this.codeContext.newOffset();
- this.codeContext.addExceptionTableEntry(
- beginningOfBody, // startPC
- here, // endPC
- here, // handlerPC
- null // catchTypeFD
- );
- this.leave(ss, this.iClassLoader.TYPE_java_lang_Throwable);
- this.writeOpcode(ss, Opcode.ATHROW);
-
- // Unlock monitor object.
- if (canCompleteNormally) {
- monitorExitOffset.set();
- this.leave(ss, null);
- }
- } finally {
- this.codeContext.restoreLocalVariables();
- }
-
- return canCompleteNormally;
- }
-
- private boolean
- compile2(ThrowStatement ts) throws CompileException {
- IClass expressionType = this.compileGetValue(ts.expression);
- this.checkThrownException(
- ts, // locatable
- expressionType, // type
- ts.getEnclosingScope() // scope
- );
- this.writeOpcode(ts, Opcode.ATHROW);
- return false;
- }
-
- private boolean
- compile2(TryStatement ts) throws CompileException {
- if (ts.optionalFinally != null) ts.finallyOffset = this.codeContext.new Offset();
-
- final CodeContext.Offset beginningOfBody = this.codeContext.newOffset();
- final CodeContext.Offset afterStatement = this.codeContext.new Offset();
-
- this.codeContext.saveLocalVariables();
- try {
-
- // Allocate a LV for the JSR of the FINALLY clause.
- //
- // Notice:
- // For unclear reasons, this variable must not overlap with any of the body's variables (although the
- // body's variables are out of scope when it comes to the FINALLY clause!?), otherwise you get
- // java.lang.VerifyError: ... Accessing value from uninitialized local variable 4
- // See bug #56.
- final short pcLvIndex = (
- ts.optionalFinally != null
- ? this.codeContext.allocateLocalVariable((short) 1)
- : (short) 0
- );
-
- // Initialize all catch clauses as "unreachable" only to check later that they ARE indeed reachable.
- for (CatchClause catchClause : ts.catchClauses) {
- IClass caughtExceptionType = this.getType(catchClause.caughtException.type);
- catchClause.reachable = (
- // Superclass or subclass of "java.lang.Error"?
- this.iClassLoader.TYPE_java_lang_Error.isAssignableFrom(caughtExceptionType)
- || caughtExceptionType.isAssignableFrom(this.iClassLoader.TYPE_java_lang_Error)
- // Superclass or subclass of "java.lang.RuntimeException"?
- || this.iClassLoader.TYPE_java_lang_RuntimeException.isAssignableFrom(caughtExceptionType)
- || caughtExceptionType.isAssignableFrom(this.iClassLoader.TYPE_java_lang_RuntimeException)
- );
- }
-
- boolean canCompleteNormally = this.compile(ts.body);
- CodeContext.Offset afterBody = this.codeContext.newOffset();
- if (canCompleteNormally) {
- this.writeBranch(ts, Opcode.GOTO, afterStatement);
- }
-
- if (beginningOfBody.offset != afterBody.offset) { // Avoid zero-length exception table entries.
- this.codeContext.saveLocalVariables();
- try {
- for (int i = 0; i < ts.catchClauses.size(); ++i) {
- try {
- this.codeContext.saveLocalVariables();
-
- CatchClause catchClause = (CatchClause) ts.catchClauses.get(i);
- IClass caughtExceptionType = this.getType(catchClause.caughtException.type);
-
- // Verify that the CATCH clause is reachable.
- if (!catchClause.reachable) {
- this.compileError("Catch clause is unreachable", catchClause.getLocation());
- }
-
- // Allocate the "exception variable".
- LocalVariableSlot exceptionVarSlot = this.codeContext.allocateLocalVariable(
- (short) 1,
- catchClause.caughtException.name,
- caughtExceptionType
- );
- final short evi = exceptionVarSlot.getSlotIndex();
-
- // Kludge: Treat the exception variable like a local variable of the catch clause body.
- this.getLocalVariable(catchClause.caughtException).setSlot(exceptionVarSlot);
-
- this.codeContext.addExceptionTableEntry(
- beginningOfBody, // startPC
- afterBody, // endPC
- this.codeContext.newOffset(), // handlerPC
- caughtExceptionType.getDescriptor() // catchTypeFD
- );
- this.store(
- catchClause, // locatable
- caughtExceptionType, // lvType
- evi // lvIndex
- );
-
-
- if (this.compile(catchClause.body)) {
- canCompleteNormally = true;
- if (
- i < ts.catchClauses.size() - 1
- || ts.optionalFinally != null
- ) this.writeBranch(catchClause, Opcode.GOTO, afterStatement);
- }
- } finally {
- this.codeContext.restoreLocalVariables();
- }
- }
- } finally {
- this.codeContext.restoreLocalVariables();
- }
- }
-
- if (ts.optionalFinally != null) {
- CodeContext.Offset here = this.codeContext.newOffset();
- this.codeContext.addExceptionTableEntry(
- beginningOfBody, // startPC
- here, // endPC
- here, // handlerPC
- null // catchTypeFD
- );
-
- this.codeContext.saveLocalVariables();
- try {
-
- // Save the exception object in an anonymous local variable.
- short evi = this.codeContext.allocateLocalVariable((short) 1);
- this.store(
- ts.optionalFinally, // locatable
- this.iClassLoader.TYPE_java_lang_Object, // lvType
- evi // lvIndex
- );
- this.writeBranch(ts.optionalFinally, Opcode.JSR, ts.finallyOffset);
- this.load(
- ts.optionalFinally, // locatable
- this.iClassLoader.TYPE_java_lang_Object, // type
- evi // index
- );
- this.writeOpcode(ts.optionalFinally, Opcode.ATHROW);
-
- // Compile the "finally" body.
- ts.finallyOffset.set();
- this.store(
- ts.optionalFinally, // locatable
- this.iClassLoader.TYPE_java_lang_Object, // lvType
- pcLvIndex // lvIndex
- );
- if (this.compile(ts.optionalFinally)) {
- if (pcLvIndex > 255) {
- this.writeOpcode(ts.optionalFinally, Opcode.WIDE);
- this.writeOpcode(ts.optionalFinally, Opcode.RET);
- this.writeShort(pcLvIndex);
- } else {
- this.writeOpcode(ts.optionalFinally, Opcode.RET);
- this.writeByte(pcLvIndex);
- }
- }
- } finally {
-
- // The exception object local variable allocated above MUST NOT BE RELEASED until after the FINALLY
- // block is compiled, for otherwise you get
- // java.lang.VerifyError: ... Accessing value from uninitialized register 7
- this.codeContext.restoreLocalVariables();
- }
- }
-
- afterStatement.set();
- if (canCompleteNormally) this.leave(ts, null);
- return canCompleteNormally;
- } finally {
- this.codeContext.restoreLocalVariables();
- }
- }
-
- // ------------ FunctionDeclarator.compile() -------------
-
- private void
- compile(FunctionDeclarator fd, final ClassFile classFile) throws CompileException {
- ClassFile.MethodInfo mi;
- if (Mod.isPrivateAccess(fd.modifiers.flags)) {
- if (fd instanceof MethodDeclarator && !fd.isStatic()) {
-
- // To make the non-static private method invocable for enclosing types, enclosed types and types
- // enclosed by the same type, it is modified as follows:
- // + Access is changed from PRIVATE to PACKAGE
- // + The name is appended with "$"
- // + It is made static
- // + A parameter of type "declaring class" is prepended to the signature
- short modifiers = Mod.changeAccess(
- fd.modifiers.flags, // modifiers
- Mod.PACKAGE // newAccess
- );
- modifiers |= Mod.STATIC;
-
- mi = classFile.addMethodInfo(
- new Modifiers(modifiers, fd.modifiers.annotations), // modifiersAnd
- fd.name + '$', // methodName
- MethodDescriptor.prependParameter( // methodMD
- this.toIMethod((MethodDeclarator) fd).getDescriptor(), // md
- this.resolve(fd.getDeclaringType()).getDescriptor() // parameterFD
- )
- );
- } else
- {
-
- // To make the static private method or private constructor invocable for enclosing types, enclosed
- // types and types enclosed by the same type, it is modified as follows:
- // + Access is changed from PRIVATE to PACKAGE
- assert fd.modifiers.annotations.length == 0 : "NYI";
- short modifiers = Mod.changeAccess(fd.modifiers.flags, Mod.PACKAGE);
- mi = classFile.addMethodInfo(
- new Modifiers(modifiers, fd.modifiers.annotations), // modifiers
- fd.name, // methodName
- this.toIInvocable(fd).getDescriptor() // methodMD
- );
- }
- } else {
-
- // Non-PRIVATE function.
-
- mi = classFile.addMethodInfo(
- fd.modifiers, // modifiers
- fd.name, // methodName
- this.toIInvocable(fd).getDescriptor() // methodMD
- );
- }
-
- // Add "Exceptions" attribute (JVMS 4.7.4).
- {
- if (fd.thrownExceptions.length > 0) {
- final short eani = classFile.addConstantUtf8Info("Exceptions");
- short[] tecciis = new short[fd.thrownExceptions.length];
- for (int i = 0; i < fd.thrownExceptions.length; ++i) {
- tecciis[i] = classFile.addConstantClassInfo(this.getType(fd.thrownExceptions[i]).getDescriptor());
- }
- mi.addAttribute(new ClassFile.ExceptionsAttribute(eani, tecciis));
- }
- }
-
- // Add "Deprecated" attribute (JVMS 4.7.10)
- if (fd.hasDeprecatedDocTag()) {
- mi.addAttribute(new ClassFile.DeprecatedAttribute(classFile.addConstantUtf8Info("Deprecated")));
- }
-
- if (Mod.isAbstract(fd.modifiers.flags) || Mod.isNative(fd.modifiers.flags)) return;
-
- // Create CodeContext.
- final CodeContext codeContext = new CodeContext(mi.getClassFile(), mi.getDescriptor());
-
- CodeContext savedCodeContext = this.replaceCodeContext(codeContext);
- try {
- this.codeContext.saveLocalVariables();
-
- // Define special parameter "this".
- if (!Mod.isStatic(fd.modifiers.flags)) {
- this.codeContext.allocateLocalVariable((short) 1, "this", this.resolve(fd.getDeclaringType()));
- }
-
- if (fd instanceof ConstructorDeclarator) {
- ConstructorDeclarator constructorDeclarator = (ConstructorDeclarator) fd;
-
- // Reserve space for synthetic parameters ("this$...", "val$...").
- for (IField sf : constructorDeclarator.getDeclaringClass().syntheticFields.values()) {
- LocalVariable lv = new LocalVariable(true, sf.getType());
-
- lv.setSlot(this.codeContext.allocateLocalVariable(Descriptor.size(sf.getDescriptor()), null, null));
- constructorDeclarator.syntheticParameters.put(sf.getName(), lv);
- }
- }
-
- this.buildLocalVariableMap(fd);
-
- // Compile the constructor preamble.
- if (fd instanceof ConstructorDeclarator) {
- ConstructorDeclarator cd = (ConstructorDeclarator) fd;
- if (cd.optionalConstructorInvocation != null) {
- this.compile(cd.optionalConstructorInvocation);
- if (cd.optionalConstructorInvocation instanceof SuperConstructorInvocation) {
- this.assignSyntheticParametersToSyntheticFields(cd);
- this.initializeInstanceVariablesAndInvokeInstanceInitializers(cd);
- }
- } else {
-
- // Determine qualification for superconstructor invocation.
- IClass outerClassOfSuperclass = this.resolve(
- cd.getDeclaringClass()
- ).getSuperclass().getOuterIClass();
- QualifiedThisReference qualification = null;
- if (outerClassOfSuperclass != null) {
- qualification = new QualifiedThisReference(
- cd.getLocation(), // location
- new SimpleType(cd.getLocation(), outerClassOfSuperclass) // qualification
- );
- }
-
- // Invoke the superconstructor.
- SuperConstructorInvocation sci = new SuperConstructorInvocation(
- cd.getLocation(), // location
- qualification, // optionalQualification
- new Rvalue[0] // arguments
- );
- sci.setEnclosingScope(fd);
- this.compile(sci);
- this.assignSyntheticParametersToSyntheticFields(cd);
- this.initializeInstanceVariablesAndInvokeInstanceInitializers(cd);
- }
- }
-
- // Compile the function body.
- if (fd.optionalStatements == null) {
- this.compileError("Method must have a body", fd.getLocation());
- return;
- }
- if (this.compileStatements(fd.optionalStatements)) {
- if (this.getReturnType(fd) != IClass.VOID) {
- this.compileError("Method must return a value", fd.getLocation());
- }
- this.writeOpcode(fd, Opcode.RETURN);
- }
- } finally {
- this.codeContext.restoreLocalVariables();
- this.replaceCodeContext(savedCodeContext);
- }
-
- // Don't continue code attribute generation if we had compile errors.
- if (this.compileErrorCount > 0) return;
-
- // Fix up and reallocate as needed.
- codeContext.fixUpAndRelocate();
-
- // Do flow analysis.
- if (UnitCompiler.DEBUG) {
- try {
- codeContext.flowAnalysis(fd.toString());
- } catch (RuntimeException ex) {
- ex.printStackTrace();
- ;
- }
- } else {
- codeContext.flowAnalysis(fd.toString());
- }
-
- final short lntani;
- if (this.debugLines) {
- lntani = classFile.addConstantUtf8Info("LineNumberTable");
- } else {
- lntani = 0;
- }
-
- final short lvtani;
- if (this.debugVars) {
- UnitCompiler.makeLocalVariableNames(codeContext, mi);
- lvtani = classFile.addConstantUtf8Info("LocalVariableTable");
- } else {
- lvtani = 0;
- }
-
- // Add the code context as a code attribute to the MethodInfo.
- mi.addAttribute(new ClassFile.AttributeInfo(classFile.addConstantUtf8Info("Code")) {
-
- @Override protected void
- storeBody(DataOutputStream dos) throws IOException {
- codeContext.storeCodeAttributeBody(dos, lntani, lvtani);
- }
- });
- }
-
- /** Makes the variable name and class name Constant Pool names used by local variables. */
- private static void
- makeLocalVariableNames(final CodeContext cc, final ClassFile.MethodInfo mi) {
- ClassFile cf = mi.getClassFile();
-
- cf.addConstantUtf8Info("LocalVariableTable");
- for (LocalVariableSlot slot : cc.getAllLocalVars()) {
-
- if (slot.getName() != null) {
- String typeName = slot.getType().getDescriptor();
-
- cf.addConstantUtf8Info(typeName);
- cf.addConstantUtf8Info(slot.getName());
- }
- }
- }
-
- private void
- buildLocalVariableMap(FunctionDeclarator fd) throws CompileException {
- Map localVars = new HashMap();
-
- // Add function parameters.
- for (int i = 0; i < fd.formalParameters.parameters.length; ++i) {
- FormalParameter fp = fd.formalParameters.parameters[i];
- IClass parameterIClass = this.getType(fp.type);
- LocalVariable lv = this.getLocalVariable(
- fp,
- i == fd.formalParameters.parameters.length - 1 && fd.formalParameters.variableArity
- );
- lv.setSlot(this.codeContext.allocateLocalVariable(
- Descriptor.size(lv.type.getDescriptor()),
- fp.name,
- parameterIClass
- ));
-
- if (localVars.put(fp.name, lv) != null) {
- this.compileError("Redefinition of parameter \"" + fp.name + "\"", fd.getLocation());
- }
- }
-
- fd.localVariables = localVars;
- if (fd instanceof ConstructorDeclarator) {
- ConstructorDeclarator cd = (ConstructorDeclarator) fd;
- if (cd.optionalConstructorInvocation != null) {
- UnitCompiler.buildLocalVariableMap(cd.optionalConstructorInvocation, localVars);
- }
- }
- if (fd.optionalStatements != null) {
- for (BlockStatement bs : fd.optionalStatements) localVars = this.buildLocalVariableMap(bs, localVars);
- }
- }
-
- /** Computes and fills in the 'local variable map' for the given {@code blockStatement}. */
- private Map
- buildLocalVariableMap(BlockStatement blockStatement, final Map localVars)
- throws CompileException {
- final Map[] resVars = new Map[] { localVars };
- BlockStatementVisitor bsv = new BlockStatementVisitor() {
- // CHECKSTYLE LineLengthCheck:OFF
-
- // Basic statements that use the default handlers.
- @Override public void visitAlternateConstructorInvocation(AlternateConstructorInvocation aci) { UnitCompiler.buildLocalVariableMap(aci, localVars); }
- @Override public void visitBreakStatement(BreakStatement bs) { UnitCompiler.buildLocalVariableMap(bs, localVars); }
- @Override public void visitContinueStatement(ContinueStatement cs) { UnitCompiler.buildLocalVariableMap(cs, localVars); }
- @Override public void visitAssertStatement(AssertStatement as) { UnitCompiler.buildLocalVariableMap(as, localVars); }
- @Override public void visitEmptyStatement(EmptyStatement es) { UnitCompiler.buildLocalVariableMap(es, localVars); }
- @Override public void visitExpressionStatement(ExpressionStatement es) { UnitCompiler.buildLocalVariableMap(es, localVars); }
- @Override public void visitFieldDeclaration(FieldDeclaration fd) { UnitCompiler.buildLocalVariableMap(fd, localVars); }
- @Override public void visitReturnStatement(ReturnStatement rs) { UnitCompiler.buildLocalVariableMap(rs, localVars); }
- @Override public void visitSuperConstructorInvocation(SuperConstructorInvocation sci) { UnitCompiler.buildLocalVariableMap(sci, localVars); }
- @Override public void visitThrowStatement(ThrowStatement ts) { UnitCompiler.buildLocalVariableMap(ts, localVars); }
- @Override public void visitLocalClassDeclarationStatement(LocalClassDeclarationStatement lcds) { UnitCompiler.buildLocalVariableMap(lcds, localVars); }
-
- // More complicated statements with specialized handlers, but don't add new variables in this scope.
- @Override public void visitBlock(Block b) { try { UnitCompiler.this.buildLocalVariableMap(b, localVars); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitDoStatement(DoStatement ds) { try { UnitCompiler.this.buildLocalVariableMap(ds, localVars); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitForStatement(ForStatement fs) { try { UnitCompiler.this.buildLocalVariableMap(fs, localVars); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitForEachStatement(ForEachStatement fes) { try { UnitCompiler.this.buildLocalVariableMap(fes, localVars); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitIfStatement(IfStatement is) { try { UnitCompiler.this.buildLocalVariableMap(is, localVars); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitInitializer(Initializer i) { try { UnitCompiler.this.buildLocalVariableMap(i, localVars); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSwitchStatement(SwitchStatement ss) { try { UnitCompiler.this.buildLocalVariableMap(ss, localVars); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSynchronizedStatement(SynchronizedStatement ss) { try { UnitCompiler.this.buildLocalVariableMap(ss, localVars); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitTryStatement(TryStatement ts) { try { UnitCompiler.this.buildLocalVariableMap(ts, localVars); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitWhileStatement(WhileStatement ws) { try { UnitCompiler.this.buildLocalVariableMap(ws, localVars); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
-
- // More complicated statements with specialized handlers, that can add variables in this scope.
- @Override public void visitLabeledStatement(LabeledStatement ls) { try { resVars[0] = UnitCompiler.this.buildLocalVariableMap(ls, localVars); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitLocalVariableDeclarationStatement(LocalVariableDeclarationStatement lvds) { try { resVars[0] = UnitCompiler.this.buildLocalVariableMap(lvds, localVars); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- // CHECKSTYLE LineLengthCheck:ON
- };
- try { blockStatement.accept(bsv); } catch (UncheckedCompileException uce) {
- throw uce.compileException; // SUPPRESS CHECKSTYLE AvoidHidingCause
- }
- return resVars[0];
- }
-
- // Default handlers.
-
- private static Map
- buildLocalVariableMap(Statement s, final Map localVars) {
- return (s.localVariables = localVars);
- }
-
- private static Map
- buildLocalVariableMap(ConstructorInvocation ci, final Map localVars) {
- return (ci.localVariables = localVars);
- }
-
- // Specialized handlers.
- private void
- buildLocalVariableMap(Block block, Map localVars) throws CompileException {
- block.localVariables = localVars;
- for (BlockStatement bs : block.statements) localVars = this.buildLocalVariableMap(bs, localVars);
- }
-
- private void
- buildLocalVariableMap(DoStatement ds, final Map localVars) throws CompileException {
- ds.localVariables = localVars;
- this.buildLocalVariableMap(ds.body, localVars);
- }
-
- private void
- buildLocalVariableMap(ForStatement fs, final Map localVars)
- throws CompileException {
- Map inner = localVars;
- if (fs.optionalInit != null) {
- inner = this.buildLocalVariableMap(fs.optionalInit, localVars);
- }
- fs.localVariables = inner;
- this.buildLocalVariableMap(fs.body, inner);
- }
-
- private void
- buildLocalVariableMap(ForEachStatement fes, final Map localVars)
- throws CompileException {
- Map vars = new HashMap();
- vars.putAll(localVars);
- LocalVariable elementLv = this.getLocalVariable(fes.currentElement, false);
- vars.put(fes.currentElement.name, elementLv);
- fes.localVariables = vars;
- this.buildLocalVariableMap(fes.body, vars);
- }
-
- private void
- buildLocalVariableMap(IfStatement is, final Map localVars) throws CompileException {
- is.localVariables = localVars;
- this.buildLocalVariableMap(is.thenStatement, localVars);
- if (is.optionalElseStatement != null) {
- this.buildLocalVariableMap(is.optionalElseStatement, localVars);
- }
- }
-
- private void
- buildLocalVariableMap(Initializer i, final Map localVars) throws CompileException {
- this.buildLocalVariableMap(i.block, localVars);
- }
-
- private void
- buildLocalVariableMap(SwitchStatement ss, final Map localVars)
- throws CompileException {
- ss.localVariables = localVars;
- Map vars = localVars;
- for (SwitchStatement.SwitchBlockStatementGroup sbsg : ss.sbsgs) {
- for (BlockStatement bs : sbsg.blockStatements) vars = this.buildLocalVariableMap(bs, vars);
- }
- }
-
- private void
- buildLocalVariableMap(SynchronizedStatement ss, final Map localVars)
- throws CompileException {
- ss.localVariables = localVars;
- this.buildLocalVariableMap(ss.body, localVars);
- }
-
- private void
- buildLocalVariableMap(TryStatement ts, final Map localVars)
- throws CompileException {
- ts.localVariables = localVars;
- this.buildLocalVariableMap(ts.body, localVars);
- for (CatchClause cc : ts.catchClauses) this.buildLocalVariableMap(cc, localVars);
- if (ts.optionalFinally != null) {
- this.buildLocalVariableMap(ts.optionalFinally, localVars);
- }
- }
-
- private void
- buildLocalVariableMap(WhileStatement ws, final Map localVars)
- throws CompileException {
- ws.localVariables = localVars;
- this.buildLocalVariableMap(ws.body, localVars);
- }
-
- private Map
- buildLocalVariableMap(LabeledStatement ls, final Map localVars)
- throws CompileException {
- ls.localVariables = localVars;
- return this.buildLocalVariableMap((BlockStatement) ls.body, localVars);
- }
-
- private Map
- buildLocalVariableMap(LocalVariableDeclarationStatement lvds, final Map localVars)
- throws CompileException {
- Map newVars = new HashMap();
- newVars.putAll(localVars);
- for (VariableDeclarator vd : lvds.variableDeclarators) {
- LocalVariable lv = this.getLocalVariable(lvds, vd);
- if (newVars.put(vd.name, lv) != null) {
- this.compileError("Redefinition of local variable \"" + vd.name + "\" ", vd.getLocation());
- }
- }
- lvds.localVariables = newVars;
- return newVars;
- }
-
- /** Adds the given {@code localVars} to the 'local variable map' of the given {@code catchClause}. */
- protected void
- buildLocalVariableMap(CatchClause catchClause, Map localVars) throws CompileException {
- Map vars = new HashMap();
- vars.putAll(localVars);
- LocalVariable lv = this.getLocalVariable(catchClause.caughtException);
- vars.put(catchClause.caughtException.name, lv);
- this.buildLocalVariableMap(catchClause.body, vars);
- }
-
- /** @return The {@link LocalVariable} corresponding with the {@code parameter} */
- public LocalVariable
- getLocalVariable(FormalParameter parameter) throws CompileException {
- return this.getLocalVariable(parameter, false);
- }
-
- /**
- * @param isVariableArityParameter Whether the {@code parameter} is the last parameter of a 'variable arity'
- * (a.k.a. 'varargs') method declaration
- * @return The {@link LocalVariable} corresponding with the {@code parameter}
- */
- public LocalVariable
- getLocalVariable(FormalParameter parameter, boolean isVariableArityParameter)
- throws CompileException {
- if (parameter.localVariable == null) {
- assert parameter.type != null;
- IClass parameterType = this.getType(parameter.type);
- if (isVariableArityParameter) {
- parameterType = parameterType.getArrayIClass(this.iClassLoader.TYPE_java_lang_Object);
- }
- parameter.localVariable = new LocalVariable(parameter.finaL, parameterType);
- }
- return parameter.localVariable;
- }
-
- // ------------------ Rvalue.compile() ----------------
-
- /** Called to check whether the given {@link Rvalue} compiles or not. */
- private void
- fakeCompile(Rvalue rv) throws CompileException {
-
- final Offset from = this.codeContext.newOffset();
-
- this.compileContext(rv);
- this.compileGet(rv);
-
- Offset to = this.codeContext.newOffset();
-
- this.codeContext.removeCode(from, to);
- }
-
- /** Some {@link Rvalue}s compile more efficiently when their value is not needed, e.g. "i++". */
- private void
- compile(Rvalue rv) throws CompileException {
-
- RvalueVisitor rvv = new RvalueVisitor() {
- // CHECKSTYLE LineLengthCheck:OFF
- @Override public void visitArrayLength(ArrayLength al) { try { UnitCompiler.this.compile2(al); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitAssignment(Assignment a) { try { UnitCompiler.this.compile2(a); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitUnaryOperation(UnaryOperation uo) { try { UnitCompiler.this.compile2(uo); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitBinaryOperation(BinaryOperation bo) { try { UnitCompiler.this.compile2(bo); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCast(Cast c) { try { UnitCompiler.this.compile2(c); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitClassLiteral(ClassLiteral cl) { try { UnitCompiler.this.compile2(cl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitConditionalExpression(ConditionalExpression ce) { try { UnitCompiler.this.compile2(ce); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCrement(Crement c) { try { UnitCompiler.this.compile2(c); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitInstanceof(Instanceof io) { try { UnitCompiler.this.compile2(io); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitMethodInvocation(MethodInvocation mi) { try { UnitCompiler.this.compile2(mi); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSuperclassMethodInvocation(SuperclassMethodInvocation smi) { try { UnitCompiler.this.compile2(smi); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitIntegerLiteral(IntegerLiteral il) { try { UnitCompiler.this.compile2(il); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFloatingPointLiteral(FloatingPointLiteral fpl) { try { UnitCompiler.this.compile2(fpl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitBooleanLiteral(BooleanLiteral bl) { try { UnitCompiler.this.compile2(bl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCharacterLiteral(CharacterLiteral cl) { try { UnitCompiler.this.compile2(cl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitStringLiteral(StringLiteral sl) { try { UnitCompiler.this.compile2(sl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNullLiteral(NullLiteral nl) { try { UnitCompiler.this.compile2(nl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSimpleConstant(SimpleConstant sl) { try { UnitCompiler.this.compile2(sl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewAnonymousClassInstance(NewAnonymousClassInstance naci) { try { UnitCompiler.this.compile2(naci); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewArray(NewArray na) { try { UnitCompiler.this.compile2(na); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewInitializedArray(NewInitializedArray nia) { try { UnitCompiler.this.compile2(nia); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewClassInstance(NewClassInstance nci) { try { UnitCompiler.this.compile2(nci); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitParameterAccess(ParameterAccess pa) { try { UnitCompiler.this.compile2(pa); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitQualifiedThisReference(QualifiedThisReference qtr) { try { UnitCompiler.this.compile2(qtr); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitThisReference(ThisReference tr) { try { UnitCompiler.this.compile2(tr); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
-
- @Override public void visitAmbiguousName(AmbiguousName an) { try { UnitCompiler.this.compile2(an); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitArrayAccessExpression(ArrayAccessExpression aae) { try { UnitCompiler.this.compile2(aae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldAccess(FieldAccess fa) { try { UnitCompiler.this.compile2(fa); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldAccessExpression(FieldAccessExpression fae) { try { UnitCompiler.this.compile2(fae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSuperclassFieldAccessExpression(SuperclassFieldAccessExpression scfae) { try { UnitCompiler.this.compile2(scfae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitLocalVariableAccess(LocalVariableAccess lva) { try { UnitCompiler.this.compile2(lva); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitParenthesizedExpression(ParenthesizedExpression pe) { try { UnitCompiler.this.compile2(pe); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- // CHECKSTYLE LineLengthCheck:ON
- };
- try {
- rv.accept(rvv);
- } catch (UncheckedCompileException uce) {
- throw uce.compileException; // SUPPRESS CHECKSTYLE AvoidHidingCause
- }
- }
-
- private void
- compile2(Rvalue rv) throws CompileException {
- this.pop(rv, this.compileGetValue(rv));
- }
-
- private void
- compile2(Assignment a) throws CompileException {
- if (a.operator == "=") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- this.compileContext(a.lhs);
- this.assignmentConversion(
- a, // locatable
- this.compileGetValue(a.rhs), // sourceType
- this.getType(a.lhs), // targetType
- this.getConstantValue(a.rhs) // optionalConstantValue
- );
- this.compileSet(a.lhs);
- return;
- }
-
- // Implement "|= ^= &= *= /= %= += -= <<= >>= >>>=".
- int lhsCs = this.compileContext(a.lhs);
- this.dup(a, lhsCs);
- IClass lhsType = this.compileGet(a.lhs);
- IClass resultType = this.compileArithmeticBinaryOperation(
- a, // locatable
- lhsType, // lhsType
- a.operator.substring( // operator
- 0,
- a.operator.length() - 1
- ).intern(), /* <= IMPORTANT! */
- a.rhs // rhs
- );
-
- // Convert the result to LHS type (JLS7 15.26.2).
- if (
- !this.tryIdentityConversion(resultType, lhsType)
- && !this.tryNarrowingPrimitiveConversion(a, resultType, lhsType)
- && !this.tryBoxingConversion(a, resultType, lhsType) // Java 5
- ) this.compileError("Operand types unsuitable for '" + a.operator + "'", a.getLocation());
-
- // Assign the result to the left operand.
- this.compileSet(a.lhs);
- }
-
- private void
- compile2(Crement c) throws CompileException {
-
- // Optimized crement of integer local variable.
- LocalVariable lv = this.isIntLv(c);
- if (lv != null) {
- this.compileLocalVariableCrement(c, lv);
- return;
- }
-
- int cs = this.compileContext(c.operand);
- this.dup(c, cs);
- IClass type = this.compileGet(c.operand);
- IClass promotedType = this.unaryNumericPromotion(c, type);
- this.writeOpcode(c, UnitCompiler.ilfd(
- promotedType,
- Opcode.ICONST_1,
- Opcode.LCONST_1,
- Opcode.FCONST_1,
- Opcode.DCONST_1
- ));
- if (c.operator == "++") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- this.writeOpcode(c, Opcode.IADD + UnitCompiler.ilfd(promotedType));
- } else
- if (c.operator == "--") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- this.writeOpcode(c, Opcode.ISUB + UnitCompiler.ilfd(promotedType));
- } else {
- this.compileError("Unexpected operator \"" + c.operator + "\"", c.getLocation());
- }
-
- this.reverseUnaryNumericPromotion(c, promotedType, type);
- this.compileSet(c.operand);
- }
-
- private void
- compile2(ParenthesizedExpression pe) throws CompileException {
- this.compile(pe.value);
- }
-
- private boolean
- compile2(AlternateConstructorInvocation aci) throws CompileException {
- ConstructorDeclarator declaringConstructor = (ConstructorDeclarator) aci.getEnclosingScope();
- IClass declaringIClass = this.resolve(declaringConstructor.getDeclaringClass());
-
- this.writeOpcode(aci, Opcode.ALOAD_0);
- if (declaringIClass.getOuterIClass() != null) this.writeOpcode(aci, Opcode.ALOAD_1);
- this.invokeConstructor(
- aci, // locatable
- declaringConstructor, // scope
- (Rvalue) null, // optionalEnclosingInstance
- declaringIClass, // targetClass
- aci.arguments // arguments
- );
- return true;
- }
-
- private boolean
- compile2(SuperConstructorInvocation sci) throws CompileException {
- ConstructorDeclarator declaringConstructor = (ConstructorDeclarator) sci.getEnclosingScope();
- this.writeOpcode(sci, Opcode.ALOAD_0);
- ClassDeclaration declaringClass = declaringConstructor.getDeclaringClass();
- IClass superclass = this.resolve(declaringClass).getSuperclass();
-
- Rvalue optionalEnclosingInstance;
- if (sci.optionalQualification != null) {
- optionalEnclosingInstance = sci.optionalQualification;
- } else {
- IClass outerIClassOfSuperclass = superclass.getOuterIClass();
- if (outerIClassOfSuperclass == null) {
- optionalEnclosingInstance = null;
- } else {
- optionalEnclosingInstance = new QualifiedThisReference(
- sci.getLocation(), // location
- new SimpleType(sci.getLocation(), outerIClassOfSuperclass) // qualification
- );
- optionalEnclosingInstance.setEnclosingBlockStatement(sci);
- }
- }
- this.invokeConstructor(
- sci, // locatable
- declaringConstructor, // scope
- optionalEnclosingInstance, // optionalEnclosingInstance
- superclass, // targetClass
- sci.arguments // arguments
- );
- return true;
- }
-
- /**
- * Some {@link Rvalue}s compile more efficiently when their value is the condition for a branch.
- *
- * Notice that if "this" is a constant, then either {@code dst} is never branched to, or it is unconditionally
- * branched to. "Unexamined code" errors may result during bytecode validation.
- *
- * @param dst Where to jump
- * @param orientation {@link #JUMP_IF_TRUE} or {@link #JUMP_IF_FALSE}
- */
- private void
- compileBoolean(Rvalue rv, final CodeContext.Offset dst, final boolean orientation) throws CompileException {
-
- RvalueVisitor rvv = new RvalueVisitor() {
- // CHECKSTYLE LineLengthCheck:OFF
- @Override public void visitArrayLength(ArrayLength al) { try { UnitCompiler.this.compileBoolean2(al, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitAssignment(Assignment a) { try { UnitCompiler.this.compileBoolean2(a, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitUnaryOperation(UnaryOperation uo) { try { UnitCompiler.this.compileBoolean2(uo, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitBinaryOperation(BinaryOperation bo) { try { UnitCompiler.this.compileBoolean2(bo, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCast(Cast c) { try { UnitCompiler.this.compileBoolean2(c, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitClassLiteral(ClassLiteral cl) { try { UnitCompiler.this.compileBoolean2(cl, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitConditionalExpression(ConditionalExpression ce) { try { UnitCompiler.this.compileBoolean2(ce, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCrement(Crement c) { try { UnitCompiler.this.compileBoolean2(c, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitInstanceof(Instanceof io) { try { UnitCompiler.this.compileBoolean2(io, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitMethodInvocation(MethodInvocation mi) { try { UnitCompiler.this.compileBoolean2(mi, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSuperclassMethodInvocation(SuperclassMethodInvocation smi) { try { UnitCompiler.this.compileBoolean2(smi, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitIntegerLiteral(IntegerLiteral il) { try { UnitCompiler.this.compileBoolean2(il, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFloatingPointLiteral(FloatingPointLiteral fpl) { try { UnitCompiler.this.compileBoolean2(fpl, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitBooleanLiteral(BooleanLiteral bl) { try { UnitCompiler.this.compileBoolean2(bl, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCharacterLiteral(CharacterLiteral cl) { try { UnitCompiler.this.compileBoolean2(cl, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitStringLiteral(StringLiteral sl) { try { UnitCompiler.this.compileBoolean2(sl, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNullLiteral(NullLiteral nl) { try { UnitCompiler.this.compileBoolean2(nl, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSimpleConstant(SimpleConstant sl) { try { UnitCompiler.this.compileBoolean2(sl, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewAnonymousClassInstance(NewAnonymousClassInstance naci) { try { UnitCompiler.this.compileBoolean2(naci, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewArray(NewArray na) { try { UnitCompiler.this.compileBoolean2(na, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewInitializedArray(NewInitializedArray nia) { try { UnitCompiler.this.compileBoolean2(nia, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewClassInstance(NewClassInstance nci) { try { UnitCompiler.this.compileBoolean2(nci, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitParameterAccess(ParameterAccess pa) { try { UnitCompiler.this.compileBoolean2(pa, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitQualifiedThisReference(QualifiedThisReference qtr) { try { UnitCompiler.this.compileBoolean2(qtr, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitThisReference(ThisReference tr) { try { UnitCompiler.this.compileBoolean2(tr, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
-
- @Override public void visitAmbiguousName(AmbiguousName an) { try { UnitCompiler.this.compileBoolean2(an, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitArrayAccessExpression(ArrayAccessExpression aae) { try { UnitCompiler.this.compileBoolean2(aae, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldAccess(FieldAccess fa) { try { UnitCompiler.this.compileBoolean2(fa, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldAccessExpression(FieldAccessExpression fae) { try { UnitCompiler.this.compileBoolean2(fae, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSuperclassFieldAccessExpression(SuperclassFieldAccessExpression scfae) { try { UnitCompiler.this.compileBoolean2(scfae, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitLocalVariableAccess(LocalVariableAccess lva) { try { UnitCompiler.this.compileBoolean2(lva, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitParenthesizedExpression(ParenthesizedExpression pe) { try { UnitCompiler.this.compileBoolean2(pe, dst, orientation); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- // CHECKSTYLE LineLengthCheck:ON
- };
- try {
- rv.accept(rvv);
- } catch (UncheckedCompileException uce) {
- throw uce.compileException; // SUPPRESS CHECKSTYLE AvoidHidingCause
- }
- }
-
- /**
- * @param dst Where to jump
- * @param orientation {@link #JUMP_IF_TRUE} or {@link #JUMP_IF_FALSE}
- */
- private void
- compileBoolean2(Rvalue rv, CodeContext.Offset dst, boolean orientation) throws CompileException {
- IClass type = this.compileGetValue(rv);
- IClassLoader icl = this.iClassLoader;
- if (type == icl.TYPE_java_lang_Boolean) {
- this.unboxingConversion(rv, icl.TYPE_java_lang_Boolean, IClass.BOOLEAN);
- } else
- if (type != IClass.BOOLEAN) {
- this.compileError("Not a boolean expression", rv.getLocation());
- }
- this.writeBranch(rv, orientation == UnitCompiler.JUMP_IF_TRUE ? Opcode.IFNE : Opcode.IFEQ, dst);
- }
-
- /**
- * @param dst Where to jump
- * @param orientation {@link #JUMP_IF_TRUE} or {@link #JUMP_IF_FALSE}
- */
- private void
- compileBoolean2(UnaryOperation ue, CodeContext.Offset dst, boolean orientation) throws CompileException {
- if (ue.operator == "!") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- this.compileBoolean(ue.operand, dst, !orientation);
- return;
- }
-
- this.compileError("Boolean expression expected", ue.getLocation());
- }
-
- /**
- * @param dst Where to jump
- * @param orientation {@link #JUMP_IF_TRUE} or {@link #JUMP_IF_FALSE}
- */
- private void
- compileBoolean2(BinaryOperation bo, CodeContext.Offset dst, boolean orientation) throws CompileException {
-
- if (bo.op == "|" || bo.op == "^" || bo.op == "&") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- this.compileBoolean2((Rvalue) bo, dst, orientation);
- return;
- }
-
- if (bo.op == "||" || bo.op == "&&") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- Object lhsCv = this.getConstantValue(bo.lhs);
- if (lhsCv instanceof Boolean) {
- if (((Boolean) lhsCv).booleanValue() ^ bo.op == "||") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- // "true && a", "false || a"
- this.compileBoolean(
- bo.rhs,
- dst,
- UnitCompiler.JUMP_IF_TRUE ^ orientation == UnitCompiler.JUMP_IF_FALSE
- );
- } else {
- // "false && a", "true || a"
- this.compileBoolean(
- bo.lhs,
- dst,
- UnitCompiler.JUMP_IF_TRUE ^ orientation == UnitCompiler.JUMP_IF_FALSE
- );
- this.fakeCompile(bo.rhs);
- }
- return;
- }
- Object rhsCv = this.getConstantValue(bo.rhs);
- if (rhsCv instanceof Boolean) {
- if (((Boolean) rhsCv).booleanValue() ^ bo.op == "||") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- // "a && true", "a || false"
- this.compileBoolean(
- bo.lhs,
- dst,
- UnitCompiler.JUMP_IF_TRUE ^ orientation == UnitCompiler.JUMP_IF_FALSE
- );
- } else {
- // "a && false", "a || true"
- this.pop(bo.lhs, this.compileGetValue(bo.lhs));
- this.compileBoolean(
- bo.rhs,
- dst,
- UnitCompiler.JUMP_IF_TRUE ^ orientation == UnitCompiler.JUMP_IF_FALSE
- );
- }
- return;
- }
-
- // SUPPRESS CHECKSTYLE StringLiteralEquality
- if (bo.op == "||" ^ orientation == UnitCompiler.JUMP_IF_FALSE) {
- this.compileBoolean(bo.lhs, dst, UnitCompiler.JUMP_IF_TRUE ^ orientation == UnitCompiler.JUMP_IF_FALSE);
- this.compileBoolean(bo.rhs, dst, UnitCompiler.JUMP_IF_TRUE ^ orientation == UnitCompiler.JUMP_IF_FALSE);
- } else {
- CodeContext.Offset end = this.codeContext.new Offset();
- this.compileBoolean(bo.lhs, end, UnitCompiler.JUMP_IF_FALSE ^ orientation == UnitCompiler.JUMP_IF_FALSE); // SUPPRESS CHECKSTYLE LineLength
- this.compileBoolean(bo.rhs, dst, UnitCompiler.JUMP_IF_TRUE ^ orientation == UnitCompiler.JUMP_IF_FALSE);
- end.set();
- }
- return;
- }
-
- if (
- bo.op == "==" // SUPPRESS CHECKSTYLE StringLiteralEquality
- || bo.op == "!=" // SUPPRESS CHECKSTYLE StringLiteralEquality
- || bo.op == "<=" // SUPPRESS CHECKSTYLE StringLiteralEquality
- || bo.op == ">=" // SUPPRESS CHECKSTYLE StringLiteralEquality
- || bo.op == "<" // SUPPRESS CHECKSTYLE StringLiteralEquality
- || bo.op == ">" // SUPPRESS CHECKSTYLE StringLiteralEquality
- ) {
- int opIdx = (
- bo.op == "==" ? 0 : // SUPPRESS CHECKSTYLE StringLiteralEquality
- bo.op == "!=" ? 1 : // SUPPRESS CHECKSTYLE StringLiteralEquality
- bo.op == "<" ? 2 : // SUPPRESS CHECKSTYLE StringLiteralEquality
- bo.op == ">=" ? 3 : // SUPPRESS CHECKSTYLE StringLiteralEquality
- bo.op == ">" ? 4 : // SUPPRESS CHECKSTYLE StringLiteralEquality
- bo.op == "<=" ? 5 : // SUPPRESS CHECKSTYLE StringLiteralEquality
- Integer.MIN_VALUE
- );
- if (orientation == UnitCompiler.JUMP_IF_FALSE) opIdx ^= 1;
-
- // Comparison with "null".
- {
- boolean lhsIsNull = this.getConstantValue(bo.lhs) == null;
- boolean rhsIsNull = this.getConstantValue(bo.rhs) == null;
-
- if (lhsIsNull || rhsIsNull) {
- if (bo.op != "==" && bo.op != "!=") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- this.compileError(
- "Operator \"" + bo.op + "\" not allowed on operand \"null\"",
- bo.getLocation()
- );
- }
-
- if (!lhsIsNull) {
-
- // x == null
- IClass lhsType = this.compileGetValue(bo.lhs);
- if (lhsType.isPrimitive()) {
- this.compileError(
- "Cannot compare primitive type \"" + lhsType.toString() + "\" with \"null\"",
- bo.getLocation()
- );
- }
- } else
- if (!rhsIsNull) {
-
- // null == x
- IClass rhsType = this.compileGetValue(bo.rhs);
- if (rhsType.isPrimitive()) {
- this.compileError(
- "Cannot compare \"null\" with primitive type \"" + rhsType.toString() + "\"",
- bo.getLocation()
- );
- }
- } else
- {
-
- // null == null
- this.pushConstant(bo, null);
- }
- this.writeBranch(bo, Opcode.IFNULL + opIdx, dst);
- return;
- }
- }
-
- IClass lhsType = this.compileGetValue(bo.lhs);
- CodeContext.Inserter convertLhsInserter = this.codeContext.newInserter();
- IClass rhsType = this.compileGetValue(bo.rhs);
-
- // 15.20.1 Numerical comparison.
- if (
- this.getUnboxedType(lhsType).isPrimitiveNumeric()
- && this.getUnboxedType(rhsType).isPrimitiveNumeric()
- && !(
- (bo.op == "==" || bo.op == "!=") // SUPPRESS CHECKSTYLE StringLiteralEquality
- && !lhsType.isPrimitive()
- && !rhsType.isPrimitive()
- )
- ) {
- IClass promotedType = this.binaryNumericPromotion(bo, lhsType, convertLhsInserter, rhsType);
- if (promotedType == IClass.INT) {
- this.writeBranch(bo, Opcode.IF_ICMPEQ + opIdx, dst);
- } else
- if (promotedType == IClass.LONG) {
- this.writeOpcode(bo, Opcode.LCMP);
- this.writeBranch(bo, Opcode.IFEQ + opIdx, dst);
- } else
- if (promotedType == IClass.FLOAT) {
- if (bo.op == ">" || bo.op == ">=") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- this.writeOpcode(bo, Opcode.FCMPL);
- } else {
- this.writeOpcode(bo, Opcode.FCMPG);
- }
- this.writeBranch(bo, Opcode.IFEQ + opIdx, dst);
- } else
- if (promotedType == IClass.DOUBLE) {
- if (bo.op == ">" || bo.op == ">=") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- this.writeOpcode(bo, Opcode.DCMPL);
- } else {
- this.writeOpcode(bo, Opcode.DCMPG);
- }
- this.writeBranch(bo, Opcode.IFEQ + opIdx, dst);
- } else
- {
- throw new JaninoRuntimeException("Unexpected promoted type \"" + promotedType + "\"");
- }
- return;
- }
-
- // JLS7 15.21.2 Boolean Equality Operators == and !=.
- if (
- (lhsType == IClass.BOOLEAN && this.getUnboxedType(rhsType) == IClass.BOOLEAN)
- || (rhsType == IClass.BOOLEAN && this.getUnboxedType(lhsType) == IClass.BOOLEAN)
- ) {
- if (bo.op != "==" && bo.op != "!=") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- this.compileError("Operator \"" + bo.op + "\" not allowed on boolean operands", bo.getLocation());
- }
- IClassLoader icl = this.iClassLoader;
-
- // Unbox LHS if necessary.
- if (lhsType == icl.TYPE_java_lang_Boolean) {
- this.codeContext.pushInserter(convertLhsInserter);
- try {
- this.unboxingConversion(bo, icl.TYPE_java_lang_Boolean, IClass.BOOLEAN);
- } finally {
- this.codeContext.popInserter();
- }
- }
-
- // Unbox RHS if necessary.
- if (rhsType == icl.TYPE_java_lang_Boolean) {
- this.unboxingConversion(bo, icl.TYPE_java_lang_Boolean, IClass.BOOLEAN);
- }
-
- this.writeBranch(bo, Opcode.IF_ICMPEQ + opIdx, dst);
- return;
- }
-
- // Reference comparison.
- // Note: Comparison with "null" is already handled above.
- if (!lhsType.isPrimitive() && !rhsType.isPrimitive()) {
- if (bo.op != "==" && bo.op != "!=") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- this.compileError("Operator \"" + bo.op + "\" not allowed on reference operands", bo.getLocation());
- }
- if (
- !this.isCastReferenceConvertible(lhsType, rhsType)
- || !this.isCastReferenceConvertible(rhsType, lhsType)
- ) this.compileError("Incomparable types '" + lhsType + "' and '" + rhsType + "'", bo.getLocation());
- this.writeBranch(bo, Opcode.IF_ACMPEQ + opIdx, dst);
- return;
- }
-
- this.compileError("Cannot compare types \"" + lhsType + "\" and \"" + rhsType + "\"", bo.getLocation());
- }
-
- this.compileError("Boolean expression expected", bo.getLocation());
- }
-
- /**
- * @param dst Where to jump
- * @param orientation {@link #JUMP_IF_TRUE} or {@link #JUMP_IF_FALSE}
- */
- private void
- compileBoolean2(ParenthesizedExpression pe, CodeContext.Offset dst, boolean orientation) throws CompileException {
- this.compileBoolean(pe.value, dst, orientation);
- }
-
- /**
- * Generates code that determines the context of the {@link Rvalue} and puts it on the operand stack. Most
- * expressions do not have a "context", but some do. E.g. for "x[y]", the context is "x, y". The bottom line is
- * that for statements like "x[y] += 3" the context is only evaluated once.
- *
- * @return The size of the context on the operand stack
- */
- private int
- compileContext(Rvalue rv) throws CompileException {
- final int[] res = new int[1];
- RvalueVisitor rvv = new RvalueVisitor() {
- // CHECKSTYLE LineLengthCheck:OFF
- @Override public void visitArrayLength(ArrayLength al) { try { res[0] = UnitCompiler.this.compileContext2(al); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitAssignment(Assignment a) { res[0] = UnitCompiler.this.compileContext2(a); }
- @Override public void visitUnaryOperation(UnaryOperation uo) { res[0] = UnitCompiler.this.compileContext2(uo); }
- @Override public void visitBinaryOperation(BinaryOperation bo) { res[0] = UnitCompiler.this.compileContext2(bo); }
- @Override public void visitCast(Cast c) { res[0] = UnitCompiler.this.compileContext2(c); }
- @Override public void visitClassLiteral(ClassLiteral cl) { res[0] = UnitCompiler.this.compileContext2(cl); }
- @Override public void visitConditionalExpression(ConditionalExpression ce) { res[0] = UnitCompiler.this.compileContext2(ce); }
- @Override public void visitCrement(Crement c) { res[0] = UnitCompiler.this.compileContext2(c); }
- @Override public void visitInstanceof(Instanceof io) { res[0] = UnitCompiler.this.compileContext2(io); }
- @Override public void visitMethodInvocation(MethodInvocation mi) { res[0] = UnitCompiler.this.compileContext2(mi); }
- @Override public void visitSuperclassMethodInvocation(SuperclassMethodInvocation smi) { res[0] = UnitCompiler.this.compileContext2(smi); }
- @Override public void visitIntegerLiteral(IntegerLiteral il) { res[0] = UnitCompiler.this.compileContext2(il); }
- @Override public void visitFloatingPointLiteral(FloatingPointLiteral fpl) { res[0] = UnitCompiler.this.compileContext2(fpl); }
- @Override public void visitBooleanLiteral(BooleanLiteral bl) { res[0] = UnitCompiler.this.compileContext2(bl); }
- @Override public void visitCharacterLiteral(CharacterLiteral cl) { res[0] = UnitCompiler.this.compileContext2(cl); }
- @Override public void visitStringLiteral(StringLiteral sl) { res[0] = UnitCompiler.this.compileContext2(sl); }
- @Override public void visitNullLiteral(NullLiteral nl) { res[0] = UnitCompiler.this.compileContext2(nl); }
- @Override public void visitSimpleConstant(SimpleConstant sl) { res[0] = UnitCompiler.this.compileContext2(sl); }
- @Override public void visitNewAnonymousClassInstance(NewAnonymousClassInstance naci) { res[0] = UnitCompiler.this.compileContext2(naci); }
- @Override public void visitNewArray(NewArray na) { res[0] = UnitCompiler.this.compileContext2(na); }
- @Override public void visitNewInitializedArray(NewInitializedArray nia) { res[0] = UnitCompiler.this.compileContext2(nia); }
- @Override public void visitNewClassInstance(NewClassInstance nci) { res[0] = UnitCompiler.this.compileContext2(nci); }
- @Override public void visitParameterAccess(ParameterAccess pa) { res[0] = UnitCompiler.this.compileContext2(pa); }
- @Override public void visitQualifiedThisReference(QualifiedThisReference qtr) { res[0] = UnitCompiler.this.compileContext2(qtr); }
- @Override public void visitThisReference(ThisReference tr) { res[0] = UnitCompiler.this.compileContext2(tr); }
-
- @Override public void visitAmbiguousName(AmbiguousName an) { try { res[0] = UnitCompiler.this.compileContext2(an); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitArrayAccessExpression(ArrayAccessExpression aae) { try { res[0] = UnitCompiler.this.compileContext2(aae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldAccess(FieldAccess fa) { try { res[0] = UnitCompiler.this.compileContext2(fa); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldAccessExpression(FieldAccessExpression fae) { try { res[0] = UnitCompiler.this.compileContext2(fae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSuperclassFieldAccessExpression(SuperclassFieldAccessExpression scfae) { try { res[0] = UnitCompiler.this.compileContext2(scfae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitLocalVariableAccess(LocalVariableAccess lva) { res[0] = UnitCompiler.this.compileContext2(lva); }
- @Override public void visitParenthesizedExpression(ParenthesizedExpression pe) { try { res[0] = UnitCompiler.this.compileContext2(pe); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- // CHECKSTYLE LineLengthCheck:ON
- };
- try {
- rv.accept(rvv);
- return res[0];
- } catch (UncheckedCompileException uce) {
- throw uce.compileException; // SUPPRESS CHECKSTYLE AvoidHidingCause
- }
- }
-
- @SuppressWarnings("static-method") private int
- compileContext2(Rvalue rv) { return 0; }
-
- private int
- compileContext2(AmbiguousName an) throws CompileException {
- return this.compileContext(this.toRvalueOrCompileException(this.reclassify(an)));
- }
-
- private int
- compileContext2(FieldAccess fa) throws CompileException {
- if (fa.field.isStatic()) {
- Rvalue rv = fa.lhs.toRvalue();
- if (rv != null) {
- this.warning(
- "CNSFA",
- "Left-hand side of static field access should be a type, not an rvalue",
- fa.lhs.getLocation()
- );
- // JLS7 15.11.1.3.1.1:
- this.pop(fa.lhs, this.compileGetValue(rv));
- }
- return 0;
- } else {
- this.compileGetValue(this.toRvalueOrCompileException(fa.lhs));
- return 1;
- }
- }
-
- private int
- compileContext2(ArrayLength al) throws CompileException {
- if (!this.compileGetValue(al.lhs).isArray()) {
- this.compileError("Cannot determine length of non-array type", al.getLocation());
- }
- return 1;
- }
-
- private int
- compileContext2(ArrayAccessExpression aae) throws CompileException {
- IClass lhsType = this.compileGetValue(aae.lhs);
- if (!lhsType.isArray()) {
- this.compileError(
- "Subscript not allowed on non-array type \"" + lhsType.toString() + "\"",
- aae.getLocation()
- );
- }
-
- IClass indexType = this.compileGetValue(aae.index);
- if (
- !this.tryIdentityConversion(indexType, IClass.INT)
- && !this.tryWideningPrimitiveConversion(aae, indexType, IClass.INT)
- ) this.compileError(
- "Index expression of type \"" + indexType + "\" cannot be widened to \"int\"",
- aae.getLocation()
- );
-
- return 2;
- }
-
- private int
- compileContext2(FieldAccessExpression fae) throws CompileException {
- this.determineValue(fae);
- return this.compileContext(fae.value);
- }
-
- private int
- compileContext2(SuperclassFieldAccessExpression scfae) throws CompileException {
- this.determineValue(scfae);
- return this.compileContext(scfae.value);
- }
-
- private int
- compileContext2(ParenthesizedExpression pe) throws CompileException {
- return this.compileContext(pe.value);
- }
-
- /**
- * Generates code that determines the value of the {@link Rvalue} and puts it on the operand stack. This method
- * relies on that the "context" of the {@link Rvalue} is on top of the operand stack (see {@link
- * #compileContext(Rvalue)}).
- *
- * @return The type of the {@link Rvalue}
- */
- private IClass
- compileGet(Rvalue rv) throws CompileException {
- final IClass[] res = new IClass[1];
- RvalueVisitor rvv = new RvalueVisitor() {
- // CHECKSTYLE LineLengthCheck:OFF
- @Override public void visitArrayLength(ArrayLength al) { res[0] = UnitCompiler.this.compileGet2(al); }
- @Override public void visitAssignment(Assignment a) { try { res[0] = UnitCompiler.this.compileGet2(a); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitUnaryOperation(UnaryOperation uo) { try { res[0] = UnitCompiler.this.compileGet2(uo); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitBinaryOperation(BinaryOperation bo) { try { res[0] = UnitCompiler.this.compileGet2(bo); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCast(Cast c) { try { res[0] = UnitCompiler.this.compileGet2(c); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitClassLiteral(ClassLiteral cl) { try { res[0] = UnitCompiler.this.compileGet2(cl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitConditionalExpression(ConditionalExpression ce) { try { res[0] = UnitCompiler.this.compileGet2(ce); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCrement(Crement c) { try { res[0] = UnitCompiler.this.compileGet2(c); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitInstanceof(Instanceof io) { try { res[0] = UnitCompiler.this.compileGet2(io); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitMethodInvocation(MethodInvocation mi) { try { res[0] = UnitCompiler.this.compileGet2(mi); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSuperclassMethodInvocation(SuperclassMethodInvocation smi) { try { res[0] = UnitCompiler.this.compileGet2(smi); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitIntegerLiteral(IntegerLiteral il) { try { res[0] = UnitCompiler.this.compileGet2(il); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFloatingPointLiteral(FloatingPointLiteral fpl) { try { res[0] = UnitCompiler.this.compileGet2(fpl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitBooleanLiteral(BooleanLiteral bl) { try { res[0] = UnitCompiler.this.compileGet2(bl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCharacterLiteral(CharacterLiteral cl) { try { res[0] = UnitCompiler.this.compileGet2(cl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitStringLiteral(StringLiteral sl) { try { res[0] = UnitCompiler.this.compileGet2(sl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNullLiteral(NullLiteral nl) { try { res[0] = UnitCompiler.this.compileGet2(nl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSimpleConstant(SimpleConstant sl) { try { res[0] = UnitCompiler.this.compileGet2(sl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewAnonymousClassInstance(NewAnonymousClassInstance naci) { try { res[0] = UnitCompiler.this.compileGet2(naci); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewArray(NewArray na) { try { res[0] = UnitCompiler.this.compileGet2(na); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewInitializedArray(NewInitializedArray nia) { try { res[0] = UnitCompiler.this.compileGet2(nia); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewClassInstance(NewClassInstance nci) { try { res[0] = UnitCompiler.this.compileGet2(nci); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitParameterAccess(ParameterAccess pa) { try { res[0] = UnitCompiler.this.compileGet2(pa); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitQualifiedThisReference(QualifiedThisReference qtr) { try { res[0] = UnitCompiler.this.compileGet2(qtr); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitThisReference(ThisReference tr) { try { res[0] = UnitCompiler.this.compileGet2(tr); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
-
- @Override public void visitAmbiguousName(AmbiguousName an) { try { res[0] = UnitCompiler.this.compileGet2(an); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitArrayAccessExpression(ArrayAccessExpression aae) { try { res[0] = UnitCompiler.this.compileGet2(aae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldAccess(FieldAccess fa) { try { res[0] = UnitCompiler.this.compileGet2(fa); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldAccessExpression(FieldAccessExpression fae) { try { res[0] = UnitCompiler.this.compileGet2(fae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSuperclassFieldAccessExpression(SuperclassFieldAccessExpression scfae) { try { res[0] = UnitCompiler.this.compileGet2(scfae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitLocalVariableAccess(LocalVariableAccess lva) { res[0] = UnitCompiler.this.compileGet2(lva); }
- @Override public void visitParenthesizedExpression(ParenthesizedExpression pe) { try { res[0] = UnitCompiler.this.compileGet2(pe); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- // CHECKSTYLE LineLengthCheck:ON
- };
- try {
- rv.accept(rvv);
- return res[0];
- } catch (UncheckedCompileException uce) {
- throw uce.compileException; // SUPPRESS CHECKSTYLE AvoidHidingCause
- }
- }
-
- private IClass
- compileGet2(BooleanRvalue brv) throws CompileException {
- CodeContext.Offset isTrue = this.codeContext.new Offset();
- this.compileBoolean(brv, isTrue, UnitCompiler.JUMP_IF_TRUE);
- this.writeOpcode(brv, Opcode.ICONST_0);
- CodeContext.Offset end = this.codeContext.new Offset();
- this.writeBranch(brv, Opcode.GOTO, end);
- isTrue.set();
- this.writeOpcode(brv, Opcode.ICONST_1);
- end.set();
-
- return IClass.BOOLEAN;
- }
-
- private IClass
- compileGet2(AmbiguousName an) throws CompileException {
- return this.compileGet(this.toRvalueOrCompileException(this.reclassify(an)));
- }
-
- private IClass
- compileGet2(LocalVariableAccess lva) { return this.load(lva, lva.localVariable); }
-
- private IClass
- compileGet2(FieldAccess fa) throws CompileException {
- this.checkAccessible(fa.field, fa.getEnclosingBlockStatement());
- this.getfield(fa, fa.field);
- return fa.field.getType();
- }
-
- private IClass
- compileGet2(ArrayLength al) {
- this.writeOpcode(al, Opcode.ARRAYLENGTH);
- return IClass.INT;
- }
-
- private IClass
- compileGet2(ThisReference tr) throws CompileException {
- this.referenceThis(tr);
- return this.getIClass(tr);
- }
-
- private IClass
- compileGet2(QualifiedThisReference qtr) throws CompileException {
- this.referenceThis(
- qtr, // locatable
- this.getDeclaringClass(qtr), // declaringClass
- this.getDeclaringTypeBodyDeclaration(qtr), // declaringTypeBodyDeclaration
- this.getTargetIClass(qtr) // targetIClass
- );
- return this.getTargetIClass(qtr);
- }
-
- private IClass
- compileGet2(ClassLiteral cl) throws CompileException {
- final Location loc = cl.getLocation();
- final IClassLoader icl = this.iClassLoader;
- IClass iClass = this.getType(cl.type);
-
- if (iClass.isPrimitive()) {
-
- // Primitive class literal.
- this.writeOpcode(cl, Opcode.GETSTATIC);
- String wrapperClassDescriptor = (
- iClass == IClass.VOID ? "Ljava/lang/Void;" :
- iClass == IClass.BYTE ? "Ljava/lang/Byte;" :
- iClass == IClass.CHAR ? "Ljava/lang/Character;" :
- iClass == IClass.DOUBLE ? "Ljava/lang/Double;" :
- iClass == IClass.FLOAT ? "Ljava/lang/Float;" :
- iClass == IClass.INT ? "Ljava/lang/Integer;" :
- iClass == IClass.LONG ? "Ljava/lang/Long;" :
- iClass == IClass.SHORT ? "Ljava/lang/Short;" :
- iClass == IClass.BOOLEAN ? "Ljava/lang/Boolean;" :
- null
- );
- if (wrapperClassDescriptor == null) {
- throw new JaninoRuntimeException("SNO: Unidentifiable primitive type \"" + iClass + "\"");
- }
-
- this.writeConstantFieldrefInfo(
- wrapperClassDescriptor, // classFD
- "TYPE", // fieldName
- "Ljava/lang/Class;" // fieldFD
- );
- return icl.TYPE_java_lang_Class;
- }
-
- // Non-primitive class literal.
-
- TypeDeclaration declaringType;
- for (Scope s = cl.getEnclosingBlockStatement();; s = s.getEnclosingScope()) {
- if (s instanceof TypeDeclaration) {
- declaringType = (AbstractTypeDeclaration) s;
- break;
- }
- }
-
- // Check if synthetic method "static Class class$(String className)" is already declared.
- if (declaringType.getMethodDeclaration("class$") == null) this.declareClassDollarMethod(cl);
-
- // Determine the statics of the declaring class (this is where static fields declarations are found).
- List extends BlockStatement> statics;
- if (declaringType instanceof ClassDeclaration) {
- statics = ((ClassDeclaration) declaringType).variableDeclaratorsAndInitializers;
- } else
- if (declaringType instanceof InterfaceDeclaration) {
- statics = ((InterfaceDeclaration) declaringType).constantDeclarations;
- } else {
- throw new JaninoRuntimeException(
- "SNO: AbstractTypeDeclaration is neither ClassDeclaration nor InterfaceDeclaration"
- );
- }
-
- String className = Descriptor.toClassName(iClass.getDescriptor());
-
- // Compose the "class-dollar" field name. This i done as follows:
- // Type Class-name Field-name
- // String java.lang.String class$java$lang$String
- // String[] [Ljava.lang.String; array$Ljava$lang$String
- // String[][] [[Ljava.lang.String; array$$Ljava$lang$String
- // String[][][] [[[java.lang.String; array$$$Ljava$lang$String
- // int[] [I array$I
- // int[][] [[I array$$I
- String classDollarFieldName;
- {
- if (className.startsWith("[")) {
- classDollarFieldName = "array" + className.replace('.', '$').replace('[', '$');
- if (classDollarFieldName.endsWith(";")) {
- classDollarFieldName = classDollarFieldName.substring(0, classDollarFieldName.length() - 1);
- }
- } else
- {
- classDollarFieldName = "class$" + className.replace('.', '$');
- }
- }
-
- // Declare the static "class dollar field" if not already done.
- ADD_CLASS_DOLLAR_FIELD: {
- for (BlockStatement bs : statics) {
- if (!((TypeBodyDeclaration) bs).isStatic()) continue;
- if (bs instanceof FieldDeclaration) {
- for (VariableDeclarator vd : ((FieldDeclaration) bs).variableDeclarators) {
- if (vd.name.equals(classDollarFieldName)) {
- break ADD_CLASS_DOLLAR_FIELD;
- }
- }
- }
- }
-
- Type classType = new SimpleType(loc, icl.TYPE_java_lang_Class);
- FieldDeclaration fd = new FieldDeclaration(
- loc, // location
- null, // optionalDocComment
- new Modifiers(Mod.STATIC), // modifiers
- classType, // type
- new VariableDeclarator[] { // variableDeclarators
- new VariableDeclarator(
- loc, // location
- classDollarFieldName, // name
- 0, // brackets
- (Rvalue) null // optionalInitializer
- )
- }
- );
- if (declaringType instanceof ClassDeclaration) {
- ((ClassDeclaration) declaringType).addFieldDeclaration(fd);
- } else
- if (declaringType instanceof InterfaceDeclaration) {
- ((InterfaceDeclaration) declaringType).addConstantDeclaration(fd);
- } else {
- throw new JaninoRuntimeException(
- "SNO: AbstractTypeDeclaration is neither ClassDeclaration nor InterfaceDeclaration"
- );
- }
- }
-
- // return (class$X != null) ? class$X : (class$X = class$("X"));
- Type declaringClassOrInterfaceType = new SimpleType(loc, this.resolve(declaringType));
- Lvalue classDollarFieldAccess = new FieldAccessExpression(
- loc, // location
- declaringClassOrInterfaceType, // lhs
- classDollarFieldName // fieldName
- );
- ConditionalExpression ce = new ConditionalExpression(
- loc, // location
- new BinaryOperation( // lhs
- loc, // location
- classDollarFieldAccess, // lhs
- "!=", // op
- new NullLiteral(loc, "null") // rhs
- ),
- classDollarFieldAccess, // mhs
- new Assignment( // rhs
- loc, // location
- classDollarFieldAccess, // lhs
- "=", // operator
- new MethodInvocation( // rhs
- loc, // location
- declaringClassOrInterfaceType, // optionalTarget
- "class$", // methodName
- new Rvalue[] { // arguments
- new StringLiteral(
- loc, // location
- '"' + className + '"' // constantValue
- )
- }
- )
- )
- );
- ce.setEnclosingBlockStatement(cl.getEnclosingBlockStatement());
- return this.compileGet(ce);
- }
- private IClass
- compileGet2(Assignment a) throws CompileException {
- if (a.operator == "=") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- int lhsCs = this.compileContext(a.lhs);
- IClass rhsType = this.compileGetValue(a.rhs);
- IClass lhsType = this.getType(a.lhs);
- Object rhsCv = this.getConstantValue(a.rhs);
- this.assignmentConversion(a, rhsType, lhsType, rhsCv);
- this.dupx(a, lhsType, lhsCs);
- this.compileSet(a.lhs);
- return lhsType;
- }
-
- // Implement "|= ^= &= *= /= %= += -= <<= >>= >>>=".
- int lhsCs = this.compileContext(a.lhs);
- this.dup(a, lhsCs);
- IClass lhsType = this.compileGet(a.lhs);
- IClass resultType = this.compileArithmeticBinaryOperation(
- a, // locatable
- lhsType, // lhsType
- a.operator.substring( // operator
- 0,
- a.operator.length() - 1
- ).intern(), /* <= IMPORTANT! */
- a.rhs // rhs
- );
- // Convert the result to LHS type (JLS7 15.26.2).
- if (
- !this.tryIdentityConversion(resultType, lhsType)
- && !this.tryNarrowingPrimitiveConversion(a, resultType, lhsType)
- ) throw new JaninoRuntimeException("SNO: \"" + a.operator + "\" reconversion failed");
- this.dupx(a, lhsType, lhsCs);
- this.compileSet(a.lhs);
- return lhsType;
- }
-
- private IClass
- compileGet2(ConditionalExpression ce) throws CompileException {
- IClass mhsType, rhsType;
- CodeContext.Inserter mhsConvertInserter, rhsConvertInserter;
- CodeContext.Offset toEnd = this.codeContext.new Offset();
- {
- Object cv = this.getConstantValue(ce.lhs);
- if (cv instanceof Boolean) {
- if (((Boolean) cv).booleanValue()) {
- mhsType = this.compileGetValue(ce.mhs);
- mhsConvertInserter = this.codeContext.newInserter();
- rhsType = this.getType(ce.rhs);
- rhsConvertInserter = null;
- } else {
- mhsType = this.getType(ce.mhs);
- mhsConvertInserter = null;
- rhsType = this.compileGetValue(ce.rhs);
- rhsConvertInserter = this.codeContext.currentInserter();
- }
- } else {
- CodeContext.Offset toRhs = this.codeContext.new Offset();
-
- this.compileBoolean(ce.lhs, toRhs, UnitCompiler.JUMP_IF_FALSE);
- mhsType = this.compileGetValue(ce.mhs);
- mhsConvertInserter = this.codeContext.newInserter();
- this.writeBranch(ce, Opcode.GOTO, toEnd);
- toRhs.set();
- rhsType = this.compileGetValue(ce.rhs);
- rhsConvertInserter = this.codeContext.currentInserter();
- }
- }
- IClass expressionType;
- if (mhsType == rhsType) {
-
- // JLS7 15.25, list 1, bullet 1: "b ? T : T => T"
- expressionType = mhsType;
- } else
- if (this.tryUnboxingConversion(ce.mhs, mhsType, rhsType, mhsConvertInserter)) {
-
- // JLS7 15.25, list 1, bullet 2: "b ? Integer : int => int"
- expressionType = rhsType;
- } else
- if (this.tryUnboxingConversion(ce.rhs, rhsType, mhsType, rhsConvertInserter)) {
-
- // JLS7 15.25, list 1, bullet 2: "b ? int : Integer => int"
- expressionType = mhsType;
- } else
- if (this.getConstantValue(ce.mhs) == null && !rhsType.isPrimitive()) {
-
- // JLS7 15.25, list 1, bullet 3: "b ? null : ReferenceType => ReferenceType"
- expressionType = rhsType;
- } else
- if (!mhsType.isPrimitive() && this.getConstantValue(ce.rhs) == null) {
-
- // JLS7 15.25, list 1, bullet 3: "b ? ReferenceType : null => ReferenceType"
- expressionType = mhsType;
- } else
- if (this.isConvertibleToPrimitiveNumeric(mhsType) && this.isConvertibleToPrimitiveNumeric(rhsType)) {
-
- // TODO JLS7 15.25, list 1, bullet 4, bullet 1: "b ? Byte : Short => short"
- // TODO JLS7 15.25, list 1, bullet 4, bullet 2: "b ? 127 : byte => byte"
- // TODO JLS7 15.25, list 1, bullet 4, bullet 3: "b ? 127 : byte => byte"
-
- // JLS7 15.25, list 1, bullet 4, bullet 4: "b ? Integer : Double => double"
- expressionType = this.binaryNumericPromotion(
- ce, // locatable
- mhsType, // type1
- mhsConvertInserter, // convertInserter1
- rhsType, // type2
- rhsConvertInserter // convertInserter2
- );
- } else
- if (!mhsType.isPrimitive() && !rhsType.isPrimitive()) {
-
- // JLS7 15.25, list 1, bullet 5: "b ? Base : Derived => Base"
- if (mhsType.isAssignableFrom(rhsType)) {
- expressionType = mhsType;
- } else
- if (rhsType.isAssignableFrom(mhsType)) {
- expressionType = rhsType;
- } else
- {
- this.compileError(
- "Reference types \"" + mhsType + "\" and \"" + rhsType + "\" don't match",
- ce.getLocation()
- );
- return this.iClassLoader.TYPE_java_lang_Object;
- }
- } else
- {
- this.compileError(
- "Incompatible expression types \"" + mhsType + "\" and \"" + rhsType + "\"",
- ce.getLocation()
- );
- return this.iClassLoader.TYPE_java_lang_Object;
- }
- toEnd.set();
-
- return expressionType;
- }
-
- private IClass
- compileGet2(Crement c) throws CompileException {
-
- // Optimized crement of integer local variable.
- LocalVariable lv = this.isIntLv(c);
- if (lv != null) {
- if (!c.pre) this.load(c, lv);
- this.compileLocalVariableCrement(c, lv);
- if (c.pre) this.load(c, lv);
- return lv.type;
- }
-
- // Compile operand context.
- int cs = this.compileContext(c.operand);
- // DUP operand context.
- this.dup(c, cs);
- // Get operand value.
- IClass type = this.compileGet(c.operand);
- // DUPX operand value.
- if (!c.pre) this.dupx(c, type, cs);
- // Apply "unary numeric promotion".
- IClass promotedType = this.unaryNumericPromotion(c, type);
- // Crement.
- this.writeOpcode(c, UnitCompiler.ilfd(
- promotedType,
- Opcode.ICONST_1,
- Opcode.LCONST_1,
- Opcode.FCONST_1,
- Opcode.DCONST_1
- ));
- if (c.operator == "++") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- this.writeOpcode(c, Opcode.IADD + UnitCompiler.ilfd(promotedType));
- } else
- if (c.operator == "--") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- this.writeOpcode(c, Opcode.ISUB + UnitCompiler.ilfd(promotedType));
- } else {
- this.compileError("Unexpected operator \"" + c.operator + "\"", c.getLocation());
- }
- this.reverseUnaryNumericPromotion(c, promotedType, type);
- // DUPX cremented operand value.
- if (c.pre) this.dupx(c, type, cs);
- // Set operand.
- this.compileSet(c.operand);
-
- return type;
- }
-
- private void
- compileLocalVariableCrement(Crement c, LocalVariable lv) {
- this.crement(c, lv, c.operator);
- }
-
- private void
- crement(Locatable locatable, LocalVariable lv, String operator) {
- if (lv.getSlotIndex() > 255) {
- this.writeOpcode(locatable, Opcode.WIDE);
- this.writeOpcode(locatable, Opcode.IINC);
- this.writeShort(lv.getSlotIndex());
- this.writeShort(operator == "++" ? 1 : -1); // SUPPRESS CHECKSTYLE StringLiteralEquality
- } else {
- this.writeOpcode(locatable, Opcode.IINC);
- this.writeByte(lv.getSlotIndex());
- this.writeByte(operator == "++" ? 1 : -1); // SUPPRESS CHECKSTYLE StringLiteralEquality
- }
- }
-
- private IClass
- compileGet2(ArrayAccessExpression aae) throws CompileException {
- IClass lhsComponentType = this.getType(aae);
- this.writeOpcode(aae, Opcode.IALOAD + UnitCompiler.ilfdabcs(lhsComponentType));
- return lhsComponentType;
- }
-
- private IClass
- compileGet2(FieldAccessExpression fae) throws CompileException {
- this.determineValue(fae);
- return this.compileGet(fae.value);
- }
-
- private IClass
- compileGet2(SuperclassFieldAccessExpression scfae) throws CompileException {
- this.determineValue(scfae);
- return this.compileGet(scfae.value);
- }
-
- private IClass
- compileGet2(UnaryOperation uo) throws CompileException {
-
- if (uo.operator == "!") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- return this.compileGet2((BooleanRvalue) uo);
- }
-
- if (uo.operator == "+") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- return this.unaryNumericPromotion(
- uo,
- this.convertToPrimitiveNumericType(uo, this.compileGetValue(uo.operand))
- );
- }
-
- if (uo.operator == "-") { // SUPPRESS CHECKSTYLE StringLiteralEquality
-
- {
- Object ncv = this.getNegatedConstantValue(uo.operand);
- if (ncv != UnitCompiler.NOT_CONSTANT) {
- return this.unaryNumericPromotion(uo, this.pushConstant(uo, ncv));
- }
- }
-
- IClass promotedType = this.unaryNumericPromotion(
- uo,
- this.convertToPrimitiveNumericType(uo, this.compileGetValue(uo.operand))
- );
- this.writeOpcode(uo, Opcode.INEG + UnitCompiler.ilfd(promotedType));
- return promotedType;
- }
-
- if (uo.operator == "~") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- IClass operandType = this.compileGetValue(uo.operand);
-
- IClass promotedType = this.unaryNumericPromotion(uo, operandType);
- if (promotedType == IClass.INT) {
- this.writeOpcode(uo, Opcode.ICONST_M1);
- this.writeOpcode(uo, Opcode.IXOR);
- return IClass.INT;
- }
- if (promotedType == IClass.LONG) {
- this.writeOpcode(uo, Opcode.LDC2_W);
- this.writeConstantLongInfo(-1L);
- this.writeOpcode(uo, Opcode.LXOR);
- return IClass.LONG;
- }
- this.compileError("Operator \"~\" not applicable to type \"" + promotedType + "\"", uo.getLocation());
- }
-
- this.compileError("Unexpected operator \"" + uo.operator + "\"", uo.getLocation());
- return this.iClassLoader.TYPE_java_lang_Object;
- }
-
- private IClass
- compileGet2(Instanceof io) throws CompileException {
- IClass lhsType = this.compileGetValue(io.lhs);
- IClass rhsType = this.getType(io.rhs);
- if (
- lhsType.isInterface() || rhsType.isInterface()
- // We cannot precompute the result from type information as the value might be null, but we should detect
- // when the instanceof is statically impossible.
- || lhsType.isAssignableFrom(rhsType)
- || rhsType.isAssignableFrom(lhsType)
- ) {
- this.writeOpcode(io, Opcode.INSTANCEOF);
- this.writeConstantClassInfo(rhsType.getDescriptor());
- } else {
- this.compileError("\"" + lhsType + "\" can never be an instance of \"" + rhsType + "\"", io.getLocation());
- }
- return IClass.BOOLEAN;
- }
-
- private IClass
- compileGet2(BinaryOperation bo) throws CompileException {
- if (
- bo.op == "||" // SUPPRESS CHECKSTYLE StringLiteralEquality
- || bo.op == "&&" // SUPPRESS CHECKSTYLE StringLiteralEquality
- || bo.op == "==" // SUPPRESS CHECKSTYLE StringLiteralEquality
- || bo.op == "!=" // SUPPRESS CHECKSTYLE StringLiteralEquality
- || bo.op == "<" // SUPPRESS CHECKSTYLE StringLiteralEquality
- || bo.op == ">" // SUPPRESS CHECKSTYLE StringLiteralEquality
- || bo.op == "<=" // SUPPRESS CHECKSTYLE StringLiteralEquality
- || bo.op == ">=" // SUPPRESS CHECKSTYLE StringLiteralEquality
- ) {
- // Eventually calls "compileBoolean()".
- return this.compileGet2((BooleanRvalue) bo);
- }
-
- // Implements "| ^ & * / % + - << >> >>>".
- return this.compileArithmeticOperation(
- bo, // locatable
- null, // type
- bo.unrollLeftAssociation(), // operands
- bo.op // operator
- );
- }
-
- private IClass
- compileGet2(Cast c) throws CompileException {
-
- // JLS7 5.5 Casting Conversion.
- IClass tt = this.getType(c.targetType);
- IClass vt = this.compileGetValue(c.value);
- if (
- this.tryIdentityConversion(vt, tt)
- || this.tryWideningPrimitiveConversion(c, vt, tt)
- || this.tryNarrowingPrimitiveConversion(c, vt, tt)
- || this.tryWideningReferenceConversion(vt, tt)
- || this.tryNarrowingReferenceConversion(c, vt, tt)
- || this.tryBoxingConversion(c, vt, tt)
- || this.tryUnboxingConversion(c, vt, tt, null)
- ) return tt;
-
- // JAVAC obviously also permits 'boxing conversion followed by widening reference conversion' and 'unboxing
- // conversion followed by widening primitive conversion', although these are not described in JLS7 5.5. For the
- // sake of compatibility, we implement them.
- // See also http://jira.codehaus.org/browse/JANINO-153
- {
- IClass boxedType = this.isBoxingConvertible(vt);
- if (boxedType != null && this.isWideningReferenceConvertible(boxedType, tt)) {
- this.boxingConversion(c, vt, boxedType);
- return tt;
- }
-
- IClass unboxedType = this.isUnboxingConvertible(vt);
- if (unboxedType != null && this.isWideningPrimitiveConvertible(unboxedType, tt)) {
- this.unboxingConversion(c, vt, unboxedType);
- this.tryWideningPrimitiveConversion(c, unboxedType, tt);
- return tt;
- }
- }
-
- this.compileError("Cannot cast \"" + vt + "\" to \"" + tt + "\"", c.getLocation());
- return tt;
- }
-
- private IClass
- compileGet2(ParenthesizedExpression pe) throws CompileException {
- return this.compileGet(pe.value);
- }
-
- private IClass
- compileGet2(MethodInvocation mi) throws CompileException {
- IClass.IMethod iMethod = this.findIMethod(mi);
-
- if (mi.optionalTarget == null) {
-
- // JLS7 6.5.7.1, 15.12.4.1.1.1
- TypeBodyDeclaration scopeTbd;
- ClassDeclaration scopeClassDeclaration;
- {
- Scope s;
- for (
- s = mi.getEnclosingBlockStatement();
- !(s instanceof TypeBodyDeclaration);
- s = s.getEnclosingScope()
- );
- scopeTbd = (TypeBodyDeclaration) s;
- if (!(s instanceof ClassDeclaration)) s = s.getEnclosingScope();
- scopeClassDeclaration = (ClassDeclaration) s;
- }
- if (iMethod.isStatic()) {
- this.warning(
- "IASM",
- "Implicit access to static method \"" + iMethod.toString() + "\"",
- mi.getLocation()
- );
- // JLS7 15.12.4.1.1.1.1
- ;
- } else {
- this.warning(
- "IANSM",
- "Implicit access to non-static method \"" + iMethod.toString() + "\"",
- mi.getLocation()
- );
- // JLS7 15.12.4.1.1.1.2
- if (scopeTbd.isStatic()) {
- this.compileError(
- "Instance method \"" + iMethod.toString() + "\" cannot be invoked in static context",
- mi.getLocation()
- );
- }
- this.referenceThis(
- mi, // locatable
- scopeClassDeclaration, // declaringClass
- scopeTbd, // declaringTypeBodyDeclaration
- iMethod.getDeclaringIClass() // targetIClass
- );
- }
- } else {
-
- // 6.5.7.2
- boolean staticContext = this.isType(mi.optionalTarget);
- if (staticContext) {
- this.getType(this.toTypeOrCompileException(mi.optionalTarget));
- } else
- {
- this.compileGetValue(this.toRvalueOrCompileException(mi.optionalTarget));
- }
- if (iMethod.isStatic()) {
- if (!staticContext) {
-
- // JLS7 15.12.4.1.2.1
- this.pop(mi.optionalTarget, this.getType(mi.optionalTarget));
- }
- } else {
- if (staticContext) {
- this.compileError(
- "Instance method \"" + mi.methodName + "\" cannot be invoked in static context",
- mi.getLocation()
- );
- }
- }
- }
-
- // Evaluate method parameters (JLS7 15.12.4.2).
- // If this method is vararg, rewritten all args starting from lastParamIndex to the end as if they were elements
- // of an array.
- IClass[] parameterTypes = iMethod.getParameterTypes();
- Rvalue[] adjustedArgs = null;
- final int actualSize = mi.arguments.length;
- if (iMethod.isVarargs() && iMethod.argsNeedAdjust()) {
- adjustedArgs = new Rvalue[parameterTypes.length];
- Rvalue[] lastArgs = new Rvalue[actualSize - parameterTypes.length + 1];
- final Location loc = mi.getLocation();
-
- if (lastArgs.length > 0) {
- for (int i = 0, j = parameterTypes.length - 1; i < lastArgs.length; ++i, ++j) {
- lastArgs[i] = mi.arguments[j];
- }
- }
-
- for (int i = parameterTypes.length - 2; i >= 0; --i) {
- adjustedArgs[i] = mi.arguments[i];
- }
- adjustedArgs[adjustedArgs.length - 1] = new NewInitializedArray(
- loc, // location
- parameterTypes[parameterTypes.length - 1], // arrayIClass
- new ArrayInitializer(loc, lastArgs) // arrayInitializer
- );
- } else {
- adjustedArgs = mi.arguments;
- }
-
- for (int i = 0; i < adjustedArgs.length; ++i) {
- this.assignmentConversion(
- mi, // location
- this.compileGetValue(adjustedArgs[i]), // sourceType
- parameterTypes[i], // targetType
- this.getConstantValue(adjustedArgs[i]) // optionalConstantValue
- );
- }
-
- // Invoke!
- this.checkAccessible(iMethod, mi.getEnclosingBlockStatement());
- if (iMethod.getDeclaringIClass().isInterface()) {
- this.invoke(mi, iMethod);
- } else {
- if (!iMethod.isStatic() && iMethod.getAccess() == Access.PRIVATE) {
-
- // In order to make a non-static private method invocable for enclosing types, enclosed types and types
- // enclosed by the same type, "compile(FunctionDeclarator)" modifies it on-the-fly as follows:
- // + Access is changed from PRIVATE to PACKAGE
- // + The name is appended with "$"
- // + It is made static
- // + A parameter of type "declaring class" is prepended to the signature
- // Hence, the invocation of such a method must be modified accordingly.
- this.writeOpcode(mi, Opcode.INVOKESTATIC);
- this.writeConstantMethodrefInfo(
- iMethod.getDeclaringIClass().getDescriptor(), // classFD
- iMethod.getName() + '$', // methodName
- MethodDescriptor.prependParameter( // methodMD
- iMethod.getDescriptor(),
- iMethod.getDeclaringIClass().getDescriptor()
- )
- );
- } else
- {
- this.invoke(mi, iMethod);
- }
- }
- return iMethod.getReturnType();
- }
-
- private IClass
- compileGet2(SuperclassMethodInvocation scmi) throws CompileException {
- final IClass.IMethod iMethod = this.findIMethod(scmi);
-
- Scope s;
- for (
- s = scmi.getEnclosingBlockStatement();
- s instanceof Statement || s instanceof CatchClause;
- s = s.getEnclosingScope()
- );
- FunctionDeclarator fd = s instanceof FunctionDeclarator ? (FunctionDeclarator) s : null;
- if (fd == null) {
- this.compileError("Cannot invoke superclass method in non-method scope", scmi.getLocation());
- return IClass.INT;
- }
- if (Mod.isStatic(fd.modifiers.flags)) {
- this.compileError("Cannot invoke superclass method in static context", scmi.getLocation());
- }
- this.load(scmi, this.resolve(fd.getDeclaringType()), 0);
-
- // Evaluate method parameters.
- // TODO: adjust args
- IClass[] parameterTypes = iMethod.getParameterTypes();
- for (int i = 0; i < scmi.arguments.length; ++i) {
- this.assignmentConversion(
- scmi, // locatable
- this.compileGetValue(scmi.arguments[i]), // sourceType
- parameterTypes[i], // targetType
- this.getConstantValue(scmi.arguments[i]) // optionalConstantValue
- );
- }
-
- // Invoke!
- this.writeOpcode(scmi, Opcode.INVOKESPECIAL);
- this.writeConstantMethodrefInfo(
- iMethod.getDeclaringIClass().getDescriptor(), // classFD
- scmi.methodName, // methodName
- iMethod.getDescriptor() // methodMD
- );
- return iMethod.getReturnType();
- }
-
- private IClass
- compileGet2(NewClassInstance nci) throws CompileException {
- if (nci.iClass == null) nci.iClass = this.getType(nci.type);
-
- this.writeOpcode(nci, Opcode.NEW);
- this.writeConstantClassInfo(nci.iClass.getDescriptor());
- this.writeOpcode(nci, Opcode.DUP);
-
- if (nci.iClass.isInterface()) this.compileError("Cannot instantiate \"" + nci.iClass + "\"", nci.getLocation());
- this.checkAccessible(nci.iClass, nci.getEnclosingBlockStatement());
- if (nci.iClass.isAbstract()) {
- this.compileError("Cannot instantiate abstract \"" + nci.iClass + "\"", nci.getLocation());
- }
-
- // Determine the enclosing instance for the new object.
- Rvalue optionalEnclosingInstance;
- if (nci.optionalQualification != null) {
- if (nci.iClass.getOuterIClass() == null) {
- this.compileError("Static member class cannot be instantiated with qualified NEW");
- }
-
- // Enclosing instance defined by qualification (JLS7 15.9.2.BL1.B3.B2).
- optionalEnclosingInstance = nci.optionalQualification;
- } else {
- Scope s = nci.getEnclosingBlockStatement();
- for (; !(s instanceof TypeBodyDeclaration); s = s.getEnclosingScope());
- TypeBodyDeclaration enclosingTypeBodyDeclaration = (TypeBodyDeclaration) s;
- TypeDeclaration enclosingTypeDeclaration = (TypeDeclaration) s.getEnclosingScope();
-
- if (
- !(enclosingTypeDeclaration instanceof ClassDeclaration)
- || enclosingTypeBodyDeclaration.isStatic()
- ) {
-
- // No enclosing instance in
- // + interface method declaration or
- // + static type body declaration (here: method or initializer or field declarator)
- // context (JLS7 15.9.2.BL1.B3.B1.B1).
- if (nci.iClass.getOuterIClass() != null) {
- this.compileError(
- "Instantiation of \"" + nci.type + "\" requires an enclosing instance",
- nci.getLocation()
- );
- }
- optionalEnclosingInstance = null;
- } else
- {
-
- // Determine the type of the enclosing instance for the new object.
- IClass optionalOuterIClass = nci.iClass.getDeclaringIClass();
- if (optionalOuterIClass == null) {
-
- // No enclosing instance needed for a top-level class object.
- optionalEnclosingInstance = null;
- } else {
-
- // Find an appropriate enclosing instance for the new inner class object among the enclosing
- // instances of the current object (JLS7 15.9.2.BL1.B3.B1.B2).
- optionalEnclosingInstance = new QualifiedThisReference(
- nci.getLocation(), // location
- new SimpleType( // qualification
- nci.getLocation(),
- optionalOuterIClass
- )
- );
- optionalEnclosingInstance.setEnclosingBlockStatement(nci.getEnclosingBlockStatement());
- }
- }
- }
-
- this.invokeConstructor(
- nci, // l
- nci.getEnclosingBlockStatement(), // scope
- optionalEnclosingInstance, // optionalEnclosingInstance
- nci.iClass, // targetClass
- nci.arguments // arguments
- );
- return nci.iClass;
- }
-
- private IClass
- compileGet2(NewAnonymousClassInstance naci) throws CompileException {
- // Find constructors.
- AnonymousClassDeclaration acd = naci.anonymousClassDeclaration;
- IClass sc = this.resolve(acd).getSuperclass();
- IClass.IConstructor[] iConstructors = sc.getDeclaredIConstructors();
- if (iConstructors.length == 0) throw new JaninoRuntimeException("SNO: Base class has no constructors");
-
- // Determine most specific constructor.
- IClass.IConstructor iConstructor = (IClass.IConstructor) this.findMostSpecificIInvocable(
- naci, // locatable
- iConstructors, // iInvocables
- naci.arguments, // arguments
- acd // contextScope
- );
-
- IClass[] pts = iConstructor.getParameterTypes();
-
- // Determine formal parameters of anonymous constructor.
- FormalParameters parameters;
- Location loc = naci.getLocation();
- {
- List l = new ArrayList();
-
- // Pass the enclosing instance of the base class as parameter #1.
- if (naci.optionalQualification != null) l.add(new FormalParameter(
- loc, // location
- true, // finaL
- new SimpleType(loc, this.getType(naci.optionalQualification)), // type
- "this$base" // name
- ));
- for (int i = 0; i < pts.length; ++i) l.add(new FormalParameter(
- loc, // location
- true, // finaL
- new SimpleType(loc, pts[i]), // type
- "p" + i // name
- ));
- parameters = new FormalParameters(
- loc,
- (FormalParameter[]) l.toArray(new FormalParameter[l.size()]),
- false
- );
- }
-
- // Determine thrown exceptions of anonymous constructor.
- IClass[] tes = iConstructor.getThrownExceptions();
- Type[] tets = new Type[tes.length];
- for (int i = 0; i < tes.length; ++i) tets[i] = new SimpleType(loc, tes[i]);
-
- // The anonymous constructor merely invokes the constructor of its superclass.
- int j = 0;
- Rvalue optionalQualificationAccess;
- if (naci.optionalQualification == null) {
- optionalQualificationAccess = null;
- } else
- {
- optionalQualificationAccess = new ParameterAccess(loc, parameters.parameters[j++]);
- }
- Rvalue[] parameterAccesses = new Rvalue[pts.length];
- for (int i = 0; i < pts.length; ++i) {
- parameterAccesses[i] = new ParameterAccess(loc, parameters.parameters[j++]);
- }
-
- // Generate the anonymous constructor for the anonymous class (JLS7 15.9.5.1).
- ConstructorDeclarator anonymousConstructor = new ConstructorDeclarator(
- loc, // location
- null, // optionalDocComment
- new Modifiers(Mod.PACKAGE), // modifiers
- parameters, // parameters
- tets, // thrownExceptions
- new SuperConstructorInvocation( // optionalConstructorInvocation
- loc, // location
- optionalQualificationAccess, // optionalQualification
- parameterAccesses // arguments
- ),
- Collections.EMPTY_LIST // optionalStatements
- );
-
- // Compile the anonymous class.
- acd.addConstructor(anonymousConstructor);
- try {
- this.compile(acd);
-
- // Instantiate the anonymous class.
- this.writeOpcode(naci, Opcode.NEW);
- this.writeConstantClassInfo(this.resolve(naci.anonymousClassDeclaration).getDescriptor());
-
- // TODO: adjust argument (for varargs case ?)
- // Invoke the anonymous constructor.
- this.writeOpcode(naci, Opcode.DUP);
- Rvalue[] arguments2;
- if (naci.optionalQualification == null) {
- arguments2 = naci.arguments;
- } else {
- arguments2 = new Rvalue[naci.arguments.length + 1];
- arguments2[0] = naci.optionalQualification;
- System.arraycopy(naci.arguments, 0, arguments2, 1, naci.arguments.length);
- }
-
- // Adjust if needed.
- // TODO: Not doing this now because we don't need vararg-annonymous class (yet).
-
-// Rvalue[] adjustedArgs = null;
-// final int paramsTypeLength = iConstructor.getParameterTypes().length;
-// if (argsNeedAdjusting[0]) {
-// adjustedArgs = new Rvalue[paramsTypeLength];
-// }
-
- // Notice: The enclosing instance of the anonymous class is "this", not the qualification of the
- // NewAnonymousClassInstance.
- Scope s;
- for (
- s = naci.getEnclosingBlockStatement();
- !(s instanceof TypeBodyDeclaration);
- s = s.getEnclosingScope()
- );
- ThisReference oei;
- if (((TypeBodyDeclaration) s).isStatic()) {
- oei = null;
- } else
- {
- oei = new ThisReference(loc);
- oei.setEnclosingBlockStatement(naci.getEnclosingBlockStatement());
- }
- this.invokeConstructor(
- naci, // locatable
- naci.getEnclosingBlockStatement(), // scope
- oei, // optionalEnclosingInstance
- this.resolve(naci.anonymousClassDeclaration), // targetClass
- arguments2 // arguments
- );
- } finally {
-
- // Remove the synthetic constructor that was temporarily added. This is necessary because this NACI
- // expression (and all other expressions) are sometimes compiled more than once (see "fakeCompile()"), and
- // we'd end up with TWO synthetic constructors. See JANINO-143.
- acd.constructors.remove(acd.constructors.size() - 1);
- }
- return this.resolve(naci.anonymousClassDeclaration);
- }
- private IClass
- compileGet2(ParameterAccess pa) throws CompileException {
- LocalVariable lv = this.getLocalVariable(pa.formalParameter);
- this.load(pa, lv);
- return lv.type;
- }
- private IClass
- compileGet2(NewArray na) throws CompileException {
- for (Rvalue dimExpr : na.dimExprs) {
- IClass dimType = this.compileGetValue(dimExpr);
- if (dimType != IClass.INT && this.unaryNumericPromotion(
- na, // locatable
- dimType // type
- ) != IClass.INT) this.compileError("Invalid array size expression type", na.getLocation());
- }
-
- return this.newArray(
- na, // locatable
- na.dimExprs.length, // dimExprCount
- na.dims, // dims
- this.getType(na.type) // componentType
- );
- }
- private IClass
- compileGet2(NewInitializedArray nia) throws CompileException {
- IClass at = nia.arrayType == null ? nia.arrayIClass : this.getType(nia.arrayType);
- this.compileGetValue(nia.arrayInitializer, at);
- return at;
- }
- private void
- compileGetValue(ArrayInitializer ai, IClass arrayType) throws CompileException {
- if (!arrayType.isArray()) {
- this.compileError("Array initializer not allowed for non-array type \"" + arrayType.toString() + "\"");
- }
- IClass ct = arrayType.getComponentType();
-
- this.pushConstant(ai, new Integer(ai.values.length));
- this.newArray(
- ai, // locatable
- 1, // dimExprCount
- 0, // dims
- ct // componentType
- );
-
- for (int i = 0; i < ai.values.length; ++i) {
- this.writeOpcode(ai, Opcode.DUP);
- this.pushConstant(ai, new Integer(i));
- ArrayInitializerOrRvalue aiorv = ai.values[i];
- if (aiorv instanceof Rvalue) {
- Rvalue rv = (Rvalue) aiorv;
- this.assignmentConversion(
- ai, // locatable
- this.compileGetValue(rv), // sourceType
- ct, // targetType
- this.getConstantValue(rv) // optionalConstantValue
- );
- } else
- if (aiorv instanceof ArrayInitializer) {
- this.compileGetValue((ArrayInitializer) aiorv, ct);
- } else
- {
- throw new JaninoRuntimeException(
- "Unexpected array initializer or rvalue class " + aiorv.getClass().getName()
- );
- }
- this.writeOpcode(ai, Opcode.IASTORE + UnitCompiler.ilfdabcs(ct));
- }
- }
- private IClass
- compileGet2(Literal l) throws CompileException {
- return this.pushConstant(l, this.getConstantValue(l));
- }
- private IClass
- compileGet2(SimpleConstant sl) throws CompileException {
- return this.pushConstant(sl, sl.value);
- }
-
- /**
- * Convenience function that calls {@link #compileContext(Rvalue)} and {@link #compileGet(Rvalue)}.
- *
- * @return The type of the Rvalue
- */
- private IClass
- compileGetValue(Rvalue rv) throws CompileException {
- Object cv = this.getConstantValue(rv);
- if (cv != UnitCompiler.NOT_CONSTANT) {
- this.fakeCompile(rv); // To check that, e.g., "a" compiles in "true || a".
- this.pushConstant(rv, cv);
- return this.getType(rv);
- }
-
- this.compileContext(rv);
- return this.compileGet(rv);
- }
-
- // -------------------- Rvalue.getConstantValue() -----------------
-
- /**
- * Special return value for the {@link #getConstantValue(Java.Rvalue)} method family indicating that the given
- * {@link Java.Rvalue} does not evaluate to a constant value.
- */
- public static final Object NOT_CONSTANT = IClass.NOT_CONSTANT;
-
- /**
- * Attempts to evaluate as a constant expression.
- *
- * @return {@link #NOT_CONSTANT} iff the rvalue is not a constant value
- */
- public final Object
- getConstantValue(Rvalue rv) throws CompileException {
- if (rv.constantValue != Rvalue.CONSTANT_VALUE_UNKNOWN) return rv.constantValue;
-
- final Object[] res = new Object[1];
- RvalueVisitor rvv = new RvalueVisitor() {
- // CHECKSTYLE LineLengthCheck:OFF
- @Override public void visitArrayLength(ArrayLength al) { res[0] = UnitCompiler.this.getConstantValue2(al); }
- @Override public void visitAssignment(Assignment a) { res[0] = UnitCompiler.this.getConstantValue2(a); }
- @Override public void visitUnaryOperation(UnaryOperation uo) { try { res[0] = UnitCompiler.this.getConstantValue2(uo); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitBinaryOperation(BinaryOperation bo) { try { res[0] = UnitCompiler.this.getConstantValue2(bo); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCast(Cast c) { try { res[0] = UnitCompiler.this.getConstantValue2(c); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitClassLiteral(ClassLiteral cl) { res[0] = UnitCompiler.this.getConstantValue2(cl); }
- @Override public void visitConditionalExpression(ConditionalExpression ce) { try { res[0] = UnitCompiler.this.getConstantValue2(ce); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCrement(Crement c) { res[0] = UnitCompiler.this.getConstantValue2(c); }
- @Override public void visitInstanceof(Instanceof io) { res[0] = UnitCompiler.this.getConstantValue2(io); }
- @Override public void visitMethodInvocation(MethodInvocation mi) { res[0] = UnitCompiler.this.getConstantValue2(mi); }
- @Override public void visitSuperclassMethodInvocation(SuperclassMethodInvocation smi) { res[0] = UnitCompiler.this.getConstantValue2(smi); }
- @Override public void visitIntegerLiteral(IntegerLiteral il) { try { res[0] = UnitCompiler.this.getConstantValue2(il); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFloatingPointLiteral(FloatingPointLiteral fpl) { try { res[0] = UnitCompiler.this.getConstantValue2(fpl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitBooleanLiteral(BooleanLiteral bl) { res[0] = UnitCompiler.this.getConstantValue2(bl); }
- @Override public void visitCharacterLiteral(CharacterLiteral cl) { res[0] = UnitCompiler.this.getConstantValue2(cl); }
- @Override public void visitStringLiteral(StringLiteral sl) { res[0] = UnitCompiler.this.getConstantValue2(sl); }
- @Override public void visitNullLiteral(NullLiteral nl) { res[0] = UnitCompiler.this.getConstantValue2(nl); }
- @Override public void visitSimpleConstant(SimpleConstant sl) { res[0] = UnitCompiler.this.getConstantValue2(sl); }
- @Override public void visitNewAnonymousClassInstance(NewAnonymousClassInstance naci) { res[0] = UnitCompiler.this.getConstantValue2(naci); }
- @Override public void visitNewArray(NewArray na) { res[0] = UnitCompiler.this.getConstantValue2(na); }
- @Override public void visitNewInitializedArray(NewInitializedArray nia) { res[0] = UnitCompiler.this.getConstantValue2(nia); }
- @Override public void visitNewClassInstance(NewClassInstance nci) { res[0] = UnitCompiler.this.getConstantValue2(nci); }
- @Override public void visitParameterAccess(ParameterAccess pa) { res[0] = UnitCompiler.this.getConstantValue2(pa); }
- @Override public void visitQualifiedThisReference(QualifiedThisReference qtr) { res[0] = UnitCompiler.this.getConstantValue2(qtr); }
- @Override public void visitThisReference(ThisReference tr) { res[0] = UnitCompiler.this.getConstantValue2(tr); }
-
- @Override public void visitAmbiguousName(AmbiguousName an) { try { res[0] = UnitCompiler.this.getConstantValue2(an); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitArrayAccessExpression(ArrayAccessExpression aae) { res[0] = UnitCompiler.this.getConstantValue2(aae); }
- @Override public void visitFieldAccess(FieldAccess fa) { try { res[0] = UnitCompiler.this.getConstantValue2(fa); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldAccessExpression(FieldAccessExpression fae) { res[0] = UnitCompiler.this.getConstantValue2(fae); }
- @Override public void visitSuperclassFieldAccessExpression(SuperclassFieldAccessExpression scfae) { res[0] = UnitCompiler.this.getConstantValue2(scfae); }
- @Override public void visitLocalVariableAccess(LocalVariableAccess lva) { res[0] = UnitCompiler.this.getConstantValue2(lva); }
- @Override public void visitParenthesizedExpression(ParenthesizedExpression pe) { try { res[0] = UnitCompiler.this.getConstantValue2(pe); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- // CHECKSTYLE LineLengthCheck:ON
- };
- try {
- rv.accept(rvv);
- rv.constantValue = res[0];
- return rv.constantValue;
- } catch (UncheckedCompileException uce) {
- throw uce.compileException; // SUPPRESS CHECKSTYLE AvoidHidingCause
- }
- }
-
- @SuppressWarnings("static-method") private Object
- getConstantValue2(Rvalue rv) { return UnitCompiler.NOT_CONSTANT; }
-
- private Object
- getConstantValue2(AmbiguousName an) throws CompileException {
- return this.getConstantValue(this.toRvalueOrCompileException(this.reclassify(an)));
- }
-
- @SuppressWarnings("static-method") private Object
- getConstantValue2(FieldAccess fa) throws CompileException {
- return fa.field.getConstantValue();
- }
-
- private Object
- getConstantValue2(UnaryOperation uo) throws CompileException {
- if (uo.operator.equals("+")) return this.getConstantValue(uo.operand);
- if (uo.operator.equals("-")) return this.getNegatedConstantValue(uo.operand);
- if (uo.operator.equals("!")) {
- Object cv = this.getConstantValue(uo.operand);
- return (
- cv == Boolean.TRUE ? Boolean.FALSE :
- cv == Boolean.FALSE ? Boolean.TRUE :
- UnitCompiler.NOT_CONSTANT
- );
- }
- return UnitCompiler.NOT_CONSTANT;
- }
-
- private Object
- getConstantValue2(ConditionalExpression ce) throws CompileException {
- Object lhsValue = this.getConstantValue(ce.lhs);
- if (lhsValue instanceof Boolean) {
- return (
- ((Boolean) lhsValue).booleanValue()
- ? this.getConstantValue(ce.mhs)
- : this.getConstantValue(ce.rhs)
- );
- }
- return UnitCompiler.NOT_CONSTANT;
- }
-
- private Object
- getConstantValue2(BinaryOperation bo) throws CompileException {
-
- // "|", "^", "&", "*", "/", "%", "+", "-", "==", "!=".
- if (
- // CHECKSTYLE StringLiteralEquality:OFF
- bo.op == "|"
- || bo.op == "^"
- || bo.op == "&"
- || bo.op == "*"
- || bo.op == "/"
- || bo.op == "%"
- || bo.op == "+"
- || bo.op == "-"
- || bo.op == "=="
- || bo.op == "!="
- // CHECKSTYLE StringLiteralEquality:ON
- ) {
-
- // Unroll the constant operands.
- List cvs = new ArrayList();
- for (Iterator it = bo.unrollLeftAssociation(); it.hasNext();) {
- Object cv = this.getConstantValue(((Rvalue) it.next()));
- if (cv == UnitCompiler.NOT_CONSTANT) return UnitCompiler.NOT_CONSTANT;
- cvs.add(cv);
- }
-
- // Compute the constant value of the unrolled binary operation.
- Iterator it = cvs.iterator();
- Object lhs = it.next();
- while (it.hasNext()) {
- if (lhs == UnitCompiler.NOT_CONSTANT) return UnitCompiler.NOT_CONSTANT;
-
- Object rhs = it.next();
-
- // String concatenation?
- // SUPPRESS CHECKSTYLE StringLiteralEquality
- if (bo.op == "+" && (lhs instanceof String || rhs instanceof String)) {
- StringBuilder sb = new StringBuilder(lhs.toString()).append(rhs);
- while (it.hasNext()) sb.append(it.next().toString());
- return sb.toString();
- }
-
- if (lhs instanceof Number && rhs instanceof Number) {
- try {
- if (lhs instanceof Double || rhs instanceof Double) {
- double lhsD = ((Number) lhs).doubleValue();
- double rhsD = ((Number) rhs).doubleValue();
- lhs = (
- // CHECKSTYLE StringLiteralEquality:OFF
- bo.op == "*" ? new Double(lhsD * rhsD) :
- bo.op == "/" ? new Double(lhsD / rhsD) :
- bo.op == "%" ? new Double(lhsD % rhsD) :
- bo.op == "+" ? new Double(lhsD + rhsD) :
- bo.op == "-" ? new Double(lhsD - rhsD) :
- bo.op == "==" ? Boolean.valueOf(lhsD == rhsD) :
- bo.op == "!=" ? Boolean.valueOf(lhsD != rhsD) :
- UnitCompiler.NOT_CONSTANT
- // CHECKSTYLE StringLiteralEquality:ON
- );
- continue;
- }
- if (lhs instanceof Float || rhs instanceof Float) {
- float lhsF = ((Number) lhs).floatValue();
- float rhsF = ((Number) rhs).floatValue();
- lhs = (
- // CHECKSTYLE StringLiteralEquality:OFF
- bo.op == "*" ? new Float(lhsF * rhsF) :
- bo.op == "/" ? new Float(lhsF / rhsF) :
- bo.op == "%" ? new Float(lhsF % rhsF) :
- bo.op == "+" ? new Float(lhsF + rhsF) :
- bo.op == "-" ? new Float(lhsF - rhsF) :
- bo.op == "==" ? Boolean.valueOf(lhsF == rhsF) :
- bo.op == "!=" ? Boolean.valueOf(lhsF != rhsF) :
- UnitCompiler.NOT_CONSTANT
- // CHECKSTYLE StringLiteralEquality:ON
- );
- continue;
- }
- if (lhs instanceof Long || rhs instanceof Long) {
- long lhsL = ((Number) lhs).longValue();
- long rhsL = ((Number) rhs).longValue();
- lhs = (
- // CHECKSTYLE StringLiteralEquality:OFF
- bo.op == "|" ? new Long(lhsL | rhsL) :
- bo.op == "^" ? new Long(lhsL ^ rhsL) :
- bo.op == "&" ? new Long(lhsL & rhsL) :
- bo.op == "*" ? new Long(lhsL * rhsL) :
- bo.op == "/" ? new Long(lhsL / rhsL) :
- bo.op == "%" ? new Long(lhsL % rhsL) :
- bo.op == "+" ? new Long(lhsL + rhsL) :
- bo.op == "-" ? new Long(lhsL - rhsL) :
- bo.op == "==" ? Boolean.valueOf(lhsL == rhsL) :
- bo.op == "!=" ? Boolean.valueOf(lhsL != rhsL) :
- UnitCompiler.NOT_CONSTANT
- // CHECKSTYLE StringLiteralEquality:ON
- );
- continue;
- }
- if (
- lhs instanceof Integer || lhs instanceof Byte || lhs instanceof Short
- || rhs instanceof Integer || lhs instanceof Byte || lhs instanceof Short
- ) {
- int lhsI = ((Number) lhs).intValue();
- int rhsI = ((Number) rhs).intValue();
- lhs = (
- // CHECKSTYLE StringLiteralEquality:OFF
- bo.op == "|" ? new Integer(lhsI | rhsI) :
- bo.op == "^" ? new Integer(lhsI ^ rhsI) :
- bo.op == "&" ? new Integer(lhsI & rhsI) :
- bo.op == "*" ? new Integer(lhsI * rhsI) :
- bo.op == "/" ? new Integer(lhsI / rhsI) :
- bo.op == "%" ? new Integer(lhsI % rhsI) :
- bo.op == "+" ? new Integer(lhsI + rhsI) :
- bo.op == "-" ? new Integer(lhsI - rhsI) :
- bo.op == "==" ? Boolean.valueOf(lhsI == rhsI) :
- bo.op == "!=" ? Boolean.valueOf(lhsI != rhsI) :
- UnitCompiler.NOT_CONSTANT
- // CHECKSTYLE StringLiteralEquality:ON
- );
- continue;
- }
- } catch (ArithmeticException ae) {
-
- // Most likely a divide by zero or modulo by zero. Guess we can't make this expression into a
- // constant.
- return UnitCompiler.NOT_CONSTANT;
- }
- throw new IllegalStateException();
- }
-
- if (lhs instanceof Character && rhs instanceof Character) {
- char lhsC = ((Character) lhs).charValue();
- char rhsC = ((Character) rhs).charValue();
- lhs = (
- bo.op == "==" ? Boolean.valueOf(lhsC == rhsC) : // SUPPRESS CHECKSTYLE StringLiteralEquality
- bo.op == "!=" ? Boolean.valueOf(lhsC != rhsC) : // SUPPRESS CHECKSTYLE StringLiteralEquality
- UnitCompiler.NOT_CONSTANT
- );
- continue;
- }
-
- if (lhs == null || rhs == null) {
- lhs = (
- bo.op == "==" ? Boolean.valueOf(lhs == rhs) : // SUPPRESS CHECKSTYLE StringLiteralEquality
- bo.op == "!=" ? Boolean.valueOf(lhs != rhs) : // SUPPRESS CHECKSTYLE StringLiteralEquality
- UnitCompiler.NOT_CONSTANT
- );
- continue;
- }
-
- return UnitCompiler.NOT_CONSTANT;
- }
- return lhs;
- }
-
- // "&&" and "||" with constant LHS operand.
- if (bo.op == "&&" || bo.op == "||") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- Object lhsValue = this.getConstantValue(bo.lhs);
- if (lhsValue instanceof Boolean) {
- boolean lhsBv = ((Boolean) lhsValue).booleanValue();
- return (
- bo.op == "&&" // SUPPRESS CHECKSTYLE StringLiteralEquality
- ? (lhsBv ? this.getConstantValue(bo.rhs) : Boolean.FALSE)
- : (lhsBv ? Boolean.TRUE : this.getConstantValue(bo.rhs))
- );
- }
- }
-
- return UnitCompiler.NOT_CONSTANT;
- }
-
- private Object
- getConstantValue2(Cast c) throws CompileException {
- Object cv = this.getConstantValue(c.value);
- if (cv == UnitCompiler.NOT_CONSTANT) return UnitCompiler.NOT_CONSTANT;
-
- if (cv instanceof Number) {
- IClass tt = this.getType(c.targetType);
- if (tt == IClass.BYTE) return new Byte(((Number) cv).byteValue());
- if (tt == IClass.SHORT) return new Short(((Number) cv).shortValue());
- if (tt == IClass.INT) return new Integer(((Number) cv).intValue());
- if (tt == IClass.LONG) return new Long(((Number) cv).longValue());
- if (tt == IClass.FLOAT) return new Float(((Number) cv).floatValue());
- if (tt == IClass.DOUBLE) return new Double(((Number) cv).doubleValue());
- }
-
- return UnitCompiler.NOT_CONSTANT;
- }
-
- private Object
- getConstantValue2(ParenthesizedExpression pe) throws CompileException {
- return this.getConstantValue(pe.value);
- }
-
- @SuppressWarnings("static-method") private Object
- getConstantValue2(IntegerLiteral il) throws CompileException {
- String v = il.value;
- if (v.startsWith("0x")) {
- return (
- v.endsWith("L") || v.endsWith("l")
- ? (Object) Long.valueOf(UnitCompiler.hex2Long(il, v.substring(2, v.length() - 1)))
- : Integer.valueOf(UnitCompiler.hex2Int(il, v.substring(2)))
- );
- }
- if (v.startsWith("0")) {
- return (
- v.endsWith("L") || v.endsWith("l")
- ? (Object) Long.valueOf(UnitCompiler.oct2Long(il, v.substring(0, v.length() - 1)))
- : Integer.valueOf(UnitCompiler.oct2Int(il, v))
- );
- }
- try {
- return (
- v.endsWith("L") || v.endsWith("l")
- ? (Object) new Long(v.substring(0, v.length() - 1))
- : new Integer(v)
- );
- } catch (NumberFormatException e) {
- // SUPPRESS CHECKSTYLE AvoidHidingCause
- throw UnitCompiler.compileException(il, "Value of decimal integer literal '" + v + "' is out of range");
- }
- }
-
- @SuppressWarnings("static-method") private Object
- getConstantValue2(FloatingPointLiteral fpl) throws CompileException {
-
- String v = fpl.value;
-
- char lastChar = v.charAt(v.length() - 1);
- if (lastChar == 'f' || lastChar == 'F') {
- v = v.substring(0, v.length() - 1);
-
- float fv;
- try {
- fv = Float.parseFloat(v);
- } catch (NumberFormatException e) {
- throw new JaninoRuntimeException("SNO: parsing float literal '" + v + "': " + e.getMessage(), e);
- }
- if (Float.isInfinite(fv)) {
- throw UnitCompiler.compileException(fpl, "Value of float literal '" + v + "' is out of range");
- }
- if (Float.isNaN(fv)) {
- throw new JaninoRuntimeException("SNO: parsing float literal '" + v + "' results in NaN");
- }
-
- // Check for FLOAT underrun.
- if (fv == 0.0F) {
- for (int i = 0; i < v.length(); ++i) {
- char c = v.charAt(i);
- if ("123456789".indexOf(c) != -1) {
- throw UnitCompiler.compileException(
- fpl,
- "Literal '" + v + "' is too small to be represented as a float"
- );
- }
- if (c != '0' && c != '.') break;
- }
- }
-
- return new Float(fv);
- }
-
- if (lastChar == 'd' || lastChar == 'D') v = v.substring(0, v.length() - 1);
-
- double dv;
- try {
- dv = Double.parseDouble(v);
- } catch (NumberFormatException e) {
- throw new JaninoRuntimeException("SNO: parsing double literal '" + v + "': " + e.getMessage(), e);
- }
- if (Double.isInfinite(dv)) {
- throw UnitCompiler.compileException(fpl, "Value of double literal '" + v + "' is out of range");
- }
- if (Double.isNaN(dv)) {
- throw new JaninoRuntimeException("SNO: parsing double literal '" + v + "' results is NaN");
- }
-
- // Check for DOUBLE underrun.
- if (dv == 0.0F) {
- for (int i = 0; i < v.length(); ++i) {
- char c = v.charAt(i);
- if ("123456789".indexOf(c) != -1) {
- throw UnitCompiler.compileException(
- fpl,
- "Literal '" + v + "' is too small to be represented as a double"
- );
- }
- if (c != '0' && c != '.') break;
- }
- }
-
- return new Double(dv);
- }
-
- @SuppressWarnings("static-method") private Object
- getConstantValue2(BooleanLiteral bl) {
- if (bl.value == "true") return Boolean.TRUE; // SUPPRESS CHECKSTYLE StringLiteralEquality
- if (bl.value == "false") return Boolean.FALSE; // SUPPRESS CHECKSTYLE StringLiteralEquality
- throw new JaninoRuntimeException(bl.value);
- }
-
- @SuppressWarnings("static-method") private Object
- getConstantValue2(CharacterLiteral cl) {
- String v = cl.value;
- return Character.valueOf(UnitCompiler.unescape(v.substring(1, v.length() - 1)).charAt(0));
- }
-
- @SuppressWarnings("static-method") private Object
- getConstantValue2(StringLiteral sl) {
- if (sl == null || sl.value == null) {
- return "";
- }
- String v = sl.value;
- return UnitCompiler.unescape(v.substring(1, v.length() - 1));
- }
-
- @SuppressWarnings("static-method") private Object
- getConstantValue2(NullLiteral nl) { return null; }
-
- @SuppressWarnings("static-method") private Object
- getConstantValue2(SimpleConstant sl) { return sl.value; }
-
- /**
- * Attempts to evaluate the negated value of a constant {@link Rvalue}. This is particularly relevant for the
- * smallest value of an integer or long literal.
- *
- * @return {@link #NOT_CONSTANT} iff value is not constant; otherwise a {@link String}, {@link Byte}, {@link
- * Short}, {@link Integer}, {@link Boolean}, {@link Character}, {@link Float}, {@link Long}, {@link Double}
- * or {@code null}
- */
- private Object
- getNegatedConstantValue(Rvalue rv) throws CompileException {
- final Object[] res = new Object[1];
- RvalueVisitor rvv = new RvalueVisitor() {
- // CHECKSTYLE LineLengthCheck:OFF
- @Override public void visitArrayLength(ArrayLength al) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(al); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitAssignment(Assignment a) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(a); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitUnaryOperation(UnaryOperation uo) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(uo); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitBinaryOperation(BinaryOperation bo) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(bo); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCast(Cast c) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(c); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitClassLiteral(ClassLiteral cl) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(cl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitConditionalExpression(ConditionalExpression ce) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(ce); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCrement(Crement c) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(c); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitInstanceof(Instanceof io) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(io); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitMethodInvocation(MethodInvocation mi) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(mi); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSuperclassMethodInvocation(SuperclassMethodInvocation smi) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(smi); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitIntegerLiteral(IntegerLiteral il) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(il); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFloatingPointLiteral(FloatingPointLiteral fpl) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(fpl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitBooleanLiteral(BooleanLiteral bl) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(bl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCharacterLiteral(CharacterLiteral cl) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(cl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitStringLiteral(StringLiteral sl) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(sl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNullLiteral(NullLiteral nl) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(nl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSimpleConstant(SimpleConstant sl) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(sl); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewAnonymousClassInstance(NewAnonymousClassInstance naci) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(naci); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewArray(NewArray na) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(na); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewInitializedArray(NewInitializedArray nia) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(nia); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewClassInstance(NewClassInstance nci) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(nci); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitParameterAccess(ParameterAccess pa) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(pa); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitQualifiedThisReference(QualifiedThisReference qtr) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(qtr); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitThisReference(ThisReference tr) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(tr); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
-
- @Override public void visitAmbiguousName(AmbiguousName an) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(an); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitArrayAccessExpression(ArrayAccessExpression aae) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(aae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldAccess(FieldAccess fa) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(fa); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldAccessExpression(FieldAccessExpression fae) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(fae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSuperclassFieldAccessExpression(SuperclassFieldAccessExpression scfae) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(scfae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitLocalVariableAccess(LocalVariableAccess lva) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(lva); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitParenthesizedExpression(ParenthesizedExpression pe) { try { res[0] = UnitCompiler.this.getNegatedConstantValue2(pe); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- // CHECKSTYLE LineLengthCheck:ON
- };
- try {
- rv.accept(rvv);
- return res[0];
- } catch (UncheckedCompileException uce) {
- throw uce.compileException; // SUPPRESS CHECKSTYLE AvoidHidingCause
- }
- }
- private Object
- getNegatedConstantValue2(Rvalue rv) throws CompileException {
- Object cv = this.getConstantValue(rv);
- if (cv instanceof Byte) return new Byte((byte) -((Byte) cv).byteValue());
- if (cv instanceof Short) return new Short((short) -((Short) cv).shortValue());
- if (cv instanceof Integer) return new Integer(-((Integer) cv).intValue());
- if (cv instanceof Long) return new Long(-((Long) cv).longValue());
- if (cv instanceof Float) return new Float(-((Float) cv).floatValue());
- if (cv instanceof Double) return new Double(-((Double) cv).doubleValue());
- return UnitCompiler.NOT_CONSTANT;
- }
- private Object
- getNegatedConstantValue2(UnaryOperation uo) throws CompileException {
- return (
- uo.operator.equals("+") ? this.getNegatedConstantValue(uo.operand) :
- uo.operator.equals("-") ? this.getConstantValue(uo.operand) :
- UnitCompiler.NOT_CONSTANT
- );
- }
- private Object
- getNegatedConstantValue2(ParenthesizedExpression pe) throws CompileException {
- return this.getNegatedConstantValue(pe.value);
- }
- private Object
- getNegatedConstantValue2(IntegerLiteral il) throws CompileException {
- String v = il.value;
- if ("2147483648".equals(v) || "020000000000".equals(v)) {
- return new Integer(Integer.MIN_VALUE);
- }
- char lastChar = v.charAt(v.length() - 1);
- if (lastChar == 'l' || lastChar == 'L') {
- String v2 = v.substring(0, v.length() - 1);
- if ("9223372036854775808".equals(v2) || "01000000000000000000000".equals(v2)) {
- return new Long(Long.MIN_VALUE);
- }
- }
- return this.getNegatedConstantValue2((Rvalue) il);
- }
-
- // ------------ BlockStatement.generatesCode() -------------
-
- /** Checks whether invocation of {@link #compile(BlockStatement)} would generate more than zero code bytes. */
- private boolean
- generatesCode(BlockStatement bs) throws CompileException {
- final boolean[] res = new boolean[1];
- BlockStatementVisitor bsv = new BlockStatementVisitor() {
- // CHECKSTYLE LineLengthCheck:OFF
- @Override public void visitInitializer(Initializer i) { try { res[0] = UnitCompiler.this.generatesCode2(i); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldDeclaration(FieldDeclaration fd) { try { res[0] = UnitCompiler.this.generatesCode2(fd); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitLabeledStatement(LabeledStatement ls) { res[0] = UnitCompiler.this.generatesCode2(ls); }
- @Override public void visitBlock(Block b) { try { res[0] = UnitCompiler.this.generatesCode2(b); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitExpressionStatement(ExpressionStatement es) { res[0] = UnitCompiler.this.generatesCode2(es); }
- @Override public void visitIfStatement(IfStatement is) { res[0] = UnitCompiler.this.generatesCode2(is); }
- @Override public void visitForStatement(ForStatement fs) { res[0] = UnitCompiler.this.generatesCode2(fs); }
- @Override public void visitForEachStatement(ForEachStatement fes) { res[0] = UnitCompiler.this.generatesCode2(fes); }
- @Override public void visitWhileStatement(WhileStatement ws) { res[0] = UnitCompiler.this.generatesCode2(ws); }
- @Override public void visitTryStatement(TryStatement ts) { res[0] = UnitCompiler.this.generatesCode2(ts); }
- @Override public void visitSwitchStatement(SwitchStatement ss) { res[0] = UnitCompiler.this.generatesCode2(ss); }
- @Override public void visitSynchronizedStatement(SynchronizedStatement ss) { res[0] = UnitCompiler.this.generatesCode2(ss); }
- @Override public void visitDoStatement(DoStatement ds) { res[0] = UnitCompiler.this.generatesCode2(ds); }
- @Override public void visitLocalVariableDeclarationStatement(LocalVariableDeclarationStatement lvds) { res[0] = UnitCompiler.this.generatesCode2(lvds); }
- @Override public void visitReturnStatement(ReturnStatement rs) { res[0] = UnitCompiler.this.generatesCode2(rs); }
- @Override public void visitThrowStatement(ThrowStatement ts) { res[0] = UnitCompiler.this.generatesCode2(ts); }
- @Override public void visitBreakStatement(BreakStatement bs) { res[0] = UnitCompiler.this.generatesCode2(bs); }
- @Override public void visitContinueStatement(ContinueStatement cs) { res[0] = UnitCompiler.this.generatesCode2(cs); }
- @Override public void visitAssertStatement(AssertStatement as) { res[0] = UnitCompiler.this.generatesCode2(as); }
- @Override public void visitEmptyStatement(EmptyStatement es) { res[0] = UnitCompiler.this.generatesCode2(es); }
- @Override public void visitLocalClassDeclarationStatement(LocalClassDeclarationStatement lcds) { res[0] = UnitCompiler.this.generatesCode2(lcds); }
- @Override public void visitAlternateConstructorInvocation(AlternateConstructorInvocation aci) { res[0] = UnitCompiler.this.generatesCode2(aci); }
- @Override public void visitSuperConstructorInvocation(SuperConstructorInvocation sci) { res[0] = UnitCompiler.this.generatesCode2(sci); }
- // CHECKSTYLE LineLengthCheck:ON
- };
- try {
- bs.accept(bsv);
- return res[0];
- } catch (UncheckedCompileException uce) {
- throw uce.compileException; // SUPPRESS CHECKSTYLE AvoidHidingCause
- }
- }
-
- @SuppressWarnings("static-method") private boolean
- generatesCode2(BlockStatement bs) { return true; }
-
- @SuppressWarnings("static-method") private boolean
- generatesCode2(AssertStatement as) { return true; }
-
- @SuppressWarnings("static-method") private boolean
- generatesCode2(EmptyStatement es) { return false; }
-
- @SuppressWarnings("static-method") private boolean
- generatesCode2(LocalClassDeclarationStatement lcds) { return false; }
-
- private boolean
- generatesCode2(Initializer i) throws CompileException { return this.generatesCode(i.block); }
-
- private boolean
- generatesCode2(List l) throws CompileException {
- for (BlockStatement bs : l) if (this.generatesCode(bs)) return true;
- return false;
- }
-
- private boolean
- generatesCode2(Block b) throws CompileException { return this.generatesCode2(b.statements); }
-
- private boolean
- generatesCode2(FieldDeclaration fd) throws CompileException {
- // Code is only generated if at least one of the declared variables has a non-constant-final initializer.
- for (VariableDeclarator vd : fd.variableDeclarators) {
- if (this.getNonConstantFinalInitializer(fd, vd) != null) return true;
- }
- return false;
- }
-
- // ------------ BlockStatement.leave() -------------
-
- /**
- * Clean up the statement context. This is currently relevant for "try ... catch ... finally" statements (execute
- * "finally" clause) and "synchronized" statements (monitorexit).
- *
- * Statements like "return", "break", "continue" must call this method for all the statements they terminate.
- *
- * Notice: If {@code optionalStackValueType} is {@code null}, then the operand stack is empty; otherwise
- * exactly one operand with that type is on the stack. This information is vital to implementations of {@link
- * #leave(BlockStatement, IClass)} that require a specific operand stack state (e.g. an empty operand stack for
- * JSR).
- */
- private void
- leave(BlockStatement bs, final IClass optionalStackValueType) {
- BlockStatementVisitor bsv = new BlockStatementVisitor() {
- // CHECKSTYLE LineLengthCheck:OFF
- @Override public void visitInitializer(Initializer i) { UnitCompiler.this.leave2(i, optionalStackValueType); }
- @Override public void visitFieldDeclaration(FieldDeclaration fd) { UnitCompiler.this.leave2(fd, optionalStackValueType); }
- @Override public void visitLabeledStatement(LabeledStatement ls) { UnitCompiler.this.leave2(ls, optionalStackValueType); }
- @Override public void visitBlock(Block b) { UnitCompiler.this.leave2(b, optionalStackValueType); }
- @Override public void visitExpressionStatement(ExpressionStatement es) { UnitCompiler.this.leave2(es, optionalStackValueType); }
- @Override public void visitIfStatement(IfStatement is) { UnitCompiler.this.leave2(is, optionalStackValueType); }
- @Override public void visitForStatement(ForStatement fs) { UnitCompiler.this.leave2(fs, optionalStackValueType); }
- @Override public void visitForEachStatement(ForEachStatement fes) { UnitCompiler.this.leave2(fes, optionalStackValueType); }
- @Override public void visitWhileStatement(WhileStatement ws) { UnitCompiler.this.leave2(ws, optionalStackValueType); }
- @Override public void visitTryStatement(TryStatement ts) { UnitCompiler.this.leave2(ts, optionalStackValueType); }
- @Override public void visitSwitchStatement(SwitchStatement ss) { UnitCompiler.this.leave2(ss, optionalStackValueType); }
- @Override public void visitSynchronizedStatement(SynchronizedStatement ss) { UnitCompiler.this.leave2(ss, optionalStackValueType); }
- @Override public void visitDoStatement(DoStatement ds) { UnitCompiler.this.leave2(ds, optionalStackValueType); }
- @Override public void visitLocalVariableDeclarationStatement(LocalVariableDeclarationStatement lvds) { UnitCompiler.this.leave2(lvds, optionalStackValueType); }
- @Override public void visitReturnStatement(ReturnStatement rs) { UnitCompiler.this.leave2(rs, optionalStackValueType); }
- @Override public void visitThrowStatement(ThrowStatement ts) { UnitCompiler.this.leave2(ts, optionalStackValueType); }
- @Override public void visitBreakStatement(BreakStatement bs) { UnitCompiler.this.leave2(bs, optionalStackValueType); }
- @Override public void visitContinueStatement(ContinueStatement cs) { UnitCompiler.this.leave2(cs, optionalStackValueType); }
- @Override public void visitAssertStatement(AssertStatement as) { UnitCompiler.this.leave2(as, optionalStackValueType); }
- @Override public void visitEmptyStatement(EmptyStatement es) { UnitCompiler.this.leave2(es, optionalStackValueType); }
- @Override public void visitLocalClassDeclarationStatement(LocalClassDeclarationStatement lcds) { UnitCompiler.this.leave2(lcds, optionalStackValueType); }
- @Override public void visitAlternateConstructorInvocation(AlternateConstructorInvocation aci) { UnitCompiler.this.leave2(aci, optionalStackValueType); }
- @Override public void visitSuperConstructorInvocation(SuperConstructorInvocation sci) { UnitCompiler.this.leave2(sci, optionalStackValueType); }
- // CHECKSTYLE LineLengthCheck:ON
- };
- bs.accept(bsv);
- }
-
- private void
- leave2(BlockStatement bs, IClass optionalStackValueType) {}
-
- private void
- leave2(SynchronizedStatement ss, IClass optionalStackValueType) {
- this.load(ss, this.iClassLoader.TYPE_java_lang_Object, ss.monitorLvIndex);
- this.writeOpcode(ss, Opcode.MONITOREXIT);
- }
-
- private void
- leave2(TryStatement ts, IClass optionalStackValueType) {
- if (ts.finallyOffset != null) {
-
- this.codeContext.saveLocalVariables();
- try {
- short sv = 0;
-
- // Obviously, JSR must always be executed with the operand stack being empty; otherwise we get
- // "java.lang.VerifyError: Inconsistent stack height 1 != 2"
- if (optionalStackValueType != null) {
- sv = this.codeContext.allocateLocalVariable(
- Descriptor.size(optionalStackValueType.getDescriptor())
- );
- this.store(ts, optionalStackValueType, sv);
- }
-
- this.writeBranch(ts, Opcode.JSR, ts.finallyOffset);
-
- if (optionalStackValueType != null) {
- this.load(ts, optionalStackValueType, sv);
- }
- } finally {
- this.codeContext.restoreLocalVariables();
- }
- }
- }
-
- // ---------------- Lvalue.compileSet() -----------------
-
- /**
- * Generates code that stores a value in the {@link Lvalue}. Expects the {@link Lvalue}'s context (see {@link
- * #compileContext}) and a value of the {@link Lvalue}'s type on the operand stack.
- */
- private void
- compileSet(Lvalue lv) throws CompileException {
-
- LvalueVisitor lvv = new LvalueVisitor() {
- // CHECKSTYLE LineLengthCheck:OFF
- @Override public void visitAmbiguousName(AmbiguousName an) { try { UnitCompiler.this.compileSet2(an); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitArrayAccessExpression(ArrayAccessExpression aae) { try { UnitCompiler.this.compileSet2(aae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldAccess(FieldAccess fa) { try { UnitCompiler.this.compileSet2(fa); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldAccessExpression(FieldAccessExpression fae) { try { UnitCompiler.this.compileSet2(fae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSuperclassFieldAccessExpression(SuperclassFieldAccessExpression scfae) { try { UnitCompiler.this.compileSet2(scfae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitLocalVariableAccess(LocalVariableAccess lva) { UnitCompiler.this.compileSet2(lva); }
- @Override public void visitParenthesizedExpression(ParenthesizedExpression pe) { try { UnitCompiler.this.compileSet2(pe); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- // CHECKSTYLE LineLengthCheck:ON
- };
- try {
- lv.accept(lvv);
- } catch (UncheckedCompileException uce) {
- throw uce.compileException; // SUPPRESS CHECKSTYLE AvoidHidingCause
- }
- }
- private void
- compileSet2(AmbiguousName an) throws CompileException {
- this.compileSet(this.toLvalueOrCompileException(this.reclassify(an)));
- }
-
- private void
- compileSet2(LocalVariableAccess lva) { this.store(lva, lva.localVariable); }
-
- private void
- compileSet2(FieldAccess fa) throws CompileException {
- this.checkAccessible(fa.field, fa.getEnclosingBlockStatement());
- this.putfield(fa, fa.field);
- }
- private void
- compileSet2(ArrayAccessExpression aae) throws CompileException {
- this.writeOpcode(aae, Opcode.IASTORE + UnitCompiler.ilfdabcs(this.getType(aae)));
- }
- private void
- compileSet2(FieldAccessExpression fae) throws CompileException {
- this.determineValue(fae);
- this.compileSet(this.toLvalueOrCompileException(fae.value));
- }
- private void
- compileSet2(SuperclassFieldAccessExpression scfae) throws CompileException {
- this.determineValue(scfae);
- this.compileSet(this.toLvalueOrCompileException(scfae.value));
- }
- private void
- compileSet2(ParenthesizedExpression pe) throws CompileException {
- this.compileSet(this.toLvalueOrCompileException(pe.value));
- }
-
- // ---------------- Atom.getType() ----------------
-
- private IClass
- getType(Atom a) throws CompileException {
- final IClass[] res = new IClass[1];
- AtomVisitor av = new AtomVisitor() {
- // CHECKSTYLE LineLengthCheck:OFF
- // AtomVisitor
- @Override public void visitPackage(Package p) { try { res[0] = UnitCompiler.this.getType2(p); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- // TypeVisitor
- @Override public void visitArrayType(ArrayType at) { try { res[0] = UnitCompiler.this.getType2(at); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitBasicType(BasicType bt) { res[0] = UnitCompiler.this.getType2(bt); }
- @Override public void visitReferenceType(ReferenceType rt) { try { res[0] = UnitCompiler.this.getType2(rt); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitRvalueMemberType(RvalueMemberType rmt) { try { res[0] = UnitCompiler.this.getType2(rmt); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSimpleType(SimpleType st) { res[0] = UnitCompiler.this.getType2(st); }
- // RvalueVisitor
- @Override public void visitArrayLength(ArrayLength al) { res[0] = UnitCompiler.this.getType2(al); }
- @Override public void visitAssignment(Assignment a) { try { res[0] = UnitCompiler.this.getType2(a); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitUnaryOperation(UnaryOperation uo) { try { res[0] = UnitCompiler.this.getType2(uo); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitBinaryOperation(BinaryOperation bo) { try { res[0] = UnitCompiler.this.getType2(bo); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCast(Cast c) { try { res[0] = UnitCompiler.this.getType2(c); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitClassLiteral(ClassLiteral cl) { res[0] = UnitCompiler.this.getType2(cl); }
- @Override public void visitConditionalExpression(ConditionalExpression ce) { try { res[0] = UnitCompiler.this.getType2(ce); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitCrement(Crement c) { try { res[0] = UnitCompiler.this.getType2(c); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitInstanceof(Instanceof io) { res[0] = UnitCompiler.this.getType2(io); }
- @Override public void visitMethodInvocation(MethodInvocation mi) { try { res[0] = UnitCompiler.this.getType2(mi); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSuperclassMethodInvocation(SuperclassMethodInvocation smi) { try { res[0] = UnitCompiler.this.getType2(smi); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitIntegerLiteral(IntegerLiteral il) { res[0] = UnitCompiler.this.getType2(il); }
- @Override public void visitFloatingPointLiteral(FloatingPointLiteral fpl) { res[0] = UnitCompiler.this.getType2(fpl); }
- @Override public void visitBooleanLiteral(BooleanLiteral bl) { res[0] = UnitCompiler.this.getType2(bl); }
- @Override public void visitCharacterLiteral(CharacterLiteral cl) { res[0] = UnitCompiler.this.getType2(cl); }
- @Override public void visitStringLiteral(StringLiteral sl) { res[0] = UnitCompiler.this.getType2(sl); }
- @Override public void visitNullLiteral(NullLiteral nl) { res[0] = UnitCompiler.this.getType2(nl); }
- @Override public void visitSimpleConstant(SimpleConstant sl) { res[0] = UnitCompiler.this.getType2(sl); }
- @Override public void visitNewAnonymousClassInstance(NewAnonymousClassInstance naci) { res[0] = UnitCompiler.this.getType2(naci); }
- @Override public void visitNewArray(NewArray na) { try { res[0] = UnitCompiler.this.getType2(na); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewInitializedArray(NewInitializedArray nia) { try { res[0] = UnitCompiler.this.getType2(nia); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitNewClassInstance(NewClassInstance nci) { try { res[0] = UnitCompiler.this.getType2(nci); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitParameterAccess(ParameterAccess pa) { try { res[0] = UnitCompiler.this.getType2(pa); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitQualifiedThisReference(QualifiedThisReference qtr) { try { res[0] = UnitCompiler.this.getType2(qtr); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitThisReference(ThisReference tr) { try { res[0] = UnitCompiler.this.getType2(tr); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- // LvalueVisitor
- @Override public void visitAmbiguousName(AmbiguousName an) { try { res[0] = UnitCompiler.this.getType2(an); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitArrayAccessExpression(ArrayAccessExpression aae) { try { res[0] = UnitCompiler.this.getType2(aae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldAccess(FieldAccess fa) { try { res[0] = UnitCompiler.this.getType2(fa); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitFieldAccessExpression(FieldAccessExpression fae) { try { res[0] = UnitCompiler.this.getType2(fae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitSuperclassFieldAccessExpression(SuperclassFieldAccessExpression scfae) { try { res[0] = UnitCompiler.this.getType2(scfae); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitLocalVariableAccess(LocalVariableAccess lva) { res[0] = UnitCompiler.this.getType2(lva); }
- @Override public void visitParenthesizedExpression(ParenthesizedExpression pe) { try { res[0] = UnitCompiler.this.getType2(pe); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- // CHECKSTYLE LineLengthCheck:ON
- };
- try {
- a.accept(av);
- return res[0] != null ? res[0] : this.iClassLoader.TYPE_java_lang_Object;
- } catch (UncheckedCompileException uce) {
- throw uce.compileException; // SUPPRESS CHECKSTYLE AvoidHidingCause
- }
- }
-
- @SuppressWarnings("static-method") private IClass
- getType2(SimpleType st) { return st.iClass; }
-
- @SuppressWarnings("static-method") private IClass
- getType2(BasicType bt) {
- switch (bt.index) {
- case BasicType.VOID: return IClass.VOID;
- case BasicType.BYTE: return IClass.BYTE;
- case BasicType.SHORT: return IClass.SHORT;
- case BasicType.CHAR: return IClass.CHAR;
- case BasicType.INT: return IClass.INT;
- case BasicType.LONG: return IClass.LONG;
- case BasicType.FLOAT: return IClass.FLOAT;
- case BasicType.DOUBLE: return IClass.DOUBLE;
- case BasicType.BOOLEAN: return IClass.BOOLEAN;
- default: throw new JaninoRuntimeException("Invalid index " + bt.index);
- }
- }
- private IClass
- getType2(ReferenceType rt) throws CompileException {
- String[] identifiers = rt.identifiers;
-
- IClass result = this.getReferenceType(
- rt.getLocation(),
- rt.getEnclosingScope(),
- identifiers,
- identifiers.length
- );
- if (result == null) {
- this.compileError("Reference type '" + rt + "' not found", rt.getLocation());
- return this.iClassLoader.TYPE_java_lang_Object;
- }
-
- return result;
- }
-
- /** @return The resolved {@link IClass}, or {@code null} */
- private IClass
- getReferenceType(Location location, Scope scope, String[] identifiers, int n) throws CompileException {
-
- if (n == 1) {
- return this.getReferenceType(location, identifiers[0], scope);
- }
-
- // JLS7 6.5.5.1 Unnamed package member type name (one identifier).
- // JLS7 6.5.5.2.1 Qualified type name (two or more identifiers).
- {
- String className = Java.join(identifiers, ".", 0, n);
- IClass result = this.findTypeByName(location, className);
- if (result != null) return result;
- }
-
- // JLS7 6.5.5.2.2 referenceType '.' memberTypeName
- if (n >= 2) {
- IClass enclosingType = this.getReferenceType(location, scope, identifiers, n - 1);
- if (enclosingType != null) {
- String memberTypeName = identifiers[n - 1];
- IClass memberType = this.findMemberType(enclosingType, memberTypeName, location);
- if (memberType == null) {
- this.compileError(
- "'" + enclosingType + "' declares no member type '" + memberTypeName + "'",
- location
- );
- return this.iClassLoader.TYPE_java_lang_Object;
- }
- return memberType;
- }
- }
-
- return null;
- }
-
- /**
- * JLS7 6.5.5.1 Simple type name (single identifier)
- *
- * @return The resolved {@link IClass}, or {@code null}
- */
- private IClass
- getReferenceType(Location location, String simpleTypeName, Scope scope) throws CompileException {
- BlockStatement scopeBlockStatement = null;
- TypeDeclaration scopeTypeDeclaration = null;
- CompilationUnit scopeCompilationUnit;
- for (Scope s = scope.getEnclosingScope();; s = s.getEnclosingScope()) {
- if (s instanceof BlockStatement && scopeBlockStatement == null) {
- scopeBlockStatement = (BlockStatement) s;
- }
- if (s instanceof TypeDeclaration && scopeTypeDeclaration == null) {
- scopeTypeDeclaration = (TypeDeclaration) s;
- }
- if (s instanceof CompilationUnit) {
- scopeCompilationUnit = (CompilationUnit) s;
- break;
- }
- }
-
- // JLS7 ??? Type variable.
- if (scopeTypeDeclaration instanceof NamedTypeDeclaration) {
- TypeParameter[]
- optionalTypeParameters = ((NamedTypeDeclaration) scopeTypeDeclaration).getOptionalTypeParameters();
- if (optionalTypeParameters != null) {
- for (TypeParameter tp : optionalTypeParameters) {
- if (tp.name.equals(simpleTypeName)) {
- IClass[] boundTypes;
- if (tp.optionalBound == null) {
- boundTypes = new IClass[] { this.iClassLoader.TYPE_java_lang_Object };
- } else {
- boundTypes = new IClass[tp.optionalBound.length];
- for (int i = 0; i < boundTypes.length; i++) {
- boundTypes[i] = this.getType(tp.optionalBound[i]);
- }
- }
- return boundTypes[0];
- }
- }
- }
- }
-
- // 6.5.5.1.1 Local class.
- {
- LocalClassDeclaration lcd = UnitCompiler.findLocalClassDeclaration(
- scope,
- simpleTypeName
- );
- if (lcd != null) return this.resolve(lcd);
- }
-
- // 6.5.5.1.2 Member type.
- if (scopeTypeDeclaration != null) { // If enclosed by another type declaration...
- for (
- Scope s = scopeTypeDeclaration;
- !(s instanceof CompilationUnit);
- s = s.getEnclosingScope()
- ) {
- if (s instanceof TypeDeclaration) {
- IClass mt = this.findMemberType(
- this.resolve((AbstractTypeDeclaration) s),
- simpleTypeName,
- location
- );
- if (mt != null) return mt;
- }
- }
- }
-
- // 6.5.5.1.4a Single-type import.
- {
- IClass importedClass = this.importSingleType(simpleTypeName, location);
- if (importedClass != null) return importedClass;
- }
-
- // 6.5.5.1.4b Type declared in same compilation unit.
- {
- PackageMemberTypeDeclaration pmtd = (
- scopeCompilationUnit.getPackageMemberTypeDeclaration(simpleTypeName)
- );
- if (pmtd != null) return this.resolve(pmtd);
- }
-
- // 6.5.5.1.5 Type declared in other compilation unit of same package.
- {
- String pkg = (
- scopeCompilationUnit.optionalPackageDeclaration == null ? null :
- scopeCompilationUnit.optionalPackageDeclaration.packageName
- );
- String className = pkg == null ? simpleTypeName : pkg + "." + simpleTypeName;
- IClass result = this.findTypeByName(location, className);
- if (result != null) return result;
- }
-
- // 6.5.5.1.6 Type-import-on-demand declaration.
- {
- IClass importedClass = this.importTypeOnDemand(simpleTypeName, location);
- if (importedClass != null) return importedClass;
- }
-
- // JLS7 6.5.2.BL1.B2: Type imported through single static import.
- {
- List l = (List) this.singleStaticImports.get(simpleTypeName);
- if (l != null) {
- IClass importedMemberType = null;
- for (Iterator it = l.iterator(); it.hasNext();) {
- Object o = it.next();
- if (o instanceof IClass) {
- IClass mt = (IClass) o;
- if (!this.isAccessible(mt, scopeBlockStatement)) continue;
- if (importedMemberType != null && importedMemberType != mt) {
- this.compileError(
- "Ambiguous static imports: \""
- + importedMemberType.toString()
- + "\" vs. \""
- + mt.toString()
- + "\""
- );
- }
- importedMemberType = mt;
- }
- }
- if (importedMemberType != null) return importedMemberType;
- }
- }
-
- // JLS7 6.5.2.BL1.B2: Type imported through static-import-on-demand.
- {
- IClass importedMemberType = null;
- for (IClass ic : this.staticImportsOnDemand) {
- IClass[] memberTypes = ic.getDeclaredIClasses();
- for (IClass mt : memberTypes) {
- if (!this.isAccessible(mt, scopeBlockStatement)) continue;
- if (mt.getDescriptor().endsWith('$' + simpleTypeName + ';')) {
- if (importedMemberType != null) {
- this.compileError(
- "Ambiguous static imports: \""
- + importedMemberType.toString()
- + "\" vs. \""
- + mt.toString()
- + "\""
- );
- }
- importedMemberType = mt;
- }
- }
- }
- if (importedMemberType != null) return importedMemberType;
- }
-
- // Unnamed package member type.
- {
- IClass result = this.findTypeByName(location, simpleTypeName);
- if (result != null) return result;
- }
-
- // 6.5.5.1.8 Give up.
- this.compileError("Cannot determine simple type name \"" + simpleTypeName + "\"", location);
- return this.iClassLoader.TYPE_java_lang_Object;
- }
-
- private IClass
- getType2(RvalueMemberType rvmt) throws CompileException {
- IClass rvt = this.getType(rvmt.rvalue);
- IClass memberType = this.findMemberType(rvt, rvmt.identifier, rvmt.getLocation());
- if (memberType == null) {
- this.compileError("\"" + rvt + "\" has no member type \"" + rvmt.identifier + "\"", rvmt.getLocation());
- }
- return memberType;
- }
-
- private IClass
- getType2(ArrayType at) throws CompileException {
- return this.getType(at.componentType).getArrayIClass(this.iClassLoader.TYPE_java_lang_Object);
- }
-
- private IClass
- getType2(AmbiguousName an) throws CompileException {
- return this.getType(this.reclassify(an));
- }
-
- private IClass
- getType2(Package p) throws CompileException {
- this.compileError("Unknown variable or type \"" + p.name + "\"", p.getLocation());
- return this.iClassLoader.TYPE_java_lang_Object;
- }
-
- @SuppressWarnings("static-method") private IClass
- getType2(LocalVariableAccess lva) {
- return lva.localVariable.type;
- }
-
- @SuppressWarnings("static-method") private IClass
- getType2(FieldAccess fa) throws CompileException {
- return fa.field.getType();
- }
-
- @SuppressWarnings("static-method") private IClass
- getType2(ArrayLength al) {
- return IClass.INT;
- }
-
- private IClass
- getType2(ThisReference tr) throws CompileException {
- return this.getIClass(tr);
- }
-
- private IClass
- getType2(QualifiedThisReference qtr) throws CompileException {
- return this.getTargetIClass(qtr);
- }
-
- private IClass
- getType2(ClassLiteral cl) {
- return this.iClassLoader.TYPE_java_lang_Class;
- }
-
- private IClass
- getType2(Assignment a) throws CompileException {
- return this.getType(a.lhs);
- }
-
- private IClass
- getType2(ConditionalExpression ce) throws CompileException {
- IClass mhsType = this.getType(ce.mhs);
- IClass rhsType = this.getType(ce.rhs);
-
- if (mhsType == rhsType) {
-
- // JLS7 15.25, list 1, bullet 1: "b ? T : T => T"
- return mhsType;
- } else
- if (this.isUnboxingConvertible(mhsType) == rhsType) {
-
- // JLS7 15.25, list 1, bullet 2: "b ? Integer : int => int"
- return rhsType;
- } else
- if (this.isUnboxingConvertible(rhsType) == mhsType) {
-
- // JLS7 15.25, list 1, bullet 2: "b ? int : Integer => int"
- return mhsType;
- } else
- if (this.getConstantValue(ce.mhs) == null && !rhsType.isPrimitive()) {
-
- // JLS7 15.25, list 1, bullet 3: "b ? null : ReferenceType => ReferenceType"
- return rhsType;
- } else
- if (!mhsType.isPrimitive() && this.getConstantValue(ce.rhs) == null) {
-
- // JLS7 15.25, list 1, bullet 3: "b ? ReferenceType : null => ReferenceType"
- return mhsType;
- } else
- if (this.isConvertibleToPrimitiveNumeric(mhsType) && this.isConvertibleToPrimitiveNumeric(rhsType)) {
-
- // JLS7 15.25, list 1, bullet 4, bullet 1: "b ? Byte : Short => short"
- if (
- (mhsType == IClass.BYTE || mhsType == this.iClassLoader.TYPE_java_lang_Byte)
- && (rhsType == IClass.SHORT || rhsType == this.iClassLoader.TYPE_java_lang_Short)
- ) return IClass.SHORT;
- if (
- (rhsType == IClass.BYTE || rhsType == this.iClassLoader.TYPE_java_lang_Byte)
- && (mhsType == IClass.SHORT || mhsType == this.iClassLoader.TYPE_java_lang_Short)
- ) return IClass.SHORT;
-
- // JLS7 15.25, list 1, bullet 4, bullet 2: "b ? 127 : byte => byte"
- if (
- (mhsType == IClass.BYTE || mhsType == IClass.SHORT || mhsType == IClass.CHAR)
- && ce.rhs.constantValue != null
- && this.assignmentConversion(ce.rhs, ce.rhs.constantValue, mhsType) != null
- ) return mhsType;
- if (
- (rhsType == IClass.BYTE || rhsType == IClass.SHORT || rhsType == IClass.CHAR)
- && ce.mhs.constantValue != null
- && this.assignmentConversion(ce.mhs, ce.mhs.constantValue, rhsType) != null
- ) return rhsType;
-
- // TODO JLS7 15.25, list 1, bullet 4, bullet 3: "b ? 127 : byte => byte"
-
- // JLS7 15.25, list 1, bullet 4, bullet 4: "b ? Integer : Double => double"
- return this.binaryNumericPromotionType(ce, this.getUnboxedType(mhsType), this.getUnboxedType(rhsType));
- } else
- if (!mhsType.isPrimitive() && !rhsType.isPrimitive()) {
-
- // JLS7 15.25, list 1, bullet 5: "b ? Base : Derived => Base"
- if (mhsType.isAssignableFrom(rhsType)) {
- return mhsType;
- } else
- if (rhsType.isAssignableFrom(mhsType)) {
- return rhsType;
- } else {
- this.compileError(
- "Reference types \"" + mhsType + "\" and \"" + rhsType + "\" don't match",
- ce.getLocation()
- );
- return this.iClassLoader.TYPE_java_lang_Object;
- }
- } else
- {
- this.compileError(
- "Incompatible expression types \"" + mhsType + "\" and \"" + rhsType + "\"",
- ce.getLocation()
- );
- return this.iClassLoader.TYPE_java_lang_Object;
- }
- }
-
- private IClass
- getType2(Crement c) throws CompileException {
- return this.getType(c.operand);
- }
-
- private IClass
- getType2(ArrayAccessExpression aae) throws CompileException {
- return this.getType(aae.lhs).getComponentType();
- }
-
- private IClass
- getType2(FieldAccessExpression fae) throws CompileException {
- this.determineValue(fae);
- return this.getType(fae.value);
- }
-
- private IClass
- getType2(SuperclassFieldAccessExpression scfae) throws CompileException {
- this.determineValue(scfae);
- return this.getType(scfae.value);
- }
-
- private IClass
- getType2(UnaryOperation uo) throws CompileException {
- if (uo.operator == "!") return IClass.BOOLEAN; // SUPPRESS CHECKSTYLE StringLiteralEquality
-
- // SUPPRESS CHECKSTYLE StringLiteralEquality
- if (uo.operator == "+" || uo.operator == "-" || uo.operator == "~") {
- return this.unaryNumericPromotionType(uo, this.getUnboxedType(this.getType(uo.operand)));
- }
-
- this.compileError("Unexpected operator \"" + uo.operator + "\"", uo.getLocation());
- return IClass.BOOLEAN;
- }
-
- @SuppressWarnings("static-method") private IClass
- getType2(Instanceof io) { return IClass.BOOLEAN; }
-
- private IClass
- getType2(BinaryOperation bo) throws CompileException {
- if (
- // CHECKSTYLE StringLiteralEquality:OFF
- bo.op == "||"
- || bo.op == "&&"
- || bo.op == "=="
- || bo.op == "!="
- || bo.op == "<"
- || bo.op == ">"
- || bo.op == "<="
- || bo.op == ">="
- // CHECKSTYLE StringLiteralEquality:ON
- ) return IClass.BOOLEAN;
-
- if (bo.op == "|" || bo.op == "^" || bo.op == "&") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- IClass lhsType = this.getType(bo.lhs);
- return (
- lhsType == IClass.BOOLEAN || lhsType == this.iClassLoader.TYPE_java_lang_Boolean
- ? IClass.BOOLEAN
- : this.binaryNumericPromotionType(bo, lhsType, this.getType(bo.rhs))
- );
- }
-
- // SUPPRESS CHECKSTYLE StringLiteralEquality
- if (bo.op == "*" || bo.op == "/" || bo.op == "%" || bo.op == "+" || bo.op == "-") {
- IClassLoader icl = this.iClassLoader;
-
- // Unroll the operands of this binary operation.
- Iterator ops = bo.unrollLeftAssociation();
-
- // Check the far left operand type.
- IClass lhsType = this.getUnboxedType(this.getType(((Rvalue) ops.next())));
- if (bo.op == "+" && lhsType == icl.TYPE_java_lang_String) { // SUPPRESS CHECKSTYLE StringLiteralEquality
- return icl.TYPE_java_lang_String;
- }
-
- // Determine the expression type.
- do {
- IClass rhsType = this.getUnboxedType(this.getType(((Rvalue) ops.next())));
- if (bo.op == "+" && rhsType == icl.TYPE_java_lang_String) { // SUPPRESS CHECKSTYLE StringLiteralEquality
- return icl.TYPE_java_lang_String;
- }
- lhsType = this.binaryNumericPromotionType(bo, lhsType, rhsType);
- } while (ops.hasNext());
- return lhsType;
- }
-
- if (bo.op == "<<" || bo.op == ">>" || bo.op == ">>>") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- IClass lhsType = this.getType(bo.lhs);
- return this.unaryNumericPromotionType(bo, lhsType);
- }
-
- this.compileError("Unexpected operator \"" + bo.op + "\"", bo.getLocation());
- return this.iClassLoader.TYPE_java_lang_Object;
- }
-
- /** @return Iff {@code type} is a primitive wrapper type, the unwrapped {@code type}, otherwise {@code type} */
- private IClass
- getUnboxedType(IClass type) {
- IClass c = this.isUnboxingConvertible(type);
- return c != null ? c : type;
- }
-
- private IClass
- getType2(Cast c) throws CompileException {
- return this.getType(c.targetType);
- }
-
- private IClass
- getType2(ParenthesizedExpression pe) throws CompileException {
- return this.getType(pe.value);
- }
-
- private IClass
- getType2(MethodInvocation mi) throws CompileException {
- //TODO: cache this (as blackhole)
- if (mi.iMethod == null) {
- mi.iMethod = this.findIMethod(mi);
- }
- return mi.iMethod.getReturnType();
- }
-
- private IClass
- getType2(SuperclassMethodInvocation scmi) throws CompileException {
- return this.findIMethod(scmi).getReturnType();
- }
-
- private IClass
- getType2(NewClassInstance nci) throws CompileException {
- if (nci.iClass == null) nci.iClass = this.getType(nci.type);
- return nci.iClass;
- }
-
- private IClass
- getType2(NewAnonymousClassInstance naci) {
- return this.resolve(naci.anonymousClassDeclaration);
- }
-
- private IClass
- getType2(ParameterAccess pa) throws CompileException {
- return this.getLocalVariable(pa.formalParameter).type;
- }
-
- private IClass
- getType2(NewArray na) throws CompileException {
- IClass res = this.getType(na.type);
- return res.getArrayIClass(na.dimExprs.length + na.dims, this.iClassLoader.TYPE_java_lang_Object);
- }
-
- private IClass
- getType2(NewInitializedArray nia) throws CompileException {
- return nia.arrayType == null ? nia.arrayIClass : this.getType(nia.arrayType);
- }
-
- @SuppressWarnings("static-method") private IClass
- getType2(IntegerLiteral il) {
- String v = il.value;
- char lastChar = v.charAt(v.length() - 1);
- return lastChar == 'l' || lastChar == 'L' ? IClass.LONG : IClass.INT;
- }
-
- @SuppressWarnings("static-method") private IClass
- getType2(FloatingPointLiteral fpl) {
- String v = fpl.value;
- char lastChar = v.charAt(v.length() - 1);
- return lastChar == 'f' || lastChar == 'F' ? IClass.FLOAT : IClass.DOUBLE;
- }
-
- @SuppressWarnings("static-method") private IClass
- getType2(BooleanLiteral bl) {
- return IClass.BOOLEAN;
- }
-
- @SuppressWarnings("static-method") private IClass
- getType2(CharacterLiteral cl) {
- return IClass.CHAR;
- }
-
- private IClass
- getType2(StringLiteral sl) {
- return this.iClassLoader.TYPE_java_lang_String;
- }
-
- @SuppressWarnings("static-method") private IClass
- getType2(NullLiteral nl) {
- return IClass.VOID;
- }
-
- private IClass
- getType2(SimpleConstant sl) {
- Object v = sl.value;
- if (v instanceof Byte) return IClass.BYTE;
- if (v instanceof Short) return IClass.SHORT;
- if (v instanceof Integer) return IClass.INT;
- if (v instanceof Long) return IClass.LONG;
- if (v instanceof Float) return IClass.FLOAT;
- if (v instanceof Double) return IClass.DOUBLE;
- if (v instanceof Boolean) return IClass.BOOLEAN;
- if (v instanceof Character) return IClass.CHAR;
- if (v instanceof String) return this.iClassLoader.TYPE_java_lang_String;
- if (v == null) return IClass.VOID;
- throw new JaninoRuntimeException("Invalid SimpleLiteral value type '" + v.getClass() + "'");
- }
-
- // ---------------- Atom.isType() ---------------
-
- private boolean
- isType(Atom a) throws CompileException {
- final boolean[] res = new boolean[1];
- AtomVisitor av = new AtomVisitor() {
- // CHECKSTYLE LineLengthCheck:OFF
- // AtomVisitor
- @Override public void visitPackage(Package p) { res[0] = UnitCompiler.this.isType2(p); }
- // TypeVisitor
- @Override public void visitArrayType(ArrayType at) { res[0] = UnitCompiler.this.isType2(at); }
- @Override public void visitBasicType(BasicType bt) { res[0] = UnitCompiler.this.isType2(bt); }
- @Override public void visitReferenceType(ReferenceType rt) { res[0] = UnitCompiler.this.isType2(rt); }
- @Override public void visitRvalueMemberType(RvalueMemberType rmt) { res[0] = UnitCompiler.this.isType2(rmt); }
- @Override public void visitSimpleType(SimpleType st) { res[0] = UnitCompiler.this.isType2(st); }
- // RvalueVisitor
- @Override public void visitArrayLength(ArrayLength al) { res[0] = UnitCompiler.this.isType2(al); }
- @Override public void visitAssignment(Assignment a) { res[0] = UnitCompiler.this.isType2(a); }
- @Override public void visitUnaryOperation(UnaryOperation uo) { res[0] = UnitCompiler.this.isType2(uo); }
- @Override public void visitBinaryOperation(BinaryOperation bo) { res[0] = UnitCompiler.this.isType2(bo); }
- @Override public void visitCast(Cast c) { res[0] = UnitCompiler.this.isType2(c); }
- @Override public void visitClassLiteral(ClassLiteral cl) { res[0] = UnitCompiler.this.isType2(cl); }
- @Override public void visitConditionalExpression(ConditionalExpression ce) { res[0] = UnitCompiler.this.isType2(ce); }
- @Override public void visitCrement(Crement c) { res[0] = UnitCompiler.this.isType2(c); }
- @Override public void visitInstanceof(Instanceof io) { res[0] = UnitCompiler.this.isType2(io); }
- @Override public void visitMethodInvocation(MethodInvocation mi) { res[0] = UnitCompiler.this.isType2(mi); }
- @Override public void visitSuperclassMethodInvocation(SuperclassMethodInvocation smi) { res[0] = UnitCompiler.this.isType2(smi); }
- @Override public void visitIntegerLiteral(IntegerLiteral il) { res[0] = UnitCompiler.this.isType2(il); }
- @Override public void visitFloatingPointLiteral(FloatingPointLiteral fpl) { res[0] = UnitCompiler.this.isType2(fpl); }
- @Override public void visitBooleanLiteral(BooleanLiteral bl) { res[0] = UnitCompiler.this.isType2(bl); }
- @Override public void visitCharacterLiteral(CharacterLiteral cl) { res[0] = UnitCompiler.this.isType2(cl); }
- @Override public void visitStringLiteral(StringLiteral sl) { res[0] = UnitCompiler.this.isType2(sl); }
- @Override public void visitNullLiteral(NullLiteral nl) { res[0] = UnitCompiler.this.isType2(nl); }
- @Override public void visitSimpleConstant(SimpleConstant sl) { res[0] = UnitCompiler.this.isType2(sl); }
- @Override public void visitNewAnonymousClassInstance(NewAnonymousClassInstance naci) { res[0] = UnitCompiler.this.isType2(naci); }
- @Override public void visitNewArray(NewArray na) { res[0] = UnitCompiler.this.isType2(na); }
- @Override public void visitNewInitializedArray(NewInitializedArray nia) { res[0] = UnitCompiler.this.isType2(nia); }
- @Override public void visitNewClassInstance(NewClassInstance nci) { res[0] = UnitCompiler.this.isType2(nci); }
- @Override public void visitParameterAccess(ParameterAccess pa) { res[0] = UnitCompiler.this.isType2(pa); }
- @Override public void visitQualifiedThisReference(QualifiedThisReference qtr) { res[0] = UnitCompiler.this.isType2(qtr); }
- @Override public void visitThisReference(ThisReference tr) { res[0] = UnitCompiler.this.isType2(tr); }
- // LvalueVisitor
- @Override public void visitAmbiguousName(AmbiguousName an) { try { res[0] = UnitCompiler.this.isType2(an); } catch (CompileException e) { throw new UncheckedCompileException(e); } }
- @Override public void visitArrayAccessExpression(ArrayAccessExpression aae) { res[0] = UnitCompiler.this.isType2(aae); }
- @Override public void visitFieldAccess(FieldAccess fa) { res[0] = UnitCompiler.this.isType2(fa); }
- @Override public void visitFieldAccessExpression(FieldAccessExpression fae) { res[0] = UnitCompiler.this.isType2(fae); }
- @Override public void visitSuperclassFieldAccessExpression(SuperclassFieldAccessExpression scfae) { res[0] = UnitCompiler.this.isType2(scfae); }
- @Override public void visitLocalVariableAccess(LocalVariableAccess lva) { res[0] = UnitCompiler.this.isType2(lva); }
- @Override public void visitParenthesizedExpression(ParenthesizedExpression pe) { res[0] = UnitCompiler.this.isType2(pe); }
- // CHECKSTYLE LineLengthCheck:ON
- };
- try {
- a.accept(av);
- return res[0];
- } catch (UncheckedCompileException uce) {
- throw uce.compileException; // SUPPRESS CHECKSTYLE AvoidHidingCause
- }
- }
-
- @SuppressWarnings("static-method") private boolean
- isType2(Atom a) { return a instanceof Type; }
-
- private boolean
- isType2(AmbiguousName an) throws CompileException { return this.isType(this.reclassify(an)); }
-
- /**
- * Determines whether the given {@link IClass.IMember} is accessible in the given context, according to
- * JLS7 6.6.1.BL1.B4. Issues a {@link #compileError(String)} if not.
- */
- private boolean
- isAccessible(IClass.IMember member, Scope contextScope) throws CompileException {
-
- // You have to check that both the class and member are accessible in this scope.
- IClass declaringIClass = member.getDeclaringIClass();
- boolean acc = this.isAccessible(declaringIClass, contextScope);
- acc = acc && this.isAccessible(declaringIClass, member.getAccess(), contextScope);
- return acc;
- }
-
- /**
- * Checks whether the given {@link IClass.IMember} is accessible in the given context, according to JLS7
- * 6.6.1.BL1.B4. Issues a {@link #compileError(String)} if not.
- */
- private void
- checkAccessible(IClass.IMember member, BlockStatement contextBlockStatement) throws CompileException {
-
- // You have to check that both the class and member are accessible in this scope.
- IClass declaringIClass = member.getDeclaringIClass();
- this.checkAccessible(declaringIClass, contextBlockStatement);
- this.checkAccessible(declaringIClass, member.getAccess(), contextBlockStatement);
- }
-
- /**
- * Determines whether a member (class, interface, field or method) declared in a given class is accessible from a
- * given block statement context, according to JLS7 6.6.1.4.
- */
- private boolean
- isAccessible(IClass iClassDeclaringMember, Access memberAccess, Scope contextScope) throws CompileException {
- return null == this.internalCheckAccessible(iClassDeclaringMember, memberAccess, contextScope);
- }
-
- /**
- * Verifies that a member (class, interface, field or method) declared in a given class is accessible from a given
- * block statement context, according to JLS7 6.6.1.4. Issue a {@link #compileError(String)} if not.
- */
- private void
- checkAccessible(
- IClass iClassDeclaringMember,
- Access memberAccess,
- BlockStatement contextBlockStatement
- ) throws CompileException {
- String message = this.internalCheckAccessible(iClassDeclaringMember, memberAccess, contextBlockStatement);
- if (message != null) this.compileError(message, contextBlockStatement.getLocation());
- }
-
- /**
- * @return a descriptive text iff a member declared in that {@link IClass} with that {@link Access} is inaccessible
- */
- private String
- internalCheckAccessible(
- IClass iClassDeclaringMember,
- Access memberAccess,
- Scope contextScope
- ) throws CompileException {
-
- // At this point, memberAccess is PUBLIC, DEFAULT, PROTECTED or PRIVATE.
-
- // PUBLIC members are always accessible.
- if (memberAccess == Access.PUBLIC) return null;
-
- // At this point, the member is DEFAULT, PROECTEDED or PRIVATE accessible.
-
- // Determine the class declaring the context.
- IClass iClassDeclaringContext = null;
- for (Scope s = contextScope; !(s instanceof CompilationUnit); s = s.getEnclosingScope()) {
- if (s instanceof TypeDeclaration) {
- iClassDeclaringContext = this.resolve((TypeDeclaration) s);
- break;
- }
- }
-
- // Access is always allowed for block statements declared in the same class as the member.
- if (iClassDeclaringContext == iClassDeclaringMember) return null;
-
- // Check whether the member and the context block statement are enclosed by the same top-level type.
- if (iClassDeclaringContext != null) {
- IClass topLevelIClassEnclosingMember = iClassDeclaringMember;
- for (IClass c = iClassDeclaringMember.getDeclaringIClass(); c != null; c = c.getDeclaringIClass()) {
- topLevelIClassEnclosingMember = c;
- }
- IClass topLevelIClassEnclosingContextBlockStatement = iClassDeclaringContext;
- for (
- IClass c = iClassDeclaringContext.getDeclaringIClass();
- c != null;
- c = c.getDeclaringIClass()
- ) topLevelIClassEnclosingContextBlockStatement = c;
-
- if (topLevelIClassEnclosingMember == topLevelIClassEnclosingContextBlockStatement) return null;
- }
-
- if (memberAccess == Access.PRIVATE) {
- return "Private member cannot be accessed from type \"" + iClassDeclaringContext + "\".";
- }
-
- // At this point, the member is DEFAULT or PROTECTED accessible.
-
- // Check whether the member and the context block statement are declared in the same package.
- if (Descriptor.areInSamePackage(
- iClassDeclaringMember.getDescriptor(),
- iClassDeclaringContext.getDescriptor()
- )) return null;
-
- if (memberAccess == Access.DEFAULT) {
- return (
- "Member with \""
- + memberAccess
- + "\" access cannot be accessed from type \""
- + iClassDeclaringContext
- + "\"."
- );
- }
-
- // At this point, the member is PROTECTED accessible.
-
- // Check whether the class declaring the context block statement is a subclass of the class declaring the
- // member or a nested class whose parent is a subclass
- {
- IClass parentClass = iClassDeclaringContext;
- do {
- if (iClassDeclaringMember.isAssignableFrom(parentClass)) {
- return null;
- }
- parentClass = parentClass.getOuterIClass();
- } while (parentClass != null);
- }
-
- return (
- "Protected member cannot be accessed from type \""
- + iClassDeclaringContext
- + "\", which is neither declared in the same package as nor is a subclass of \""
- + iClassDeclaringMember
- + "\"."
- );
- }
-
- /**
- * Determines whether the given {@link IClass} is accessible in the given context, according to JLS7 6.6.1.2 and
- * 6.6.1.4.
- */
- private boolean
- isAccessible(IClass type, Scope contextScope) throws CompileException {
- return null == this.internalCheckAccessible(type, contextScope);
- }
-
- /**
- * Checks whether the given {@link IClass} is accessible in the given context, according to JLS7 6.6.1.2 and
- * 6.6.1.4. Issues a {@link #compileError(String)} if not.
- */
- private void
- checkAccessible(IClass type, BlockStatement contextBlockStatement) throws CompileException {
- String message = this.internalCheckAccessible(type, contextBlockStatement);
- if (message != null) this.compileError(message, contextBlockStatement.getLocation());
- }
-
- private String
- internalCheckAccessible(IClass type, Scope contextScope) throws CompileException {
-
- // Determine the type declaring the type.
- IClass iClassDeclaringType = type.getDeclaringIClass();
-
- // Check accessibility of package member type.
- if (iClassDeclaringType == null) {
- if (type.getAccess() == Access.PUBLIC) {
- return null;
- } else
- if (type.getAccess() == Access.DEFAULT) {
-
- // Determine the type declaring the context block statement.
- IClass iClassDeclaringContextBlockStatement;
- for (Scope s = contextScope;; s = s.getEnclosingScope()) {
- if (s instanceof TypeDeclaration) {
- iClassDeclaringContextBlockStatement = this.resolve((TypeDeclaration) s);
- break;
- }
- if (s instanceof EnclosingScopeOfTypeDeclaration) {
- iClassDeclaringContextBlockStatement = this.resolve(
- ((EnclosingScopeOfTypeDeclaration) s).typeDeclaration
- );
- break;
- }
- }
-
- // Check whether the type is accessed from within the same package.
- String packageDeclaringType = Descriptor.getPackageName(type.getDescriptor());
- String
- contextPackage = Descriptor.getPackageName(iClassDeclaringContextBlockStatement.getDescriptor());
- if (
- packageDeclaringType == null
- ? contextPackage != null
- : !packageDeclaringType.equals(contextPackage)
- ) return "\"" + type + "\" is inaccessible from this package";
- return null;
- } else
- {
- throw new JaninoRuntimeException("\"" + type + "\" has unexpected access \"" + type.getAccess() + "\"");
- }
- }
-
- // "type" is a member type at this point.
- return this.internalCheckAccessible(iClassDeclaringType, type.getAccess(), contextScope);
- }
-
- private Type
- toTypeOrCompileException(Atom a) throws CompileException {
- Type result = a.toType();
- if (result == null) {
- this.compileError("Expression \"" + a.toString() + "\" is not a type", a.getLocation());
- return new SimpleType(a.getLocation(), this.iClassLoader.TYPE_java_lang_Object);
- }
- return result;
- }
-
- private Rvalue
- toRvalueOrCompileException(final Atom a) throws CompileException {
- Rvalue result = a.toRvalue();
- if (result == null) {
- this.compileError("Expression \"" + a.toString() + "\" is not an rvalue", a.getLocation());
- return new StringLiteral(a.getLocation(), "\"X\"");
- }
- return result;
- }
-
- private Lvalue
- toLvalueOrCompileException(final Atom a) throws CompileException {
- Lvalue result = a.toLvalue();
- if (result == null) {
- this.compileError("Expression \"" + a.toString() + "\" is not an lvalue", a.getLocation());
- return new Lvalue(a.getLocation()) {
- @Override public String toString() { return a.toString(); }
- @Override public void accept(AtomVisitor visitor) {}
- @Override public void accept(RvalueVisitor visitor) {}
- @Override public void accept(LvalueVisitor visitor) {}
- @Override public void accept(ElementValueVisitor visitor) {}
- };
- }
- return result;
- }
-
- /**
- * Copies the values of the synthetic parameters of this constructor ("this$..." and "val$...") to the synthetic
- * fields of the object ("this$..." and "val$...").
- */
- void
- assignSyntheticParametersToSyntheticFields(ConstructorDeclarator cd) throws CompileException {
- for (IClass.IField sf : cd.getDeclaringClass().syntheticFields.values()) {
- LocalVariable syntheticParameter = (LocalVariable) cd.syntheticParameters.get(sf.getName());
- if (syntheticParameter == null) {
- throw new JaninoRuntimeException(
- "SNO: Synthetic parameter for synthetic field \""
- + sf.getName()
- + "\" not found"
- );
- }
- ExpressionStatement es = new ExpressionStatement(new Assignment(
- cd.getLocation(), // location
- new FieldAccess( // lhs
- cd.getLocation(), // location
- new ThisReference(cd.getLocation()), // lhs
- sf // field
- ),
- "=", // operator
- new LocalVariableAccess( // rhs
- cd.getLocation(), // location
- syntheticParameter // localVariable
- )
- ));
- es.setEnclosingScope(cd);
- this.compile(es);
- }
- }
-
- /** Compiles the instance variable initializers and the instance initializers in their lexical order. */
- void
- initializeInstanceVariablesAndInvokeInstanceInitializers(ConstructorDeclarator cd) throws CompileException {
-
- // Compilation of block statments can create synthetic variables, so we must not use an iterator.
- List vdai = cd.getDeclaringClass().variableDeclaratorsAndInitializers;
- for (int i = 0; i < vdai.size(); i++) {
- BlockStatement bs = (BlockStatement) vdai.get(i);
-
- if (!((TypeBodyDeclaration) bs).isStatic()) {
- if (!this.compile(bs)) {
- this.compileError(
- "Instance variable declarator or instance initializer does not complete normally",
- bs.getLocation()
- );
- }
- }
- }
- }
-
- /**
- * Statements that jump out of blocks ("return", "break", "continue") must call this method to make sure that the
- * "finally" clauses of all "try...catch" statements are executed.
- */
- private void
- leaveStatements(Scope from, Scope to, IClass optionalStackValueType) {
- for (Scope s = from; s != to; s = s.getEnclosingScope()) {
- if (s instanceof BlockStatement) {
- this.leave((BlockStatement) s, optionalStackValueType);
- }
- }
- }
-
- /**
- * The LHS operand of type {@code lhsType} is expected on the stack.
- *
- * The following operators are supported: {@code | ^ & * / % + - << >> >>>}
- */
- private IClass
- compileArithmeticBinaryOperation(
- Locatable locatable,
- IClass lhsType,
- String operator,
- Rvalue rhs
- ) throws CompileException {
- return this.compileArithmeticOperation(
- locatable,
- lhsType,
- Arrays.asList(new Rvalue[] { rhs }).iterator(),
- operator
- );
- }
-
- /**
- * Execute an arithmetic operation on a sequence of {@code operands}. If {@code type} is non-null, the first
- * operand with that type is already on the stack.
- *
- * The following operators are supported: {@code | ^ & * / % + - << >> >>>}
- */
- private IClass
- compileArithmeticOperation(
- final Locatable locatable,
- IClass type,
- Iterator operands,
- String operator
- ) throws CompileException {
- if (operator == "|" || operator == "^" || operator == "&") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- final int iopcode = (
- // CHECKSTYLE StringLiteralEquality:OFF
- operator == "&" ? Opcode.IAND :
- operator == "|" ? Opcode.IOR :
- operator == "^" ? Opcode.IXOR :
- // CHECKSTYLE StringLiteralEquality:OFF
- Integer.MAX_VALUE
- );
-
- do {
- Rvalue operand = (Rvalue) operands.next();
-
- if (type == null) {
- type = this.compileGetValue(operand);
- } else {
- CodeContext.Inserter convertLhsInserter = this.codeContext.newInserter();
- IClass rhsType = this.compileGetValue(operand);
-
- if (type.isPrimitiveNumeric() && rhsType.isPrimitiveNumeric()) {
- IClass promotedType = this.binaryNumericPromotion(locatable, type, convertLhsInserter, rhsType);
- if (promotedType == IClass.INT) {
- this.writeOpcode(locatable, iopcode);
- } else
- if (promotedType == IClass.LONG) {
- this.writeOpcode(locatable, iopcode + 1);
- } else
- {
- this.compileError((
- "Operator \""
- + operator
- + "\" not defined on types \""
- + type
- + "\" and \""
- + rhsType
- + "\""
- ), locatable.getLocation());
- }
- type = promotedType;
- } else
- if (
- (type == IClass.BOOLEAN || this.getUnboxedType(type) == IClass.BOOLEAN)
- && (rhsType == IClass.BOOLEAN || this.getUnboxedType(rhsType) == IClass.BOOLEAN)
- ) {
- IClassLoader icl = this.iClassLoader;
- if (type == icl.TYPE_java_lang_Boolean) {
- this.codeContext.pushInserter(convertLhsInserter);
- try {
- this.unboxingConversion(locatable, icl.TYPE_java_lang_Boolean, IClass.BOOLEAN);
- } finally {
- this.codeContext.popInserter();
- }
- }
- if (rhsType == icl.TYPE_java_lang_Boolean) {
- this.unboxingConversion(locatable, icl.TYPE_java_lang_Boolean, IClass.BOOLEAN);
- }
- this.writeOpcode(locatable, iopcode);
- type = IClass.BOOLEAN;
- } else
- {
- this.compileError((
- "Operator \""
- + operator
- + "\" not defined on types \""
- + type
- + "\" and \""
- + rhsType
- + "\""
- ), locatable.getLocation());
- type = IClass.INT;
- }
- }
- } while (operands.hasNext());
- return type;
- }
-
- // SUPPRESS CHECKSTYLE StringLiteralEquality
- if (operator == "*" || operator == "/" || operator == "%" || operator == "+" || operator == "-") {
- final int iopcode = (
- operator == "*" ? Opcode.IMUL :
- operator == "/" ? Opcode.IDIV :
- operator == "%" ? Opcode.IREM :
- operator == "+" ? Opcode.IADD :
- operator == "-" ? Opcode.ISUB : Integer.MAX_VALUE
- );
-
- do {
- Rvalue operand = (Rvalue) operands.next();
-
- IClass operandType = this.getType(operand);
- IClassLoader icl = this.iClassLoader;
-
- // String concatenation?
- // SUPPRESS CHECKSTYLE StringLiteralEquality
- if (
- operator == "+"
- && (type == icl.TYPE_java_lang_String || operandType == icl.TYPE_java_lang_String)
- ) {
- return this.compileStringConcatenation(locatable, type, operand, operands);
- }
-
- if (type == null) {
- type = this.compileGetValue(operand);
- } else {
- CodeContext.Inserter convertLhsInserter = this.codeContext.newInserter();
- IClass rhsType = this.compileGetValue(operand);
-
- type = this.binaryNumericPromotion(locatable, type, convertLhsInserter, rhsType);
-
- int opcode;
- if (type == IClass.INT) {
- opcode = iopcode;
- } else
- if (type == IClass.LONG) {
- opcode = iopcode + 1;
- } else
- if (type == IClass.FLOAT) {
- opcode = iopcode + 2;
- } else
- if (type == IClass.DOUBLE) {
- opcode = iopcode + 3;
- } else
- {
- this.compileError("Unexpected promoted type \"" + type + "\"", locatable.getLocation());
- opcode = iopcode;
- }
- this.writeOpcode(locatable, opcode);
- }
- } while (operands.hasNext());
- return type;
- }
-
- if (operator == "<<" || operator == ">>" || operator == ">>>") { // SUPPRESS CHECKSTYLE StringLiteralEquality
- final int iopcode = (
- operator == "<<" ? Opcode.ISHL :
- operator == ">>" ? Opcode.ISHR :
- operator == ">>>" ? Opcode.IUSHR : Integer.MAX_VALUE
- );
-
- do {
- Rvalue operand = (Rvalue) operands.next();
-
- if (type == null) {
- type = this.compileGetValue(operand);
- } else {
- CodeContext.Inserter convertLhsInserter = this.codeContext.newInserter();
- final IClass rhsType = this.compileGetValue(operand);
-
- IClass promotedLhsType;
- this.codeContext.pushInserter(convertLhsInserter);
- try {
- promotedLhsType = this.unaryNumericPromotion(locatable, type);
- } finally {
- this.codeContext.popInserter();
- }
- if (promotedLhsType != IClass.INT && promotedLhsType != IClass.LONG) {
- this.compileError(
- "Shift operation not allowed on operand type \"" + type + "\"",
- locatable.getLocation()
- );
- }
-
- IClass promotedRhsType = this.unaryNumericPromotion(locatable, rhsType);
- if (promotedRhsType != IClass.INT && promotedRhsType != IClass.LONG) {
- this.compileError(
- "Shift distance of type \"" + rhsType + "\" is not allowed",
- locatable.getLocation()
- );
- }
-
- if (promotedRhsType == IClass.LONG) this.writeOpcode(locatable, Opcode.L2I);
-
- this.writeOpcode(locatable, promotedLhsType == IClass.LONG ? iopcode + 1 : iopcode);
- type = promotedLhsType;
- }
- } while (operands.hasNext());
- return type;
- }
-
- throw new JaninoRuntimeException("Unexpected operator \"" + operator + "\"");
- }
-
- /**
- * @param type If non-null, the first operand with that type is already on the stack
- * @param operand The next operand
- * @param operands All following operands ({@link Iterator} over {@link Rvalue}s)
- */
- private IClass
- compileStringConcatenation(
- final Locatable locatable,
- IClass type,
- Rvalue operand,
- Iterator operands
- ) throws CompileException {
- boolean operandOnStack;
- if (type != null) {
- this.stringConversion(locatable, type);
- operandOnStack = true;
- } else
- {
- operandOnStack = false;
- }
-
- // Compute list of operands and merge consecutive constant operands.
- List tmp = new ArrayList();
- do {
- Object cv = this.getConstantValue(operand);
- if (cv == UnitCompiler.NOT_CONSTANT) {
- // Non-constant operand.
- final Rvalue finalOperand = operand;
- tmp.add(new Compilable() {
-
- @Override public void
- compile() throws CompileException {
- UnitCompiler.this.stringConversion(locatable, UnitCompiler.this.compileGetValue(finalOperand));
- }
- });
-
- operand = operands.hasNext() ? (Rvalue) operands.next() : null;
- } else
- {
- // Constant operand. Check to see whether the next operand is also constant.
- if (operands.hasNext()) {
- operand = (Rvalue) operands.next();
- Object cv2 = this.getConstantValue(operand);
- if (cv2 != UnitCompiler.NOT_CONSTANT) {
- StringBuilder sb = new StringBuilder(cv.toString()).append(cv2);
- for (;;) {
- if (!operands.hasNext()) {
- operand = null;
- break;
- }
- operand = (Rvalue) operands.next();
- Object cv3 = this.getConstantValue(operand);
- if (cv3 == UnitCompiler.NOT_CONSTANT) break;
- sb.append(cv3);
- }
- cv = sb.toString();
- }
- } else
- {
- operand = null;
- }
- // Break long string constants up into UTF8-able chunks.
- final String[] ss = UnitCompiler.makeUtf8Able(cv.toString());
- for (final String s : ss) {
- tmp.add(new Compilable() {
- @Override public void
- compile() throws CompileException { UnitCompiler.this.pushConstant(locatable, s); }
- });
- }
- }
- } while (operand != null);
-
- // At this point "tmp" contains an optimized sequence of Strings (representing constant portions) and Rvalues
- // (non-constant portions).
-
- if (tmp.size() <= (operandOnStack ? UnitCompiler.STRING_CONCAT_LIMIT - 1 : UnitCompiler.STRING_CONCAT_LIMIT)) {
-
- // String concatenation through "a.concat(b).concat(c)".
- for (Compilable c : tmp) {
- c.compile();
-
- // Concatenate.
- if (operandOnStack) {
- this.invoke(locatable, this.iClassLoader.METH_java_lang_String__concat__java_lang_String);
- } else
- {
- operandOnStack = true;
- }
- }
- return this.iClassLoader.TYPE_java_lang_String;
- }
-
- // String concatenation through "new StringBuilder(a).append(b).append(c).append(d).toString()".
- Iterator it = tmp.iterator();
-
- // "new StringBuilder(String a)":
- if (operandOnStack) {
- this.writeOpcode(locatable, Opcode.NEW);
- this.writeConstantClassInfo(Descriptor.JAVA_LANG_STRINGBUILDER);
- this.writeOpcode(locatable, Opcode.DUP_X1);
- this.writeOpcode(locatable, Opcode.SWAP);
- } else
- {
- this.writeOpcode(locatable, Opcode.NEW);
- this.writeConstantClassInfo(Descriptor.JAVA_LANG_STRINGBUILDER);
- this.writeOpcode(locatable, Opcode.DUP);
- ((Compilable) it.next()).compile();
- }
- this.invoke(locatable, this.iClassLoader.CTOR_java_lang_StringBuilder__java_lang_String);
-
- while (it.hasNext()) {
- ((Compilable) it.next()).compile();
-
- // "StringBuilder.append(String b)":
- this.invoke(locatable, this.iClassLoader.METH_java_lang_StringBuilder__append__java_lang_String);
- }
-
- // "StringBuilder.toString()":
- this.invoke(locatable, this.iClassLoader.METH_java_lang_StringBuilder__toString);
-
- return this.iClassLoader.TYPE_java_lang_String;
- }
-
- /** Helper interface for string conversion. */
- interface Compilable { void compile() throws CompileException; }
-
- /** Converts object of type "sourceType" to type "String" (JLS7 15.18.1.1). */
- private void
- stringConversion(Locatable locatable, IClass sourceType) throws CompileException {
- this.invoke(locatable, (
- sourceType == IClass.BYTE ? this.iClassLoader.METH_java_lang_String__valueOf__int :
- sourceType == IClass.SHORT ? this.iClassLoader.METH_java_lang_String__valueOf__int :
- sourceType == IClass.INT ? this.iClassLoader.METH_java_lang_String__valueOf__int :
- sourceType == IClass.LONG ? this.iClassLoader.METH_java_lang_String__valueOf__long :
- sourceType == IClass.FLOAT ? this.iClassLoader.METH_java_lang_String__valueOf__float :
- sourceType == IClass.DOUBLE ? this.iClassLoader.METH_java_lang_String__valueOf__double :
- sourceType == IClass.CHAR ? this.iClassLoader.METH_java_lang_String__valueOf__char :
- sourceType == IClass.BOOLEAN ? this.iClassLoader.METH_java_lang_String__valueOf__boolean :
- this.iClassLoader.METH_java_lang_String__valueOf__java_lang_Object
- ));
- }
-
- /**
- * Expects the object to initialize on the stack.
- *
- * Notice: This method is used both for explicit constructor invocation (first statement of a constructor body) and
- * implicit constructor invocation (right after NEW).
- *
- * @param optionalEnclosingInstance Used if the target class is an inner class
- */
- private void
- invokeConstructor(
- Locatable locatable,
- Scope scope,
- Rvalue optionalEnclosingInstance,
- IClass targetClass,
- Rvalue[] arguments
- ) throws CompileException {
- // Find constructors.
- IClass.IConstructor[] iConstructors = targetClass.getDeclaredIConstructors();
- if (iConstructors.length == 0) {
- throw new JaninoRuntimeException(
- "SNO: Target class \"" + targetClass.getDescriptor() + "\" has no constructors"
- );
- }
-
- IClass.IConstructor iConstructor = (IClass.IConstructor) this.findMostSpecificIInvocable(
- locatable, // l
- iConstructors, // iInvocables
- arguments, // arguments
- scope // contextScope
- );
-
- // Check exceptions that the constructor may throw.
- IClass[] thrownExceptions = iConstructor.getThrownExceptions();
- for (IClass te : thrownExceptions) {
- this.checkThrownException(locatable, te, scope);
- }
-
- // Pass enclosing instance as a synthetic parameter.
- if (optionalEnclosingInstance != null) {
- IClass outerIClass = targetClass.getOuterIClass();
- if (outerIClass != null) {
- IClass eiic = this.compileGetValue(optionalEnclosingInstance);
- if (!outerIClass.isAssignableFrom(eiic)) {
- this.compileError(
- "Type of enclosing instance (\"" + eiic + "\") is not assignable to \"" + outerIClass + "\"",
- locatable.getLocation()
- );
- }
- }
- }
-
- // Pass local variables to constructor as synthetic parameters.
- {
- IClass.IField[] syntheticFields = targetClass.getSyntheticIFields();
-
- // Determine enclosing function declarator and type declaration.
- TypeBodyDeclaration scopeTbd;
- TypeDeclaration scopeTypeDeclaration;
- {
- Scope s = scope;
- for (; !(s instanceof TypeBodyDeclaration); s = s.getEnclosingScope());
- scopeTbd = (TypeBodyDeclaration) s;
- scopeTypeDeclaration = scopeTbd.getDeclaringType();
- }
-
- if (!(scopeTypeDeclaration instanceof ClassDeclaration)) {
- if (syntheticFields.length > 0) {
- throw new JaninoRuntimeException("SNO: Target class has synthetic fields");
- }
- return;
- }
-
- ClassDeclaration scopeClassDeclaration = (ClassDeclaration) scopeTypeDeclaration;
- for (IClass.IField sf : syntheticFields) {
- if (!sf.getName().startsWith("val$")) continue;
- IClass.IField eisf = (IClass.IField) scopeClassDeclaration.syntheticFields.get(sf.getName());
- if (eisf != null) {
- if (scopeTbd instanceof MethodDeclarator) {
- this.load(locatable, this.resolve(scopeClassDeclaration), 0);
- this.getfield(locatable, eisf);
- } else
- if (scopeTbd instanceof ConstructorDeclarator) {
- ConstructorDeclarator constructorDeclarator = (ConstructorDeclarator) scopeTbd;
- LocalVariable syntheticParameter = (
- (LocalVariable) constructorDeclarator.syntheticParameters.get(sf.getName())
- );
- if (syntheticParameter == null) {
- this.compileError((
- "Compiler limitation: Constructor cannot access local variable \""
- + sf.getName().substring(4)
- + "\" declared in an enclosing block because none of the methods accesses it. "
- + "As a workaround, declare a dummy method that accesses the local variable."
- ), locatable.getLocation());
- this.writeOpcode(locatable, Opcode.ACONST_NULL);
- } else {
- this.load(locatable, syntheticParameter);
- }
- } else
- if (scopeTbd instanceof FieldDeclaration) {
- this.compileError((
- "Compiler limitation: Field initializers cannot access local variable \""
- + sf.getName().substring(4)
- + "\" declared in an enclosing block because none of the methods accesses it. "
- + "As a workaround, declare a dummy method that accesses the local variable."
- ), locatable.getLocation());
- this.writeOpcode(scopeTbd, Opcode.ACONST_NULL);
- } else
- {
- throw new AssertionError(scopeTbd);
- }
- } else {
- String localVariableName = sf.getName().substring(4);
- LocalVariable lv;
- DETERMINE_LV: {
- Scope s;
-
- // Does one of the enclosing blocks declare a local variable with that name?
- for (s = scope; s instanceof BlockStatement; s = s.getEnclosingScope()) {
- BlockStatement bs = (BlockStatement) s;
- Scope es = bs.getEnclosingScope();
-
- List extends BlockStatement> statements;
- if (es instanceof Block) {
- statements = ((Block) es).statements;
- } else
- if (es instanceof FunctionDeclarator) {
- statements = ((FunctionDeclarator) es).optionalStatements;
- } else
- if (es instanceof ForEachStatement) {
- FunctionDeclarator.FormalParameter fp = ((ForEachStatement) es).currentElement;
- if (fp.name.equals(localVariableName)) {
- lv = this.getLocalVariable(fp);
- break DETERMINE_LV;
- }
- continue;
- } else
- {
- continue;
- }
-
- for (BlockStatement bs2 : statements) {
- if (bs2 == bs) break;
- if (bs2 instanceof LocalVariableDeclarationStatement) {
- LocalVariableDeclarationStatement lvds = (
- (LocalVariableDeclarationStatement) bs2
- );
- for (VariableDeclarator vd : lvds.variableDeclarators) {
- if (vd.name.equals(localVariableName)) {
- lv = this.getLocalVariable(lvds, vd);
- break DETERMINE_LV;
- }
- }
- }
- }
- }
-
- // Does the declaring function declare a parameter with that name?
- while (!(s instanceof FunctionDeclarator)) s = s.getEnclosingScope();
- FunctionDeclarator fd = (FunctionDeclarator) s;
- for (FormalParameter fp : fd.formalParameters.parameters) {
- if (fp.name.equals(localVariableName)) {
- lv = this.getLocalVariable(fp);
- break DETERMINE_LV;
- }
- }
- throw new JaninoRuntimeException(
- "SNO: Synthetic field \""
- + sf.getName()
- + "\" neither maps a synthetic field of an enclosing instance nor a local variable"
- );
- }
- this.load(locatable, lv);
- }
- }
- }
-
- // Evaluate constructor arguments.
- Rvalue[] adjustedArgs = null;
- IClass[] parameterTypes = iConstructor.getParameterTypes();
- int actualSize = arguments.length;
- if (iConstructor.isVarargs() && iConstructor.argsNeedAdjust()) {
- adjustedArgs = new Rvalue[parameterTypes.length];
- Rvalue[] lastArgs = new Rvalue[actualSize - parameterTypes.length + 1];
- for (int i = 0, j = parameterTypes.length - 1; i < lastArgs.length; ++i, ++j) {
- lastArgs[i] = arguments[j];
- }
-
- for (int i = parameterTypes.length - 2; i >= 0; --i) {
- adjustedArgs[i] = arguments[i];
- }
- Location loc = (lastArgs.length == 0 ? locatable : lastArgs[lastArgs.length - 1]).getLocation();
- adjustedArgs[adjustedArgs.length - 1] = new NewInitializedArray(
- loc, // location
- parameterTypes[parameterTypes.length - 1], // arrayIClass
- new ArrayInitializer(loc, lastArgs) // arrayInitializer
- );
- arguments = adjustedArgs;
- }
-
- for (int i = 0; i < arguments.length; ++i) {
- this.assignmentConversion(
- locatable, // locatable
- this.compileGetValue(arguments[i]), // sourceType
- parameterTypes[i], // targetType
- this.getConstantValue(arguments[i]) // optionalConstantValue
- );
- }
-
- // Invoke!
- // Notice that the method descriptor is "iConstructor.getDescriptor()" prepended with the synthetic parameters.
- this.invoke(locatable, iConstructor);
- }
-
- /** @return The {@link IField}s that are declared by the {@code fieldDeclaration} */
- private IClass.IField[]
- getIFields(final FieldDeclaration fieldDeclaration) {
- IClass.IField[] res = new IClass.IField[fieldDeclaration.variableDeclarators.length];
- for (int i = 0; i < res.length; ++i) {
- final VariableDeclarator variableDeclarator = fieldDeclaration.variableDeclarators[i];
- res[i] = this.resolve(fieldDeclaration.getDeclaringType()).new IField() {
-
- // Implement IMember.
- @Override public Access
- getAccess() {
- switch (fieldDeclaration.modifiers.flags & Mod.PPP) {
- case Mod.PRIVATE:
- return Access.PRIVATE;
- case Mod.PROTECTED:
- return Access.PROTECTED;
- case Mod.PACKAGE:
- return Access.DEFAULT;
- case Mod.PUBLIC:
- return Access.PUBLIC;
- default:
- throw new JaninoRuntimeException("Invalid access");
- }
- }
-
- @Override public Annotation[]
- getAnnotations() { return fieldDeclaration.modifiers.annotations; }
-
- // Implement "IField".
-
- @Override public boolean
- isStatic() { return Mod.isStatic(fieldDeclaration.modifiers.flags); }
-
- @Override public IClass
- getType() throws CompileException {
- return UnitCompiler.this.getType(fieldDeclaration.type).getArrayIClass(
- variableDeclarator.brackets,
- UnitCompiler.this.iClassLoader.TYPE_java_lang_Object
- );
- }
-
- @Override public String
- getName() { return variableDeclarator.name; }
-
- @Override public Object
- getConstantValue() throws CompileException {
- if (
- Mod.isFinal(fieldDeclaration.modifiers.flags)
- && variableDeclarator.optionalInitializer instanceof Rvalue
- ) {
- Object constantInitializerValue = UnitCompiler.this.getConstantValue(
- (Rvalue) variableDeclarator.optionalInitializer
- );
- if (constantInitializerValue != UnitCompiler.NOT_CONSTANT) {
- return UnitCompiler.this.assignmentConversion(
- variableDeclarator.optionalInitializer, // locatable
- constantInitializerValue, // value
- this.getType() // targetType
- );
- }
- }
- return UnitCompiler.NOT_CONSTANT;
- }
- };
- }
- return res;
- }
-
- /**
- * Determine the non-constant-final initializer of the given {@link VariableDeclarator}.
- *
- * @return {@code null} if the variable is declared without an initializer or if the initializer is
- * constant-final
- */
- ArrayInitializerOrRvalue
- getNonConstantFinalInitializer(FieldDeclaration fd, VariableDeclarator vd) throws CompileException {
-
- // Check if optional initializer exists.
- if (vd.optionalInitializer == null) return null;
-
- // Check if initializer is constant-final.
- if (
- Mod.isStatic(fd.modifiers.flags)
- && Mod.isFinal(fd.modifiers.flags)
- && vd.optionalInitializer instanceof Rvalue
- && this.getConstantValue((Rvalue) vd.optionalInitializer) != UnitCompiler.NOT_CONSTANT
- ) return null;
-
- return vd.optionalInitializer;
- }
-
- private Atom
- reclassify(AmbiguousName an) throws CompileException {
- if (an.reclassified == null) {
- an.reclassified = this.reclassifyName(
- an.getLocation(),
- an.getEnclosingBlockStatement(),
- an.identifiers, an.n
- );
- }
- return an.reclassified;
- }
-
- /** Reclassifies the ambiguous name consisting of the first {@code n} of the {@code identifiers} (JLS7 6.5.2.2). */
- private Atom
- reclassifyName(Location location, Scope scope, final String[] identifiers, int n) throws CompileException {
-
- if (n == 1) return this.reclassifyName(
- location,
- scope,
- identifiers[0]
- );
-
- // 6.5.2.2
- Atom lhs = this.reclassifyName(
- location,
- scope,
- identifiers, n - 1
- );
- String rhs = identifiers[n - 1];
-
- // 6.5.2.2.1
- if (UnitCompiler.DEBUG) System.out.println("lhs = " + lhs);
- if (lhs instanceof Package) {
- String className = ((Package) lhs).name + '.' + rhs;
- IClass result = this.findTypeByName(location, className);
- if (result != null) return new SimpleType(location, result);
-
- return new Package(location, className);
- }
-
- // 6.5.2.2.3.2 EXPRESSION.length
- if ("length".equals(rhs) && this.getType(lhs).isArray()) {
- ArrayLength al = new ArrayLength(location, this.toRvalueOrCompileException(lhs));
- if (!(scope instanceof BlockStatement)) {
- this.compileError("\".length\" only allowed in expression context");
- return al;
- }
- al.setEnclosingBlockStatement((BlockStatement) scope);
- return al;
- }
-
- IClass lhsType = this.getType(lhs);
-
- // Notice: Don't need to check for 6.5.2.2.2.1 TYPE.METHOD and 6.5.2.2.3.1 EXPRESSION.METHOD here because that
- // has been done before.
-
- {
- IClass.IField field = this.findIField(lhsType, rhs, location);
- if (field != null) {
- // 6.5.2.2.2.2 TYPE.FIELD
- // 6.5.2.2.3.2 EXPRESSION.FIELD
- FieldAccess fa = new FieldAccess(
- location,
- lhs,
- field
- );
- fa.setEnclosingBlockStatement((BlockStatement) scope);
- return fa;
- }
- }
-
- IClass[] classes = lhsType.getDeclaredIClasses();
- for (final IClass memberType : classes) {
- String name = Descriptor.toClassName(memberType.getDescriptor());
- name = name.substring(name.lastIndexOf('$') + 1);
- if (name.equals(rhs)) {
-
- // 6.5.2.2.2.3 TYPE.TYPE
- // 6.5.2.2.3.3 EXPRESSION.TYPE
- return new SimpleType(location, memberType);
- }
- }
-
- this.compileError(
- "\"" + rhs + "\" is neither a method, a field, nor a member class of \"" + lhsType + "\"",
- location
- );
- return new Atom(location) {
- @Override public String toString() { return Java.join(identifiers, "."); }
- @Override public final void accept(AtomVisitor visitor) {}
- };
- }
-
- /**
- * Find the named {@link IClass} in this compilation unit, or through the {@link #iClassLoader}.
- *
- * @param className Fully qualified class name, e.g. "pkg1.pkg2.Outer$Inner".
- * @return {@code null} iff an {@code IClass} with that name could not be loaded
- * @throws CompileException An exception was raised while loading the {@link IClass}
- */
- private IClass
- findTypeByName(Location location, String className) throws CompileException {
-
- // Is the type defined in the same compilation unit?
- IClass res = this.findClass(className);
- if (res != null) return res;
-
- try {
- return this.iClassLoader.loadIClass(Descriptor.fromClassName(className));
- } catch (ClassNotFoundException ex) {
- // SUPPRESS CHECKSTYLE AvoidHidingCause
- if (ex.getException() instanceof CompileException) throw (CompileException) ex.getException();
- throw new CompileException(className, location, ex);
- }
- }
-
- /** JLS7 6.5.2.1 */
- private Atom
- reclassifyName(Location location, Scope scope, final String identifier) throws CompileException {
-
- // Determine scope block statement, type body declaration, type and compilation unit.
- TypeBodyDeclaration scopeTbd = null;
- AbstractTypeDeclaration scopeTypeDeclaration = null;
- CompilationUnit scopeCompilationUnit;
- {
- Scope s = scope;
- while (
- (s instanceof BlockStatement || s instanceof CatchClause)
- && !(s instanceof TypeBodyDeclaration)
- ) s = s.getEnclosingScope();
- if (s instanceof TypeBodyDeclaration) {
- scopeTbd = (TypeBodyDeclaration) s;
- s = s.getEnclosingScope();
- }
- if (s instanceof TypeDeclaration) {
- scopeTypeDeclaration = (AbstractTypeDeclaration) s;
- s = s.getEnclosingScope();
- }
- while (!(s instanceof CompilationUnit)) s = s.getEnclosingScope();
- scopeCompilationUnit = (CompilationUnit) s;
- }
-
- // 6.5.2.1.BL1
-
- // 6.5.2.BL1.B1.B1.1 (JLS7: 6.5.2.BL1.B1.B1.1) / 6.5.6.1.1 Local variable.
- // 6.5.2.BL1.B1.B1.2 (JLS7: 6.5.2.BL1.B1.B1.2) / 6.5.6.1.1 Parameter.
- {
- Scope s = scope;
- if (s instanceof BlockStatement) {
- BlockStatement bs = (BlockStatement) s;
- LocalVariable lv = bs.findLocalVariable(identifier);
- if (lv != null) {
- LocalVariableAccess lva = new LocalVariableAccess(location, lv);
- lva.setEnclosingBlockStatement(bs);
- return lva;
- }
- s = s.getEnclosingScope();
- }
- while (s instanceof BlockStatement || s instanceof CatchClause) s = s.getEnclosingScope();
- if (s instanceof FunctionDeclarator) {
- s = s.getEnclosingScope();
- }
- if (s instanceof InnerClassDeclaration) {
- InnerClassDeclaration icd = (InnerClassDeclaration) s; // SUPPRESS CHECKSTYLE UsageDistance
-
- s = s.getEnclosingScope();
- if (s instanceof AnonymousClassDeclaration) {
- s = s.getEnclosingScope();
- } else
- if (s instanceof FieldDeclaration) {
- s = s.getEnclosingScope().getEnclosingScope();
- }
- while (s instanceof BlockStatement) {
- LocalVariable lv = ((BlockStatement) s).findLocalVariable(identifier);
- if (lv != null) {
- if (!lv.finaL) {
- this.compileError(
- "Cannot access non-final local variable \""
- + identifier
- + "\" from inner class"
- );
- }
- final IClass lvType = lv.type;
- IClass.IField iField = new SimpleIField(
- this.resolve(icd),
- "val$" + identifier,
- lvType
- );
- icd.defineSyntheticField(iField);
- FieldAccess fa = new FieldAccess(
- location, // location
- new QualifiedThisReference( // lhs
- location, // location
- new SimpleType(location, this.resolve(icd)) // qualification
- ),
- iField // field
- );
- fa.setEnclosingBlockStatement((BlockStatement) scope);
- return fa;
- }
- s = s.getEnclosingScope();
- while (s instanceof BlockStatement) s = s.getEnclosingScope();
- if (!(s instanceof FunctionDeclarator)) break;
- s = s.getEnclosingScope();
- if (!(s instanceof InnerClassDeclaration)) break;
- icd = (InnerClassDeclaration) s;
- s = s.getEnclosingScope();
- }
- }
- }
-
- // 6.5.2.BL1.B1.B1.3 (JLS7: 6.5.2.BL1.B1.B1.3) / 6.5.6.1.2.1 Field.
- BlockStatement enclosingBlockStatement = null;
- for (Scope s = scope; !(s instanceof CompilationUnit); s = s.getEnclosingScope()) {
- if (s instanceof BlockStatement && enclosingBlockStatement == null) {
- enclosingBlockStatement = (BlockStatement) s;
- }
- if (s instanceof TypeDeclaration) {
- final AbstractTypeDeclaration enclosingTypeDecl = (AbstractTypeDeclaration) s;
- final IClass etd = this.resolve(enclosingTypeDecl);
- final IClass.IField f = this.findIField(etd, identifier, location);
- if (f != null) {
- if (f.isStatic()) {
- this.warning("IASF", (
- "Implicit access to static field \""
- + identifier
- + "\" of declaring class (better write \""
- + f.getDeclaringIClass()
- + '.'
- + f.getName()
- + "\")"
- ), location);
- } else
- if (f.getDeclaringIClass() == etd) {
- this.warning("IANSF", (
- "Implicit access to non-static field \""
- + identifier
- + "\" of declaring class (better write \"this."
- + f.getName()
- + "\")"
- ), location);
- } else {
- this.warning("IANSFEI", (
- "Implicit access to non-static field \""
- + identifier
- + "\" of enclosing instance (better write \""
- + f.getDeclaringIClass()
- + ".this."
- + f.getName()
- + "\")"
- ), location);
- }
-
- SimpleType ct = new SimpleType(scopeTypeDeclaration.getLocation(), etd);
- Atom lhs;
- if (scopeTbd.isStatic()) {
-
- // Field access in static method context.
- lhs = ct;
- } else
- {
-
- // Field access in non-static method context.
- if (f.isStatic()) {
-
- // Access to static field.
- lhs = ct;
- } else {
-
- // Access to non-static field.
- lhs = new QualifiedThisReference(location, ct);
- }
- }
- Rvalue res = new FieldAccess(
- location,
- lhs,
- f
- );
- res.setEnclosingBlockStatement(enclosingBlockStatement);
- return res;
- }
- }
- }
-
- // JLS7 6.5.2.BL1.B2.1 Static field imported through single static import.
- {
- List l = (List) this.singleStaticImports.get(identifier);
- if (l != null) {
- for (Object o : l) {
- if (o instanceof IField) {
- FieldAccess fieldAccess = new FieldAccess(
- location,
- new SimpleType(location, ((IField) o).getDeclaringIClass()),
- (IField) o
- );
- fieldAccess.setEnclosingBlockStatement(enclosingBlockStatement);
- return fieldAccess;
- }
- }
- }
- }
-
- // JLS7 6.5.2.BL1.B2.2 Static field imported through static-import-on-demand.
- {
- IField importedField = null;
- for (IClass iClass : this.staticImportsOnDemand) {
-
- IField f = iClass.getDeclaredIField(identifier);
- if (f != null) {
-
- // JLS7 7.5.4 Static-Import-on-Demand Declaration
- if (!this.isAccessible(f, enclosingBlockStatement)) continue;
-
- if (importedField != null) {
- this.compileError(
- "Ambiguous static field import: \""
- + importedField.toString()
- + "\" vs. \""
- + f.toString()
- + "\""
- );
- }
- importedField = f;
- }
- }
- if (importedField != null) {
- if (!importedField.isStatic()) this.compileError("Cannot static-import non-static field");
- FieldAccess fieldAccess = new FieldAccess(
- location,
- new SimpleType(location, importedField.getDeclaringIClass()),
- importedField
- );
- fieldAccess.setEnclosingBlockStatement(enclosingBlockStatement);
- return fieldAccess;
- }
- }
-
- // Hack: "java" MUST be a package, not a class.
- if ("java".equals(identifier)) return new Package(location, identifier);
-
- // JLS7: 6.5.2.BL1.B3.1 Unnamed package class
- // JLS7: 6.5.2.BL1.B3.2 Unnamed package interface
- // JLS7: 7.4.2
- {
- IClass unnamedPackageType = this.findTypeByName(location, identifier);
- if (unnamedPackageType != null) return new SimpleType(location, unnamedPackageType);
- }
-
- // 6.5.2.BL1.B1.B2.1 (JLS7: 6.5.2.BL1.B3.3) Local class.
- {
- LocalClassDeclaration lcd = UnitCompiler.findLocalClassDeclaration(scope, identifier);
- if (lcd != null) return new SimpleType(location, this.resolve(lcd));
- }
-
- // 6.5.2.BL1.B1.B2.2 (JLS7: 6.5.2.BL1.B3.4) Member type.
- if (scopeTypeDeclaration != null) {
- IClass memberType = this.findMemberType(
- this.resolve(scopeTypeDeclaration),
- identifier,
- location
- );
- if (memberType != null) return new SimpleType(location, memberType);
- }
-
- // 6.5.2.BL1.B1.B3.1 (JLS7: 6.5.2.BL1.B1.B4.1) Single type import.
- {
- IClass iClass = this.importSingleType(identifier, location);
- if (iClass != null) return new SimpleType(location, iClass);
- }
-
- // 6.5.2.BL1.B1.B3.2 (JLS7: 6.5.2.BL1.B1.B3.1) Package member class/interface declared in this compilation
- // unit.
- // Notice that JLS2 looks this up AFTER local class, member type, single type import, while JLS3 looks this up
- // BEFORE local class, member type, single type import.
- {
- PackageMemberTypeDeclaration pmtd = scopeCompilationUnit.getPackageMemberTypeDeclaration(identifier);
- if (pmtd != null) return new SimpleType(location, this.resolve(pmtd));
- }
-
- // 6.5.2.BL1.B1.B4 Class or interface declared in same package.
- // Notice: Why is this missing in JLS3?
- {
- String className = (
- scopeCompilationUnit.optionalPackageDeclaration == null
- ? identifier
- : scopeCompilationUnit.optionalPackageDeclaration.packageName + '.' + identifier
- );
- IClass result = this.findTypeByName(location, className);
- if (result != null) return new SimpleType(location, result);
- }
-
- // 6.5.2.BL1.B1.B5 (JLS7: 6.5.2.BL1.B1.B4.2), 6.5.2.BL1.B1.B6 Type-import-on-demand.
- {
- IClass importedClass = this.importTypeOnDemand(identifier, location);
- if (importedClass != null) {
- return new SimpleType(location, importedClass);
- }
- }
-
- // JLS7 6.5.2.BL1.B1.B4.3 Type imported through single static import.
- {
- List l = (List) this.singleStaticImports.get(identifier);
- if (l != null) {
- for (Object o : l) {
- if (o instanceof IClass) return new SimpleType(null, (IClass) o);
- }
- }
- }
-
- // JLS7 6.5.2.BL1.B1.B4.4 Type imported through static-import-on-demand.
- {
- IClass importedType = null;
- for (IClass ic : this.staticImportsOnDemand) {
- IClass[] memberTypes = ic.getDeclaredIClasses();
- for (IClass memberType : memberTypes) {
- if (!this.isAccessible(memberType, scope)) continue;
- if (memberType.getDescriptor().endsWith('$' + identifier + ';')) {
- if (importedType != null) {
- this.compileError(
- "Ambiguous static type import: \""
- + importedType.toString()
- + "\" vs. \""
- + memberType.toString()
- + "\""
- );
- }
- importedType = memberType;
- }
- }
- }
- if (importedType != null) return new SimpleType(null, importedType);
- }
-
- // 6.5.2.BL1.B1.B7 Package name
- return new Package(location, identifier);
- }
-
- private void
- determineValue(FieldAccessExpression fae) throws CompileException {
- if (fae.value != null) return;
-
- IClass lhsType = this.getType(fae.lhs);
-
- if (fae.fieldName.equals("length") && lhsType.isArray()) {
- fae.value = new ArrayLength(
- fae.getLocation(),
- this.toRvalueOrCompileException(fae.lhs)
- );
- } else {
- IClass.IField iField = this.findIField(lhsType, fae.fieldName, fae.getLocation());
- if (iField == null) {
- this.compileError(
- "\"" + this.getType(fae.lhs).toString() + "\" has no field \"" + fae.fieldName + "\"",
- fae.getLocation()
- );
- fae.value = new Rvalue(fae.getLocation()) {
- @Override public String toString() { return "???"; }
- @Override public void accept(AtomVisitor visitor) {}
- @Override public void accept(RvalueVisitor visitor) {}
- @Override public void accept(ElementValueVisitor visitor) {}
- };
- return;
- }
-
- fae.value = new FieldAccess(
- fae.getLocation(),
- fae.lhs,
- iField
- );
- }
- fae.value.setEnclosingBlockStatement(fae.getEnclosingBlockStatement());
- }
-
- /** "super.fld", "Type.super.fld" */
- private void
- determineValue(SuperclassFieldAccessExpression scfae) throws CompileException {
- if (scfae.value != null) return;
-
- Rvalue lhs;
- {
- ThisReference tr = new ThisReference(scfae.getLocation());
- tr.setEnclosingBlockStatement(scfae.getEnclosingBlockStatement());
- IClass type;
- if (scfae.optionalQualification != null) {
- type = this.getType(scfae.optionalQualification);
- } else
- {
- type = this.getType(tr);
- }
- lhs = new Cast(scfae.getLocation(), new SimpleType(scfae.getLocation(), type.getSuperclass()), tr);
- }
-
- IClass.IField iField = this.findIField(this.getType(lhs), scfae.fieldName, scfae.getLocation());
- if (iField == null) {
- this.compileError("Class has no field \"" + scfae.fieldName + "\"", scfae.getLocation());
- scfae.value = new Rvalue(scfae.getLocation()) {
- @Override public String toString() { return "???"; }
- @Override public void accept(AtomVisitor visitor) {}
- @Override public void accept(RvalueVisitor visitor) {}
- @Override public void accept(ElementValueVisitor visitor) {}
- };
- return;
- }
- scfae.value = new FieldAccess(
- scfae.getLocation(),
- lhs,
- iField
- );
- scfae.value.setEnclosingBlockStatement(scfae.getEnclosingBlockStatement());
- }
-
- /**
- * Find named methods of "targetType", examine the argument types and choose the most specific method. Check that
- * only the allowed exceptions are thrown.
- *
- * Notice that the returned {@link IClass.IMethod} may be declared in an enclosing type.
- *
- * @return The selected {@link IClass.IMethod} or {@code null}
- */
- public IClass.IMethod
- findIMethod(MethodInvocation mi) throws CompileException {
- IClass.IMethod iMethod;
- FIND_METHOD: {
-
- if (mi.optionalTarget == null) {
-
- // Method invocation by simple method name... method must be declared by an enclosing type declaration.
- for (
- Scope s = mi.getEnclosingBlockStatement();
- !(s instanceof CompilationUnit);
- s = s.getEnclosingScope()
- ) {
- if (s instanceof TypeDeclaration) {
- TypeDeclaration td = (TypeDeclaration) s;
-
- // Find methods with specified name.
- iMethod = this.findIMethod(
- this.resolve(td), // targetType
- mi // invocation
- );
- if (iMethod != null) break FIND_METHOD;
- }
- }
- } else
- {
-
- // Method invocation by "target": "expr.meth(arguments)" -- method must be declared by the target's
- // type.
- iMethod = this.findIMethod(
- this.getType(mi.optionalTarget), // targetType
- mi // invocable
- );
- if (iMethod != null) break FIND_METHOD;
- }
-
- // Static method declared through single static import?
- {
- List l = (List) this.singleStaticImports.get(mi.methodName);
- if (l != null) {
- iMethod = null;
- for (Object o : l) {
- if (o instanceof IMethod) {
- IClass declaringIClass = ((IMethod) o).getDeclaringIClass();
- IMethod im = this.findIMethod(
- declaringIClass, // targetType
- mi // invocable
- );
- if (im != null) {
- if (iMethod != null && iMethod != im) {
- this.compileError(
- "Ambiguous static method import: \""
- + iMethod.toString()
- + "\" vs. \""
- + im.toString()
- + "\""
- );
- }
- iMethod = im;
- }
- }
- }
- if (iMethod != null) break FIND_METHOD;
- }
- }
-
- // Static method declared through static-import-on-demand?
- iMethod = null;
- for (IClass iClass : this.staticImportsOnDemand) {
- IMethod im = this.findIMethod(
- iClass, // targetType
- mi // invocation
- );
- if (im != null) {
- if (iMethod != null) {
- this.compileError(
- "Ambiguous static method import: \""
- + iMethod.toString()
- + "\" vs. \""
- + im.toString()
- + "\""
- );
- }
- iMethod = im;
- }
- }
- if (iMethod != null) break FIND_METHOD;
-
- this.compileError((
- "A method named \""
- + mi.methodName
- + "\" is not declared in any enclosing class nor any supertype, nor through a static import"
- ), mi.getLocation());
- return this.fakeIMethod(this.iClassLoader.TYPE_java_lang_Object, mi.methodName, mi.arguments);
- }
-
- this.checkThrownExceptions(mi, iMethod);
- return iMethod;
- }
-
- /**
- * Find a {@link IClass.IMethod} in the given {@code targetType}, its superclasses or superinterfaces with the
- * given {@code name} and for the given {@code arguments}. If more than one such method exists, choose the most
- * specific one (JLS7 15.11.2).
- *
- * @return {@code null} if no appropriate method could be found
- */
- private IClass.IMethod
- findIMethod(IClass targetType, Invocation invocation) throws CompileException {
-
- // Get all methods.
- List ms = new ArrayList();
- this.getIMethods(targetType, invocation.methodName, ms);
-
- // Interfaces inherit the methods declared in 'Object'.
- if (targetType.isInterface()) {
- IClass.IMethod[] oms = this.iClassLoader.TYPE_java_lang_Object.getDeclaredIMethods(invocation.methodName);
- for (IMethod om : oms) {
- if (!om.isStatic() && om.getAccess() == Access.PUBLIC) ms.add(om);
- }
- }
-
- if (ms.size() == 0) return null;
-
- // Determine arguments' types, choose the most specific method.
- return (IClass.IMethod) this.findMostSpecificIInvocable(
- invocation, // locatable
- (IClass.IMethod[]) ms.toArray(new IClass.IMethod[ms.size()]), // iInvocables
- invocation.arguments, // arguments
- invocation.getEnclosingBlockStatement() // contextScope
- );
- }
-
- private IMethod
- fakeIMethod(IClass targetType, final String name, Rvalue[] arguments) throws CompileException {
- final IClass[] pts = new IClass[arguments.length];
- for (int i = 0; i < arguments.length; ++i) pts[i] = this.getType(arguments[i]);
- return targetType.new IMethod() {
- @Override public String getName() { return name; }
- @Override public IClass getReturnType() { return IClass.INT; }
- @Override public boolean isStatic() { return false; }
- @Override public boolean isAbstract() { return false; }
- @Override public boolean isVarargs() { return false; }
- @Override public IClass[] getParameterTypes2() { return pts; }
- @Override public IClass[] getThrownExceptions2() { return new IClass[0]; }
- @Override public Access getAccess() { return Access.PUBLIC; }
- @Override public Annotation[] getAnnotations() { return new Annotation[0]; }
- };
- }
-
- /**
- * Add all methods with the given {@code methodName} that are declared by the {@code type}, its superclasses and
- * all their superinterfaces to the result list {@code v}.
- */
- public void
- getIMethods(IClass type, String methodName, List v) throws CompileException {
-
- // Check methods declared by this type.
- {
- IClass.IMethod[] ims = type.getDeclaredIMethods(methodName);
- for (IMethod im : ims) v.add(im);
- }
-
- // Check superclass.
- IClass superclass = type.getSuperclass();
- if (superclass != null) this.getIMethods(superclass, methodName, v);
-
- // Check superinterfaces.
- IClass[] interfaces = type.getInterfaces();
- for (IClass interfacE : interfaces) this.getIMethods(interfacE, methodName, v);
- }
-
- /** @return The {@link IClass.IMethod} that implements the {@code superclassMethodInvocation} */
- public IClass.IMethod
- findIMethod(SuperclassMethodInvocation superclassMethodInvocation) throws CompileException {
- ClassDeclaration declaringClass;
- for (Scope s = superclassMethodInvocation.getEnclosingBlockStatement();; s = s.getEnclosingScope()) {
- if (s instanceof FunctionDeclarator) {
- FunctionDeclarator fd = (FunctionDeclarator) s;
- if (Mod.isStatic(fd.modifiers.flags)) {
- this.compileError(
- "Superclass method cannot be invoked in static context",
- superclassMethodInvocation.getLocation()
- );
- }
- }
- if (s instanceof ClassDeclaration) {
- declaringClass = (ClassDeclaration) s;
- break;
- }
- }
- IClass superclass = this.resolve(declaringClass).getSuperclass();
- IMethod iMethod = this.findIMethod(
- superclass, // targetType
- superclassMethodInvocation // invocation
- );
- if (iMethod == null) {
- this.compileError(
- "Class \"" + superclass + "\" has no method named \"" + superclassMethodInvocation.methodName + "\"",
- superclassMethodInvocation.getLocation()
- );
- return this.fakeIMethod(
- superclass,
- superclassMethodInvocation.methodName,
- superclassMethodInvocation.arguments
- );
- }
- this.checkThrownExceptions(superclassMethodInvocation, iMethod);
- return iMethod;
- }
-
- /**
- * Determine the arguments' types, determine the applicable invocables and choose the most specific invocable
- * and adjust arguments as needed (for varargs case).
- *
- * @param iInvocables Length must be greater than zero
- * @return The selected {@link IClass.IInvocable}
- */
- private IClass.IInvocable
- findMostSpecificIInvocable(
- Locatable locatable,
- final IInvocable[] iInvocables,
- final Rvalue[] arguments,
- Scope contextScope
- ) throws CompileException {
-
- // Determine arguments' types.
- final IClass[] argumentTypes = new IClass[arguments.length];
- for (int i = 0; i < arguments.length; ++i) {
- argumentTypes[i] = this.getType(arguments[i]);
- }
-
- // Determine most specific invocable WITHOUT boxing.
- IInvocable ii = this.findMostSpecificIInvocable(locatable, iInvocables, argumentTypes, false, contextScope);
- if (ii != null) return ii;
-
- // Determine most specific invocable WITH boxing.
- ii = this.findMostSpecificIInvocable(locatable, iInvocables, argumentTypes, true, contextScope);
- if (ii != null) return ii;
-
- // Report a nice compile error.
- StringBuilder sb = new StringBuilder("No applicable constructor/method found for ");
- if (argumentTypes.length == 0) {
- sb.append("zero actual parameters");
- } else {
- sb.append("actual parameters \"").append(argumentTypes[0]);
- for (int i = 1; i < argumentTypes.length; ++i) {
- sb.append(", ").append(argumentTypes[i]);
- }
- sb.append("\"");
- }
- sb.append("; candidates are: ").append('"' + iInvocables[0].toString() + '"');
- for (int i = 1; i < iInvocables.length; ++i) {
- sb.append(", ").append('"' + iInvocables[i].toString() + '"');
- }
- this.compileError(sb.toString(), locatable.getLocation());
-
- // Well, returning a "fake" IInvocable is a bit tricky, because the iInvocables can be of different types.
- if (iInvocables[0] instanceof IClass.IConstructor) {
- return iInvocables[0].getDeclaringIClass().new IConstructor() {
- @Override public boolean isVarargs() { return false; }
- @Override public IClass[] getParameterTypes2() { return argumentTypes; }
- @Override public Access getAccess() { return Access.PUBLIC; }
- @Override public IClass[] getThrownExceptions2() { return new IClass[0]; }
- @Override public Annotation[] getAnnotations() { return new Annotation[0]; }
- };
- } else
- if (iInvocables[0] instanceof IClass.IMethod) {
- final String methodName = ((IClass.IMethod) iInvocables[0]).getName();
- return iInvocables[0].getDeclaringIClass().new IMethod() {
- @Override public boolean isStatic() { return true; }
- @Override public boolean isAbstract() { return false; }
- @Override public IClass getReturnType() { return IClass.INT; }
- @Override public String getName() { return methodName; }
- @Override public Access getAccess() { return Access.PUBLIC; }
- @Override public boolean isVarargs() { return false; }
- @Override public IClass[] getParameterTypes2() { return argumentTypes; }
- @Override public IClass[] getThrownExceptions2() { return new IClass[0]; }
- @Override public Annotation[] getAnnotations() { return new Annotation[0]; }
- };
- } else
- {
- return iInvocables[0];
- }
- }
-
- /**
- * Determine the applicable invocables and choose the most specific invocable.
- *
- * @return The maximally specific {@link IClass.IInvocable} or {@code null} if no {@link IClass.IInvocable} is
- * applicable
- */
- public IClass.IInvocable
- findMostSpecificIInvocable(
- Locatable locatable,
- final IInvocable[] iInvocables,
- IClass[] argumentTypes,
- boolean boxingPermitted,
- Scope contextScope
- ) throws CompileException {
-
- if (UnitCompiler.DEBUG) {
- System.out.println("Argument types:");
- for (IClass argumentType : argumentTypes) System.out.println(argumentType);
- }
-
- // Select applicable methods (15.12.2.1).
- List applicableIInvocables = new ArrayList();
- List varargApplicables = new ArrayList();
-
- NEXT_METHOD:
- for (IClass.IInvocable ii : iInvocables) {
- boolean argsNeedAdjust = false;
-
- // Ignore inaccessible invocables.
- if (!this.isAccessible(ii, contextScope)) continue;
-
- // Check parameter count.
- final IClass[] parameterTypes = ii.getParameterTypes();
- int formalParamCount = parameterTypes.length;
- int nUncheckedArg = argumentTypes.length;
- final boolean isVarargs = ii.isVarargs();
-
- // Match the last formal parameter with all args starting from that index (or none).
- VARARGS:
- if (isVarargs) {
-
- // Decrement the count to get the index.
- formalParamCount--;
- final IClass lastParamType = parameterTypes[formalParamCount].getComponentType();
- final int lastActualArg = nUncheckedArg - 1;
-
- // If the two have the same argCount and the last actual arg is an array of the same type accept it
- // (e.g. "void foo(int a, double...b) VS foo(1, new double[0]").
- if (
- formalParamCount == lastActualArg
- && argumentTypes[lastActualArg].isArray()
- && this.isMethodInvocationConvertible(
- argumentTypes[lastActualArg].getComponentType(),
- lastParamType,
- boxingPermitted
- )
- ) {
- nUncheckedArg--;
- } else {
- for (int idx = lastActualArg; idx >= formalParamCount; --idx) {
-
- // Is method invocation conversion possible (5.3)?
- // if (UnitCompiler.DEBUG) System.out.println(lastParamType + " <=> " + argumentTypes[idx]);
- if (!this.isMethodInvocationConvertible(argumentTypes[idx], lastParamType, boxingPermitted)) {
- formalParamCount++;
- break VARARGS;
- }
-
- nUncheckedArg--;
- }
- argsNeedAdjust = true;
- }
- }
-
- if (formalParamCount == nUncheckedArg) {
- for (int j = 0; j < nUncheckedArg; ++j) {
-
- // Is method invocation conversion possible (5.3)?
- if (UnitCompiler.DEBUG) System.out.println(parameterTypes[j] + " <=> " + argumentTypes[j]);
- if (!this.isMethodInvocationConvertible(argumentTypes[j], parameterTypes[j], boxingPermitted)) {
- continue NEXT_METHOD;
- }
- }
-
- // Applicable!
- if (UnitCompiler.DEBUG) System.out.println("Applicable!");
-
- // Varargs has lower priority.
- if (isVarargs) {
- ii.setArgsNeedAdjust(argsNeedAdjust);
- varargApplicables.add(ii);
- } else {
- applicableIInvocables.add(ii);
- }
- }
- }
-
- // Choose the most specific invocable (15.12.2.2).
- if (applicableIInvocables.size() == 1) {
- return (IClass.IInvocable) applicableIInvocables.get(0);
- }
-
- // No method found by previous phase(s).
- if (applicableIInvocables.size() == 0 && !varargApplicables.isEmpty()) {
- //TODO: 15.12.2.3 (type-conversion?)
-
- // 15.12.2.4 : Phase 3: Identify Applicable Variable Arity Methods
- applicableIInvocables = varargApplicables;
- if (applicableIInvocables.size() == 1) {
- return (IClass.IInvocable) applicableIInvocables.get(0);
- }
- }
-
- if (applicableIInvocables.size() == 0) return null;
-
- // 15.12.2.5. Determine the "maximally specific invocables".
- List maximallySpecificIInvocables = new ArrayList();
- for (IClass.IInvocable applicableIInvocable : applicableIInvocables) {
- int moreSpecific = 0, lessSpecific = 0;
- for (IClass.IInvocable mostSpecificIInvocable : maximallySpecificIInvocables) {
- if (applicableIInvocable.isMoreSpecificThan(mostSpecificIInvocable)) {
- ++moreSpecific;
- } else
- if (applicableIInvocable.isLessSpecificThan(mostSpecificIInvocable)) {
- ++lessSpecific;
- }
- }
- if (moreSpecific == maximallySpecificIInvocables.size()) {
- maximallySpecificIInvocables.clear();
- maximallySpecificIInvocables.add(applicableIInvocable);
- } else
- if (lessSpecific < maximallySpecificIInvocables.size()) {
- maximallySpecificIInvocables.add(applicableIInvocable);
- } else
- {
- ;
- }
- if (UnitCompiler.DEBUG) System.out.println("maximallySpecificIInvocables=" + maximallySpecificIInvocables);
- }
-
- if (maximallySpecificIInvocables.size() == 1) return (IClass.IInvocable) maximallySpecificIInvocables.get(0);
-
- ONE_NON_ABSTRACT_INVOCABLE:
- if (maximallySpecificIInvocables.size() > 1 && iInvocables[0] instanceof IClass.IMethod) {
-
- // Check if all methods have the same signature (i.e. the types of all their parameters are identical) and
- // exactly one of the methods is non-abstract (JLS7 15.12.2.2.BL2.B1).
- IClass.IMethod theNonAbstractMethod = null;
- {
- Iterator it = maximallySpecificIInvocables.iterator();
- IClass.IMethod m = (IClass.IMethod) it.next();
- final IClass[] parameterTypesOfFirstMethod = m.getParameterTypes();
- for (;;) {
- if (!m.isAbstract()) {
- if (theNonAbstractMethod == null) {
- theNonAbstractMethod = m;
- } else {
- IClass declaringIClass = m.getDeclaringIClass();
- IClass theNonAbstractMethodDeclaringIClass = theNonAbstractMethod.getDeclaringIClass();
- if (declaringIClass == theNonAbstractMethodDeclaringIClass) {
- if (m.getReturnType() == theNonAbstractMethod.getReturnType()) {
- throw new JaninoRuntimeException(
- "Two non-abstract methods '" + m + "' have the same parameter types, "
- + "declaring type and return type"
- );
- } else
- if (m.getReturnType().isAssignableFrom(theNonAbstractMethod.getReturnType())) {
- ;
- } else
- if (theNonAbstractMethod.getReturnType().isAssignableFrom(m.getReturnType())) {
- theNonAbstractMethod = m;
- } else
- {
- throw new JaninoRuntimeException("Incompatible return types");
- }
- } else
- if (declaringIClass.isAssignableFrom(theNonAbstractMethodDeclaringIClass)) {
- ;
- } else
- if (theNonAbstractMethodDeclaringIClass.isAssignableFrom(declaringIClass)) {
- theNonAbstractMethod = m;
- } else
- {
- throw new JaninoRuntimeException(
- "SNO: Types declaring '"
- + theNonAbstractMethod
- + "' are not assignable"
- );
- }
- }
- }
- if (!it.hasNext()) break;
-
- m = (IClass.IMethod) it.next();
- IClass[] pts = m.getParameterTypes();
- for (int i = 0; i < pts.length; ++i) {
- if (pts[i] != parameterTypesOfFirstMethod[i]) break ONE_NON_ABSTRACT_INVOCABLE;
- }
- }
- }
-
- // JLS7 15.12.2.2.BL2.B1.B1
- if (theNonAbstractMethod != null) return theNonAbstractMethod;
-
- // JLS7 15.12.2.2.BL2.B1.B2
- // Check "that exception [te1] is declared in the THROWS clause of each of the maximally specific methods".
- Set s = new HashSet();
- {
- IClass[][] tes = new IClass[maximallySpecificIInvocables.size()][];
- Iterator it = maximallySpecificIInvocables.iterator();
- for (int i = 0; i < tes.length; ++i) {
- tes[i] = ((IClass.IMethod) it.next()).getThrownExceptions();
- }
- for (int i = 0; i < tes.length; ++i) {
- EACH_EXCEPTION:
- for (IClass te1 : tes[i]) {
- EACH_METHOD:
- for (int k = 0; k < tes.length; ++k) {
- if (k == i) continue;
- for (IClass te2 : tes[k]) {
- if (te2.isAssignableFrom(te1)) continue EACH_METHOD;
- }
- continue EACH_EXCEPTION;
- }
- s.add(te1);
- }
- }
- }
-
- // Return a "dummy" method.
- final IClass.IMethod im = (IClass.IMethod) maximallySpecificIInvocables.get(0);
- final IClass[] tes = (IClass[]) s.toArray(new IClass[s.size()]);
- return im.getDeclaringIClass().new IMethod() {
- @Override public String getName() { return im.getName(); }
- @Override public IClass getReturnType() throws CompileException { return im.getReturnType(); } // SUPPRESS CHECKSTYLE LineLength
- @Override public boolean isAbstract() { return im.isAbstract(); }
- @Override public boolean isStatic() { return im.isStatic(); }
- @Override public Access getAccess() { return im.getAccess(); }
- @Override public boolean isVarargs() { return im.isVarargs(); }
- @Override public IClass[] getParameterTypes2() throws CompileException { return im.getParameterTypes(); } // SUPPRESS CHECKSTYLE LineLength
- @Override public IClass[] getThrownExceptions2() { return tes; }
- @Override public Annotation[] getAnnotations() { return im.getAnnotations(); } // SUPPRESS CHECKSTYLE LineLength
- };
- }
-
- if (!boxingPermitted) return null; // To try again.
-
- // JLS7 15.12.2.2.BL2.B2
- {
- StringBuilder sb = new StringBuilder("Invocation of constructor/method with argument type(s) \"");
- for (int i = 0; i < argumentTypes.length; ++i) {
- if (i > 0) sb.append(", ");
- sb.append(Descriptor.toString(argumentTypes[i].getDescriptor()));
- }
- sb.append("\" is ambiguous: ");
- for (int i = 0; i < maximallySpecificIInvocables.size(); ++i) {
- if (i > 0) sb.append(" vs. ");
- sb.append("\"" + maximallySpecificIInvocables.get(i) + "\"");
- }
- this.compileError(sb.toString(), locatable.getLocation());
- }
-
- return iInvocables[0];
- }
-
- /** Checks if "method invocation conversion" (5.3) is possible. */
- private boolean
- isMethodInvocationConvertible(
- IClass sourceType,
- IClass targetType,
- boolean boxingPermitted
- ) throws CompileException {
-
- // 5.3 Identity conversion.
- if (sourceType == targetType) return true;
-
- // 5.3 Widening primitive conversion.
- if (this.isWideningPrimitiveConvertible(sourceType, targetType)) return true;
-
- // 5.3 Widening reference conversion.
- if (this.isWideningReferenceConvertible(sourceType, targetType)) return true;
-
- // JLS7 5.3 A boxing conversion (JLS7 5.1.7) optionally followed by widening reference conversion.
- if (boxingPermitted) {
- IClass boxedType = this.isBoxingConvertible(sourceType);
- if (boxedType != null) {
- return (
- this.isIdentityConvertible(boxedType, targetType)
- || this.isWideningReferenceConvertible(boxedType, targetType)
- );
- }
- }
-
- // JLS7 5.3 An unboxing conversion (JLS7 5.1.8) optionally followed by a widening primitive conversion.
- if (boxingPermitted) {
- IClass unboxedType = this.isUnboxingConvertible(sourceType);
- if (unboxedType != null) {
- return (
- this.isIdentityConvertible(unboxedType, targetType)
- || this.isWideningPrimitiveConvertible(unboxedType, targetType)
- );
- }
- }
-
- // 5.3 TODO: FLOAT or DOUBLE value set conversion
-
- return false;
- }
-
- /** @throws CompileException if the {@link Invocation} throws exceptions that are disallowed in the given scope */
- private void
- checkThrownExceptions(Invocation in, IMethod iMethod) throws CompileException {
- IClass[] thrownExceptions = iMethod.getThrownExceptions();
- for (IClass thrownException : thrownExceptions) {
- this.checkThrownException(
- in, // locatable
- thrownException, // type
- in.getEnclosingBlockStatement() // scope
- );
- }
- }
-
- /**
- * @throws CompileException The exception with the given {@code type} must not be thrown in the given {@code scope}
- */
- private void
- checkThrownException(Locatable locatable, IClass type, Scope scope) throws CompileException {
-
- // Thrown object must be assignable to "Throwable".
- if (!this.iClassLoader.TYPE_java_lang_Throwable.isAssignableFrom(type)) {
- this.compileError(
- "Thrown object of type \"" + type + "\" is not assignable to \"Throwable\"",
- locatable.getLocation()
- );
- }
-
- // "RuntimeException" and "Error" are never checked.
- if (
- this.iClassLoader.TYPE_java_lang_RuntimeException.isAssignableFrom(type)
- || this.iClassLoader.TYPE_java_lang_Error.isAssignableFrom(type)
- ) return;
-
- for (;; scope = scope.getEnclosingScope()) {
-
- // Match against enclosing "try...catch" blocks.
- if (scope instanceof TryStatement) {
- TryStatement ts = (TryStatement) scope;
- for (int i = 0; i < ts.catchClauses.size(); ++i) {
- CatchClause cc = (CatchClause) ts.catchClauses.get(i);
- IClass caughtType = this.getType(cc.caughtException.type);
- if (caughtType.isAssignableFrom(type)) {
-
- // This catch clause definitely catches the exception.
- cc.reachable = true;
- return;
- }
-
- CATCH_SUBTYPE:
- if (type.isAssignableFrom(caughtType)) {
-
- // This catch clause catches only a subtype of the exception type.
- for (int j = 0; j < i; ++j) {
- if (this.getType(
- ((CatchClause) ts.catchClauses.get(j)).caughtException.type
- ).isAssignableFrom(caughtType)) {
-
- // A preceding catch clause is more general than this catch clause.
- break CATCH_SUBTYPE;
- }
- }
-
- // This catch clause catches PART OF the actual exceptions.
- cc.reachable = true;
- }
- }
- } else
-
- // Match against "throws" clause of declaring function.
- if (scope instanceof FunctionDeclarator) {
- FunctionDeclarator fd = (FunctionDeclarator) scope;
- for (Type thrownException : fd.thrownExceptions) {
- if (this.getType(thrownException).isAssignableFrom(type)) return;
- }
- break;
- } else
-
- if (scope instanceof TypeBodyDeclaration) {
- break;
- }
- }
-
- this.compileError((
- "Thrown exception of type \""
- + type
- + "\" is neither caught by a \"try...catch\" block "
- + "nor declared in the \"throws\" clause of the declaring function"
- ), locatable.getLocation());
- }
-
- private IClass
- getTargetIClass(QualifiedThisReference qtr) throws CompileException {
-
- // Determine target type.
- if (qtr.targetIClass == null) {
- qtr.targetIClass = this.getType(qtr.qualification);
- }
- return qtr.targetIClass;
- }
-
- /** Checks whether the operand is an integer-like local variable. */
- LocalVariable
- isIntLv(Crement c) throws CompileException {
- if (!(c.operand instanceof AmbiguousName)) return null;
- AmbiguousName an = (AmbiguousName) c.operand;
-
- Atom rec = this.reclassify(an);
- if (!(rec instanceof LocalVariableAccess)) return null;
- LocalVariableAccess lva = (LocalVariableAccess) rec;
-
- LocalVariable lv = lva.localVariable;
- if (lv.finaL) this.compileError("Must not increment or decrement \"final\" local variable", lva.getLocation());
- if (
- lv.type == IClass.BYTE
- || lv.type == IClass.SHORT
- || lv.type == IClass.INT
- || lv.type == IClass.CHAR
- ) return lv;
- return null;
- }
-
- private IClass
- resolve(final TypeDeclaration td) {
- final AbstractTypeDeclaration atd = (AbstractTypeDeclaration) td;
- if (atd.resolvedType == null) atd.resolvedType = new IClass() {
-
-// final TypeParameter[] optionalTypeParameters = (
-// atd instanceof NamedTypeDeclaration
-// ? ((NamedTypeDeclaration) atd).getOptionalTypeParameters()
-// : null
-// );
-
- @Override protected IClass.IMethod[]
- getDeclaredIMethods2() {
- IClass.IMethod[] res = new IClass.IMethod[atd.getMethodDeclarations().size()];
- int i = 0;
- for (MethodDeclarator md : atd.getMethodDeclarations()) {
- res[i++] = UnitCompiler.this.toIMethod(md);
- }
- return res;
- }
-
- private IClass[] declaredClasses;
-
- @Override protected IClass[]
- getDeclaredIClasses2() {
- if (this.declaredClasses == null) {
- Collection mtds = td.getMemberTypeDeclarations();
- IClass[] mts = new IClass[mtds.size()];
- int i = 0;
- for (MemberTypeDeclaration mtd : mtds) {
- mts[i++] = UnitCompiler.this.resolve(mtd);
- }
- this.declaredClasses = mts;
- }
- return this.declaredClasses;
- }
-
- @Override protected IClass
- getDeclaringIClass2() {
- Scope s = atd;
- for (; !(s instanceof TypeBodyDeclaration); s = s.getEnclosingScope()) {
- if (s instanceof CompilationUnit) return null;
- }
- return UnitCompiler.this.resolve((AbstractTypeDeclaration) s.getEnclosingScope());
- }
-
- @Override protected IClass
- getOuterIClass2() {
- AbstractTypeDeclaration oc = (AbstractTypeDeclaration) UnitCompiler.getOuterClass(atd);
- if (oc == null) return null;
- return UnitCompiler.this.resolve(oc);
- }
-
- @Override protected final String
- getDescriptor2() { return Descriptor.fromClassName(atd.getClassName()); }
-
- @Override public boolean
- isArray() { return false; }
-
- @Override protected IClass
- getComponentType2() { throw new JaninoRuntimeException("SNO: Non-array type has no component type"); }
-
- @Override public boolean
- isPrimitive() { return false; }
-
- @Override public boolean
- isPrimitiveNumeric() { return false; }
-
- @Override protected IConstructor[]
- getDeclaredIConstructors2() {
- if (atd instanceof ClassDeclaration) {
- ConstructorDeclarator[] cs = ((ClassDeclaration) atd).getConstructors();
-
- IClass.IConstructor[] res = new IClass.IConstructor[cs.length];
- for (int i = 0; i < cs.length; ++i) res[i] = UnitCompiler.this.toIConstructor(cs[i]);
- return res;
- }
- return new IClass.IConstructor[0];
- }
-
- @Override protected IField[]
- getDeclaredIFields2() {
- if (atd instanceof ClassDeclaration) {
- ClassDeclaration cd = (ClassDeclaration) atd;
- List l = new ArrayList();
-
- // Determine variable declarators of type declaration.
- for (BlockStatement vdoi : cd.variableDeclaratorsAndInitializers) {
- if (vdoi instanceof FieldDeclaration) {
- FieldDeclaration fd = (FieldDeclaration) vdoi;
- IClass.IField[] flds = UnitCompiler.this.getIFields(fd);
- for (IField fld : flds) l.add(fld);
- }
- }
- return (IClass.IField[]) l.toArray(new IClass.IField[l.size()]);
- } else
- if (atd instanceof InterfaceDeclaration) {
- InterfaceDeclaration id = (InterfaceDeclaration) atd;
- List l = new ArrayList();
-
- // Determine static fields.
- for (BlockStatement bs : id.constantDeclarations) {
- if (bs instanceof FieldDeclaration) {
- FieldDeclaration fd = (FieldDeclaration) bs;
- IClass.IField[] flds = UnitCompiler.this.getIFields(fd);
- for (IField fld : flds) l.add(fld);
- }
- }
- return (IClass.IField[]) l.toArray(new IClass.IField[l.size()]);
- } else {
- throw new JaninoRuntimeException(
- "SNO: AbstractTypeDeclaration is neither ClassDeclaration nor InterfaceDeclaration"
- );
- }
- }
-
- @Override public IField[]
- getSyntheticIFields() {
- if (atd instanceof ClassDeclaration) {
- Collection c = ((ClassDeclaration) atd).syntheticFields.values();
- return (IField[]) c.toArray(new IField[c.size()]);
- }
- return new IField[0];
- }
-
- @Override protected IClass
- getSuperclass2() throws CompileException {
- if (atd instanceof AnonymousClassDeclaration) {
- IClass bt = UnitCompiler.this.getType(((AnonymousClassDeclaration) atd).baseType);
- return bt.isInterface() ? UnitCompiler.this.iClassLoader.TYPE_java_lang_Object : bt;
- }
- if (atd instanceof NamedClassDeclaration) {
- NamedClassDeclaration ncd = (NamedClassDeclaration) atd;
- if (ncd.optionalExtendedType == null) return UnitCompiler.this.iClassLoader.TYPE_java_lang_Object;
- IClass superclass = UnitCompiler.this.getType(ncd.optionalExtendedType);
- if (superclass.isInterface()) {
- UnitCompiler.this.compileError(
- "\"" + superclass.toString() + "\" is an interface; classes can only extend a class",
- td.getLocation()
- );
- }
- return superclass;
- }
- return null;
- }
-
- @Override public Access
- getAccess() { return UnitCompiler.modifiers2Access(atd.getModifierFlags()); }
-
- @Override public boolean
- isFinal() { return Mod.isFinal(atd.getModifierFlags()); }
-
- @Override protected IClass[]
- getInterfaces2() throws CompileException {
- if (atd instanceof AnonymousClassDeclaration) {
- IClass bt = UnitCompiler.this.getType(((AnonymousClassDeclaration) atd).baseType);
- return bt.isInterface() ? new IClass[] { bt } : new IClass[0];
- } else
- if (atd instanceof NamedClassDeclaration) {
- NamedClassDeclaration ncd = (NamedClassDeclaration) atd;
- IClass[] res = new IClass[ncd.implementedTypes.length];
- for (int i = 0; i < res.length; ++i) {
- res[i] = UnitCompiler.this.getType(ncd.implementedTypes[i]);
- if (!res[i].isInterface()) {
- UnitCompiler.this.compileError((
- "\""
- + res[i].toString()
- + "\" is not an interface; classes can only implement interfaces"
- ), td.getLocation());
- }
- }
- return res;
- } else
- if (atd instanceof InterfaceDeclaration) {
- InterfaceDeclaration id = (InterfaceDeclaration) atd;
- IClass[] res = new IClass[id.extendedTypes.length];
- for (int i = 0; i < res.length; ++i) {
- res[i] = UnitCompiler.this.getType(id.extendedTypes[i]);
- if (!res[i].isInterface()) {
- UnitCompiler.this.compileError((
- "\""
- + res[i].toString()
- + "\" is not an interface; interfaces can only extend interfaces"
- ), td.getLocation());
- }
- }
- return res;
- } else {
- throw new JaninoRuntimeException(
- "SNO: AbstractTypeDeclaration is neither ClassDeclaration nor InterfaceDeclaration"
- );
- }
- }
-
- @Override public boolean
- isAbstract() { return atd instanceof InterfaceDeclaration || Mod.isAbstract(atd.getModifierFlags()); }
-
- @Override public boolean
- isInterface() { return atd instanceof InterfaceDeclaration; }
- };
-
- return atd.resolvedType;
- }
-
- private void
- referenceThis(
- Locatable locatable,
- ClassDeclaration declaringClass,
- TypeBodyDeclaration declaringTypeBodyDeclaration,
- IClass targetIClass
- ) throws CompileException {
- List path = UnitCompiler.getOuterClasses(declaringClass);
-
- if (declaringTypeBodyDeclaration.isStatic()) {
- this.compileError("No current instance available in static context", locatable.getLocation());
- }
-
- int j;
- TARGET_FOUND: {
- for (j = 0; j < path.size(); ++j) {
-
- // Notice: JLS7 15.9.2.BL1.B3.B1.B2 seems to be wrong: Obviously, JAVAC does not only allow
- //
- // O is the nth lexically enclosing class
- //
- // , but also
- //
- // O is assignable from the nth lexically enclosing class
- //
- // However, this strategy bears the risk of ambiguities, because "O" may be assignable from more than
- // one enclosing class.
- if (targetIClass.isAssignableFrom(this.resolve((TypeDeclaration) path.get(j)))) {
- break TARGET_FOUND;
- }
- }
- this.compileError(
- "\"" + declaringClass + "\" is not enclosed by \"" + targetIClass + "\"",
- locatable.getLocation()
- );
- }
-
- int i;
- if (declaringTypeBodyDeclaration instanceof ConstructorDeclarator) {
- if (j == 0) {
- this.writeOpcode(locatable, Opcode.ALOAD_0);
- return;
- }
-
- ConstructorDeclarator constructorDeclarator = (
- (ConstructorDeclarator) declaringTypeBodyDeclaration
- );
- String spn = "this$" + (path.size() - 2);
- LocalVariable syntheticParameter = (
- (LocalVariable) constructorDeclarator.syntheticParameters.get(spn)
- );
- if (syntheticParameter == null) {
- throw new JaninoRuntimeException("SNO: Synthetic parameter \"" + spn + "\" not found");
- }
- this.load(locatable, syntheticParameter);
- i = 1;
- } else {
- this.writeOpcode(locatable, Opcode.ALOAD_0);
- i = 0;
- }
- for (; i < j; ++i) {
- final InnerClassDeclaration inner = (InnerClassDeclaration) path.get(i);
- final TypeDeclaration outer = (TypeDeclaration) path.get(i + 1);
-
- SimpleIField sf = new SimpleIField(
- this.resolve(inner), // declaringIClass
- "this$" + (path.size() - i - 2), // name
- this.resolve(outer) // type
- );
- inner.defineSyntheticField(sf);
- this.getfield(locatable, sf);
- }
- }
-
- /**
- * Return a list consisting of the given {@code inner} class and all its outer classes.
- *
- * @return {@link List} of {@link TypeDeclaration}
- */
- private static List
- getOuterClasses(TypeDeclaration inner) {
- List path = new ArrayList();
- for (TypeDeclaration ic = inner; ic != null; ic = UnitCompiler.getOuterClass(ic)) path.add(ic);
- return path;
- }
-
- /** @return The {@link TypeDeclaration} that immediately encloses the {@code typeDeclaration}, or {@code null} */
- static TypeDeclaration
- getOuterClass(TypeDeclaration typeDeclaration) {
-
- // Package member class declaration.
- if (typeDeclaration instanceof PackageMemberClassDeclaration) return null;
-
- // Local class declaration.
- if (typeDeclaration instanceof LocalClassDeclaration) {
- Scope s = typeDeclaration.getEnclosingScope();
- for (; !(s instanceof FunctionDeclarator); s = s.getEnclosingScope());
- if ((s instanceof MethodDeclarator) && Mod.isStatic(((FunctionDeclarator) s).modifiers.flags)) return null;
- for (; !(s instanceof TypeDeclaration); s = s.getEnclosingScope());
- TypeDeclaration immediatelyEnclosingTypeDeclaration = (TypeDeclaration) s;
- return (
- immediatelyEnclosingTypeDeclaration instanceof ClassDeclaration
- ) ? immediatelyEnclosingTypeDeclaration : null;
- }
-
- // Member class declaration.
- if (
- typeDeclaration instanceof MemberClassDeclaration
- && Mod.isStatic(((MemberClassDeclaration) typeDeclaration).getModifierFlags())
- ) return null;
-
- // Anonymous class declaration, interface declaration.
- Scope s = typeDeclaration;
- for (; !(s instanceof TypeBodyDeclaration); s = s.getEnclosingScope()) {
- if (s instanceof ConstructorInvocation) return null;
- if (s instanceof CompilationUnit) return null;
- }
- //if (!(s instanceof ClassDeclaration)) return null;
- if (((TypeBodyDeclaration) s).isStatic()) return null;
- return (AbstractTypeDeclaration) s.getEnclosingScope();
- }
-
- private IClass
- getIClass(ThisReference tr) throws CompileException {
- if (tr.iClass == null) {
-
- // Compile error if in static function context.
- Scope s;
- for (
- s = tr.getEnclosingBlockStatement();
- s instanceof Statement || s instanceof CatchClause;
- s = s.getEnclosingScope()
- );
- if (s instanceof FunctionDeclarator) {
- FunctionDeclarator function = (FunctionDeclarator) s;
- if (Mod.isStatic(function.modifiers.flags)) {
- this.compileError("No current instance available in static method", tr.getLocation());
- }
- }
-
- // Determine declaring type.
- while (!(s instanceof TypeDeclaration)) {
- s = s.getEnclosingScope();
- }
- if (!(s instanceof ClassDeclaration)) {
- this.compileError("Only methods of classes can have a current instance", tr.getLocation());
- }
- tr.iClass = this.resolve((ClassDeclaration) s);
- }
- return tr.iClass;
- }
-
- private IClass
- getReturnType(FunctionDeclarator fd) throws CompileException {
- if (fd.returnType == null) {
- fd.returnType = this.getType(fd.type);
- }
- return fd.returnType;
- }
-
- /** @return the {@link IConstructor} that implements the {@code constructorDeclarator} */
- IClass.IConstructor
- toIConstructor(final ConstructorDeclarator constructorDeclarator) {
- if (constructorDeclarator.iConstructor != null) return constructorDeclarator.iConstructor;
-
- constructorDeclarator.iConstructor = this.resolve(constructorDeclarator.getDeclaringType()).new IConstructor() {
-
- // Implement IMember.
- @Override public Access
- getAccess() {
- switch (constructorDeclarator.modifiers.flags & Mod.PPP) {
- case Mod.PRIVATE:
- return Access.PRIVATE;
- case Mod.PROTECTED:
- return Access.PROTECTED;
- case Mod.PACKAGE:
- return Access.DEFAULT;
- case Mod.PUBLIC:
- return Access.PUBLIC;
- default:
- throw new JaninoRuntimeException("Invalid access");
- }
- }
-
- @Override public Annotation[]
- getAnnotations() { return constructorDeclarator.modifiers.annotations; }
-
- // Implement IInvocable.
-
- @Override public String
- getDescriptor2() throws CompileException {
- if (!(constructorDeclarator.getDeclaringClass() instanceof InnerClassDeclaration)) {
- return super.getDescriptor2();
- }
-
- List parameterFds = new ArrayList();
-
- // Convert enclosing instance reference into prepended constructor parameters.
- IClass outerClass = UnitCompiler.this.resolve(
- constructorDeclarator.getDeclaringClass()
- ).getOuterIClass();
- if (outerClass != null) parameterFds.add(outerClass.getDescriptor());
-
- // Convert synthetic fields into prepended constructor parameters.
- for (IField sf : constructorDeclarator.getDeclaringClass().syntheticFields.values()) {
- if (sf.getName().startsWith("val$")) parameterFds.add(sf.getType().getDescriptor());
- }
-
- // Process the 'normal' (declared) function parameters.
- FormalParameter[] parameters = constructorDeclarator.formalParameters.parameters;
- for (int i = 0; i < parameters.length; ++i) {
- IClass parameterType = UnitCompiler.this.getType(parameters[i].type);
- if (i == parameters.length - 1 && constructorDeclarator.formalParameters.variableArity) {
- parameterType = parameterType.getArrayIClass(
- UnitCompiler.this.iClassLoader.TYPE_java_lang_Object
- );
- }
- parameterFds.add(parameterType.getDescriptor());
- }
- return new MethodDescriptor(
- (String[]) parameterFds.toArray(new String[parameterFds.size()]), // parameterFds
- Descriptor.VOID // returnFd
- ).toString();
- }
-
- @Override public boolean
- isVarargs() { return Mod.isVarargs(constructorDeclarator.modifiers.flags); }
-
- @Override public IClass[]
- getParameterTypes2() throws CompileException {
- FormalParameter[] parameters = constructorDeclarator.formalParameters.parameters;
- IClass[] res = new IClass[parameters.length];
- for (int i = 0; i < parameters.length; ++i) {
- IClass parameterType = UnitCompiler.this.getType(parameters[i].type);
- if (i == parameters.length - 1 && constructorDeclarator.formalParameters.variableArity) {
- parameterType = parameterType.getArrayIClass(
- UnitCompiler.this.iClassLoader.TYPE_java_lang_Object
- );
- }
- res[i] = parameterType;
- }
- return res;
- }
-
- @Override public IClass[]
- getThrownExceptions2() throws CompileException {
- IClass[] res = new IClass[constructorDeclarator.thrownExceptions.length];
- for (int i = 0; i < res.length; ++i) {
- res[i] = UnitCompiler.this.getType(constructorDeclarator.thrownExceptions[i]);
- }
- return res;
- }
-
- @Override public String
- toString() {
- StringBuilder sb = new StringBuilder().append(
- constructorDeclarator.getDeclaringType().getClassName()
- ).append('(');
-
- FormalParameter[] parameters = constructorDeclarator.formalParameters.parameters;
- for (int i = 0; i < parameters.length; ++i) {
- if (i != 0) sb.append(", ");
- sb.append(parameters[i].toString(
- i == parameters.length - 1
- && constructorDeclarator.formalParameters.variableArity
- ));
- }
- return sb.append(')').toString();
- }
- };
- return constructorDeclarator.iConstructor;
- }
-
- /** @return The {@link IMethod} that implements the {@code methodDeclarator} */
- public IClass.IMethod
- toIMethod(final MethodDeclarator methodDeclarator) {
- if (methodDeclarator.iMethod != null) return methodDeclarator.iMethod;
- methodDeclarator.iMethod = this.resolve(methodDeclarator.getDeclaringType()).new IMethod() {
-
- // Implement IMember.
- @Override public Access
- getAccess() {
- switch (methodDeclarator.modifiers.flags & Mod.PPP) {
- case Mod.PRIVATE:
- return Access.PRIVATE;
- case Mod.PROTECTED:
- return Access.PROTECTED;
- case Mod.PACKAGE:
- return Access.DEFAULT;
- case Mod.PUBLIC:
- return Access.PUBLIC;
- default:
- throw new JaninoRuntimeException("Invalid access");
- }
- }
-
- @Override public Annotation[]
- getAnnotations() { return methodDeclarator.modifiers.annotations; }
-
- // Implement IInvocable.
-
- @Override public boolean
- isVarargs() { return Mod.isVarargs(methodDeclarator.modifiers.flags); }
-
- @Override public IClass[]
- getParameterTypes2() throws CompileException {
- FormalParameter[] parameters = methodDeclarator.formalParameters.parameters;
- IClass[] res = new IClass[parameters.length];
- for (int i = 0; i < parameters.length; ++i) {
- IClass parameterType = UnitCompiler.this.getType(parameters[i].type);
- if (i == parameters.length - 1 && methodDeclarator.formalParameters.variableArity) {
- parameterType = parameterType.getArrayIClass(
- UnitCompiler.this.iClassLoader.TYPE_java_lang_Object
- );
- }
- res[i] = parameterType;
- }
- return res;
- }
-
- @Override public IClass[]
- getThrownExceptions2() throws CompileException {
- IClass[] res = new IClass[methodDeclarator.thrownExceptions.length];
- for (int i = 0; i < res.length; ++i) {
- res[i] = UnitCompiler.this.getType(methodDeclarator.thrownExceptions[i]);
- }
- return res;
- }
-
- // Implement IMethod.
-
- @Override public boolean
- isStatic() { return Mod.isStatic(methodDeclarator.modifiers.flags); }
-
- @Override public boolean
- isAbstract() {
- return (
- (methodDeclarator.getDeclaringType() instanceof InterfaceDeclaration)
- || Mod.isAbstract(methodDeclarator.modifiers.flags)
- );
- }
-
- @Override public IClass
- getReturnType() throws CompileException { return UnitCompiler.this.getReturnType(methodDeclarator); }
-
- @Override public String
- getName() { return methodDeclarator.name; }
- };
- return methodDeclarator.iMethod;
- }
-
- private IClass.IInvocable
- toIInvocable(final FunctionDeclarator fd) {
- final IClass.IInvocable[] result = new IClass.IInvocable[1];
- fd.accept(new Visitor.FunctionDeclaratorVisitor() {
- // CHECKSTYLE LineLength:OFF
- @Override public void visitMethodDeclarator(MethodDeclarator md) { result[0] = UnitCompiler.this.toIMethod((MethodDeclarator) fd); }
- @Override public void visitConstructorDeclarator(ConstructorDeclarator cd) { result[0] = UnitCompiler.this.toIConstructor((ConstructorDeclarator) fd); }
- // CHECKSTYLE LineLength:ON
- });
- return result[0];
- }
-
- /** If the given name was declared in a simple type import, load that class. */
- private IClass
- importSingleType(String simpleTypeName, Location location) throws CompileException {
- String[] ss = this.getSingleTypeImport(simpleTypeName, location);
- if (ss == null) return null;
-
- IClass iClass = this.findTypeByFullyQualifiedName(location, ss);
- if (iClass == null) {
- this.compileError("Imported class \"" + Java.join(ss, ".") + "\" could not be loaded", location);
- return this.iClassLoader.TYPE_java_lang_Object;
- }
- return iClass;
- }
-
- /**
- * Check if the given simple name was imported through a single type import.
- *
- * @param name The simple type name, e.g. {@code Inner}
- * @return The fully qualified name, e.g. { "pkg", "Outer", "Inner" }
, or {@code null}
- */
- public String[]
- getSingleTypeImport(String name, Location location) throws CompileException {
-
- // Resolve all single type imports (if not already done).
- if (this.singleTypeImports == null) {
-
- // Collect all single type import declarations.
- final List stids = new ArrayList();
- for (ImportDeclaration id : this.compilationUnit.importDeclarations) {
- id.accept(new ImportVisitor() {
-
- @Override public void
- visitSingleTypeImportDeclaration(SingleTypeImportDeclaration stid) { stids.add(stid); }
-
- @Override public void visitTypeImportOnDemandDeclaration(TypeImportOnDemandDeclaration tiodd) {}
- @Override public void visitSingleStaticImportDeclaration(SingleStaticImportDeclaration ssid) {}
- @Override public void visitStaticImportOnDemandDeclaration(StaticImportOnDemandDeclaration siodd) {}
- });
- }
-
- // Resolve all single type imports.
- this.singleTypeImports = new HashMap();
- for (SingleTypeImportDeclaration stid : stids) {
-
- String[] ids = stid.identifiers;
- String simpleName = UnitCompiler.last(ids);
-
- // Check for re-import of same simple name.
- String[] prev = (String[]) this.singleTypeImports.put(simpleName, ids);
- if (prev != null && !Arrays.equals(prev, ids)) {
- UnitCompiler.this.compileError((
- "Class \"" + simpleName + "\" was previously imported as "
- + "\"" + Java.join(prev, ".") + "\", now as \"" + Java.join(ids, ".") + "\""
- ), stid.getLocation());
- }
-
- if (this.findTypeByFullyQualifiedName(location, ids) == null) {
- UnitCompiler.this.compileError(
- "A class '" + Java.join(ids, ".") + "' could not be found",
- stid.getLocation()
- );
- }
- }
- }
-
- return (String[]) this.singleTypeImports.get(name);
- }
- /** To be used only by {@link #getSingleTypeImport(String, Location)}; {@code null} means "not yet initialized" */
- private Map singleTypeImports;
-
- /**
- * 6.5.2.BL1.B1.B5, 6.5.2.BL1.B1.B6 Type-import-on-demand.
- * 6.5.5.1.6 Type-import-on-demand declaration.
- *
- * @return {@code null} if the given {@code simpleTypeName} cannot be resolved through any of the
- * import-on-demand directives
- */
- public IClass
- importTypeOnDemand(String simpleTypeName, Location location) throws CompileException {
-
- // Check cache. (A cache for unimportable types is not required, because the class is importable 99.9%.)
- {
- IClass importedClass = (IClass) this.onDemandImportableTypes.get(simpleTypeName);
- if (importedClass != null) return importedClass;
- }
- // Cache miss...
-
- // Compile all import-on-demand declarations (done here as late as possible).
- if (this.typeImportsOnDemand == null) {
- this.typeImportsOnDemand = new ArrayList();
- this.typeImportsOnDemand.add(new String[] { "java", "lang" });
- for (ImportDeclaration id : this.compilationUnit.importDeclarations) {
- id.accept(new ImportVisitor() {
- @Override public void visitSingleTypeImportDeclaration(SingleTypeImportDeclaration stid) {}
-
- @Override public void
- visitTypeImportOnDemandDeclaration(TypeImportOnDemandDeclaration tiodd) {
- UnitCompiler.this.typeImportsOnDemand.add(tiodd.identifiers);
- }
-
- @Override public void visitSingleStaticImportDeclaration(SingleStaticImportDeclaration ssid) {}
- @Override public void visitStaticImportOnDemandDeclaration(StaticImportOnDemandDeclaration siodd) {}
- });
- }
- }
-
- IClass importedClass = null;
- for (String[] packageComponents : this.typeImportsOnDemand) {
- String[] typeComponents = UnitCompiler.concat(packageComponents, simpleTypeName);
- IClass iClass = this.findTypeByFullyQualifiedName(location, typeComponents);
- if (iClass != null) {
- if (importedClass != null && importedClass != iClass) {
- this.compileError(
- "Ambiguous class name: \"" + importedClass + "\" vs. \"" + iClass + "\"",
- location
- );
- }
- importedClass = iClass;
- }
- }
- if (importedClass == null) return null;
-
- // Put in cache and return.
- this.onDemandImportableTypes.put(simpleTypeName, importedClass);
- return importedClass;
- }
- /** To be used only by {@link #importTypeOnDemand(String, Location)}; {@code null} means "not yet initialized. */
- private Collection typeImportsOnDemand;
- /** To be used only by {@link #importTypeOnDemand(String, Location)}; cache for on-demand-imported types. */
- private final Map onDemandImportableTypes = new HashMap();
-
- private void
- declareClassDollarMethod(ClassLiteral cl) {
-
- // Method "class$" is not yet declared; declare it like
- //
- // static java.lang.Class class$(java.lang.String className) {
- // try {
- // return java.lang.Class.forName(className);
- // } catch (java.lang.ClassNotFoundException e) {
- // throw new java.lang.NoClassDefFoundError(e.getMessage());
- // }
- // }
- //
- Location loc = cl.getLocation();
- AbstractTypeDeclaration declaringType;
- for (Scope s = cl.getEnclosingBlockStatement();; s = s.getEnclosingScope()) {
- if (s instanceof AbstractTypeDeclaration) {
- declaringType = (AbstractTypeDeclaration) s;
- break;
- }
- }
-
- // try {
- // return Class.forName(className);
- final MethodInvocation mi = new MethodInvocation(
- loc, // location
- new SimpleType(loc, this.iClassLoader.TYPE_java_lang_Class), // optionalTarget
- "forName", // methodName
- new Rvalue[] { // arguments
- new AmbiguousName(loc, new String[] { "className" })
- }
- );
-
- IClass classNotFoundExceptionIClass;
- try {
- classNotFoundExceptionIClass = this.iClassLoader.loadIClass("Ljava/lang/ClassNotFoundException;");
- } catch (ClassNotFoundException ex) {
- throw new JaninoRuntimeException("Loading class \"ClassNotFoundException\": " + ex.getMessage(), ex);
- }
- if (classNotFoundExceptionIClass == null) {
- throw new JaninoRuntimeException("SNO: Cannot load \"ClassNotFoundException\"");
- }
-
- IClass noClassDefFoundErrorIClass;
- try {
- noClassDefFoundErrorIClass = this.iClassLoader.loadIClass("Ljava/lang/NoClassDefFoundError;");
- } catch (ClassNotFoundException ex) {
- throw new JaninoRuntimeException("Loading class \"NoClassDefFoundError\": " + ex.getMessage(), ex);
- }
- if (noClassDefFoundErrorIClass == null) {
- throw new JaninoRuntimeException("SNO: Cannot load \"NoClassFoundError\"");
- }
-
- // catch (ClassNotFoundException e) {
- Block b = new Block(loc);
- // throw new NoClassDefFoundError(e.getMessage());
- b.addStatement(new ThrowStatement(loc, new NewClassInstance(
- loc, // location
- (Rvalue) null, // optionalQualification
- new SimpleType(loc, noClassDefFoundErrorIClass), // type
- new Rvalue[] { // arguments
- new MethodInvocation(
- loc, // location
- new AmbiguousName(loc, new String[] { "ex" }), // optionalTarget
- "getMessage", // methodName
- new Rvalue[0] // arguments
- )
- }
- )));
-
- List l = new ArrayList();
- l.add(new CatchClause(
- loc, // location
- new FormalParameter( // caughtException
- loc, // location
- true, // finaL
- new SimpleType(loc, classNotFoundExceptionIClass), // type
- "ex" // name
- ),
- b // body
- ));
- TryStatement ts = new TryStatement(
- loc, // location
- new ReturnStatement(loc, mi), // body
- l, // catchClauses
- null // optionalFinally
- );
-
- List statements = new ArrayList();
- statements.add(ts);
-
- // Class class$(String className)
- FormalParameter parameter = new FormalParameter(
- loc, // location
- false, // finaL
- new SimpleType(loc, this.iClassLoader.TYPE_java_lang_String), // type
- "className" // name
- );
- MethodDeclarator cdmd = new MethodDeclarator(
- loc, // location
- null, // optionalDocComment
- new Modifiers(Mod.STATIC), // modifiers
- new SimpleType(loc, this.iClassLoader.TYPE_java_lang_Class), // type
- "class$", // name
- new FormalParameters( // parameters
- loc,
- new FormalParameter[] { parameter },
- false
- ),
- new Type[0], // thrownExceptions
- statements // optionalStatements
- );
-
- declaringType.addDeclaredMethod(cdmd);
- declaringType.invalidateMethodCaches();
- }
-
- /**
- * @param value A {@link Character}, {@link Byte}, {@link Short}, {@link Integer}, {@link Long}, {@link Float},
- * {@link Double}, {@link String}, {@link Boolean} or {@code null}
- */
- private IClass
- pushConstant(Locatable locatable, Object value) throws CompileException {
-
- PUSH_INTEGER_CONSTANT: {
- int iv;
- if (value instanceof Character) {
- iv = ((Character) value).charValue();
- } else
- if (value instanceof Byte) {
- iv = ((Byte) value).intValue();
- } else
- if (value instanceof Short) {
- iv = ((Short) value).intValue();
- } else
- if (value instanceof Integer) {
- iv = ((Integer) value).intValue();
- } else
- {
- break PUSH_INTEGER_CONSTANT;
- }
-
- if (iv >= -1 && iv <= 5) {
- this.writeOpcode(locatable, Opcode.ICONST_0 + iv);
- } else
- if (iv >= Byte.MIN_VALUE && iv <= Byte.MAX_VALUE) {
- this.writeOpcode(locatable, Opcode.BIPUSH);
- this.writeByte((byte) iv);
- } else
- {
- this.writeLdc(locatable, this.addConstantIntegerInfo(iv));
- }
- return IClass.INT;
- }
-
- if (value instanceof Long) {
- long lv = ((Long) value).longValue();
-
- if (lv == 0L) {
- this.writeOpcode(locatable, Opcode.LCONST_0);
- } else
- if (lv == 1L) {
- this.writeOpcode(locatable, Opcode.LCONST_1);
- } else
- {
- this.writeOpcode(locatable, Opcode.LDC2_W);
- this.writeConstantLongInfo(lv);
- }
- return IClass.LONG;
- }
-
- if (value instanceof Float) {
- float fv = ((Float) value).floatValue();
-
- if (
- Float.floatToIntBits(fv) == Float.floatToIntBits(0.0F) // POSITIVE zero!
- || fv == 1.0F
- || fv == 2.0F
- ) {
- this.writeOpcode(locatable, Opcode.FCONST_0 + (int) fv);
- } else
- {
- this.writeLdc(locatable, this.addConstantFloatInfo(fv));
- }
- return IClass.FLOAT;
- }
-
- if (value instanceof Double) {
- double dv = ((Double) value).doubleValue();
-
- if (
- Double.doubleToLongBits(dv) == Double.doubleToLongBits(0.0D) // POSITIVE zero!
- || dv == 1.0D
- ) {
- this.writeOpcode(locatable, Opcode.DCONST_0 + (int) dv);
- } else
- {
- this.writeOpcode(locatable, Opcode.LDC2_W);
- this.writeConstantDoubleInfo(dv);
- }
- return IClass.DOUBLE;
- }
-
- if (value instanceof String) {
- String s = (String) value;
- String[] ss = UnitCompiler.makeUtf8Able(s);
- this.writeLdc(locatable, this.addConstantStringInfo(ss[0]));
- for (int i = 1; i < ss.length; ++i) {
- this.writeLdc(locatable, this.addConstantStringInfo(ss[i]));
- this.invoke(locatable, this.iClassLoader.METH_java_lang_String__concat__java_lang_String);
- }
- return this.iClassLoader.TYPE_java_lang_String;
- }
-
- if (Boolean.TRUE.equals(value)) {
- this.writeOpcode(locatable, Opcode.ICONST_1);
- return IClass.BOOLEAN;
- }
-
- if (Boolean.FALSE.equals(value)) {
- this.writeOpcode(locatable, Opcode.ICONST_0);
- return IClass.BOOLEAN;
- }
-
- if (value == null) {
- this.writeOpcode(locatable, Opcode.ACONST_NULL);
- return IClass.VOID;
- }
-
- throw new JaninoRuntimeException("Unknown literal '" + value + "'");
- }
-
- private static int
- hex2Int(Locatable locatable, String value) throws CompileException {
- int result = 0;
- for (int i = 0; i < value.length(); ++i) {
- if ((result & 0xf0000000) != 0) {
- throw UnitCompiler.compileException(
- locatable,
- "Value of hexadecimal integer literal \"" + value + "\" is out of range"
- );
- }
- result = (result << 4) + Character.digit(value.charAt(i), 16);
- }
- return result;
- }
-
- private static int
- oct2Int(Locatable locatable, String value) throws CompileException {
- int result = 0;
- for (int i = 0; i < value.length(); ++i) {
- if ((result & 0xe0000000) != 0) {
- throw UnitCompiler.compileException(
- locatable,
- "Value of octal integer literal '" + value + "' is out of range"
- );
- }
- result = (result << 3) + Character.digit(value.charAt(i), 8);
- }
- return result;
- }
-
- private static long
- hex2Long(Locatable locatable, String value) throws CompileException {
- long result = 0L;
- for (int i = 0; i < value.length(); ++i) {
- if ((result & 0xf000000000000000L) != 0L) {
- throw UnitCompiler.compileException(
- locatable,
- "Value of hexadecimal long literal \"" + value + "\" is out of range"
- );
- }
- result = (result << 4) + Character.digit(value.charAt(i), 16);
- }
- return result;
- }
-
- private static long
- oct2Long(Locatable locatable, String value) throws CompileException {
- long result = 0L;
- for (int i = 0; i < value.length(); ++i) {
- if ((result & 0xe000000000000000L) != 0) {
- throw UnitCompiler.compileException(
- locatable,
- "Value of octal long literal '" + value + "' is out of range"
- );
- }
- result = (result << 3) + Character.digit(value.charAt(i), 8);
- }
- return result;
- }
-
- /**
- * Only strings that can be UTF8-encoded into 65535 bytes can be stored as a constant string info.
- *
- * @param s The string to split into suitable chunks
- * @return The chunks that can be UTF8-encoded into 65535 bytes
- */
- private static String[]
- makeUtf8Able(String s) {
- if (s.length() < (65536 / 3)) return new String[] { s };
-
- int sLength = s.length(), utfLength = 0;
- int from = 0;
- List l = new ArrayList();
- for (int i = 0;; i++) {
- if (i == sLength) {
- l.add(s.substring(from));
- break;
- }
- if (utfLength >= 65532) {
- l.add(s.substring(from, i));
- if (i + (65536 / 3) > sLength) {
- l.add(s.substring(i));
- break;
- }
- from = i;
- utfLength = 0;
- }
- int c = s.charAt(i);
- if (c >= 0x0001 && c <= 0x007F) {
- ++utfLength;
- } else
- if (c > 0x07FF) {
- utfLength += 3;
- } else
- {
- utfLength += 2;
- }
- }
- return (String[]) l.toArray(new String[l.size()]);
-
- }
- private void
- writeLdc(Locatable locatable, short index) {
- if (0 <= index && index <= 255) {
- this.writeOpcode(locatable, Opcode.LDC);
- this.writeByte((byte) index);
- } else {
- this.writeOpcode(locatable, Opcode.LDC_W);
- this.writeShort(index);
- }
- }
-
- /** Implements "assignment conversion" (JLS7 5.2). */
- private void
- assignmentConversion(
- Locatable locatable,
- IClass sourceType,
- IClass targetType,
- Object optionalConstantValue
- ) throws CompileException {
- if (!this.tryAssignmentConversion(locatable, sourceType, targetType, optionalConstantValue)) {
- this.compileError(
- "Assignment conversion not possible from type \"" + sourceType + "\" to type \"" + targetType + "\"",
- locatable.getLocation()
- );
- }
- }
-
- private boolean
- tryAssignmentConversion(
- Locatable locatable,
- IClass sourceType,
- IClass targetType,
- Object optionalConstantValue
- ) throws CompileException {
- if (UnitCompiler.DEBUG) {
- System.out.println(
- "assignmentConversion("
- + sourceType
- + ", "
- + targetType
- + ", "
- + optionalConstantValue
- + ")"
- );
- }
-
- // JLS7 5.1.1 Identity conversion.
- if (this.tryIdentityConversion(sourceType, targetType)) return true;
-
- // JLS7 5.1.2 Widening primitive conversion.
- if (this.tryWideningPrimitiveConversion(locatable, sourceType, targetType)) return true;
-
- // JLS7 5.1.4 Widening reference conversion.
- if (this.isWideningReferenceConvertible(sourceType, targetType)) return true;
-
- // A boxing conversion (JLS7 5.1.7) optionally followed by a widening reference conversion.
- {
- IClass boxedType = this.isBoxingConvertible(sourceType);
- if (boxedType != null) {
- if (this.tryIdentityConversion(boxedType, targetType)) {
- this.boxingConversion(locatable, sourceType, boxedType);
- return true;
- }
- if (this.isWideningReferenceConvertible(boxedType, targetType)) {
- this.boxingConversion(locatable, sourceType, boxedType);
- return true;
- }
- }
- }
-
- // An unboxing conversion (JLS7 5.1.8) optionally followed by a widening primitive conversion.
- {
- IClass unboxedType = this.isUnboxingConvertible(sourceType);
- if (unboxedType != null) {
- if (this.tryIdentityConversion(unboxedType, targetType)) {
- this.unboxingConversion(locatable, sourceType, unboxedType);
- return true;
- }
- if (this.isWideningPrimitiveConvertible(unboxedType, targetType)) {
- this.unboxingConversion(locatable, sourceType, unboxedType);
- this.tryWideningPrimitiveConversion(locatable, unboxedType, targetType);
- return true;
- }
- }
- }
-
- // 5.2 Special narrowing primitive conversion.
- if (optionalConstantValue != UnitCompiler.NOT_CONSTANT) {
- if (this.tryConstantAssignmentConversion(
- locatable,
- optionalConstantValue, // constantValue
- targetType // targetType
- )) return true;
- }
-
- return false;
- }
-
- /** Implements "assignment conversion" (JLS7 5.2) on a constant value. */
- private Object
- assignmentConversion(Locatable locatable, Object value, IClass targetType) throws CompileException {
- if (targetType == IClass.BOOLEAN) {
- if (value instanceof Boolean) return value;
- } else
- if (targetType == this.iClassLoader.TYPE_java_lang_String) {
- if (value instanceof String) return value;
- } else
- if (targetType == IClass.BYTE) {
- if (value instanceof Byte) {
- return value;
- } else
- if (value instanceof Short || value instanceof Integer) {
- int x = ((Number) value).intValue();
- if (x >= Byte.MIN_VALUE && x <= Byte.MAX_VALUE) return new Byte((byte) x);
- } else
- if (value instanceof Character) {
- int x = ((Character) value).charValue();
- if (x >= Byte.MIN_VALUE && x <= Byte.MAX_VALUE) return new Byte((byte) x);
- }
- } else
- if (targetType == IClass.SHORT) {
- if (value instanceof Byte) {
- return new Short(((Number) value).shortValue());
- } else
- if (value instanceof Short) {
- return value;
- } else
- if (value instanceof Character) {
- int x = ((Character) value).charValue();
- if (x >= Short.MIN_VALUE && x <= Short.MAX_VALUE) return new Short((short) x);
- } else
- if (value instanceof Integer) {
- int x = ((Integer) value).intValue();
- if (x >= Short.MIN_VALUE && x <= Short.MAX_VALUE) return new Short((short) x);
- }
- } else
- if (targetType == IClass.CHAR) {
- if (value instanceof Short) {
- return value;
- } else
- if (value instanceof Byte || value instanceof Short || value instanceof Integer) {
- int x = ((Number) value).intValue();
- if (x >= Character.MIN_VALUE && x <= Character.MAX_VALUE) return new Character((char) x);
- }
- } else
- if (targetType == IClass.INT) {
- if (value instanceof Integer) {
- return value;
- } else
- if (value instanceof Byte || value instanceof Short) {
- return new Integer(((Number) value).intValue());
- } else
- if (value instanceof Character) {
- return new Integer(((Character) value).charValue());
- }
- } else
- if (targetType == IClass.LONG) {
- if (value instanceof Long) {
- return value;
- } else
- if (value instanceof Byte || value instanceof Short || value instanceof Integer) {
- return new Long(((Number) value).longValue());
- } else
- if (value instanceof Character) {
- return new Long(((Character) value).charValue());
- }
- } else
- if (targetType == IClass.FLOAT) {
- if (value instanceof Float) {
- return value;
- } else
- if (value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long) {
- return new Float(((Number) value).floatValue());
- } else
- if (value instanceof Character) {
- return new Float(((Character) value).charValue());
- }
- } else
- if (targetType == IClass.DOUBLE) {
- if (value instanceof Double) {
- return value;
- } else
- if (
- value instanceof Byte
- || value instanceof Short
- || value instanceof Integer
- || value instanceof Long
- || value instanceof Float
- ) {
- return new Double(((Number) value).doubleValue());
- } else
- if (value instanceof Character) {
- return new Double(((Character) value).charValue());
- }
- } else
- if (value == null && !targetType.isPrimitive()) {
- return null;
- }
-
- if (value == null) {
- this.compileError((
- "Cannot convert 'null' to type '"
- + targetType.toString()
- + "'"
- ), locatable.getLocation());
- } else
- {
- this.compileError((
- "Cannot convert constant of type '"
- + value.getClass().getName()
- + "' to type '"
- + targetType.toString()
- + "'"
- ), locatable.getLocation());
- }
- return value;
- }
-
- /**
- * Implements "unary numeric promotion" (JLS7 5.6.1).
- *
- * @return The promoted type
- */
- private IClass
- unaryNumericPromotion(Locatable locatable, IClass type) throws CompileException {
- type = this.convertToPrimitiveNumericType(locatable, type);
-
- IClass promotedType = this.unaryNumericPromotionType(locatable, type);
-
- this.numericPromotion(locatable, type, promotedType);
- return promotedType;
- }
-
- private void
- reverseUnaryNumericPromotion(Locatable locatable, IClass sourceType, IClass targetType) throws CompileException {
- IClass unboxedType = this.isUnboxingConvertible(targetType);
- IClass pt = unboxedType != null ? unboxedType : targetType;
- if (
- !this.tryIdentityConversion(sourceType, pt)
- && !this.tryNarrowingPrimitiveConversion(
- locatable, // locatable
- sourceType, // sourceType
- pt // targetType
- )
- ) throw new JaninoRuntimeException("SNO: reverse unary numeric promotion failed");
- if (unboxedType != null) this.boxingConversion(locatable, unboxedType, targetType);
- }
-
- /**
- * If the given type is a primitive type, return that type. If the given type is a primitive wrapper class, unbox
- * the operand on top of the operand stack and return the primitive type. Otherwise, issue a compile error.
- */
- private IClass
- convertToPrimitiveNumericType(Locatable locatable, IClass type) throws CompileException {
- if (type.isPrimitiveNumeric()) return type;
- IClass unboxedType = this.isUnboxingConvertible(type);
- if (unboxedType != null) {
- this.unboxingConversion(locatable, type, unboxedType);
- return unboxedType;
- }
- this.compileError(
- "Object of type \"" + type.toString() + "\" cannot be converted to a numeric type",
- locatable.getLocation()
- );
- return type;
- }
-
- private void
- numericPromotion(Locatable locatable, IClass sourceType, IClass targetType) {
- if (
- !this.tryIdentityConversion(sourceType, targetType)
- && !this.tryWideningPrimitiveConversion(
- locatable, // locatable
- sourceType, // sourceType
- targetType // targetType
- )
- ) throw new JaninoRuntimeException("SNO: Conversion failed");
- }
-
- private IClass
- unaryNumericPromotionType(Locatable locatable, IClass type) throws CompileException {
- if (!type.isPrimitiveNumeric()) {
- this.compileError(
- "Unary numeric promotion not possible on non-numeric-primitive type \"" + type + "\"",
- locatable.getLocation()
- );
- }
-
- return (
- type == IClass.DOUBLE ? IClass.DOUBLE :
- type == IClass.FLOAT ? IClass.FLOAT :
- type == IClass.LONG ? IClass.LONG :
- IClass.INT
- );
- }
-
- /**
- * Implements "binary numeric promotion" (5.6.2)
- *
- * @return The promoted type.
- */
- private IClass
- binaryNumericPromotion(
- Locatable locatable,
- IClass type1,
- CodeContext.Inserter convertInserter1,
- IClass type2
- ) throws CompileException {
- return this.binaryNumericPromotion(
- locatable,
- type1,
- convertInserter1,
- type2,
- this.codeContext.currentInserter()
- );
- }
-
- /**
- * Implements "binary numeric promotion" (5.6.2), which may perform unboxing conversion.
- *
- * @return The promoted type.
- */
- private IClass
- binaryNumericPromotion(
- Locatable locatable,
- IClass type1,
- CodeContext.Inserter convertInserter1,
- IClass type2,
- CodeContext.Inserter convertInserter2
- ) throws CompileException {
- IClass promotedType;
- {
- IClass c1 = this.isUnboxingConvertible(type1);
- IClass c2 = this.isUnboxingConvertible(type2);
- promotedType = this.binaryNumericPromotionType(
- locatable,
- c1 != null ? c1 : type1,
- c2 != null ? c2 : type2
- );
- }
-
- if (convertInserter1 != null) {
- this.codeContext.pushInserter(convertInserter1);
- try {
- this.numericPromotion(locatable, this.convertToPrimitiveNumericType(locatable, type1), promotedType);
- } finally {
- this.codeContext.popInserter();
- }
- }
-
- if (convertInserter2 != null) {
- this.codeContext.pushInserter(convertInserter2);
- try {
- this.numericPromotion(locatable, this.convertToPrimitiveNumericType(locatable, type2), promotedType);
- } finally {
- this.codeContext.popInserter();
- }
- }
-
- return promotedType;
- }
-
- private IClass
- binaryNumericPromotionType(Locatable locatable, IClass type1, IClass type2) throws CompileException {
- if (!type1.isPrimitiveNumeric() || !type2.isPrimitiveNumeric()) {
- this.compileError(
- "Binary numeric promotion not possible on types \"" + type1 + "\" and \"" + type2 + "\"",
- locatable.getLocation()
- );
- }
-
- return (
- type1 == IClass.DOUBLE || type2 == IClass.DOUBLE ? IClass.DOUBLE :
- type1 == IClass.FLOAT || type2 == IClass.FLOAT ? IClass.FLOAT :
- type1 == IClass.LONG || type2 == IClass.LONG ? IClass.LONG :
- IClass.INT
- );
- }
-
- /**
- * Checks whether "identity conversion" (5.1.1) is possible.
- *
- * @return Whether the conversion is possible
- */
- @SuppressWarnings("static-method") private boolean
- isIdentityConvertible(IClass sourceType, IClass targetType) { return sourceType == targetType; }
-
- /**
- * Implements "identity conversion" (5.1.1).
- *
- * @return Whether the conversion was possible
- */
- @SuppressWarnings("static-method") private boolean
- tryIdentityConversion(IClass sourceType, IClass targetType) { return sourceType == targetType; }
-
- @SuppressWarnings("static-method") private boolean
- isWideningPrimitiveConvertible(IClass sourceType, IClass targetType) {
- return UnitCompiler.PRIMITIVE_WIDENING_CONVERSIONS.get(
- sourceType.getDescriptor() + targetType.getDescriptor()
- ) != null;
- }
-
- /**
- * Implements "widening primitive conversion" (5.1.2).
- *
- * @return Whether the conversion succeeded
- */
- private boolean
- tryWideningPrimitiveConversion(Locatable locatable, IClass sourceType, IClass targetType) {
- byte[] opcodes = (byte[]) UnitCompiler.PRIMITIVE_WIDENING_CONVERSIONS.get(
- sourceType.getDescriptor() + targetType.getDescriptor()
- );
- if (opcodes != null) {
- this.writeOpcodes(locatable, opcodes);
- return true;
- }
- return false;
- }
- private static final Map PRIMITIVE_WIDENING_CONVERSIONS = new HashMap();
- static { UnitCompiler.fillConversionMap(new Object[] {
- new byte[0],
- Descriptor.BYTE + Descriptor.SHORT,
-
- Descriptor.BYTE + Descriptor.INT,
- Descriptor.SHORT + Descriptor.INT,
- Descriptor.CHAR + Descriptor.INT,
-
- new byte[] { Opcode.I2L },
- Descriptor.BYTE + Descriptor.LONG,
- Descriptor.SHORT + Descriptor.LONG,
- Descriptor.CHAR + Descriptor.LONG,
- Descriptor.INT + Descriptor.LONG,
-
- new byte[] { Opcode.I2F },
- Descriptor.BYTE + Descriptor.FLOAT,
- Descriptor.SHORT + Descriptor.FLOAT,
- Descriptor.CHAR + Descriptor.FLOAT,
- Descriptor.INT + Descriptor.FLOAT,
-
- new byte[] { Opcode.L2F },
- Descriptor.LONG + Descriptor.FLOAT,
-
- new byte[] { Opcode.I2D },
- Descriptor.BYTE + Descriptor.DOUBLE,
- Descriptor.SHORT + Descriptor.DOUBLE,
- Descriptor.CHAR + Descriptor.DOUBLE,
- Descriptor.INT + Descriptor.DOUBLE,
-
- new byte[] { Opcode.L2D },
- Descriptor.LONG + Descriptor.DOUBLE,
-
- new byte[] { Opcode.F2D },
- Descriptor.FLOAT + Descriptor.DOUBLE,
- }, UnitCompiler.PRIMITIVE_WIDENING_CONVERSIONS); }
- private static void
- fillConversionMap(Object[] array, Map map) {
- byte[] opcodes = null;
- for (Object o : array) {
- if (o instanceof byte[]) {
- opcodes = (byte[]) o;
- } else {
- map.put((String) o, opcodes);
- }
- }
- }
-
- /**
- * Checks if "widening reference conversion" (5.1.4) is possible.
- *
- * @return Whether the conversion is possible
- */
- @SuppressWarnings("static-method") private boolean
- isWideningReferenceConvertible(IClass sourceType, IClass targetType) throws CompileException {
- if (targetType.isPrimitive() || sourceType == targetType) return false;
-
- return targetType.isAssignableFrom(sourceType);
- }
-
- /**
- * Performs "widening reference conversion" (5.1.4) if possible.
- *
- * @return Whether the conversion was possible
- */
- @SuppressWarnings("static-method") private boolean
- tryWideningReferenceConversion(IClass sourceType, IClass targetType) throws CompileException {
- if (targetType.isPrimitive() || sourceType == targetType) return false;
-
- return targetType.isAssignableFrom(sourceType);
- }
-
- /** Checks whether "narrowing primitive conversion" (JLS7 5.1.3) is possible. */
- @SuppressWarnings("static-method") private boolean
- isNarrowingPrimitiveConvertible(IClass sourceType, IClass targetType) {
- return UnitCompiler.PRIMITIVE_NARROWING_CONVERSIONS.containsKey(
- sourceType.getDescriptor() + targetType.getDescriptor()
- );
- }
-
- /**
- * Implements "narrowing primitive conversion" (JLS7 5.1.3).
- *
- * @return Whether the conversion succeeded
- */
- private boolean
- tryNarrowingPrimitiveConversion(Locatable locatable, IClass sourceType, IClass targetType) {
- byte[] opcodes = (byte[]) UnitCompiler.PRIMITIVE_NARROWING_CONVERSIONS.get(
- sourceType.getDescriptor() + targetType.getDescriptor()
- );
- if (opcodes != null) {
- this.writeOpcodes(locatable, opcodes);
- return true;
- }
- return false;
- }
-
- private static final Map PRIMITIVE_NARROWING_CONVERSIONS = new HashMap();
- static { UnitCompiler.fillConversionMap(new Object[] {
- new byte[0],
- Descriptor.BYTE + Descriptor.CHAR,
- Descriptor.SHORT + Descriptor.CHAR,
- Descriptor.CHAR + Descriptor.SHORT,
-
- new byte[] { Opcode.I2B },
- Descriptor.SHORT + Descriptor.BYTE,
- Descriptor.CHAR + Descriptor.BYTE,
- Descriptor.INT + Descriptor.BYTE,
-
- new byte[] { Opcode.I2S },
- Descriptor.INT + Descriptor.SHORT,
- Descriptor.INT + Descriptor.CHAR,
-
- new byte[] { Opcode.L2I, Opcode.I2B },
- Descriptor.LONG + Descriptor.BYTE,
-
- new byte[] { Opcode.L2I, Opcode.I2S },
- Descriptor.LONG + Descriptor.SHORT,
- Descriptor.LONG + Descriptor.CHAR,
-
- new byte[] { Opcode.L2I },
- Descriptor.LONG + Descriptor.INT,
-
- new byte[] { Opcode.F2I, Opcode.I2B },
- Descriptor.FLOAT + Descriptor.BYTE,
-
- new byte[] { Opcode.F2I, Opcode.I2S },
- Descriptor.FLOAT + Descriptor.SHORT,
- Descriptor.FLOAT + Descriptor.CHAR,
-
- new byte[] { Opcode.F2I },
- Descriptor.FLOAT + Descriptor.INT,
-
- new byte[] { Opcode.F2L },
- Descriptor.FLOAT + Descriptor.LONG,
-
- new byte[] { Opcode.D2I, Opcode.I2B },
- Descriptor.DOUBLE + Descriptor.BYTE,
-
- new byte[] { Opcode.D2I, Opcode.I2S },
- Descriptor.DOUBLE + Descriptor.SHORT,
- Descriptor.DOUBLE + Descriptor.CHAR,
-
- new byte[] { Opcode.D2I },
- Descriptor.DOUBLE + Descriptor.INT,
-
- new byte[] { Opcode.D2L },
- Descriptor.DOUBLE + Descriptor.LONG,
-
- new byte[] { Opcode.D2F },
- Descriptor.DOUBLE + Descriptor.FLOAT,
- }, UnitCompiler.PRIMITIVE_NARROWING_CONVERSIONS); }
-
- /**
- * Check if "constant assignment conversion" (JLS7 5.2, paragraph 1) is possible.
- *
- * @param constantValue The constant value that is to be converted
- * @param targetType The type to convert to
- */
- private boolean
- tryConstantAssignmentConversion(Locatable locatable, Object constantValue, IClass targetType)
- throws CompileException {
- if (UnitCompiler.DEBUG) {
- System.out.println("isConstantPrimitiveAssignmentConvertible(" + constantValue + ", " + targetType + ")");
- }
-
- int cv;
- if (constantValue instanceof Byte) {
- cv = ((Byte) constantValue).byteValue();
- } else
- if (constantValue instanceof Short) {
- cv = ((Short) constantValue).shortValue();
- } else
- if (constantValue instanceof Integer) {
- cv = ((Integer) constantValue).intValue();
- } else
- if (constantValue instanceof Character) {
- cv = ((Character) constantValue).charValue();
- } else
- {
- return false;
- }
-
- if (targetType == IClass.BYTE) return cv >= Byte.MIN_VALUE && cv <= Byte.MAX_VALUE;
- if (targetType == IClass.SHORT) return cv >= Short.MIN_VALUE && cv <= Short.MAX_VALUE;
- if (targetType == IClass.CHAR) return cv >= Character.MIN_VALUE && cv <= Character.MAX_VALUE;
-
- IClassLoader icl = this.iClassLoader;
- if (targetType == icl.TYPE_java_lang_Byte && cv >= Byte.MIN_VALUE && cv <= Byte.MAX_VALUE) {
- this.boxingConversion(locatable, IClass.BYTE, targetType);
- return true;
- }
- if (targetType == icl.TYPE_java_lang_Short && cv >= Short.MIN_VALUE && cv <= Short.MAX_VALUE) {
- this.boxingConversion(locatable, IClass.SHORT, targetType);
- return true;
- }
- if (targetType == icl.TYPE_java_lang_Character && cv >= Character.MIN_VALUE && cv <= Character.MAX_VALUE) {
- this.boxingConversion(locatable, IClass.CHAR, targetType);
- return true;
- }
-
- return false;
- }
-
- /** Check whether "narrowing reference conversion" (JLS7 5.1.5) is possible. */
- private boolean
- isNarrowingReferenceConvertible(IClass sourceType, IClass targetType) throws CompileException {
- if (sourceType.isPrimitive()) return false;
- if (sourceType == targetType) return false;
-
- // 5.1.5.1
- if (sourceType.isAssignableFrom(targetType)) return true;
-
- // 5.1.5.2
- if (targetType.isInterface() && !sourceType.isFinal() && !targetType.isAssignableFrom(sourceType)) return true;
-
- // 5.1.5.3
- if (sourceType == this.iClassLoader.TYPE_java_lang_Object && targetType.isArray()) return true;
-
- // 5.1.5.4
- if (sourceType == this.iClassLoader.TYPE_java_lang_Object && targetType.isInterface()) return true;
-
- // 5.1.5.5
- if (sourceType.isInterface() && !targetType.isFinal()) return true;
-
- // 5.1.5.6
- if (sourceType.isInterface() && targetType.isFinal() && sourceType.isAssignableFrom(targetType)) return true;
-
- // 5.1.5.7
- // TODO: Check for redefinition of methods with same signature but different return type.
- if (sourceType.isInterface() && targetType.isInterface() && !targetType.isAssignableFrom(sourceType)) {
- return true;
- }
-
- // 5.1.5.8
- if (sourceType.isArray() && targetType.isArray()) {
- IClass st = sourceType.getComponentType();
- IClass tt = targetType.getComponentType();
- if (this.isNarrowingPrimitiveConvertible(st, tt) || this.isNarrowingReferenceConvertible(st, tt)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Implements "narrowing reference conversion" (5.1.5).
- *
- * @return Whether the conversion succeeded
- */
- private boolean
- tryNarrowingReferenceConversion(Locatable locatable, IClass sourceType, IClass targetType) throws CompileException {
- if (!this.isNarrowingReferenceConvertible(sourceType, targetType)) return false;
-
- this.writeOpcode(locatable, Opcode.CHECKCAST);
- this.writeConstantClassInfo(targetType.getDescriptor());
- return true;
- }
-
- /** JLS7 5.5 */
- private boolean
- isCastReferenceConvertible(IClass sourceType, IClass targetType) throws CompileException {
- return (
- this.isIdentityConvertible(sourceType, targetType)
- || this.isWideningReferenceConvertible(sourceType, targetType)
- || this.isNarrowingReferenceConvertible(sourceType, targetType)
- );
- }
-
- /** @return The boxed type or {@code null} */
- private IClass
- isBoxingConvertible(IClass sourceType) {
- IClassLoader icl = this.iClassLoader;
- if (sourceType == IClass.BOOLEAN) return icl.TYPE_java_lang_Boolean;
- if (sourceType == IClass.BYTE) return icl.TYPE_java_lang_Byte;
- if (sourceType == IClass.CHAR) return icl.TYPE_java_lang_Character;
- if (sourceType == IClass.SHORT) return icl.TYPE_java_lang_Short;
- if (sourceType == IClass.INT) return icl.TYPE_java_lang_Integer;
- if (sourceType == IClass.LONG) return icl.TYPE_java_lang_Long;
- if (sourceType == IClass.FLOAT) return icl.TYPE_java_lang_Float;
- if (sourceType == IClass.DOUBLE) return icl.TYPE_java_lang_Double;
- return null;
- }
-
- private boolean
- tryBoxingConversion(Locatable locatable, IClass sourceType, IClass targetType) throws CompileException {
- if (this.isBoxingConvertible(sourceType) == targetType) {
- this.boxingConversion(locatable, sourceType, targetType);
- return true;
- }
- return false;
- }
-
- /**
- * @param sourceType a primitive type (except VOID)
- * @param targetType the corresponding wrapper type
- */
- private void
- boxingConversion(Locatable locatable, IClass sourceType, IClass targetType) throws CompileException {
-
- // In some pre-1.5 JDKs, only some wrapper classes have the static "Target.valueOf(source)" method.
- if (targetType.hasIMethod("valueOf", new IClass[] { sourceType })) {
- this.writeOpcode(locatable, Opcode.INVOKESTATIC);
- this.writeConstantMethodrefInfo(
- targetType.getDescriptor(), // classFD
- "valueOf", // methodName
- '(' + sourceType.getDescriptor() + ')' + targetType.getDescriptor() // methodFD
- );
- return;
- }
- // new Target(source)
- this.writeOpcode(locatable, Opcode.NEW);
- this.writeConstantClassInfo(targetType.getDescriptor());
- if (Descriptor.hasSize2(sourceType.getDescriptor())) {
- this.writeOpcode(locatable, Opcode.DUP_X2);
- this.writeOpcode(locatable, Opcode.DUP_X2);
- this.writeOpcode(locatable, Opcode.POP);
- } else
- {
- this.writeOpcode(locatable, Opcode.DUP_X1);
- this.writeOpcode(locatable, Opcode.SWAP);
- }
- this.writeOpcode(locatable, Opcode.INVOKESPECIAL);
- this.writeConstantMethodrefInfo(
- targetType.getDescriptor(), // classFd
- "", // methodName
- '(' + sourceType.getDescriptor() + ')' + Descriptor.VOID // methodMd
- );
- }
-
- /** @return Iff {@code sourceType} is a primitive wrapper type, the unboxed type, otherwise {@code null} */
- private IClass
- isUnboxingConvertible(IClass sourceType) {
- IClassLoader icl = this.iClassLoader;
- if (sourceType == icl.TYPE_java_lang_Boolean) return IClass.BOOLEAN;
- if (sourceType == icl.TYPE_java_lang_Byte) return IClass.BYTE;
- if (sourceType == icl.TYPE_java_lang_Character) return IClass.CHAR;
- if (sourceType == icl.TYPE_java_lang_Short) return IClass.SHORT;
- if (sourceType == icl.TYPE_java_lang_Integer) return IClass.INT;
- if (sourceType == icl.TYPE_java_lang_Long) return IClass.LONG;
- if (sourceType == icl.TYPE_java_lang_Float) return IClass.FLOAT;
- if (sourceType == icl.TYPE_java_lang_Double) return IClass.DOUBLE;
- return null;
- }
-
- /**
- * @return Whether the {@code sourceType} is a primitive numeric type, or a wrapper type of a primitive numeric
- * type
- */
- private boolean
- isConvertibleToPrimitiveNumeric(IClass sourceType) {
- if (sourceType.isPrimitiveNumeric()) return true;
- IClass unboxedType = this.isUnboxingConvertible(sourceType);
- return unboxedType != null && unboxedType.isPrimitiveNumeric();
- }
-
- private boolean
- tryUnboxingConversion(Locatable locatable, IClass sourceType, IClass targetType, Inserter optionalInserter) {
- if (this.isUnboxingConvertible(sourceType) == targetType) {
- this.unboxingConversion(locatable, sourceType, targetType, optionalInserter);
- return true;
- }
- return false;
- }
-
- /**
- * @param targetType a primitive type (except VOID)
- * @param sourceType the corresponding wrapper type
- */
- private void
- unboxingConversion(Locatable locatable, IClass sourceType, IClass targetType, Inserter optionalInserter) {
- if (optionalInserter == null) {
- this.unboxingConversion(locatable, sourceType, targetType);
- } else {
- this.codeContext.pushInserter(optionalInserter);
- try {
- this.unboxingConversion(locatable, sourceType, targetType);
- } finally {
- this.codeContext.popInserter();
- }
- }
- }
-
- /**
- * @param targetType a primitive type (except VOID)
- * @param sourceType the corresponding wrapper type
- */
- private void
- unboxingConversion(Locatable locatable, IClass sourceType, IClass targetType) {
-
- // "source.targetValue()"
- this.writeOpcode(locatable, Opcode.INVOKEVIRTUAL);
- this.writeConstantMethodrefInfo(
- sourceType.getDescriptor(), // classFD
- targetType.toString() + "Value", // methodName
- "()" + targetType.getDescriptor() // methodFD
- );
- }
-
- /**
- * Attempts to load an {@link IClass} by fully-qualified name through {@link #iClassLoader}.
- * @param location TODO
- * @param identifiers The fully qualified type name, e.g. '{ "pkg", "Outer", "Inner" }
'
- *
- * @return {@code null} if a class with the given name could not be loaded
- * @throws CompileException The type exists, but a problem occurred when it was loaded
- */
- private IClass
- findTypeByFullyQualifiedName(Location location, String[] identifiers) throws CompileException {
-
- // Try all 'flavors', i.e. 'a.b.c', 'a.b$c', 'a$b$c'.
- String className = Java.join(identifiers, ".");
- for (;;) {
- IClass iClass = UnitCompiler.this.findTypeByName(location, className);
- if (iClass != null) return iClass;
-
- int idx = className.lastIndexOf('.');
- if (idx == -1) break;
- className = className.substring(0, idx) + '$' + className.substring(idx + 1);
- }
-
- return null;
- }
-
- // Load the value of a local variable onto the stack and return its type.
- private IClass
- load(Locatable locatable, LocalVariable localVariable) {
- this.load(locatable, localVariable.type, localVariable.getSlotIndex());
- return localVariable.type;
- }
- private void
- load(Locatable locatable, IClass type, int index) {
- if (index <= 3) {
- this.writeOpcode(locatable, Opcode.ILOAD_0 + 4 * UnitCompiler.ilfda(type) + index);
- } else
- if (index <= 255) {
- this.writeOpcode(locatable, Opcode.ILOAD + UnitCompiler.ilfda(type));
- this.writeByte(index);
- } else
- {
- this.writeOpcode(locatable, Opcode.WIDE);
- this.writeOpcode(locatable, Opcode.ILOAD + UnitCompiler.ilfda(type));
- this.writeShort(index);
- }
- }
-
- /**
- * Assign top stack top value to the given local variable.
- */
- private void
- store(Locatable locatable, LocalVariable localVariable) {
- this.store(
- locatable, // locatable
- localVariable.type, // lvType
- localVariable.getSlotIndex() // lvIndex
- );
- }
- private void
- store(Locatable locatable, IClass lvType, short lvIndex) {
- if (lvIndex <= 3) {
- this.writeOpcode(locatable, Opcode.ISTORE_0 + 4 * UnitCompiler.ilfda(lvType) + lvIndex);
- } else
- if (lvIndex <= 255) {
- this.writeOpcode(locatable, Opcode.ISTORE + UnitCompiler.ilfda(lvType));
- this.writeByte(lvIndex);
- } else
- {
- this.writeOpcode(locatable, Opcode.WIDE);
- this.writeOpcode(locatable, Opcode.ISTORE + UnitCompiler.ilfda(lvType));
- this.writeShort(lvIndex);
- }
- }
-
- private void
- getfield(Locatable locatable, IClass.IField iField) throws CompileException {
- this.writeOpcode(locatable, iField.isStatic() ? Opcode.GETSTATIC : Opcode.GETFIELD);
- this.writeConstantFieldrefInfo(
- iField.getDeclaringIClass().getDescriptor(), // classFD
- iField.getName(), // fieldName
- iField.getDescriptor() // fieldFD
- );
- }
-
- private void
- putfield(Locatable locatable, IField iField) throws CompileException {
- this.writeOpcode(locatable, iField.isStatic() ? Opcode.PUTSTATIC : Opcode.PUTFIELD);
- this.writeConstantFieldrefInfo(
- iField.getDeclaringIClass().getDescriptor(), // classFD
- iField.getName(), // fieldName
- iField.getDescriptor() // fieldFD
- );
- }
-
- private void
- dup(Locatable locatable, int n) {
- switch (n) {
-
- case 0:
- ;
- break;
-
- case 1:
- this.writeOpcode(locatable, Opcode.DUP);
- break;
-
- case 2:
- this.writeOpcode(locatable, Opcode.DUP2);
- break;
-
- default:
- throw new JaninoRuntimeException("dup(" + n + ")");
- }
- }
- private void
- dupx(Locatable locatable, IClass type, int x) {
- if (x < 0 || x > 2) throw new JaninoRuntimeException("SNO: x has value " + x);
- int dup = Opcode.DUP + x;
- int dup2 = Opcode.DUP2 + x;
- this.writeOpcode(locatable, type == IClass.LONG || type == IClass.DOUBLE ? dup2 : dup);
- }
-
- private void
- pop(Locatable locatable, IClass type) {
- if (type == IClass.VOID) return;
- this.writeOpcode(locatable, type == IClass.LONG || type == IClass.DOUBLE ? Opcode.POP2 : Opcode.POP);
- }
-
- private static int
- ilfd(final IClass t) {
- if (t == IClass.BYTE || t == IClass.CHAR || t == IClass.INT || t == IClass.SHORT || t == IClass.BOOLEAN) {
- return 0;
- }
- if (t == IClass.LONG) return 1;
- if (t == IClass.FLOAT) return 2;
- if (t == IClass.DOUBLE) return 3;
- throw new JaninoRuntimeException("Unexpected type \"" + t + "\"");
- }
-
- private static int
- ilfd(IClass t, int opcodeInt, int opcodeLong, int opcodeFloat, int opcodeDouble) {
- if (t == IClass.BYTE || t == IClass.CHAR || t == IClass.INT || t == IClass.SHORT || t == IClass.BOOLEAN) {
- return opcodeInt;
- }
- if (t == IClass.LONG) return opcodeLong;
- if (t == IClass.FLOAT) return opcodeFloat;
- if (t == IClass.DOUBLE) return opcodeDouble;
- throw new JaninoRuntimeException("Unexpected type \"" + t + "\"");
- }
-
- private static int
- ilfda(IClass t) { return !t.isPrimitive() ? 4 : UnitCompiler.ilfd(t); }
-
- private static int
- ilfdabcs(IClass t) {
- if (t == IClass.INT) return 0;
- if (t == IClass.LONG) return 1;
- if (t == IClass.FLOAT) return 2;
- if (t == IClass.DOUBLE) return 3;
- if (!t.isPrimitive()) return 4;
- if (t == IClass.BOOLEAN) return 5;
- if (t == IClass.BYTE) return 5;
- if (t == IClass.CHAR) return 6;
- if (t == IClass.SHORT) return 7;
- throw new JaninoRuntimeException("Unexpected type \"" + t + "\"");
- }
-
- private void
- invoke(Locatable locatable, IMethod iMethod) throws CompileException {
- if (iMethod.getDeclaringIClass().isInterface()) {
- this.writeOpcode(locatable, Opcode.INVOKEINTERFACE);
- this.writeConstantInterfaceMethodrefInfo(
- iMethod.getDeclaringIClass().getDescriptor(), // classFD
- iMethod.getName(), // methodName
- iMethod.getDescriptor() // methodMD
- );
- int count = 1;
- for (IClass pt : iMethod.getParameterTypes()) count += Descriptor.size(pt.getDescriptor());
- this.writeByte(count);
- this.writeByte(0);
- } else {
- this.writeOpcode(locatable, iMethod.isStatic() ? Opcode.INVOKESTATIC : Opcode.INVOKEVIRTUAL);
- this.writeConstantMethodrefInfo(
- iMethod.getDeclaringIClass().getDescriptor(), // classFD
- iMethod.getName(), // methodName
- iMethod.getDescriptor() // methodMD
- );
- }
- }
-
- private void
- invoke(Locatable locatable, IConstructor iConstructor) throws CompileException {
- this.writeOpcode(locatable, Opcode.INVOKESPECIAL);
- this.writeConstantMethodrefInfo(
- iConstructor.getDeclaringIClass().getDescriptor(), // classFD
- "", // methodName
- iConstructor.getDescriptor() // methodMD
- );
- }
-
- /**
- * Finds a named field in the given {@link IClass}. Honors superclasses and interfaces. See JLS7 8.3.
- *
- * @return {@code null} if no field is found
- */
- private IClass.IField
- findIField(IClass iClass, String name, Location location) throws CompileException {
-
- // Search for a field with the given name in the current class.
- IClass.IField f = iClass.getDeclaredIField(name);
- if (f != null) return f;
-
- // Examine superclass.
- {
- IClass superclass = iClass.getSuperclass();
- if (superclass != null) f = this.findIField(superclass, name, location);
- }
-
- // Examine interfaces.
- IClass[] ifs = iClass.getInterfaces();
- for (IClass iF : ifs) {
- IClass.IField f2 = this.findIField(iF, name, location);
- if (f2 != null) {
- if (f != null) {
- throw new CompileException((
- "Access to field \""
- + name
- + "\" is ambiguous - both \""
- + f.getDeclaringIClass()
- + "\" and \""
- + f2.getDeclaringIClass()
- + "\" declare it"
- ), location);
- }
- f = f2;
- }
- }
- return f;
- }
-
- /**
- * Finds a named type in the given {@link IClass}. Honors superclasses, interfaces and enclosing type declarations.
- *
- * @return {@code null} if no type with the given name is found
- */
- private IClass
- findMemberType(IClass iClass, String name, Location location) throws CompileException {
- IClass[] types = iClass.findMemberType(name);
- if (types.length == 0) return null;
- if (types.length == 1) return types[0];
-
- StringBuilder sb = new StringBuilder("Type \"").append(name).append("\" is ambiguous: ").append(types[0]);
- for (int i = 1; i < types.length; ++i) sb.append(" vs. ").append(types[i].toString());
- this.compileError(sb.toString(), location);
- return types[0];
- }
-
- /**
- * Find one class or interface declared in this compilation unit by name.
- *
- * @param className Fully qualified class name, e.g. "pkg1.pkg2.Outer$Inner".
- * @return {@code null} if a class or an interface with that name is not declared in this compilation unit
- */
- public IClass
- findClass(String className) {
-
- // Examine package name.
- String packageName = (
- this.compilationUnit.optionalPackageDeclaration == null ? null :
- this.compilationUnit.optionalPackageDeclaration.packageName
- );
- if (packageName != null) {
- if (!className.startsWith(packageName + '.')) return null;
- className = className.substring(packageName.length() + 1);
- }
-
- StringTokenizer st = new StringTokenizer(className, "$");
- TypeDeclaration td = this.compilationUnit.getPackageMemberTypeDeclaration(st.nextToken());
- if (td == null) return null;
- while (st.hasMoreTokens()) {
- td = td.getMemberTypeDeclaration(st.nextToken());
- if (td == null) return null;
- }
- return this.resolve(td);
- }
-
- /** Equivalent with {@link #compileError(String, Location)} with a {@code null} location argument. */
- private void
- compileError(String message) throws CompileException { this.compileError(message, null); }
-
- /**
- * Issue a compile error with the given message. This is done through the {@link ErrorHandler} that was installed
- * through {@link #setCompileErrorHandler(ErrorHandler)}. Such a handler typically throws a {@link
- * CompileException}, but it may as well decide to return normally. Consequently, the calling code must be prepared
- * that {@link #compileError(String, Location)} returns normally, and must attempt to continue compiling.
- *
- * @param message The message to report
- * @param optionalLocation The location to report
- */
- private void
- compileError(String message, Location optionalLocation) throws CompileException {
- ++this.compileErrorCount;
- if (this.optionalCompileErrorHandler != null) {
- this.optionalCompileErrorHandler.handleError(message, optionalLocation);
- } else {
- throw new CompileException(message, optionalLocation);
- }
- }
-
- /**
- * Issues a warning with the given message an location an returns. This is done through a {@link WarningHandler}
- * that was installed through {@link #setWarningHandler(WarningHandler)}.
- *
- * The {@code handle} argument qualifies the warning and is typically used by the {@link WarningHandler} to
- * suppress individual warnings.
- */
- private void
- warning(String handle, String message, Location optionalLocation) throws CompileException {
- if (this.optionalWarningHandler != null) {
- this.optionalWarningHandler.handleWarning(handle, message, optionalLocation);
- }
- }
-
- /**
- * By default, {@link CompileException}s are thrown on compile errors, but an application my install its own
- * (thread-local) {@link ErrorHandler}.
- *
- * Be aware that a single problem during compilation often causes a bunch of compile errors, so a good {@link
- * ErrorHandler} counts errors and throws a {@link CompileException} when a limit is reached.
- *
- * If the given {@link ErrorHandler} does not throw {@link CompileException}s, then {@link
- * #compileUnit(boolean, boolean, boolean)} will throw one when the compilation of the unit is finished, and errors
- * had occurred. In other words: The {@link ErrorHandler} may throw a {@link CompileException} or not, but {@link
- * #compileUnit(boolean, boolean, boolean)} will definitely throw a {@link CompileException} if one or more compile
- * errors have occurred.
- *
- * @param optionalCompileErrorHandler {@code null} to restore the default behavior (throwing a {@link
- * CompileException}
- */
- 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;
- }
-
- private CodeContext
- replaceCodeContext(CodeContext newCodeContext) {
- CodeContext oldCodeContext = this.codeContext;
- this.codeContext = newCodeContext;
- return oldCodeContext;
- }
-
- private void
- writeByte(int v) {
- if (v > Byte.MAX_VALUE - Byte.MIN_VALUE) {
- throw new JaninoRuntimeException("Byte value out of legal range");
- }
- this.codeContext.write((short) -1, (byte) v);
- }
- private void
- writeShort(int v) {
- if (v > Short.MAX_VALUE - Short.MIN_VALUE) {
- throw new JaninoRuntimeException("Short value out of legal range");
- }
- this.codeContext.write((short) -1, (byte) (v >> 8), (byte) v);
- }
- private void
- writeInt(int v) {
- this.codeContext.write((short) -1, (byte) (v >> 24), (byte) (v >> 16), (byte) (v >> 8), (byte) v);
- }
-
- private void
- writeOpcode(Locatable locatable, int opcode) {
- this.codeContext.write(locatable.getLocation().getLineNumber(), (byte) opcode);
- }
-
- private void
- writeOpcodes(Locatable locatable, byte[] opcodes) {
- this.codeContext.write(locatable.getLocation().getLineNumber(), opcodes);
- }
-
- private void
- writeBranch(Locatable locatable, int opcode, final CodeContext.Offset dst) {
- this.codeContext.writeBranch(locatable.getLocation().getLineNumber(), opcode, dst);
- }
-
- private void
- writeOffset(CodeContext.Offset src, final CodeContext.Offset dst) {
- this.codeContext.writeOffset((short) -1, src, dst);
- }
-
- // Wrappers for "ClassFile.addConstant...Info()". Saves us some coding overhead.
-
- private void
- writeConstantClassInfo(String descriptor) {
- CodeContext ca = this.codeContext;
- ca.writeShort((short) -1, ca.getClassFile().addConstantClassInfo(descriptor));
- }
- private void
- writeConstantFieldrefInfo(String classFd, String fieldName, String fieldFd) {
- CodeContext ca = this.codeContext;
- ca.writeShort((short) -1, ca.getClassFile().addConstantFieldrefInfo(classFd, fieldName, fieldFd));
- }
- private void
- writeConstantMethodrefInfo(String classFd, String methodName, String methodMd) {
- CodeContext ca = this.codeContext;
- ca.writeShort((short) -1, ca.getClassFile().addConstantMethodrefInfo(classFd, methodName, methodMd));
- }
- private void
- writeConstantInterfaceMethodrefInfo(String classFd, String methodName, String methodMd) {
- CodeContext ca = this.codeContext;
- ca.writeShort((short) -1, ca.getClassFile().addConstantInterfaceMethodrefInfo(classFd, methodName, methodMd));
- }
-/* UNUSED
- private void writeConstantStringInfo(String value) {
- this.codeContext.writeShort((short) -1, this.addConstantStringInfo(value));
- }
-*/
- private short
- addConstantStringInfo(String value) {
- return this.codeContext.getClassFile().addConstantStringInfo(value);
- }
-/* UNUSED
- private void writeConstantIntegerInfo(int value) {
- this.codeContext.writeShort((short) -1, this.addConstantIntegerInfo(value));
- }
-*/
- private short
- addConstantIntegerInfo(int value) {
- return this.codeContext.getClassFile().addConstantIntegerInfo(value);
- }
-/* UNUSED
- private void writeConstantFloatInfo(float value) {
- this.codeContext.writeShort((short) -1, this.addConstantFloatInfo(value));
- }
-*/
- private short
- addConstantFloatInfo(float value) {
- return this.codeContext.getClassFile().addConstantFloatInfo(value);
- }
- private void
- writeConstantLongInfo(long value) {
- CodeContext ca = this.codeContext;
- ca.writeShort((short) -1, ca.getClassFile().addConstantLongInfo(value));
- }
- private void
- writeConstantDoubleInfo(double value) {
- CodeContext ca = this.codeContext;
- ca.writeShort((short) -1, ca.getClassFile().addConstantDoubleInfo(value));
- }
-
- private CodeContext.Offset
- getWhereToBreak(BreakableStatement bs) {
- if (bs.whereToBreak == null) {
- bs.whereToBreak = this.codeContext.new Offset();
- }
- return bs.whereToBreak;
- }
-
- private TypeBodyDeclaration
- getDeclaringTypeBodyDeclaration(QualifiedThisReference qtr) throws CompileException {
- if (qtr.declaringTypeBodyDeclaration == null) {
-
- // Compile error if in static function context.
- Scope s;
- for (
- s = qtr.getEnclosingBlockStatement();
- !(s instanceof TypeBodyDeclaration);
- s = s.getEnclosingScope()
- );
- qtr.declaringTypeBodyDeclaration = (TypeBodyDeclaration) s;
- if (qtr.declaringTypeBodyDeclaration.isStatic()) {
- this.compileError("No current instance available in static method", qtr.getLocation());
- }
-
- // Determine declaring type.
- qtr.declaringClass = (ClassDeclaration) qtr.declaringTypeBodyDeclaration.getDeclaringType();
- }
- return qtr.declaringTypeBodyDeclaration;
- }
-
- private ClassDeclaration
- getDeclaringClass(QualifiedThisReference qtr) throws CompileException {
- if (qtr.declaringClass == null) {
- this.getDeclaringTypeBodyDeclaration(qtr);
- }
- return qtr.declaringClass;
- }
-
- private void
- referenceThis(Locatable locatable) { this.writeOpcode(locatable, Opcode.ALOAD_0); }
-
- /**
- * Expects {@code dimExprCount} values of type {@code int} on the operand stack. Creates an array of {@code
- * dimExprCount + dims} dimensions of {@code componentType}.
- *
- * @return The type of the created array
- */
- private IClass
- newArray(Locatable locatable, int dimExprCount, int dims, IClass componentType) {
- if (dimExprCount == 1 && dims == 0 && componentType.isPrimitive()) {
-
- // "new []"
- this.writeOpcode(locatable, Opcode.NEWARRAY);
- this.writeByte((
- componentType == IClass.BOOLEAN ? 4 :
- componentType == IClass.CHAR ? 5 :
- componentType == IClass.FLOAT ? 6 :
- componentType == IClass.DOUBLE ? 7 :
- componentType == IClass.BYTE ? 8 :
- componentType == IClass.SHORT ? 9 :
- componentType == IClass.INT ? 10 :
- componentType == IClass.LONG ? 11 : -1
- ));
- return componentType.getArrayIClass(this.iClassLoader.TYPE_java_lang_Object);
- }
-
- if (dimExprCount == 1) {
- IClass at = componentType.getArrayIClass(dims, this.iClassLoader.TYPE_java_lang_Object);
-
- // "new []"
- // "new