groovy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cchamp...@apache.org
Subject [14/62] [abbrv] [partial] groovy git commit: Move Java source set into `src/main/java`
Date Sun, 17 Dec 2017 14:01:25 GMT
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ErrorCollector.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ErrorCollector.java b/src/main/java/org/codehaus/groovy/control/ErrorCollector.java
new file mode 100644
index 0000000..b388caa
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ErrorCollector.java
@@ -0,0 +1,348 @@
+/*
+ *  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.control.messages.ExceptionMessage;
+import org.codehaus.groovy.control.messages.LocatedMessage;
+import org.codehaus.groovy.control.messages.Message;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.control.messages.WarningMessage;
+import org.codehaus.groovy.syntax.CSTNode;
+import org.codehaus.groovy.syntax.SyntaxException;
+
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A base class for collecting messages and errors during processing.
+ * Each CompilationUnit should have an ErrorCollector, and the SourceUnits
+ * should share their ErrorCollector with the CompilationUnit.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ */
+public class ErrorCollector {
+    
+    /**
+     * WarningMessages collected during processing
+     */
+    protected LinkedList warnings;
+    /**
+     * ErrorMessages collected during processing
+     */
+    protected LinkedList errors;
+    /**
+     * Configuration and other settings that control processing
+     */
+    protected CompilerConfiguration configuration;
+
+    /**
+     * Initialize the ErrorReporter.
+     */
+    public ErrorCollector(CompilerConfiguration configuration) {
+        this.warnings = null;
+        this.errors = null;
+        
+        this.configuration = configuration;
+    }
+    
+    public void addCollectorContents(ErrorCollector er) {
+        if (er.errors!=null) {
+            if (errors==null) {
+                errors = er.errors;
+            } else {
+                errors.addAll(er.errors);
+            }
+        }
+        if (er.warnings!=null) {
+            if (warnings==null) {
+                warnings = er.warnings;
+            } else {
+                warnings.addAll(er.warnings);
+            }            
+        }
+    }
+
+    public void addErrorAndContinue(SyntaxException error, SourceUnit source) throws CompilationFailedException {
+        addErrorAndContinue(Message.create(error, source));
+    }
+    
+    /**
+     * Adds an error to the message set, but does not cause a failure. The message is not required to have a source
+     * line and column specified, but it is best practice to try and include that information. 
+     */
+    public void addErrorAndContinue(Message message) {
+        if (this.errors == null) {
+            this.errors = new LinkedList();
+        }
+
+        this.errors.add(message);
+    }
+    
+    /**
+     * Adds a non-fatal error to the message set, which may cause a failure if the error threshold is exceeded.
+     * The message is not required to have a source line and column specified, but it is best practice to try
+     * and include that information.
+     */
+    public void addError(Message message) throws CompilationFailedException {
+        addErrorAndContinue(message);
+
+        if (errors!=null && this.errors.size() >= configuration.getTolerance()) {
+            failIfErrors();
+        }
+    }
+    
+    /**
+     * Adds an optionally-fatal error to the message set.
+     * The message is not required to have a source line and column specified, but it is best practice to try
+     * and include that information.
+     * @param fatal
+     *      if true then then processing will stop
+     */
+    public void addError(Message message, boolean fatal) throws CompilationFailedException {
+        if (fatal) {
+            addFatalError(message);
+        }
+        else {
+            addError(message);
+        }
+    }
+
+    
+    /**
+     * Convenience wrapper for addError().
+     */
+    public void addError(SyntaxException error, SourceUnit source) throws CompilationFailedException {
+        addError(Message.create(error, source), error.isFatal());
+    }
+
+
+    /**
+     * Convenience wrapper for addError().
+     */
+    public void addError(String text, CSTNode context, SourceUnit source) throws CompilationFailedException {
+        addError(new LocatedMessage(text, context, source));
+    }
+    
+    
+    /**
+     * Adds a fatal exception to the message set and throws
+     * the unit as a PhaseFailedException.
+     */
+    public void addFatalError(Message message) throws CompilationFailedException {
+        addError(message);
+        failIfErrors();
+    }
+
+
+    public void addException(Exception cause, SourceUnit source) throws CompilationFailedException {
+        addError(new ExceptionMessage(cause,configuration.getDebug(),source));
+        failIfErrors();
+    }
+
+    /**
+     * Returns true if there are any errors pending.
+     */
+    public boolean hasErrors() {
+        return this.errors != null;
+    }
+
+    /**
+     * @return the compiler configuration used to create this error collector
+     */
+    public CompilerConfiguration getConfiguration() {
+        return configuration;
+    }
+
+    /**
+     * Returns true if there are any warnings pending.
+     */
+    public boolean hasWarnings() {
+        return this.warnings != null;
+    }
+    
+    /**
+     * Returns the list of warnings, or null if there are none.
+     */
+    public List getWarnings() {
+        return this.warnings;
+    }
+
+    /**
+     * Returns the list of errors, or null if there are none.
+     */
+    public List getErrors() {
+        return this.errors;
+    }
+
+    /**
+     * Returns the number of warnings.
+     */
+    public int getWarningCount() {
+        return ((this.warnings == null) ? 0 : this.warnings.size());
+    }
+
+    /**
+     * Returns the number of errors.
+     */
+    public int getErrorCount() {
+        return ((this.errors == null) ? 0 : this.errors.size());
+    }
+
+    /**
+     * Returns the specified warning message, or null.
+     */
+    public WarningMessage getWarning(int index) {
+        if (index < getWarningCount()) {
+            return (WarningMessage) this.warnings.get(index);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the specified error message, or null.
+     */
+    public Message getError(int index) {
+        if (index < getErrorCount()) {
+            return (Message) this.errors.get(index);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the last error reported
+     */
+    public Message getLastError() {
+        return (Message) this.errors.getLast();
+    }
+    
+    /**
+     * Convenience routine to return the specified error's
+     * underlying SyntaxException, or null if it isn't one.
+     */
+    public SyntaxException getSyntaxError(int index) {
+        SyntaxException exception = null;
+
+        Message message = getError(index);
+        if (message != null && message instanceof SyntaxErrorMessage) {
+            exception = ((SyntaxErrorMessage) message).getCause();
+        }
+        return exception;
+    }
+
+    /**
+     * Convenience routine to return the specified error's
+     * underlying Exception, or null if it isn't one.
+     */
+    public Exception getException(int index) {
+        Exception exception = null;
+
+        Message message = getError(index);
+        if (message != null) {
+            if (message instanceof ExceptionMessage) {
+                exception = ((ExceptionMessage) message).getCause();
+            }
+            else if (message instanceof SyntaxErrorMessage) {
+                exception = ((SyntaxErrorMessage) message).getCause();
+            }
+        }
+        return exception;
+    }
+
+    /**
+     * Adds a WarningMessage to the message set.
+     */
+    public void addWarning(WarningMessage message) {
+        if (message.isRelevant(configuration.getWarningLevel())) {
+            if (this.warnings == null) {
+                this.warnings = new LinkedList();
+            }
+
+            this.warnings.add(message);
+        }
+    }
+
+
+    /**
+     * Convenience wrapper for addWarning() that won't create an object
+     * unless it is relevant.
+     */
+    public void addWarning(int importance, String text, CSTNode context, SourceUnit source) {
+        if (WarningMessage.isRelevant(importance, configuration.getWarningLevel())) {
+            addWarning(new WarningMessage(importance, text, context, source));
+        }
+    }
+    
+    
+    /**
+     * Convenience wrapper for addWarning() that won't create an object
+     * unless it is relevant.
+     */
+    public void addWarning(int importance, String text, Object data, CSTNode context, SourceUnit source) {
+        if (WarningMessage.isRelevant(importance, configuration.getWarningLevel())) {
+            addWarning(new WarningMessage(importance, text, data, context, source));
+        }
+    }
+   
+
+    /**
+     * Causes the current phase to fail by throwing a
+     * CompilationFailedException.
+     */
+    protected void failIfErrors() throws CompilationFailedException {
+        if (hasErrors()) {
+            throw new MultipleCompilationErrorsException(this);
+        }
+    }
+    
+    //---------------------------------------------------------------------------
+    // OUTPUT
+
+
+    private void write(PrintWriter writer, Janitor janitor, List messages, String txt) {
+        if (messages==null || messages.isEmpty()) return;
+        Iterator iterator = messages.iterator();
+        while (iterator.hasNext()) {
+            Message message = (Message) iterator.next();
+            message.write(writer, janitor);
+            
+            if (configuration.getDebug() && (message instanceof SyntaxErrorMessage)){
+                SyntaxErrorMessage sem = (SyntaxErrorMessage) message;
+                sem.getCause().printStackTrace(writer);
+            } 
+            writer.println();
+        }
+
+        writer.print(messages.size());
+        writer.print(" "+txt);
+        if (messages.size()>1) writer.print("s");
+        writer.println();
+    }
+    
+    /**
+     * Writes error messages to the specified PrintWriter.
+     */
+    public void write(PrintWriter writer, Janitor janitor) {
+        write(writer,janitor,warnings,"warning");
+        write(writer,janitor,errors,"error");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/GenericsVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/GenericsVisitor.java b/src/main/java/org/codehaus/groovy/control/GenericsVisitor.java
new file mode 100644
index 0000000..36ef5ea
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/GenericsVisitor.java
@@ -0,0 +1,188 @@
+/*
+ *  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.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+
+/**
+ * class used to verify correct usage of generics in
+ * class header (class and superclass declaration)
+ *
+ * @author Jochen Theodorou
+ */
+public class GenericsVisitor extends ClassCodeVisitorSupport {
+    private final SourceUnit source;
+
+    public GenericsVisitor(SourceUnit source) {
+        this.source = source;
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+
+    @Override
+    public void visitClass(ClassNode node) {
+        boolean error = checkWildcard(node);
+        if (error) return;
+        boolean isAnon = node instanceof InnerClassNode && ((InnerClassNode)node).isAnonymous();
+        checkGenericsUsage(node.getUnresolvedSuperClass(false), node.getSuperClass(), isAnon ? true : null);
+        ClassNode[] interfaces = node.getInterfaces();
+        for (ClassNode anInterface : interfaces) {
+            checkGenericsUsage(anInterface, anInterface.redirect());
+        }
+        node.visitContents(this);
+    }
+
+    @Override
+    public void visitField(FieldNode node) {
+        ClassNode type = node.getType();
+        checkGenericsUsage(type, type.redirect());
+        super.visitField(node);
+    }
+
+    @Override
+    public void visitConstructorCallExpression(ConstructorCallExpression call) {
+        ClassNode type = call.getType();
+        boolean isAnon = type instanceof InnerClassNode && ((InnerClassNode)type).isAnonymous();
+        checkGenericsUsage(type, type.redirect(), isAnon);
+    }
+
+    @Override
+    public void visitMethod(MethodNode node) {
+        Parameter[] parameters = node.getParameters();
+        for (Parameter param : parameters) {
+            ClassNode paramType = param.getType();
+            checkGenericsUsage(paramType, paramType.redirect());
+        }
+        ClassNode returnType = node.getReturnType();
+        checkGenericsUsage(returnType, returnType.redirect());
+        super.visitMethod(node);
+    }
+
+    private boolean checkWildcard(ClassNode cn) {
+        ClassNode sn = cn.getUnresolvedSuperClass(false);
+        if (sn == null) return false;
+        GenericsType[] generics = sn.getGenericsTypes();
+        if (generics == null) return false;
+        boolean error = false;
+        for (GenericsType generic : generics) {
+            if (generic.isWildcard()) {
+                addError("A supertype may not specify a wildcard type", sn);
+                error = true;
+            }
+        }
+        return error;
+    }
+
+    private void checkGenericsUsage(ClassNode n, ClassNode cn) {
+        checkGenericsUsage(n, cn, null);
+    }
+
+    private void checkGenericsUsage(ClassNode n, ClassNode cn, Boolean isAnonInnerClass) {
+        if (n.isGenericsPlaceHolder()) return;
+        GenericsType[] nTypes = n.getGenericsTypes();
+        GenericsType[] cnTypes = cn.getGenericsTypes();
+        // raw type usage is always allowed
+        if (nTypes == null) return;
+        // you can't parameterize a non-generified type
+        if (cnTypes == null) {
+            String message = "The class " + getPrintName(n) + " (supplied with " + plural("type parameter", nTypes.length) +
+                    ") refers to the class " + getPrintName(cn) + " which takes no parameters";
+            if (nTypes.length == 0) {
+                message += " (invalid Diamond <> usage?)";
+            }
+            addError(message, n);
+            return;
+        }
+        // parameterize a type by using all of the parameters only
+        if (nTypes.length != cnTypes.length) {
+            if (Boolean.FALSE.equals(isAnonInnerClass) && nTypes.length == 0) {
+                return; // allow Diamond for non-AIC cases from CCE
+            }
+            String message;
+            if (Boolean.TRUE.equals(isAnonInnerClass) && nTypes.length == 0) {
+                message = "Cannot use diamond <> with anonymous inner classes";
+            } else {
+                message = "The class " + getPrintName(n) + " (supplied with " + plural("type parameter", nTypes.length) +
+                        ") refers to the class " + getPrintName(cn) +
+                        " which takes " + plural("parameter", cnTypes.length);
+                if (nTypes.length == 0) {
+                    message += " (invalid Diamond <> usage?)";
+                }
+            }
+            addError(message, n);
+            return;
+        }
+        // check bounds
+        for (int i = 0; i < nTypes.length; i++) {
+            ClassNode nType = nTypes[i].getType();
+            ClassNode cnType = cnTypes[i].getType();
+            if (!nType.isDerivedFrom(cnType)) {
+                if (cnType.isInterface() && nType.implementsInterface(cnType)) continue;
+                addError("The type " + nTypes[i].getName() +
+                        " is not a valid substitute for the bounded parameter <" +
+                        getPrintName(cnTypes[i]) + ">", n);
+            }
+        }
+    }
+
+    private String plural(String orig, int count) {
+        return "" + count + " " + (count == 1 ? orig : orig + "s");
+    }
+
+    private static String getPrintName(GenericsType gt) {
+        StringBuilder ret = new StringBuilder(gt.getName());
+        ClassNode[] upperBounds = gt.getUpperBounds();
+        ClassNode lowerBound = gt.getLowerBound();
+        if (upperBounds != null) {
+            if (upperBounds.length != 1 || !"java.lang.Object".equals(getPrintName(upperBounds[0]))) {
+                ret.append(" extends ");
+                for (int i = 0; i < upperBounds.length; i++) {
+                    ret.append(getPrintName(upperBounds[i]));
+                    if (i + 1 < upperBounds.length) ret.append(" & ");
+                }
+            }
+        } else if (lowerBound != null) {
+            ret.append(" super ").append(getPrintName(lowerBound));
+        }
+        return ret.toString();
+    }
+
+    private static String getPrintName(ClassNode cn) {
+        StringBuilder ret = new StringBuilder(cn.getName());
+        GenericsType[] gts = cn.getGenericsTypes();
+        if (gts != null) {
+            ret.append("<");
+            for (int i = 0; i < gts.length; i++) {
+                if (i != 0) ret.append(",");
+                ret.append(getPrintName(gts[i]));
+            }
+            ret.append(">");
+        }
+        return ret.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/HasCleanup.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/HasCleanup.java b/src/main/java/org/codehaus/groovy/control/HasCleanup.java
new file mode 100644
index 0000000..e7f2365
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/HasCleanup.java
@@ -0,0 +1,31 @@
+/*
+ *  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;
+
+/**
+ *  An interface for things that need to be cleaned up after
+ *  operations complete.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public interface HasCleanup 
+{
+    void cleanup();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/Janitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/Janitor.java b/src/main/java/org/codehaus/groovy/control/Janitor.java
new file mode 100644
index 0000000..8d08ebd
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/Janitor.java
@@ -0,0 +1,55 @@
+/*
+ *  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 java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ *  An agent that can be used to defer cleanup operations to 
+ *  a later time.  Users much implement the HasCleanup interface.  
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public class Janitor implements HasCleanup
+{
+    private final Set pending = new HashSet();   // All objects pending cleanup
+    
+    public void register( HasCleanup object )
+    {
+        pending.add( object );
+    }
+    
+    public void cleanup()
+    {
+        Iterator iterator = pending.iterator();
+        while( iterator.hasNext() )
+        {
+            HasCleanup object = (HasCleanup)iterator.next();
+            
+            try { object.cleanup(); } catch( Exception e ) {
+                // Ignore
+            }
+        }
+        
+        pending.clear();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/LabelVerifier.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/LabelVerifier.java b/src/main/java/org/codehaus/groovy/control/LabelVerifier.java
new file mode 100644
index 0000000..1aea0be
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/LabelVerifier.java
@@ -0,0 +1,174 @@
+/*
+ *  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.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.stmt.BreakStatement;
+import org.codehaus.groovy.ast.stmt.ContinueStatement;
+import org.codehaus.groovy.ast.stmt.DoWhileStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.stmt.SwitchStatement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This class checks the handling of labels in the AST
+ *
+ * @author Jochen Theodorou
+ */
+public class LabelVerifier extends ClassCodeVisitorSupport {
+
+    private final SourceUnit source;
+    private LinkedList<String> visitedLabels;
+    private LinkedList<ContinueStatement> continueLabels;
+    private LinkedList<BreakStatement> breakLabels;
+    boolean inLoop = false;
+    boolean inSwitch = false;
+
+    public LabelVerifier(SourceUnit src) {
+        source = src;
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+
+    private void init() {
+        visitedLabels = new LinkedList<String>();
+        continueLabels = new LinkedList<ContinueStatement>();
+        breakLabels = new LinkedList<BreakStatement>();
+        inLoop = false;
+        inSwitch = false;
+    }
+
+    protected void visitClassCodeContainer(Statement code) {
+        init();
+        super.visitClassCodeContainer(code);
+        assertNoLabelsMissed();
+    }
+
+    public void visitStatement(Statement statement) {
+        List<String> labels = statement.getStatementLabels();
+
+        if (labels != null) {
+            for (String label : labels) {
+                if (breakLabels != null) {
+                    for (Iterator<BreakStatement> iter = breakLabels.iterator(); iter.hasNext(); ) {
+                        if (iter.next().getLabel().equals(label)) iter.remove();
+                    }
+                }
+                if (continueLabels != null) {
+                    for (Iterator<ContinueStatement> iter = continueLabels.iterator(); iter.hasNext(); ) {
+                        if (iter.next().getLabel().equals(label)) iter.remove();
+                    }
+                }
+                if (visitedLabels != null) {
+                    visitedLabels.add(label);
+                }
+            }
+        }
+
+        super.visitStatement(statement);
+    }
+
+    public void visitForLoop(ForStatement forLoop) {
+        boolean oldInLoop = inLoop;
+        inLoop = true;
+        super.visitForLoop(forLoop);
+        inLoop = oldInLoop;
+    }
+
+    public void visitDoWhileLoop(DoWhileStatement loop) {
+        boolean oldInLoop = inLoop;
+        inLoop = true;
+        super.visitDoWhileLoop(loop);
+        inLoop = oldInLoop;
+    }
+
+    public void visitWhileLoop(WhileStatement loop) {
+        boolean oldInLoop = inLoop;
+        inLoop = true;
+        super.visitWhileLoop(loop);
+        inLoop = oldInLoop;
+    }
+
+    public void visitBreakStatement(BreakStatement statement) {
+        String label = statement.getLabel();
+        boolean hasNamedLabel = label != null;
+        if (!hasNamedLabel && !inLoop && !inSwitch) {
+            addError("the break statement is only allowed inside loops or switches", statement);
+        } else if (hasNamedLabel && !inLoop) {
+            addError("the break statement with named label is only allowed inside loops", statement);
+        }
+        if (label != null) {
+            boolean found = false;
+            for (String element : visitedLabels) {
+                if (element.equals(label)) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) breakLabels.add(statement);
+        }
+
+        super.visitBreakStatement(statement);
+    }
+
+    public void visitContinueStatement(ContinueStatement statement) {
+        String label = statement.getLabel();
+        boolean hasNamedLabel = label != null;
+        if (!hasNamedLabel && !inLoop) {
+            addError("the continue statement is only allowed inside loops", statement);
+        }
+        if (label != null) {
+            boolean found = false;
+            for (String element : visitedLabels) {
+                if (element.equals(label)) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) continueLabels.add(statement);
+        }
+
+        super.visitContinueStatement(statement);
+    }
+
+    protected void assertNoLabelsMissed() {
+        //TODO: report multiple missing labels of the same name only once?
+        for (ContinueStatement element : continueLabels) {
+            addError("continue to missing label", element);
+        }
+        for (BreakStatement element : breakLabels) {
+            addError("break to missing label", element);
+        }
+    }
+
+    public void visitSwitch(SwitchStatement statement) {
+        boolean oldInSwitch = inSwitch;
+        inSwitch = true;
+        super.visitSwitch(statement);
+        inSwitch = oldInSwitch;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/MultipleCompilationErrorsException.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/MultipleCompilationErrorsException.java b/src/main/java/org/codehaus/groovy/control/MultipleCompilationErrorsException.java
new file mode 100644
index 0000000..0d7dc3c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/MultipleCompilationErrorsException.java
@@ -0,0 +1,64 @@
+/*
+ *  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 java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * @author Jochen Theodorou
+ */
+public class MultipleCompilationErrorsException extends
+        CompilationFailedException {
+    
+    protected ErrorCollector collector;
+    
+    public MultipleCompilationErrorsException(ErrorCollector ec) {
+        super(0, null);
+        if (ec == null) {
+            CompilerConfiguration config = super.getUnit() != null ?
+                super.getUnit().getConfiguration() :
+                new CompilerConfiguration();
+            collector = new ErrorCollector(config);
+        } else {
+            collector = ec;
+        }
+    }
+
+    public ErrorCollector getErrorCollector() {
+        return collector;
+    }
+    
+    public String getMessage() {
+        StringWriter data = new StringWriter();
+        PrintWriter writer = new PrintWriter(data);
+        Janitor janitor = new Janitor();
+
+        writer.write(super.getMessage());
+        writer.println(":");
+        try {
+            collector.write(writer, janitor);
+        }
+        finally {
+            janitor.cleanup();
+        }
+
+        return data.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/OptimizerVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/OptimizerVisitor.java b/src/main/java/org/codehaus/groovy/control/OptimizerVisitor.java
new file mode 100644
index 0000000..6bb343b
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/OptimizerVisitor.java
@@ -0,0 +1,149 @@
+/*
+ *  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.ast.ClassCodeExpressionTransformer;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.objectweb.asm.Opcodes;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType;
+
+/**
+ * Visitor to produce several optimizations:
+ * <ul>
+ * <li>to replace numbered constants with references to static fields</li>
+ * <li>remove superfluous references to GroovyObject interface</li>
+ * </ul>
+ */
+public class OptimizerVisitor extends ClassCodeExpressionTransformer {
+    private ClassNode currentClass;
+    private SourceUnit source;
+
+    // TODO make @CS lookup smarter so that we don't need both these maps
+    private final Map<Object, FieldNode> const2Objects = new HashMap<Object, FieldNode>();
+    private final Map<Object, FieldNode> const2Prims = new HashMap<Object, FieldNode>();
+    private int index;
+    private final List<FieldNode> missingFields = new LinkedList<FieldNode>();
+
+    public OptimizerVisitor(CompilationUnit cu) {
+    }
+
+    public void visitClass(ClassNode node, SourceUnit source) {
+        this.currentClass = node;
+        this.source = source;
+        const2Objects.clear();
+        const2Prims.clear();
+        missingFields.clear();
+        index = 0;
+        super.visitClass(node);
+        addMissingFields();
+        pruneUnneededGroovyObjectInterface(node);
+    }
+
+    private void pruneUnneededGroovyObjectInterface(ClassNode node) {
+        ClassNode superClass = node.getSuperClass();
+        boolean isSuperGroovy = superClass.isDerivedFromGroovyObject();
+        if (isSuperGroovy) {
+            ClassNode[] interfaces = node.getInterfaces();
+            boolean needsFix = false;
+            for (ClassNode classNode : interfaces) {
+                if (classNode.equals(ClassHelper.GROOVY_OBJECT_TYPE)) {
+                    needsFix = true;
+                    break;
+                }
+            }
+            if (needsFix) {
+                List<ClassNode> newInterfaces = new ArrayList<ClassNode>(interfaces.length);
+                for (ClassNode classNode : interfaces) {
+                    if (!classNode.equals(ClassHelper.GROOVY_OBJECT_TYPE)) {
+                        newInterfaces.add(classNode);
+                    }
+                }
+                node.setInterfaces(newInterfaces.toArray(new ClassNode[newInterfaces.size()]));
+            }
+        }
+    }
+
+    private void addMissingFields() {
+        for (FieldNode f : missingFields) {
+            currentClass.addField(f);
+        }
+    }
+
+    private void setConstField(ConstantExpression constantExpression) {
+        final Object n = constantExpression.getValue();
+        if (!(n instanceof Number)) return;
+        if (n instanceof Integer || n instanceof Double) return;
+        if (n instanceof Long && (0L == (Long) n || 1L == (Long) n)) return; // LCONST_0, LCONST_1
+
+        boolean isPrimitive = isPrimitiveType(constantExpression.getType());
+        FieldNode field = isPrimitive ? const2Prims.get(n) : const2Objects.get(n);
+        if (field != null) {
+            constantExpression.setConstantName(field.getName());
+            return;
+        }
+        String name;
+        while (true) {
+            name = "$const$" + index++;
+            if (currentClass.getDeclaredField(name) == null) break;
+        }
+        field = new FieldNode(name,
+                Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_FINAL,
+                constantExpression.getType(),
+                currentClass,
+                constantExpression);
+        field.setSynthetic(true);
+        missingFields.add(field);
+        constantExpression.setConstantName(field.getName());
+        if (isPrimitive) {
+            const2Prims.put(n, field);
+        } else {
+            const2Objects.put(n, field);
+        }
+    }
+
+    public Expression transform(Expression exp) {
+        if (exp == null) return null;
+        if (!currentClass.isInterface() && exp.getClass() == ConstantExpression.class) {
+            setConstField((ConstantExpression) exp);
+        }
+        return exp.transformExpression(this);
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+
+    public void visitClosureExpression(ClosureExpression expression) {
+        /*
+         * GROOVY-3339 - do nothing - so that numbers don't get replaced by cached constants in closure classes
+         */
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ParserPlugin.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ParserPlugin.java b/src/main/java/org/codehaus/groovy/control/ParserPlugin.java
new file mode 100644
index 0000000..9b298d8
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ParserPlugin.java
@@ -0,0 +1,36 @@
+/*
+ *  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.ast.ModuleNode;
+import org.codehaus.groovy.syntax.ParserException;
+import org.codehaus.groovy.syntax.Reduction;
+
+import java.io.Reader;
+
+/**
+ * A simple extension point to allow us to switch between the classic Groovy parser and the new Antlr based parser
+ * 
+ */
+public interface ParserPlugin {
+
+    Reduction parseCST(SourceUnit sourceUnit, Reader reader) throws CompilationFailedException;
+
+    ModuleNode buildAST(SourceUnit sourceUnit, ClassLoader classLoader, Reduction cst) throws ParserException;
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ParserPluginFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ParserPluginFactory.java b/src/main/java/org/codehaus/groovy/control/ParserPluginFactory.java
new file mode 100644
index 0000000..1d7a994
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ParserPluginFactory.java
@@ -0,0 +1,93 @@
+/*
+ *  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.GroovyRuntimeException;
+import org.codehaus.groovy.antlr.AntlrParserPluginFactory;
+
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * A factory of parser plugin instances
+ *
+ */
+public abstract class ParserPluginFactory {
+    private static Class<?> ANTLR4_CLASS=null;
+
+    /**
+     * creates the ANTLR 4 parser
+     * @return the factory for the parser
+     */
+    public static ParserPluginFactory antlr4() {
+        if (ANTLR4_CLASS==null) {
+            String name = "org.apache.groovy.parser.antlr4.Antlr4PluginFactory";
+            try {
+                ANTLR4_CLASS =
+                        Class.forName(name, false, ParserPluginFactory.class.getClassLoader());
+            } catch (Exception e) {
+                throw new GroovyRuntimeException("Could not find or load parser plugin factory for antlr4", e);
+            }
+        }
+        try {
+            return AccessController.doPrivileged(new PrivilegedExceptionAction<ParserPluginFactory>() {
+                public ParserPluginFactory run() throws Exception {
+                    return (ParserPluginFactory) ANTLR4_CLASS.newInstance();
+                }
+            });
+        } catch (PrivilegedActionException e) {
+            throw new GroovyRuntimeException("Could not create instance of parser plugin factory for antlr4", e.getCause());
+        }
+    }
+
+    /**
+     * creates the ANTLR 2.7 parser
+     * @return the factory for the parser
+     */
+    public static ParserPluginFactory antlr2() {
+        return new AntlrParserPluginFactory();
+    }
+
+    /**
+     * creates the ANTLR 2.7 parser. This method was used to switch between the pre JSR
+     * parser and the new ANTLR 2.7 based parser, but even before Groovy 1.0 this
+     * method was changed to always return the ANTLR 2.7 parser.
+     * @param useNewParser - ignored
+     * @return the ANTLR 2.7 based parser
+     */
+    @Deprecated
+    public static ParserPluginFactory newInstance(boolean useNewParser) {
+        return newInstance();
+    }
+
+    /**
+     * creates the ANTLR 2.7 parser. This method was used to switch between the pre JSR
+     * parser and the new ANTLR 2.7 based parser, but even before Groovy 1.0 this
+     * method was changed to always return the ANTLR 2.7 parser.
+     *
+     * @return the new parser factory.
+     */
+    @Deprecated
+    public static ParserPluginFactory newInstance() {
+        return antlr2();
+    }
+
+    public abstract ParserPlugin createParserPlugin();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ParserVersion.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ParserVersion.java b/src/main/java/org/codehaus/groovy/control/ParserVersion.java
new file mode 100644
index 0000000..8440611
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ParserVersion.java
@@ -0,0 +1,50 @@
+/*
+ *  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;
+
+/**
+ * Represents the version of a parser
+ *
+ * @since 2.6.0
+ */
+public enum ParserVersion {
+    /**
+     * Before Groovy 2.6.0(including 2.6.0), the default version of parser is v2
+     */
+    V_2,
+
+    /**
+     * After Groovy 3.0.0(including 3.0.0), the default version of parser is v4(i.e. the new parser Parrot)
+     */
+    V_4("Parrot");
+
+    private String name;
+
+    ParserVersion() {
+        this(null);
+    }
+
+    ParserVersion(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/Phases.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/Phases.java b/src/main/java/org/codehaus/groovy/control/Phases.java
new file mode 100644
index 0000000..47e421f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/Phases.java
@@ -0,0 +1,67 @@
+/*
+ *  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;
+
+
+
+
+/**
+ *  Compilation phase identifiers.  
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public class Phases
+{
+    public static final int INITIALIZATION        = 1;   // Opening of files and such
+    public static final int PARSING               = 2;   // Lexing, parsing, and AST building
+    public static final int CONVERSION            = 3;   // CST to AST conversion
+    public static final int SEMANTIC_ANALYSIS     = 4;   // AST semantic analysis and elucidation
+    public static final int CANONICALIZATION      = 5;   // AST completion
+    public static final int INSTRUCTION_SELECTION = 6;   // Class generation, phase 1
+    public static final int CLASS_GENERATION      = 7;   // Class generation, phase 2
+    public static final int OUTPUT                = 8;   // Output of class to disk
+    public static final int FINALIZATION          = 9;   // Cleanup
+    public static final int ALL                   = 9;   // Synonym for full compilation
+    
+    public static final String[] descriptions = {
+          "startup"
+        , "initialization"
+        , "parsing"
+        , "conversion"
+        , "semantic analysis"
+        , "canonicalization"
+        , "instruction selection"
+        , "class generation"
+        , "output"
+        , "cleanup"
+    };
+    
+    
+    
+   /**
+    *  Returns a description of the specified phase.
+    */
+    
+    public static String getDescription( int phase )
+    {
+        return descriptions[phase];
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ProcessingUnit.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ProcessingUnit.java b/src/main/java/org/codehaus/groovy/control/ProcessingUnit.java
new file mode 100644
index 0000000..d95822d
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ProcessingUnit.java
@@ -0,0 +1,180 @@
+/*
+ *  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 java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * A base class for data structures that can collect messages and errors
+ * during processing.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public abstract class ProcessingUnit {
+
+    /**
+     * The current phase
+     */
+    protected int phase;
+    /**
+     * Set true if phase is finished
+     */
+    protected boolean phaseComplete;
+
+    /**
+     * Configuration and other settings that control processing
+     */
+    protected CompilerConfiguration configuration;
+  
+    /**
+     * The ClassLoader to use during processing
+     */
+    protected GroovyClassLoader classLoader;
+    
+    /**
+     * a helper to share errors and report them
+     */
+    protected ErrorCollector errorCollector;
+
+
+    /**
+     * Initialize the ProcessingUnit to the empty state.
+     */
+
+    public ProcessingUnit(CompilerConfiguration configuration, GroovyClassLoader classLoader, ErrorCollector er) {
+
+        this.phase = Phases.INITIALIZATION;
+        this.configuration = configuration;
+        this.setClassLoader(classLoader);
+        configure((configuration == null ? new CompilerConfiguration() : configuration));
+        if (er==null) er = new ErrorCollector(getConfiguration());
+        this.errorCollector = er;
+    }
+
+
+    /**
+     * Reconfigures the ProcessingUnit.
+     */
+    public void configure(CompilerConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+
+    public CompilerConfiguration getConfiguration() {
+        return configuration;
+    }
+
+    public void setConfiguration(CompilerConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+    /**
+     * Returns the class loader in use by this ProcessingUnit.
+     */
+
+    public GroovyClassLoader getClassLoader() {
+        return classLoader;
+    }
+
+
+    /**
+     * Sets the class loader for use by this ProcessingUnit.
+     */
+
+    public void setClassLoader(final GroovyClassLoader loader) {
+        // Classloaders should only be created inside doPrivileged block
+        // This code creates a classloader, which needs permission if a security manage is installed.
+        // If this code might be invoked by code that does not have security permissions, then the classloader creation needs to occur inside a doPrivileged block.
+        this.classLoader = AccessController.doPrivileged(new PrivilegedAction<GroovyClassLoader>() {
+            public GroovyClassLoader run() {
+                ClassLoader parent = Thread.currentThread().getContextClassLoader();
+                if (parent == null) parent = ProcessingUnit.class.getClassLoader();
+                return loader == null ? new GroovyClassLoader(parent, configuration) : loader;
+            }
+        });
+    }
+
+
+    /**
+     * Returns the current phase.
+     */
+
+    public int getPhase() {
+        return this.phase;
+    }
+
+
+    /**
+     * Returns the description for the current phase.
+     */
+
+    public String getPhaseDescription() {
+        return Phases.getDescription(this.phase);
+    }
+
+    /**
+     * Errors found during the compilation should be reported through the ErrorCollector.
+     * @return
+     *      the ErrorCollector for this ProcessingUnit
+     */
+    public ErrorCollector getErrorCollector() {
+        return errorCollector;
+    }
+    
+    //---------------------------------------------------------------------------
+    // PROCESSING
+
+
+    /**
+     * Marks the current phase complete and processes any
+     * errors.
+     */
+
+    public void completePhase() throws CompilationFailedException {       
+        errorCollector.failIfErrors();
+        phaseComplete = true;
+    }
+
+
+    /**
+     * A synonym for <code>gotoPhase( phase + 1 )</code>.
+     */
+    public void nextPhase() throws CompilationFailedException {
+        gotoPhase(this.phase + 1);
+    }
+
+
+    /**
+     * Wraps up any pending operations for the current phase
+     * and switches to the next phase.
+     */
+    public void gotoPhase(int phase) throws CompilationFailedException {
+        if (!this.phaseComplete) {
+            completePhase();
+        }
+
+        this.phase = phase;
+        this.phaseComplete = false;
+    }
+
+}


Mime
View raw message