You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by cc...@apache.org on 2017/12/17 14:01:26 UTC
[15/62] [abbrv] [partial] groovy git commit: Move Java source set
into `src/main/java`
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
new file mode 100644
index 0000000..dab0e55
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
@@ -0,0 +1,1167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.control;
+
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyRuntimeException;
+import groovy.transform.CompilationUnitAware;
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.classgen.ClassCompletionVerifier;
+import org.codehaus.groovy.classgen.EnumCompletionVisitor;
+import org.codehaus.groovy.classgen.EnumVisitor;
+import org.codehaus.groovy.classgen.ExtendedVerifier;
+import org.codehaus.groovy.classgen.GeneratorContext;
+import org.codehaus.groovy.classgen.InnerClassCompletionVisitor;
+import org.codehaus.groovy.classgen.InnerClassVisitor;
+import org.codehaus.groovy.classgen.VariableScopeVisitor;
+import org.codehaus.groovy.classgen.Verifier;
+import org.codehaus.groovy.control.customizers.CompilationCustomizer;
+import org.codehaus.groovy.control.io.InputStreamReaderSource;
+import org.codehaus.groovy.control.io.ReaderSource;
+import org.codehaus.groovy.control.messages.ExceptionMessage;
+import org.codehaus.groovy.control.messages.Message;
+import org.codehaus.groovy.control.messages.SimpleMessage;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.codehaus.groovy.tools.GroovyClass;
+import org.codehaus.groovy.transform.ASTTransformationVisitor;
+import org.codehaus.groovy.transform.AnnotationCollectorTransform;
+import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
+import org.codehaus.groovy.transform.trait.TraitComposer;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.CodeSource;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The CompilationUnit collects all compilation data as it is generated by the compiler system.
+ * You can use this object to add additional source units to the compilation, or force the
+ * compilation to be run again (to affect only the deltas).
+ * <p>
+ * You can also add PhaseOperations to this compilation using the addPhaseOperation method.
+ * This is commonly used when you want to wire a new AST Transformation into the compilation.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * @author <a href="mailto:roshandawrani@codehaus.org">Roshan Dawrani</a>
+ */
+
+public class CompilationUnit extends ProcessingUnit {
+
+ //---------------------------------------------------------------------------
+ // CONSTRUCTION AND SUCH
+
+ protected ASTTransformationsContext astTransformationsContext; // AST transformations state data
+
+ protected Map<String, SourceUnit> sources; // The SourceUnits from which this unit is built
+ protected Map summariesBySourceName; // Summary of each SourceUnit
+ protected Map summariesByPublicClassName; // Summary of each SourceUnit
+ protected Map classSourcesByPublicClassName; // Summary of each Class
+ protected List<String> names; // Names for each SourceUnit in sources.
+ protected LinkedList<SourceUnit> queuedSources;
+
+ protected CompileUnit ast; // The overall AST for this CompilationUnit.
+ protected List<GroovyClass> generatedClasses; // The classes generated during classgen.
+
+ protected Verifier verifier; // For use by verify().
+
+ protected boolean debug; // Controls behavior of classgen() and other routines.
+ protected boolean configured; // Set true after the first configure() operation
+
+ protected ClassgenCallback classgenCallback; // A callback for use during classgen()
+ protected ProgressCallback progressCallback; // A callback for use during compile()
+ protected ResolveVisitor resolveVisitor;
+ protected StaticImportVisitor staticImportVisitor;
+ protected OptimizerVisitor optimizer;
+ protected ClassNodeResolver classNodeResolver;
+
+ LinkedList[] phaseOperations;
+ LinkedList[] newPhaseOperations;
+
+ /**
+ * Initializes the CompilationUnit with defaults.
+ */
+ public CompilationUnit() {
+ this(null, null, null);
+ }
+
+
+ /**
+ * Initializes the CompilationUnit with defaults except for class loader.
+ */
+ public CompilationUnit(GroovyClassLoader loader) {
+ this(null, null, loader);
+ }
+
+
+ /**
+ * Initializes the CompilationUnit with no security considerations.
+ */
+ public CompilationUnit(CompilerConfiguration configuration) {
+ this(configuration, null, null);
+ }
+
+ /**
+ * Initializes the CompilationUnit with a CodeSource for controlling
+ * security stuff and a class loader for loading classes.
+ */
+ public CompilationUnit(CompilerConfiguration configuration, CodeSource security, GroovyClassLoader loader) {
+ this(configuration, security, loader, null);
+ }
+
+ /**
+ * Initializes the CompilationUnit with a CodeSource for controlling
+ * security stuff, a class loader for loading classes, and a class
+ * loader for loading AST transformations.
+ * <b>Note</b> The transform loader must be
+ * able to load compiler classes. That means CompilationUnit.class.classLoader
+ * must be at last a parent to transformLoader. The other loader has no such constraint.
+ *
+ * @param transformLoader - the loader for transforms
+ * @param loader - loader used to resolve classes against during compilation
+ * @param security - security setting for the compilation
+ * @param configuration - compilation configuration
+ */
+ public CompilationUnit(CompilerConfiguration configuration, CodeSource security,
+ GroovyClassLoader loader, GroovyClassLoader transformLoader) {
+ super(configuration, loader, null);
+
+ this.astTransformationsContext = new ASTTransformationsContext(this, transformLoader);
+ this.names = new ArrayList<String>();
+ this.queuedSources = new LinkedList<SourceUnit>();
+ this.sources = new HashMap<String, SourceUnit>();
+ this.summariesBySourceName = new HashMap();
+ this.summariesByPublicClassName = new HashMap();
+ this.classSourcesByPublicClassName = new HashMap();
+
+ this.ast = new CompileUnit(this.classLoader, security, this.configuration);
+ this.generatedClasses = new ArrayList<GroovyClass>();
+
+ this.verifier = new Verifier();
+ this.resolveVisitor = new ResolveVisitor(this);
+ this.staticImportVisitor = new StaticImportVisitor();
+ this.optimizer = new OptimizerVisitor(this);
+
+ phaseOperations = new LinkedList[Phases.ALL + 1];
+ newPhaseOperations = new LinkedList[Phases.ALL + 1];
+ for (int i = 0; i < phaseOperations.length; i++) {
+ phaseOperations[i] = new LinkedList();
+ newPhaseOperations[i] = new LinkedList();
+ }
+ addPhaseOperation(new SourceUnitOperation() {
+ public void call(SourceUnit source) throws CompilationFailedException {
+ source.parse();
+ }
+ }, Phases.PARSING);
+ addPhaseOperation(convert, Phases.CONVERSION);
+ addPhaseOperation(new PrimaryClassNodeOperation() {
+ public void call(SourceUnit source, GeneratorContext context,
+ ClassNode classNode) throws CompilationFailedException {
+ EnumVisitor ev = new EnumVisitor(CompilationUnit.this, source);
+ ev.visitClass(classNode);
+ }
+ }, Phases.CONVERSION);
+ addPhaseOperation(resolve, Phases.SEMANTIC_ANALYSIS);
+ addPhaseOperation(staticImport, Phases.SEMANTIC_ANALYSIS);
+ addPhaseOperation(new PrimaryClassNodeOperation() {
+ @Override
+ public void call(SourceUnit source, GeneratorContext context,
+ ClassNode classNode) throws CompilationFailedException {
+ InnerClassVisitor iv = new InnerClassVisitor(CompilationUnit.this, source);
+ iv.visitClass(classNode);
+ }
+ }, Phases.SEMANTIC_ANALYSIS);
+ addPhaseOperation(new PrimaryClassNodeOperation() {
+ @Override
+ public void call(SourceUnit source, GeneratorContext context,
+ ClassNode classNode) throws CompilationFailedException {
+ if (!classNode.isSynthetic()) {
+ GenericsVisitor genericsVisitor = new GenericsVisitor(source);
+ genericsVisitor.visitClass(classNode);
+ }
+ }
+ }, Phases.SEMANTIC_ANALYSIS);
+ addPhaseOperation(new PrimaryClassNodeOperation() {
+ public void call(SourceUnit source, GeneratorContext context,
+ ClassNode classNode) throws CompilationFailedException {
+ TraitComposer.doExtendTraits(classNode, source, CompilationUnit.this);
+ }
+ }, Phases.CANONICALIZATION);
+ addPhaseOperation(compileCompleteCheck, Phases.CANONICALIZATION);
+ addPhaseOperation(classgen, Phases.CLASS_GENERATION);
+ addPhaseOperation(output);
+
+ addPhaseOperation(new PrimaryClassNodeOperation() {
+ @Override
+ public void call(SourceUnit source, GeneratorContext context,
+ ClassNode classNode) throws CompilationFailedException {
+ AnnotationCollectorTransform.ClassChanger actt = new AnnotationCollectorTransform.ClassChanger();
+ actt.transformClass(classNode);
+ }
+ }, Phases.SEMANTIC_ANALYSIS);
+ ASTTransformationVisitor.addPhaseOperations(this);
+ addPhaseOperation(new PrimaryClassNodeOperation() {
+ @Override
+ public void call(SourceUnit source, GeneratorContext context,
+ ClassNode classNode) throws CompilationFailedException {
+ StaticVerifier sv = new StaticVerifier();
+ sv.visitClass(classNode, source);
+ }
+ }, Phases.SEMANTIC_ANALYSIS);
+ addPhaseOperation(new PrimaryClassNodeOperation() {
+ @Override
+ public void call(SourceUnit source, GeneratorContext context,
+ ClassNode classNode) throws CompilationFailedException {
+ InnerClassCompletionVisitor iv = new InnerClassCompletionVisitor(CompilationUnit.this, source);
+ iv.visitClass(classNode);
+ }
+ }, Phases.CANONICALIZATION);
+ addPhaseOperation(new PrimaryClassNodeOperation() {
+ public void call(SourceUnit source, GeneratorContext context,
+ ClassNode classNode) throws CompilationFailedException {
+ EnumCompletionVisitor ecv = new EnumCompletionVisitor(CompilationUnit.this, source);
+ ecv.visitClass(classNode);
+ }
+ }, Phases.CANONICALIZATION);
+ addPhaseOperation(new PrimaryClassNodeOperation() {
+ @Override
+ public void call(SourceUnit source, GeneratorContext context,
+ ClassNode classNode) throws CompilationFailedException {
+ Object callback = classNode.getNodeMetaData(StaticCompilationMetadataKeys.DYNAMIC_OUTER_NODE_CALLBACK);
+ if (callback instanceof PrimaryClassNodeOperation) {
+ ((PrimaryClassNodeOperation) callback).call(source, context, classNode);
+ classNode.removeNodeMetaData(StaticCompilationMetadataKeys.DYNAMIC_OUTER_NODE_CALLBACK);
+ }
+ }
+ }, Phases.INSTRUCTION_SELECTION);
+
+ // apply configuration customizers if any
+ if (configuration != null) {
+ final List<CompilationCustomizer> customizers = configuration.getCompilationCustomizers();
+ for (CompilationCustomizer customizer : customizers) {
+ if (customizer instanceof CompilationUnitAware) {
+ ((CompilationUnitAware) customizer).setCompilationUnit(this);
+ }
+ addPhaseOperation(customizer, customizer.getPhase().getPhaseNumber());
+ }
+ }
+ this.classgenCallback = null;
+ this.classNodeResolver = new ClassNodeResolver();
+ }
+
+ /**
+ * Returns the class loader for loading AST transformations.
+ * @return - the transform class loader
+ */
+ public GroovyClassLoader getTransformLoader() {
+ return astTransformationsContext.getTransformLoader() == null ? getClassLoader() : astTransformationsContext.getTransformLoader();
+ }
+
+
+ public void addPhaseOperation(SourceUnitOperation op, int phase) {
+ if (phase < 0 || phase > Phases.ALL) throw new IllegalArgumentException("phase " + phase + " is unknown");
+ phaseOperations[phase].add(op);
+ }
+
+ public void addPhaseOperation(PrimaryClassNodeOperation op, int phase) {
+ if (phase < 0 || phase > Phases.ALL) throw new IllegalArgumentException("phase " + phase + " is unknown");
+ phaseOperations[phase].add(op);
+ }
+
+ public void addFirstPhaseOperation(PrimaryClassNodeOperation op, int phase) {
+ if (phase < 0 || phase > Phases.ALL) throw new IllegalArgumentException("phase " + phase + " is unknown");
+ phaseOperations[phase].add(0, op);
+ }
+
+ public void addPhaseOperation(GroovyClassOperation op) {
+ phaseOperations[Phases.OUTPUT].addFirst(op);
+ }
+
+ public void addNewPhaseOperation(SourceUnitOperation op, int phase) {
+ if (phase < 0 || phase > Phases.ALL) throw new IllegalArgumentException("phase " + phase + " is unknown");
+ newPhaseOperations[phase].add(op);
+ }
+
+ /**
+ * Configures its debugging mode and classloader classpath from a given compiler configuration.
+ * This cannot be done more than once due to limitations in {@link java.net.URLClassLoader URLClassLoader}.
+ */
+ public void configure(CompilerConfiguration configuration) {
+ super.configure(configuration);
+ this.debug = configuration.getDebug();
+
+ if (!this.configured && this.classLoader instanceof GroovyClassLoader) {
+ appendCompilerConfigurationClasspathToClassLoader(configuration, (GroovyClassLoader) this.classLoader);
+ }
+
+ this.configured = true;
+ }
+
+ private void appendCompilerConfigurationClasspathToClassLoader(CompilerConfiguration configuration, GroovyClassLoader classLoader) {
+ /*for (Iterator iterator = configuration.getClasspath().iterator(); iterator.hasNext(); ) {
+ classLoader.addClasspath((String) iterator.next());
+ }*/
+ }
+
+ /**
+ * Returns the CompileUnit that roots our AST.
+ */
+ public CompileUnit getAST() {
+ return this.ast;
+ }
+
+ /**
+ * Get the source summaries
+ */
+ public Map getSummariesBySourceName() {
+ return summariesBySourceName;
+ }
+
+ public Map getSummariesByPublicClassName() {
+ return summariesByPublicClassName;
+ }
+
+ public Map getClassSourcesByPublicClassName() {
+ return classSourcesByPublicClassName;
+ }
+
+ public boolean isPublicClass(String className) {
+ return summariesByPublicClassName.containsKey(className);
+ }
+
+ /**
+ * Get the GroovyClasses generated by compile().
+ */
+ public List getClasses() {
+ return generatedClasses;
+ }
+
+ /**
+ * Convenience routine to get the first ClassNode, for
+ * when you are sure there is only one.
+ */
+ public ClassNode getFirstClassNode() {
+ return this.ast.getModules().get(0).getClasses().get(0);
+ }
+
+ /**
+ * Convenience routine to get the named ClassNode.
+ */
+ public ClassNode getClassNode(final String name) {
+ final ClassNode[] result = new ClassNode[]{null};
+ PrimaryClassNodeOperation handler = new PrimaryClassNodeOperation() {
+ public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
+ if (classNode.getName().equals(name)) {
+ result[0] = classNode;
+ }
+ }
+ };
+
+ try {
+ applyToPrimaryClassNodes(handler);
+ } catch (CompilationFailedException e) {
+ if (debug) e.printStackTrace();
+ }
+ return result[0];
+ }
+
+ /**
+ * @return the AST transformations current context
+ */
+ public ASTTransformationsContext getASTTransformationsContext() {
+ return astTransformationsContext;
+ }
+
+ //---------------------------------------------------------------------------
+ // SOURCE CREATION
+
+
+ /**
+ * Adds a set of file paths to the unit.
+ */
+ public void addSources(String[] paths) {
+ for (String path : paths) {
+ addSource(new File(path));
+ }
+ }
+
+
+ /**
+ * Adds a set of source files to the unit.
+ */
+ public void addSources(File[] files) {
+ for (File file : files) {
+ addSource(file);
+ }
+ }
+
+
+ /**
+ * Adds a source file to the unit.
+ */
+ public SourceUnit addSource(File file) {
+ return addSource(new SourceUnit(file, configuration, classLoader, getErrorCollector()));
+ }
+
+ /**
+ * Adds a source file to the unit.
+ */
+ public SourceUnit addSource(URL url) {
+ return addSource(new SourceUnit(url, configuration, classLoader, getErrorCollector()));
+ }
+
+
+ /**
+ * Adds a InputStream source to the unit.
+ */
+ public SourceUnit addSource(String name, InputStream stream) {
+ ReaderSource source = new InputStreamReaderSource(stream, configuration);
+ return addSource(new SourceUnit(name, source, configuration, classLoader, getErrorCollector()));
+ }
+
+ public SourceUnit addSource(String name, String scriptText) {
+ return addSource(new SourceUnit(name, scriptText, configuration, classLoader, getErrorCollector()));
+ }
+
+ /**
+ * Adds a SourceUnit to the unit.
+ */
+ public SourceUnit addSource(SourceUnit source) {
+ String name = source.getName();
+ source.setClassLoader(this.classLoader);
+ for (SourceUnit su : queuedSources) {
+ if (name.equals(su.getName())) return su;
+ }
+ queuedSources.add(source);
+ return source;
+ }
+
+
+ /**
+ * Returns an iterator on the unit's SourceUnits.
+ */
+ public Iterator<SourceUnit> iterator() {
+ return new Iterator<SourceUnit>() {
+ Iterator<String> nameIterator = names.iterator();
+
+ public boolean hasNext() {
+ return nameIterator.hasNext();
+ }
+
+ public SourceUnit next() {
+ String name = nameIterator.next();
+ return sources.get(name);
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+
+ /**
+ * Adds a ClassNode directly to the unit (ie. without source).
+ * WARNING: the source is needed for error reporting, using
+ * this method without setting a SourceUnit will cause
+ * NullPinterExceptions
+ */
+ public void addClassNode(ClassNode node) {
+ ModuleNode module = new ModuleNode(this.ast);
+ this.ast.addModule(module);
+ module.addClass(node);
+ }
+
+ //---------------------------------------------------------------------------
+ // EXTERNAL CALLBACKS
+
+
+ /**
+ * A callback interface you can use to "accompany" the classgen()
+ * code as it traverses the ClassNode tree. You will be called-back
+ * for each primary and inner class. Use setClassgenCallback() before
+ * running compile() to set your callback.
+ */
+ public abstract static class ClassgenCallback {
+ public abstract void call(ClassVisitor writer, ClassNode node) throws CompilationFailedException;
+ }
+
+ /**
+ * Sets a ClassgenCallback. You can have only one, and setting
+ * it to null removes any existing setting.
+ */
+ public void setClassgenCallback(ClassgenCallback visitor) {
+ this.classgenCallback = visitor;
+ }
+
+ /**
+ * A callback interface you can use to get a callback after every
+ * unit of the compile process. You will be called-back with a
+ * ProcessingUnit and a phase indicator. Use setProgressCallback()
+ * before running compile() to set your callback.
+ */
+ public abstract static class ProgressCallback {
+
+ public abstract void call(ProcessingUnit context, int phase) throws CompilationFailedException;
+ }
+
+ /**
+ * Sets a ProgressCallback. You can have only one, and setting
+ * it to null removes any existing setting.
+ */
+ public void setProgressCallback(ProgressCallback callback) {
+ this.progressCallback = callback;
+ }
+
+ public ClassgenCallback getClassgenCallback() {
+ return classgenCallback;
+ }
+
+ public ProgressCallback getProgressCallback() {
+ return progressCallback;
+ }
+
+ //---------------------------------------------------------------------------
+ // ACTIONS
+
+
+ /**
+ * Synonym for compile(Phases.ALL).
+ */
+ public void compile() throws CompilationFailedException {
+ compile(Phases.ALL);
+ }
+
+ /**
+ * Compiles the compilation unit from sources.
+ */
+ public void compile(int throughPhase) throws CompilationFailedException {
+ //
+ // To support delta compilations, we always restart
+ // the compiler. The individual passes are responsible
+ // for not reprocessing old code.
+ gotoPhase(Phases.INITIALIZATION);
+ throughPhase = Math.min(throughPhase, Phases.ALL);
+
+ while (throughPhase >= phase && phase <= Phases.ALL) {
+
+ if (phase == Phases.SEMANTIC_ANALYSIS) {
+ doPhaseOperation(resolve);
+ if (dequeued()) continue;
+ }
+
+ processPhaseOperations(phase);
+ // Grab processing may have brought in new AST transforms into various phases, process them as well
+ processNewPhaseOperations(phase);
+
+ if (progressCallback != null) progressCallback.call(this, phase);
+ completePhase();
+ applyToSourceUnits(mark);
+
+ if (dequeued()) continue;
+
+ gotoPhase(phase + 1);
+
+ if (phase == Phases.CLASS_GENERATION) {
+ sortClasses();
+ }
+ }
+
+ errorCollector.failIfErrors();
+ }
+
+ private void processPhaseOperations(int ph) {
+ LinkedList ops = phaseOperations[ph];
+ for (Object next : ops) {
+ doPhaseOperation(next);
+ }
+ }
+
+ private void processNewPhaseOperations(int currPhase) {
+ recordPhaseOpsInAllOtherPhases(currPhase);
+ LinkedList currentPhaseNewOps = newPhaseOperations[currPhase];
+ while (!currentPhaseNewOps.isEmpty()) {
+ Object operation = currentPhaseNewOps.removeFirst();
+ // push this operation to master list and then process it.
+ phaseOperations[currPhase].add(operation);
+ doPhaseOperation(operation);
+ // if this operation has brought in more phase ops for ast transforms, keep recording them
+ // in master list of other phases and keep processing them for this phase.
+ recordPhaseOpsInAllOtherPhases(currPhase);
+ currentPhaseNewOps = newPhaseOperations[currPhase];
+ }
+
+ }
+
+ private void doPhaseOperation(Object operation) {
+ if (operation instanceof PrimaryClassNodeOperation) {
+ applyToPrimaryClassNodes((PrimaryClassNodeOperation) operation);
+ } else if (operation instanceof SourceUnitOperation) {
+ applyToSourceUnits((SourceUnitOperation) operation);
+ } else {
+ applyToGeneratedGroovyClasses((GroovyClassOperation) operation);
+ }
+ }
+
+ private void recordPhaseOpsInAllOtherPhases(int currPhase) {
+ // apart from current phase, push new operations for every other phase in the master phase ops list
+ for (int ph = Phases.INITIALIZATION; ph <= Phases.ALL; ph++) {
+ if (ph != currPhase && !newPhaseOperations[ph].isEmpty()) {
+ phaseOperations[ph].addAll(newPhaseOperations[ph]);
+ newPhaseOperations[ph].clear();
+ }
+ }
+ }
+
+ private void sortClasses() throws CompilationFailedException {
+ for (ModuleNode module : this.ast.getModules()) {
+ module.sortClasses();
+ }
+ }
+
+
+ /**
+ * Dequeues any source units add through addSource and resets the compiler phase
+ * to initialization.
+ * <p>
+ * Note: this does not mean a file is recompiled. If a SourceUnit has already passed
+ * a phase it is skipped until a higher phase is reached.
+ *
+ * @return true if there was a queued source
+ * @throws CompilationFailedException
+ */
+ protected boolean dequeued() throws CompilationFailedException {
+ boolean dequeue = !queuedSources.isEmpty();
+ while (!queuedSources.isEmpty()) {
+ SourceUnit su = queuedSources.removeFirst();
+ String name = su.getName();
+ names.add(name);
+ sources.put(name, su);
+ }
+ if (dequeue) {
+ gotoPhase(Phases.INITIALIZATION);
+ }
+ return dequeue;
+ }
+
+ /**
+ * Resolves all types
+ */
+ private final SourceUnitOperation resolve = new SourceUnitOperation() {
+ public void call(SourceUnit source) throws CompilationFailedException {
+ List<ClassNode> classes = source.ast.getClasses();
+ for (ClassNode node : classes) {
+ VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source);
+ scopeVisitor.visitClass(node);
+
+ resolveVisitor.setClassNodeResolver(classNodeResolver);
+ resolveVisitor.startResolving(node, source);
+ }
+
+ }
+ };
+
+ private final PrimaryClassNodeOperation staticImport = new PrimaryClassNodeOperation() {
+ public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
+ staticImportVisitor.visitClass(classNode, source);
+ }
+ };
+
+ /**
+ * Runs convert() on a single SourceUnit.
+ */
+ private final SourceUnitOperation convert = new SourceUnitOperation() {
+ public void call(SourceUnit source) throws CompilationFailedException {
+ source.convert();
+ CompilationUnit.this.ast.addModule(source.getAST());
+
+
+ if (CompilationUnit.this.progressCallback != null) {
+ CompilationUnit.this.progressCallback.call(source, CompilationUnit.this.phase);
+ }
+ }
+ };
+
+ private final GroovyClassOperation output = new GroovyClassOperation() {
+ public void call(GroovyClass gclass) throws CompilationFailedException {
+ String name = gclass.getName().replace('.', File.separatorChar) + ".class";
+ File path = new File(configuration.getTargetDirectory(), name);
+
+ //
+ // Ensure the path is ready for the file
+ //
+ File directory = path.getParentFile();
+ if (directory != null && !directory.exists()) {
+ directory.mkdirs();
+ }
+
+ //
+ // Create the file and write out the data
+ //
+ byte[] bytes = gclass.getBytes();
+
+ FileOutputStream stream = null;
+ try {
+ stream = new FileOutputStream(path);
+ stream.write(bytes, 0, bytes.length);
+ } catch (IOException e) {
+ getErrorCollector().addError(Message.create(e.getMessage(), CompilationUnit.this));
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+ }
+ }
+ };
+
+ /* checks if all needed classes are compiled before generating the bytecode */
+ private final SourceUnitOperation compileCompleteCheck = new SourceUnitOperation() {
+ public void call(SourceUnit source) throws CompilationFailedException {
+ List<ClassNode> classes = source.ast.getClasses();
+ for (ClassNode node : classes) {
+ CompileUnit cu = node.getCompileUnit();
+ for (Iterator iter = cu.iterateClassNodeToCompile(); iter.hasNext();) {
+ String name = (String) iter.next();
+ SourceUnit su = ast.getScriptSourceLocation(name);
+ List<ClassNode> classesInSourceUnit = su.ast.getClasses();
+ StringBuilder message = new StringBuilder();
+ message
+ .append("Compilation incomplete: expected to find the class ")
+ .append(name)
+ .append(" in ")
+ .append(su.getName());
+ if (classesInSourceUnit.isEmpty()) {
+ message.append(", but the file seems not to contain any classes");
+ } else {
+ message.append(", but the file contains the classes: ");
+ boolean first = true;
+ for (ClassNode cn : classesInSourceUnit) {
+ if (!first) {
+ message.append(", ");
+ } else {
+ first = false;
+ }
+ message.append(cn.getName());
+ }
+ }
+
+ getErrorCollector().addErrorAndContinue(
+ new SimpleMessage(message.toString(), CompilationUnit.this)
+ );
+ iter.remove();
+ }
+ }
+ }
+ };
+
+
+ /**
+ * Runs classgen() on a single ClassNode.
+ */
+ private final PrimaryClassNodeOperation classgen = new PrimaryClassNodeOperation() {
+ public boolean needSortedInput() {
+ return true;
+ }
+
+ public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
+
+ optimizer.visitClass(classNode, source); // GROOVY-4272: repositioned it here from staticImport
+
+ //
+ // Run the Verifier on the outer class
+ //
+ try {
+ verifier.visitClass(classNode);
+ } catch (GroovyRuntimeException rpe) {
+ ASTNode node = rpe.getNode();
+ getErrorCollector().addError(
+ new SyntaxException(rpe.getMessage(), node.getLineNumber(), node.getColumnNumber(), node.getLastLineNumber(), node.getLastColumnNumber()),
+ source
+ );
+ }
+
+ LabelVerifier lv = new LabelVerifier(source);
+ lv.visitClass(classNode);
+
+ ClassCompletionVerifier completionVerifier = new ClassCompletionVerifier(source);
+ completionVerifier.visitClass(classNode);
+
+ ExtendedVerifier xverifier = new ExtendedVerifier(source);
+ xverifier.visitClass(classNode);
+
+ // because the class may be generated even if a error was found
+ // and that class may have an invalid format we fail here if needed
+ getErrorCollector().failIfErrors();
+
+ //
+ // Prep the generator machinery
+ //
+ ClassVisitor visitor = createClassVisitor();
+
+ String sourceName = (source == null ? classNode.getModule().getDescription() : source.getName());
+ // only show the file name and its extension like javac does in its stacktraces rather than the full path
+ // also takes care of both \ and / depending on the host compiling environment
+ if (sourceName != null)
+ sourceName = sourceName.substring(Math.max(sourceName.lastIndexOf('\\'), sourceName.lastIndexOf('/')) + 1);
+ AsmClassGenerator generator = new AsmClassGenerator(source, context, visitor, sourceName);
+
+ //
+ // Run the generation and create the class (if required)
+ //
+ generator.visitClass(classNode);
+
+ byte[] bytes = ((ClassWriter) visitor).toByteArray();
+ generatedClasses.add(new GroovyClass(classNode.getName(), bytes));
+
+ //
+ // Handle any callback that's been set
+ //
+ if (CompilationUnit.this.classgenCallback != null) {
+ classgenCallback.call(visitor, classNode);
+ }
+
+ //
+ // Recurse for inner classes
+ //
+ LinkedList innerClasses = generator.getInnerClasses();
+ while (!innerClasses.isEmpty()) {
+ classgen.call(source, context, (ClassNode) innerClasses.removeFirst());
+ }
+ }
+ };
+
+ protected ClassVisitor createClassVisitor() {
+ CompilerConfiguration config = getConfiguration();
+ int computeMaxStackAndFrames = ClassWriter.COMPUTE_MAXS;
+ if (CompilerConfiguration.isPostJDK7(config.getTargetBytecode())
+ || Boolean.TRUE.equals(config.getOptimizationOptions().get("indy"))) {
+ computeMaxStackAndFrames += ClassWriter.COMPUTE_FRAMES;
+ }
+ return new ClassWriter(computeMaxStackAndFrames) {
+ private ClassNode getClassNode(String name) {
+ // try classes under compilation
+ CompileUnit cu = getAST();
+ ClassNode cn = cu.getClass(name);
+ if (cn!=null) return cn;
+ // try inner classes
+ cn = cu.getGeneratedInnerClass(name);
+ if (cn!=null) return cn;
+ // try class loader classes
+ try {
+ cn = ClassHelper.make(
+ cu.getClassLoader().loadClass(name,false,true),
+ false);
+ } catch (Exception e) {
+ throw new GroovyBugError(e);
+ }
+ return cn;
+ }
+ private ClassNode getCommonSuperClassNode(ClassNode c, ClassNode d) {
+ // adapted from ClassWriter code
+ if (c.isDerivedFrom(d)) return d;
+ if (d.isDerivedFrom(c)) return c;
+ if (c.isInterface() || d.isInterface()) return ClassHelper.OBJECT_TYPE;
+ do {
+ c = c.getSuperClass();
+ } while (c!=null && !d.isDerivedFrom(c));
+ if (c==null) return ClassHelper.OBJECT_TYPE;
+ return c;
+ }
+ @Override
+ protected String getCommonSuperClass(String arg1, String arg2) {
+ ClassNode a = getClassNode(arg1.replace('/', '.'));
+ ClassNode b = getClassNode(arg2.replace('/', '.'));
+ return getCommonSuperClassNode(a,b).getName().replace('.','/');
+ }
+
+ };
+ }
+
+ //---------------------------------------------------------------------------
+ // PHASE HANDLING
+
+ /**
+ * Updates the phase marker on all sources.
+ */
+ protected void mark() throws CompilationFailedException {
+ applyToSourceUnits(mark);
+ }
+
+
+ /**
+ * Marks a single SourceUnit with the current phase,
+ * if it isn't already there yet.
+ */
+ private final SourceUnitOperation mark = new SourceUnitOperation() {
+ public void call(SourceUnit source) throws CompilationFailedException {
+ if (source.phase < phase) {
+ source.gotoPhase(phase);
+ }
+
+ if (source.phase == phase && phaseComplete && !source.phaseComplete) {
+ source.completePhase();
+ }
+ }
+ };
+
+ //---------------------------------------------------------------------------
+ // LOOP SIMPLIFICATION FOR SourceUnit OPERATIONS
+
+
+ /**
+ * An callback interface for use in the applyToSourceUnits loop driver.
+ */
+ public abstract static class SourceUnitOperation {
+ public abstract void call(SourceUnit source) throws CompilationFailedException;
+ }
+
+
+ /**
+ * A loop driver for applying operations to all SourceUnits.
+ * Automatically skips units that have already been processed
+ * through the current phase.
+ */
+ public void applyToSourceUnits(SourceUnitOperation body) throws CompilationFailedException {
+ for (String name : names) {
+ SourceUnit source = sources.get(name);
+ if ((source.phase < phase) || (source.phase == phase && !source.phaseComplete)) {
+ try {
+ body.call(source);
+ } catch (CompilationFailedException e) {
+ throw e;
+ } catch (Exception e) {
+ GroovyBugError gbe = new GroovyBugError(e);
+ changeBugText(gbe, source);
+ throw gbe;
+ } catch (GroovyBugError e) {
+ changeBugText(e, source);
+ throw e;
+ }
+ }
+ }
+
+
+ getErrorCollector().failIfErrors();
+ }
+
+ //---------------------------------------------------------------------------
+ // LOOP SIMPLIFICATION FOR PRIMARY ClassNode OPERATIONS
+
+
+ /**
+ * An callback interface for use in the applyToPrimaryClassNodes loop driver.
+ */
+ public abstract static class PrimaryClassNodeOperation {
+ public abstract void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException;
+
+ public boolean needSortedInput() {
+ return false;
+ }
+ }
+
+ public abstract static class GroovyClassOperation {
+ public abstract void call(GroovyClass gclass) throws CompilationFailedException;
+ }
+
+ private static int getSuperClassCount(ClassNode element) {
+ int count = 0;
+ while (element != null) {
+ count++;
+ element = element.getSuperClass();
+ }
+ return count;
+ }
+
+ private int getSuperInterfaceCount(ClassNode element) {
+ int count = 1;
+ ClassNode[] interfaces = element.getInterfaces();
+ for (ClassNode anInterface : interfaces) {
+ count = Math.max(count, getSuperInterfaceCount(anInterface) + 1);
+ }
+ return count;
+ }
+
+ private List<ClassNode> getPrimaryClassNodes(boolean sort) {
+ List<ClassNode> unsorted = new ArrayList<ClassNode>();
+ for (ModuleNode module : this.ast.getModules()) {
+ for (ClassNode classNode : module.getClasses()) {
+ unsorted.add(classNode);
+ }
+ }
+
+ if (!sort) return unsorted;
+
+ int unsortedSize = unsorted.size();
+ int[] indexClass = new int[unsortedSize];
+ int[] indexInterface = new int[unsortedSize];
+ {
+ int i = 0;
+ for (Iterator<ClassNode> iter = unsorted.iterator(); iter.hasNext(); i++) {
+ ClassNode element = iter.next();
+ if (element.isInterface()) {
+ indexInterface[i] = getSuperInterfaceCount(element);
+ indexClass[i] = -1;
+ } else {
+ indexClass[i] = getSuperClassCount(element);
+ indexInterface[i] = -1;
+ }
+ }
+ }
+
+ List<ClassNode> sorted = getSorted(indexInterface, unsorted);
+ sorted.addAll(getSorted(indexClass, unsorted));
+ return sorted;
+ }
+
+ private static List<ClassNode> getSorted(int[] index, List<ClassNode> unsorted) {
+ int unsortedSize = unsorted.size();
+ List<ClassNode> sorted = new ArrayList<ClassNode>(unsortedSize);
+ for (int i = 0; i < unsortedSize; i++) {
+ int min = -1;
+ for (int j = 0; j < unsortedSize; j++) {
+ if (index[j] == -1) continue;
+ if (min == -1 || index[j] < index[min]) {
+ min = j;
+ }
+ }
+ if (min == -1) break;
+ sorted.add(unsorted.get(min));
+ index[min] = -1;
+ }
+ return sorted;
+ }
+
+ /**
+ * A loop driver for applying operations to all primary ClassNodes in
+ * our AST. Automatically skips units that have already been processed
+ * through the current phase.
+ */
+ public void applyToPrimaryClassNodes(PrimaryClassNodeOperation body) throws CompilationFailedException {
+ for (ClassNode classNode : getPrimaryClassNodes(body.needSortedInput())) {
+ SourceUnit context = null;
+ try {
+ context = classNode.getModule().getContext();
+ if (context == null || context.phase < phase || (context.phase == phase && !context.phaseComplete)) {
+ int offset = 1;
+ for (Iterator<InnerClassNode> iterator = classNode.getInnerClasses(); iterator.hasNext(); ) {
+ iterator.next();
+ offset++;
+ }
+ body.call(context, new GeneratorContext(this.ast, offset), classNode);
+ }
+ } catch (CompilationFailedException e) {
+ // fall through, getErrorReporter().failIfErrors() will trigger
+ } catch (NullPointerException npe) {
+ GroovyBugError gbe = new GroovyBugError("unexpected NullpointerException", npe);
+ changeBugText(gbe, context);
+ throw gbe;
+ } catch (GroovyBugError e) {
+ changeBugText(e, context);
+ throw e;
+ } catch (NoClassDefFoundError e) {
+ // effort to get more logging in case a dependency of a class is loaded
+ // although it shouldn't have
+ convertUncaughtExceptionToCompilationError(e);
+ } catch (Exception e) {
+ convertUncaughtExceptionToCompilationError(e);
+ }
+ }
+
+ getErrorCollector().failIfErrors();
+ }
+
+ private void convertUncaughtExceptionToCompilationError(final Throwable e) {
+ // check the exception for a nested compilation exception
+ ErrorCollector nestedCollector = null;
+ for (Throwable next = e.getCause(); next != e && next != null; next = next.getCause()) {
+ if (!(next instanceof MultipleCompilationErrorsException)) continue;
+ MultipleCompilationErrorsException mcee = (MultipleCompilationErrorsException) next;
+ nestedCollector = mcee.collector;
+ break;
+ }
+
+ if (nestedCollector != null) {
+ getErrorCollector().addCollectorContents(nestedCollector);
+ } else {
+ Exception err = e instanceof Exception?((Exception)e):new RuntimeException(e);
+ getErrorCollector().addError(new ExceptionMessage(err, configuration.getDebug(), this));
+ }
+ }
+
+ public void applyToGeneratedGroovyClasses(GroovyClassOperation body) throws CompilationFailedException {
+ if (this.phase != Phases.OUTPUT && !(this.phase == Phases.CLASS_GENERATION && this.phaseComplete)) {
+ throw new GroovyBugError("CompilationUnit not ready for output(). Current phase=" + getPhaseDescription());
+ }
+
+ for (GroovyClass gclass : this.generatedClasses) {
+ //
+ // Get the class and calculate its filesystem name
+ //
+ try {
+ body.call(gclass);
+ } catch (CompilationFailedException e) {
+ // fall through, getErrorReporter().failIfErrors() will trigger
+ } catch (NullPointerException npe) {
+ throw npe;
+ } catch (GroovyBugError e) {
+ changeBugText(e, null);
+ throw e;
+ } catch (Exception e) {
+ throw new GroovyBugError(e);
+ }
+ }
+
+ getErrorCollector().failIfErrors();
+ }
+
+ private void changeBugText(GroovyBugError e, SourceUnit context) {
+ e.setBugText("exception in phase '" + getPhaseDescription() + "' in source unit '" + ((context != null) ? context.getName() : "?") + "' " + e.getBugText());
+ }
+
+ public ClassNodeResolver getClassNodeResolver() {
+ return classNodeResolver;
+ }
+
+
+ public void setClassNodeResolver(ClassNodeResolver classNodeResolver) {
+ this.classNodeResolver = classNodeResolver;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/CompilePhase.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/CompilePhase.java b/src/main/java/org/codehaus/groovy/control/CompilePhase.java
new file mode 100644
index 0000000..7b25fed
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/CompilePhase.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.control;
+
+/**
+* The phases of the GroovyCompiler. This is an enum facade on top of the
+* Phases object. In general, prefer using this object over Phases.
+*
+* @author Hamlet D'Arcy
+*/
+public enum CompilePhase {
+
+ /**
+ * source files are opened and environment configured
+ */
+ INITIALIZATION(Phases.INITIALIZATION),
+
+ /**
+ * the grammar is used to to produce tree of tokens representing the source code
+ */
+ PARSING(Phases.PARSING),
+
+ /**
+ * An abstract syntax tree (AST) is created from token trees
+ */
+ CONVERSION(Phases.CONVERSION),
+
+ /**
+ * Performs consistency and validity checks that the grammar can't check for, and resolves classes
+ */
+ SEMANTIC_ANALYSIS(Phases.SEMANTIC_ANALYSIS),
+
+ /**
+ * Complete building the AST
+ */
+ CANONICALIZATION(Phases.CANONICALIZATION),
+
+ /**
+ * instruction set is chosen, for example java5 or pre java5
+ */
+ INSTRUCTION_SELECTION(Phases.INSTRUCTION_SELECTION),
+
+ /**
+ * creates the binary output in memory
+ */
+ CLASS_GENERATION(Phases.CLASS_GENERATION),
+
+ /**
+ * write the binary output to the file system
+ */
+ OUTPUT(Phases.OUTPUT),
+
+ /**
+ * Perform any last cleanup
+ */
+ FINALIZATION(Phases.FINALIZATION),
+ ;
+
+ /**
+ * The phases as an array, with a null entry.
+ */
+ public static CompilePhase[] phases = {
+ null,
+ INITIALIZATION,
+ PARSING,
+ CONVERSION,
+ SEMANTIC_ANALYSIS,
+ CANONICALIZATION,
+ INSTRUCTION_SELECTION,
+ CLASS_GENERATION,
+ OUTPUT,
+ FINALIZATION,
+ };
+
+ int phaseNumber;
+ CompilePhase(int phaseNumber) {
+ this.phaseNumber = phaseNumber;
+ }
+
+ /**
+ * Returns the underlieng integer Phase number.
+ */
+ public int getPhaseNumber() {
+ return phaseNumber;
+ }
+
+ /**
+ * Returns the CompilePhase for the given integer phase number.
+ * @param phaseNumber
+ * the phase number
+ * @return
+ * the CompilePhase or null if not found
+ */
+ public static CompilePhase fromPhaseNumber(int phaseNumber) {
+ for (CompilePhase phase : values()) {
+ if (phase.phaseNumber == phaseNumber) {
+ return phase;
+ }
+ }
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/CompilerConfiguration.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/CompilerConfiguration.java b/src/main/java/org/codehaus/groovy/control/CompilerConfiguration.java
new file mode 100644
index 0000000..9f6babe
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/CompilerConfiguration.java
@@ -0,0 +1,934 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.control;
+
+import org.apache.groovy.util.Maps;
+import org.codehaus.groovy.control.customizers.CompilationCustomizer;
+import org.codehaus.groovy.control.io.NullWriter;
+import org.codehaus.groovy.control.messages.WarningMessage;
+import org.objectweb.asm.Opcodes;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+/**
+ * Compilation control flags and coordination stuff.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * @author <a href="mailto:jim@pagesmiths.com">Jim White</a>
+ * @author <a href="mailto:cedric.champeau@gmail.com">Cedric Champeau</a>
+ */
+
+public class CompilerConfiguration {
+
+ /** This (<code>"indy"</code>) is the Optimization Option value for enabling <code>invokedynamic</code> complilation. */
+ public static final String INVOKEDYNAMIC = "indy";
+
+ /** This (<code>"1.4"</code>) is the value for targetBytecode to compile for a JDK 1.4. **/
+ public static final String JDK4 = "1.4";
+ /** This (<code>"1.5"</code>) is the value for targetBytecode to compile for a JDK 1.5. **/
+ public static final String JDK5 = "1.5";
+ /** This (<code>"1.6"</code>) is the value for targetBytecode to compile for a JDK 1.6. **/
+ public static final String JDK6 = "1.6";
+ /** This (<code>"1.7"</code>) is the value for targetBytecode to compile for a JDK 1.7. **/
+ public static final String JDK7 = "1.7";
+ /** This (<code>"1.8"</code>) is the value for targetBytecode to compile for a JDK 1.8. **/
+ public static final String JDK8 = "1.8";
+
+ /** This (<code>"1.5"</code>) is the value for targetBytecode to compile for a JDK 1.5 or later JVM. **/
+ public static final String POST_JDK5 = JDK5; // for backwards compatibility
+
+ /** This (<code>"1.4"</code>) is the value for targetBytecode to compile for a JDK 1.4 JVM. **/
+ public static final String PRE_JDK5 = JDK4;
+
+ /**
+ * JDK version to bytecode version mapping
+ */
+ public static final Map<String, Integer> JDK_TO_BYTECODE_VERSION_MAP = Maps.of(
+ JDK4, Opcodes.V1_4,
+ JDK5, Opcodes.V1_5,
+ JDK6, Opcodes.V1_6,
+ JDK7, Opcodes.V1_7,
+ JDK8, Opcodes.V1_8
+ );
+
+ /** An array of the valid targetBytecode values **/
+ public static final String[] ALLOWED_JDKS = JDK_TO_BYTECODE_VERSION_MAP.keySet().toArray(new String[0]);
+
+ // Just call getVMVersion() once.
+ public static final String CURRENT_JVM_VERSION = getVMVersion();
+
+ private static final String GROOVY_ANTLR4_OPT = "groovy.antlr4";
+
+ /**
+ * The default source encoding
+ */
+ public static final String DEFAULT_SOURCE_ENCODING = "UTF-8";
+
+ // Static initializers are executed in text order,
+ // therefore we must do this one last!
+ /**
+ * A convenience for getting a default configuration. Do not modify it!
+ * See {@link #CompilerConfiguration(Properties)} for an example on how to
+ * make a suitable copy to modify. But if you're really starting from a
+ * default context, then you probably just want <code>new CompilerConfiguration()</code>.
+ */
+ public static final CompilerConfiguration DEFAULT = new CompilerConfiguration();
+
+ /**
+ * See {@link WarningMessage} for levels.
+ */
+ private int warningLevel;
+
+ /**
+ * Encoding for source files
+ */
+ private String sourceEncoding;
+
+ /**
+ * The <code>PrintWriter</code> does nothing.
+ */
+ private PrintWriter output;
+
+ /**
+ * Directory into which to write classes
+ */
+ private File targetDirectory;
+
+ /**
+ * Classpath for use during compilation
+ */
+ private LinkedList<String> classpath;
+
+ /**
+ * If true, the compiler should produce action information
+ */
+ private boolean verbose;
+
+ /**
+ * If true, debugging code should be activated
+ */
+ private boolean debug;
+
+ /**
+ * If true, generates metadata for reflection on method parameters
+ */
+ private boolean parameters = false;
+
+ /**
+ * The number of non-fatal errors to allow before bailing
+ */
+ private int tolerance;
+
+ /**
+ * Base class name for scripts (must derive from Script)
+ */
+ private String scriptBaseClass;
+
+ private ParserPluginFactory pluginFactory;
+
+ /**
+ * extension used to find a groovy file
+ */
+ private String defaultScriptExtension;
+
+ /**
+ * extensions used to find a groovy files
+ */
+ private Set<String> scriptExtensions = new LinkedHashSet<String>();
+
+ /**
+ * if set to true recompilation is enabled
+ */
+ private boolean recompileGroovySource;
+
+ /**
+ * sets the minimum of time after a script can be recompiled.
+ */
+ private int minimumRecompilationInterval;
+
+ /**
+ * sets the bytecode version target
+ */
+ private String targetBytecode;
+
+ /**
+ * options for joint compilation (null by default == no joint compilation)
+ */
+ private Map<String, Object> jointCompilationOptions;
+
+ /**
+ * options for optimizations (empty map by default)
+ */
+ private Map<String, Boolean> optimizationOptions;
+
+ private final List<CompilationCustomizer> compilationCustomizers = new LinkedList<CompilationCustomizer>();
+
+ /**
+ * Sets a list of global AST transformations which should not be loaded even if they are
+ * defined in META-INF/org.codehaus.groovy.transform.ASTTransformation files. By default,
+ * none is disabled.
+ */
+ private Set<String> disabledGlobalASTTransformations;
+
+ private BytecodeProcessor bytecodePostprocessor;
+
+ /**
+ * defines if antlr2 parser should be used or the antlr4 one if
+ * no factory is set yet
+ */
+ private ParserVersion parserVersion = ParserVersion.V_2;
+
+ /**
+ * Sets the Flags to defaults.
+ */
+ public CompilerConfiguration() {
+ //
+ // Set in safe defaults
+
+ setWarningLevel(WarningMessage.LIKELY_ERRORS);
+ setOutput(null);
+ setTargetDirectory((File) null);
+ setClasspath("");
+ setVerbose(false);
+ setDebug(false);
+ setParameters(safeGetSystemProperty("groovy.parameters") != null);
+ setTolerance(10);
+ setScriptBaseClass(null);
+ setRecompileGroovySource(false);
+ setMinimumRecompilationInterval(100);
+ setTargetBytecode(safeGetSystemProperty("groovy.target.bytecode", getVMVersion()));
+ setDefaultScriptExtension(safeGetSystemProperty("groovy.default.scriptExtension", ".groovy"));
+
+ // Source file encoding
+ String encoding = safeGetSystemProperty("file.encoding", DEFAULT_SOURCE_ENCODING);
+ encoding = safeGetSystemProperty("groovy.source.encoding", encoding);
+ setSourceEncoding(encoding);
+
+ try {
+ setOutput(new PrintWriter(System.err));
+ } catch (Exception e) {
+ // IGNORE
+ }
+
+
+ String target = safeGetSystemProperty("groovy.target.directory");
+ if (target != null) {
+ setTargetDirectory(target);
+ }
+
+ boolean indy = false;
+ try {
+ indy = Boolean.getBoolean("groovy.target.indy");
+ } catch (Exception e) {
+ // IGNORE
+ }
+ if (DEFAULT!=null && Boolean.TRUE.equals(DEFAULT.getOptimizationOptions().get(INVOKEDYNAMIC))) {
+ indy = true;
+ }
+ Map options = new HashMap<String,Boolean>(3);
+ if (indy) {
+ options.put(INVOKEDYNAMIC, Boolean.TRUE);
+ }
+ setOptimizationOptions(options);
+
+ try {
+ String groovyAntlr4Opt = System.getProperty(GROOVY_ANTLR4_OPT);
+
+ this.parserVersion = !Boolean.valueOf(groovyAntlr4Opt)
+ ? ParserVersion.V_2
+ : ParserVersion.V_4;
+ } catch (Exception e) {
+ // IGNORE
+ }
+ }
+
+ /**
+ * Retrieves a System property, or null if any of the following exceptions occur.
+ * <ul>
+ * <li>SecurityException - if a security manager exists and its checkPropertyAccess method doesn't allow access to the specified system property.</li>
+ * <li>NullPointerException - if key is null.</li>
+ * <li>IllegalArgumentException - if key is empty.</li>
+ * </ul>
+ * @param key the name of the system property.
+ * @return value of the system property or null
+ */
+ private static String safeGetSystemProperty(String key){
+ return safeGetSystemProperty(key, null);
+ }
+
+ /**
+ * Retrieves a System property, or null if any of the following exceptions occur (Warning: Exception messages are
+ * suppressed).
+ * <ul>
+ * <li>SecurityException - if a security manager exists and its checkPropertyAccess method doesn't allow access to the specified system property.</li>
+ * <li>NullPointerException - if key is null.</li>
+ * <li>IllegalArgumentException - if key is empty.</li>
+ * </ul>
+ * @param key the name of the system property.
+ * @param def a default value.
+ * @return value of the system property or null
+ */
+ private static String safeGetSystemProperty(String key, String def){
+ try {
+ return System.getProperty(key, def);
+ } catch (SecurityException t){
+ // suppress exception
+ } catch (NullPointerException t){
+ // suppress exception
+ } catch (IllegalArgumentException t){
+ // suppress exception
+ }
+ return def;
+ }
+
+ /**
+ * Copy constructor. Use this if you have a mostly correct configuration
+ * for your compilation but you want to make a some changes programatically.
+ * An important reason to prefer this approach is that your code will most
+ * likely be forward compatible with future changes to this configuration API.
+ * <p>
+ * An example of this copy constructor at work:
+ * <pre>
+ * // In all likelihood there is already a configuration in your code's context
+ * // for you to copy, but for the sake of this example we'll use the global default.
+ * CompilerConfiguration myConfiguration = new CompilerConfiguration(CompilerConfiguration.DEFAULT);
+ * myConfiguration.setDebug(true);
+ *</pre>
+ *
+ * @param configuration The configuration to copy.
+ */
+ public CompilerConfiguration(CompilerConfiguration configuration) {
+ setWarningLevel(configuration.getWarningLevel());
+ setOutput(configuration.getOutput());
+ setTargetDirectory(configuration.getTargetDirectory());
+ setClasspathList(new LinkedList<String>(configuration.getClasspath()));
+ setVerbose(configuration.getVerbose());
+ setDebug(configuration.getDebug());
+ setParameters(configuration.getParameters());
+ setTolerance(configuration.getTolerance());
+ setScriptBaseClass(configuration.getScriptBaseClass());
+ setRecompileGroovySource(configuration.getRecompileGroovySource());
+ setMinimumRecompilationInterval(configuration.getMinimumRecompilationInterval());
+ setTargetBytecode(configuration.getTargetBytecode());
+ setDefaultScriptExtension(configuration.getDefaultScriptExtension());
+ setSourceEncoding(configuration.getSourceEncoding());
+ setTargetDirectory(configuration.getTargetDirectory());
+ Map<String, Object> jointCompilationOptions = configuration.getJointCompilationOptions();
+ if (jointCompilationOptions != null) {
+ jointCompilationOptions = new HashMap<String, Object>(jointCompilationOptions);
+ }
+ setJointCompilationOptions(jointCompilationOptions);
+ setPluginFactory(configuration.getPluginFactory());
+ setScriptExtensions(configuration.getScriptExtensions());
+ setOptimizationOptions(new HashMap<String, Boolean>(configuration.getOptimizationOptions()));
+ }
+
+ /**
+ * Sets the Flags to the specified configuration, with defaults
+ * for those not supplied.
+ * Note that those "defaults" here do <em>not</em> include checking the
+ * settings in {@link System#getProperties()} in general, only file.encoding,
+ * groovy.target.directory and groovy.source.encoding are.
+ * <p>
+ * If you want to set a few flags but keep Groovy's default
+ * configuration behavior then be sure to make your settings in
+ * a Properties that is backed by <code>System.getProperties()</code> (which
+ * is done using this constructor). That might be done like this:
+ * <pre>
+ * Properties myProperties = new Properties(System.getProperties());
+ * myProperties.setProperty("groovy.output.debug", "true");
+ * myConfiguration = new CompilerConfiguration(myProperties);
+ * </pre>
+ * And you also have to contend with a possible SecurityException when
+ * getting the system properties (See {@link java.lang.System#getProperties()}).
+ * A safer approach would be to copy a default
+ * CompilerConfiguration and make your changes there using the setter:
+ * <pre>
+ * // In all likelihood there is already a configuration for you to copy,
+ * // but for the sake of this example we'll use the global default.
+ * CompilerConfiguration myConfiguration = new CompilerConfiguration(CompilerConfiguration.DEFAULT);
+ * myConfiguration.setDebug(true);
+ * </pre>
+ * <p>
+ * <table summary="Groovy Compiler Configuration Properties">
+ * <tr>
+ * <th>Property Key</th><th>Get/Set Property Name</th>
+ * </tr>
+ * <tr>
+ * <td><code>"groovy.warnings"</code></td><td>{@link #getWarningLevel}</td></tr>
+ * <tr><td><code>"groovy.source.encoding"</code></td><td>{@link #getSourceEncoding}</td></tr>
+ * <tr><td><code>"groovy.target.directory"</code></td><td>{@link #getTargetDirectory}</td></tr>
+ * <tr><td><code>"groovy.target.bytecode"</code></td><td>{@link #getTargetBytecode}</td></tr>
+ * <tr><td><code>"groovy.classpath"</code></td><td>{@link #getClasspath}</td></tr>
+ * <tr><td><code>"groovy.output.verbose"</code></td><td>{@link #getVerbose}</td></tr>
+ * <tr><td><code>"groovy.output.debug"</code></td><td>{@link #getDebug}</td></tr>
+ * <tr><td><code>"groovy.errors.tolerance"</code></td><td>{@link #getTolerance}</td></tr>
+ * <tr><td><code>"groovy.script.extension"</code></td><td>{@link #getDefaultScriptExtension}</td></tr>
+ * <tr><td><code>"groovy.script.base"</code></td><td>{@link #getScriptBaseClass}</td></tr>
+ * <tr><td><code>"groovy.recompile"</code></td><td>{@link #getRecompileGroovySource}</td></tr>
+ * <tr><td><code>"groovy.recompile.minimumInterval"</code></td><td>{@link #getMinimumRecompilationInterval}</td></tr>
+ * <tr><td>
+ * </tr>
+ * </table>
+ *
+ * @param configuration The properties to get flag values from.
+ */
+ public CompilerConfiguration(Properties configuration) throws ConfigurationException {
+ this();
+ configure(configuration);
+ }
+
+ /**
+ * Checks if the specified bytecode version string represents a JDK 1.5+ compatible
+ * bytecode version.
+ * @param bytecodeVersion the bytecode version string (1.4, 1.5, 1.6, 1.7 or 1.8)
+ * @return true if the bytecode version is JDK 1.5+
+ */
+ public static boolean isPostJDK5(String bytecodeVersion) {
+ return new BigDecimal(bytecodeVersion).compareTo(new BigDecimal(JDK5)) >= 0;
+ }
+
+ /**
+ * Checks if the specified bytecode version string represents a JDK 1.7+ compatible
+ * bytecode version.
+ * @param bytecodeVersion the bytecode version string (1.4, 1.5, 1.6, 1.7 or 1.8)
+ * @return true if the bytecode version is JDK 1.7+
+ */
+ public static boolean isPostJDK7(String bytecodeVersion) {
+ return new BigDecimal(bytecodeVersion).compareTo(new BigDecimal(JDK7)) >= 0;
+ }
+
+ /**
+ * Method to configure a CompilerConfiguration by using Properties.
+ * For a list of available properties look at {@link #CompilerConfiguration(Properties)}.
+ * @param configuration The properties to get flag values from.
+ */
+ public void configure(Properties configuration) throws ConfigurationException {
+ String text = null;
+ int numeric = 0;
+
+ //
+ // Warning level
+
+ numeric = getWarningLevel();
+ try {
+ text = configuration.getProperty("groovy.warnings", "likely errors");
+ numeric = Integer.parseInt(text);
+ } catch (NumberFormatException e) {
+ text = text.toLowerCase();
+ if (text.equals("none")) {
+ numeric = WarningMessage.NONE;
+ }
+ else if (text.startsWith("likely")) {
+ numeric = WarningMessage.LIKELY_ERRORS;
+ }
+ else if (text.startsWith("possible")) {
+ numeric = WarningMessage.POSSIBLE_ERRORS;
+ }
+ else if (text.startsWith("paranoia")) {
+ numeric = WarningMessage.PARANOIA;
+ }
+ else {
+ throw new ConfigurationException("unrecognized groovy.warnings: " + text);
+ }
+ }
+ setWarningLevel(numeric);
+
+ //
+ // Source file encoding
+ //
+ text = configuration.getProperty("groovy.source.encoding");
+ if (text == null) {
+ text = configuration.getProperty("file.encoding", "US-ASCII");
+ }
+ setSourceEncoding(text);
+
+ //
+ // Target directory for classes
+ //
+ text = configuration.getProperty("groovy.target.directory");
+ if (text != null) setTargetDirectory(text);
+
+ text = configuration.getProperty("groovy.target.bytecode");
+ if (text != null) setTargetBytecode(text);
+
+ //
+ // Classpath
+ //
+ text = configuration.getProperty("groovy.classpath");
+ if (text != null) setClasspath(text);
+
+ //
+ // Verbosity
+ //
+ text = configuration.getProperty("groovy.output.verbose");
+ if (text != null && text.equalsIgnoreCase("true")) setVerbose(true);
+
+ //
+ // Debugging
+ //
+ text = configuration.getProperty("groovy.output.debug");
+ if (text != null && text.equalsIgnoreCase("true")) setDebug(true);
+
+ //
+ // Parameters
+ //
+ setParameters(configuration.getProperty("groovy.parameters") != null);
+
+ //
+ // Tolerance
+ //
+ numeric = 10;
+ try {
+ text = configuration.getProperty("groovy.errors.tolerance", "10");
+ numeric = Integer.parseInt(text);
+ } catch (NumberFormatException e) {
+ throw new ConfigurationException(e);
+ }
+ setTolerance(numeric);
+
+ //
+ // Script Base Class
+ //
+ text = configuration.getProperty("groovy.script.base");
+ if (text!=null) setScriptBaseClass(text);
+
+ //
+ // recompilation options
+ //
+ text = configuration.getProperty("groovy.recompile");
+ if (text != null) {
+ setRecompileGroovySource(text.equalsIgnoreCase("true"));
+ }
+
+ numeric = 100;
+ try {
+ text = configuration.getProperty("groovy.recompile.minimumIntervall");
+ if (text==null) text = configuration.getProperty("groovy.recompile.minimumInterval");
+ if (text!=null) {
+ numeric = Integer.parseInt(text);
+ } else {
+ numeric = 100;
+ }
+ } catch (NumberFormatException e) {
+ throw new ConfigurationException(e);
+ }
+ setMinimumRecompilationInterval(numeric);
+
+ // disabled global AST transformations
+ text = configuration.getProperty("groovy.disabled.global.ast.transformations");
+ if (text!=null) {
+ String[] classNames = text.split(",\\s*}");
+ Set<String> blacklist = new HashSet<String>(Arrays.asList(classNames));
+ setDisabledGlobalASTTransformations(blacklist);
+ }
+ }
+
+ /**
+ * Gets the currently configured warning level. See {@link WarningMessage}
+ * for level details.
+ */
+ public int getWarningLevel() {
+ return this.warningLevel;
+ }
+
+ /**
+ * Sets the warning level. See {@link WarningMessage} for level details.
+ */
+ public void setWarningLevel(int level) {
+ if (level < WarningMessage.NONE || level > WarningMessage.PARANOIA) {
+ this.warningLevel = WarningMessage.LIKELY_ERRORS;
+ }
+ else {
+ this.warningLevel = level;
+ }
+ }
+
+ /**
+ * Gets the currently configured source file encoding.
+ */
+ public String getSourceEncoding() {
+ return this.sourceEncoding;
+ }
+
+ /**
+ * Sets the encoding to be used when reading source files.
+ */
+ public void setSourceEncoding(String encoding) {
+ if (encoding == null) encoding = DEFAULT_SOURCE_ENCODING;
+ this.sourceEncoding = encoding;
+ }
+
+ /**
+ * Gets the currently configured output writer.
+ * @deprecated not used anymore
+ */
+ @Deprecated
+ public PrintWriter getOutput() {
+ return this.output;
+ }
+
+ /**
+ * Sets the output writer.
+ * @deprecated not used anymore, has no effect
+ */
+ @Deprecated
+ public void setOutput(PrintWriter output) {
+ if (output == null) {
+ this.output = new PrintWriter(NullWriter.DEFAULT);
+ }
+ else {
+ this.output = output;
+ }
+ }
+
+ /**
+ * Gets the target directory for writing classes.
+ */
+ public File getTargetDirectory() {
+ return this.targetDirectory;
+ }
+
+ /**
+ * Sets the target directory.
+ */
+ public void setTargetDirectory(String directory) {
+ if (directory != null && directory.length() > 0) {
+ this.targetDirectory = new File(directory);
+ } else {
+ this.targetDirectory = null;
+ }
+ }
+
+ /**
+ * Sets the target directory.
+ */
+ public void setTargetDirectory(File directory) {
+ this.targetDirectory = directory;
+ }
+
+ /**
+ * @return the classpath
+ */
+ public List<String> getClasspath() {
+ return this.classpath;
+ }
+
+ /**
+ * Sets the classpath.
+ */
+ public void setClasspath(String classpath) {
+ this.classpath = new LinkedList<String>();
+ StringTokenizer tokenizer = new StringTokenizer(classpath, File.pathSeparator);
+ while (tokenizer.hasMoreTokens()) {
+ this.classpath.add(tokenizer.nextToken());
+ }
+ }
+
+ /**
+ * sets the classpath using a list of Strings
+ * @param parts list of strings containing the classpath parts
+ */
+ public void setClasspathList(List<String> parts) {
+ this.classpath = new LinkedList<String>(parts);
+ }
+
+ /**
+ * Returns true if verbose operation has been requested.
+ */
+ public boolean getVerbose() {
+ return this.verbose;
+ }
+
+ /**
+ * Turns verbose operation on or off.
+ */
+ public void setVerbose(boolean verbose) {
+ this.verbose = verbose;
+ }
+
+ /**
+ * Returns true if debugging operation has been requested.
+ */
+ public boolean getDebug() {
+ return this.debug;
+ }
+
+ /**
+ * Returns true if parameter metadata generation has been enabled.
+ */
+ public boolean getParameters() {
+ return this.parameters;
+ }
+
+ /**
+ * Turns debugging operation on or off.
+ */
+ public void setDebug(boolean debug) {
+ this.debug = debug;
+ }
+
+ /**
+ * Turns parameter metadata generation on or off.
+ */
+ public void setParameters(boolean parameters) {
+ this.parameters = parameters;
+ }
+
+ /**
+ * Returns the requested error tolerance.
+ */
+ public int getTolerance() {
+ return this.tolerance;
+ }
+
+ /**
+ * Sets the error tolerance, which is the number of
+ * non-fatal errors (per unit) that should be tolerated before
+ * compilation is aborted.
+ */
+ public void setTolerance(int tolerance) {
+ this.tolerance = tolerance;
+ }
+
+ /**
+ * Gets the name of the base class for scripts. It must be a subclass
+ * of Script.
+ */
+ public String getScriptBaseClass() {
+ return this.scriptBaseClass;
+ }
+
+ /**
+ * Sets the name of the base class for scripts. It must be a subclass
+ * of Script.
+ */
+ public void setScriptBaseClass(String scriptBaseClass) {
+ this.scriptBaseClass = scriptBaseClass;
+ }
+
+ public ParserPluginFactory getPluginFactory() {
+ if (pluginFactory == null) {
+ pluginFactory = ParserVersion.V_2 == parserVersion
+ ? ParserPluginFactory.antlr2()
+ : ParserPluginFactory.antlr4();
+ }
+ return pluginFactory;
+ }
+
+ public void setPluginFactory(ParserPluginFactory pluginFactory) {
+ this.pluginFactory = pluginFactory;
+ }
+
+ public void setScriptExtensions(Set<String> scriptExtensions) {
+ if(scriptExtensions == null) scriptExtensions = new LinkedHashSet<String>();
+ this.scriptExtensions = scriptExtensions;
+ }
+
+ public Set<String> getScriptExtensions() {
+ if(scriptExtensions == null || scriptExtensions.isEmpty()) {
+ /*
+ * this happens
+ * * when groovyc calls FileSystemCompiler in forked mode, or
+ * * when FileSystemCompiler is run from the command line directly, or
+ * * when groovy was not started using groovyc or FileSystemCompiler either
+ */
+ scriptExtensions = SourceExtensionHandler.getRegisteredExtensions(
+ this.getClass().getClassLoader());
+ }
+ return scriptExtensions;
+ }
+
+ public String getDefaultScriptExtension() {
+ return defaultScriptExtension;
+ }
+
+
+ public void setDefaultScriptExtension(String defaultScriptExtension) {
+ this.defaultScriptExtension = defaultScriptExtension;
+ }
+
+ public void setRecompileGroovySource(boolean recompile) {
+ recompileGroovySource = recompile;
+ }
+
+ public boolean getRecompileGroovySource(){
+ return recompileGroovySource;
+ }
+
+ public void setMinimumRecompilationInterval(int time) {
+ minimumRecompilationInterval = Math.max(0,time);
+ }
+
+ public int getMinimumRecompilationInterval() {
+ return minimumRecompilationInterval;
+ }
+
+ /**
+ * Allow setting the bytecode compatibility. The parameter can take
+ * one of the values <tt>1.7</tt>, <tt>1.6</tt>, <tt>1.5</tt> or <tt>1.4</tt>.
+ * If wrong parameter then the value will default to VM determined version.
+ *
+ * @param version the bytecode compatibility mode
+ */
+ public void setTargetBytecode(String version) {
+ for (String allowedJdk : ALLOWED_JDKS) {
+ if (allowedJdk.equals(version)) {
+ this.targetBytecode = version;
+ }
+ }
+ }
+
+ /**
+ * Retrieves the compiler bytecode compatibility mode.
+ *
+ * @return bytecode compatibility mode. Can be either <tt>1.5</tt> or <tt>1.4</tt>.
+ */
+ public String getTargetBytecode() {
+ return this.targetBytecode;
+ }
+
+ private static String getVMVersion() {
+ return POST_JDK5;
+ }
+
+ /**
+ * Gets the joint compilation options for this configuration.
+ * @return the options
+ */
+ public Map<String, Object> getJointCompilationOptions() {
+ return jointCompilationOptions;
+ }
+
+ /**
+ * Sets the joint compilation options for this configuration.
+ * Using null will disable joint compilation.
+ * @param options the options
+ */
+ public void setJointCompilationOptions(Map<String, Object> options) {
+ jointCompilationOptions = options;
+ }
+
+ /**
+ * Gets the optimization options for this configuration.
+ * @return the options (always not null)
+ */
+ public Map<String, Boolean> getOptimizationOptions() {
+ return optimizationOptions;
+ }
+
+ /**
+ * Sets the optimization options for this configuration.
+ * No entry or a true for that entry means to enable that optimization,
+ * a false means the optimization is disabled.
+ * Valid keys are "all" and "int".
+ * @param options the options.
+ * @throws IllegalArgumentException if the options are null
+ */
+ public void setOptimizationOptions(Map<String, Boolean> options) {
+ if (options==null) throw new IllegalArgumentException("provided option map must not be null");
+ optimizationOptions = options;
+ }
+
+ /**
+ * Adds compilation customizers to the compilation process. A compilation customizer is a class node
+ * operation which performs various operations going from adding imports to access control.
+ * @param customizers the list of customizers to be added
+ * @return this configuration instance
+ */
+ public CompilerConfiguration addCompilationCustomizers(CompilationCustomizer... customizers) {
+ if (customizers==null) throw new IllegalArgumentException("provided customizers list must not be null");
+ compilationCustomizers.addAll(Arrays.asList(customizers));
+ return this;
+ }
+
+ /**
+ * Returns the list of compilation customizers.
+ * @return the customizers (always not null)
+ */
+ public List<CompilationCustomizer> getCompilationCustomizers() {
+ return compilationCustomizers;
+ }
+
+ /**
+ * Returns the list of disabled global AST transformation class names.
+ * @return a list of global AST transformation fully qualified class names
+ */
+ public Set<String> getDisabledGlobalASTTransformations() {
+ return disabledGlobalASTTransformations;
+ }
+
+ /**
+ * Disables global AST transformations. In order to avoid class loading side effects, it is not recommended
+ * to use MyASTTransformation.class.getName() by directly use the class name as a string. Disabled AST transformations
+ * only apply to automatically loaded global AST transformations, that is to say transformations defined in a
+ * META-INF/org.codehaus.groovy.transform.ASTTransformation file. If you explicitly add a global AST transformation
+ * in your compilation process, for example using the {@link org.codehaus.groovy.control.customizers.ASTTransformationCustomizer} or
+ * using a {@link org.codehaus.groovy.control.CompilationUnit.PrimaryClassNodeOperation}, then nothing will prevent
+ * the transformation from being loaded.
+ * @param disabledGlobalASTTransformations a set of fully qualified class names of global AST transformations
+ * which should not be loaded.
+ */
+ public void setDisabledGlobalASTTransformations(final Set<String> disabledGlobalASTTransformations) {
+ this.disabledGlobalASTTransformations = disabledGlobalASTTransformations;
+ }
+
+ public BytecodeProcessor getBytecodePostprocessor() {
+ return bytecodePostprocessor;
+ }
+
+ public void setBytecodePostprocessor(final BytecodeProcessor bytecodePostprocessor) {
+ this.bytecodePostprocessor = bytecodePostprocessor;
+ }
+
+ public ParserVersion getParserVersion() {
+ return this.parserVersion;
+ }
+
+ public void setParserVersion(ParserVersion parserVersion) {
+ this.parserVersion = parserVersion;
+ }
+
+ /**
+ * Check whether invoke dynamic enabled
+ * @return the result
+ */
+ public boolean isIndyEnabled() {
+ Boolean indyEnabled = this.getOptimizationOptions().get(INVOKEDYNAMIC);
+
+ if (null == indyEnabled) {
+ return false;
+ }
+
+ return indyEnabled;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ConfigurationException.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ConfigurationException.java b/src/main/java/org/codehaus/groovy/control/ConfigurationException.java
new file mode 100644
index 0000000..3d0658a
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ConfigurationException.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.control;
+
+import org.codehaus.groovy.GroovyExceptionInterface;
+
+
+
+
+/**
+ * Thrown when configuration data is invalid.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public class ConfigurationException extends RuntimeException implements GroovyExceptionInterface
+{
+
+ //---------------------------------------------------------------------------
+ // CONSTRUCTION AND SUCH
+
+ protected Exception cause; // The phase in which the failures occurred
+
+
+ /**
+ * Initializes the exception from a cause exception.
+ */
+
+ public ConfigurationException( Exception cause )
+ {
+ super( cause.getMessage() );
+ this.cause = cause;
+ }
+
+
+ /**
+ * Initializes the exception with just a message.
+ */
+
+ public ConfigurationException( String message )
+ {
+ super( message );
+ }
+
+
+
+ /**
+ * Returns the causing exception, if available.
+ */
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+
+
+ /**
+ * Its always fatal.
+ */
+
+ public boolean isFatal()
+ {
+ return true;
+ }
+
+
+
+ /**
+ * Set fatal is just ignored.
+ */
+
+ public void setFatal( boolean fatal )
+ {
+ }
+
+}