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:25 UTC
[14/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/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;
+ }
+
+}