All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.greenpepper.shaded.org.codehaus.janino.SimpleCompiler Maven / Gradle / Ivy

The newest version!

/*
 * 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 com.greenpepper.shaded.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 com.greenpepper.shaded.org.codehaus.commons.compiler.CompileException;
import com.greenpepper.shaded.org.codehaus.commons.compiler.Cookable;
import com.greenpepper.shaded.org.codehaus.commons.compiler.ErrorHandler;
import com.greenpepper.shaded.org.codehaus.commons.compiler.ICookable;
import com.greenpepper.shaded.org.codehaus.commons.compiler.ISimpleCompiler;
import com.greenpepper.shaded.org.codehaus.commons.compiler.Location;
import com.greenpepper.shaded.org.codehaus.commons.compiler.WarningHandler;
import com.greenpepper.shaded.org.codehaus.janino.Java.Type;
import com.greenpepper.shaded.org.codehaus.janino.Visitor.AtomVisitor;
import com.greenpepper.shaded.org.codehaus.janino.Visitor.TypeVisitor;
import com.greenpepper.shaded.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("    com.greenpepper.shaded.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"); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy