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:27 UTC
[16/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/classgen/asm/util/LoggableClassVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableClassVisitor.java b/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableClassVisitor.java
new file mode 100644
index 0000000..b794235
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableClassVisitor.java
@@ -0,0 +1,34 @@
+/*
+ * 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.classgen.asm.util;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.util.TraceClassVisitor;
+
+/**
+ * A ClassVisitor proxy, which can log bytecode generation
+ *
+ * @since 2.5.0
+ */
+public class LoggableClassVisitor extends ClassVisitor {
+ public LoggableClassVisitor(final ClassVisitor cv) {
+ super(Opcodes.ASM6, new TraceClassVisitor(cv, new LoggableTextifier(), null));
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableTextifier.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableTextifier.java b/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableTextifier.java
new file mode 100644
index 0000000..e5b0dea
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableTextifier.java
@@ -0,0 +1,438 @@
+/*
+ * 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.classgen.asm.util;
+
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.TypePath;
+import org.objectweb.asm.util.Printer;
+import org.objectweb.asm.util.Textifier;
+
+import java.util.List;
+
+/**
+ * Logging bytecode generation, which can make debugging easy
+ *
+ * @since 2.5.0
+ */
+public class LoggableTextifier extends Textifier {
+// private static final Logger LOGGER = Logger.getLogger(LoggableTextifier.class.getName());
+ private int loggedLineCnt = 0;
+
+ public LoggableTextifier() {
+ super(Opcodes.ASM6);
+ }
+
+ @Override
+ protected Textifier createTextifier() {
+ return new LoggableTextifier();
+ }
+
+ protected void log() {
+ int textSize = text.size();
+
+ for (int i = loggedLineCnt; i < textSize; i++) {
+ Object bc = text.get(i);
+
+ if (bc instanceof List && 0 == ((List) bc).size()) {
+ continue;
+ }
+
+ System.out.print(bc);
+ }
+
+ loggedLineCnt = textSize;
+ }
+
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ super.visit(version, access, name, signature, superName, interfaces);
+ log();
+ }
+
+ @Override
+ public void visitSource(String file, String debug) {
+ super.visitSource(file, debug);
+ log();
+ }
+
+ @Override
+ public Printer visitModule(final String name, final int access, final String version) {
+ Printer p = super.visitModule(name, access, version);
+ log();
+ return p;
+ }
+
+ @Override
+ public void visitOuterClass(String owner, String name, String desc) {
+ super.visitOuterClass(owner, name, desc);
+ log();
+ }
+
+ @Override
+ public Textifier visitClassAnnotation(String desc, boolean visible) {
+ Textifier t = super.visitClassAnnotation(desc, visible);
+ log();
+ return t;
+ }
+
+ @Override
+ public Printer visitClassTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ Printer t = super.visitClassTypeAnnotation(typeRef, typePath, desc, visible);
+ log();
+ return t;
+ }
+
+ @Override
+ public void visitClassAttribute(Attribute attr) {
+ super.visitClassAttribute(attr);
+ log();
+ }
+
+ @Override
+ public void visitInnerClass(String name, String outerName, String innerName, int access) {
+ super.visitInnerClass(name, outerName, innerName, access);
+ log();
+ }
+
+ @Override
+ public Textifier visitField(int access, String name, String desc, String signature, Object value) {
+ Textifier t = super.visitField(access, name, desc, signature, value);
+ log();
+ return t;
+ }
+
+ @Override
+ public Textifier visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ Textifier t = super.visitMethod(access, name, desc, signature, exceptions);
+ log();
+ return t;
+ }
+
+ @Override
+ public void visitClassEnd() {
+ super.visitClassEnd();
+ log();
+ }
+
+ @Override
+ public void visitRequire(String require, int access, String version) {
+ super.visitRequire(require, access, version);
+ log();
+ }
+
+ @Override
+ public void visitExport(String export, int access, String... modules) {
+ super.visitExport(export, access, modules);
+ log();
+ }
+
+ @Override
+ public void visitUse(String use) {
+ super.visitUse(use);
+ log();
+ }
+
+ @Override
+ public void visitProvide(String provide, String... providers) {
+ super.visitProvide(provide, providers);
+ log();
+ }
+
+ @Override
+ public void visitModuleEnd() {
+ super.visitModuleEnd();
+ log();
+ }
+
+ @Override
+ public void visit(String name, Object value) {
+ super.visit(name, value);
+ log();
+ }
+
+ @Override
+ public void visitEnum(String name, String desc, String value) {
+ super.visitEnum(name, desc, value);
+ log();
+ }
+
+ @Override
+ public Textifier visitAnnotation(String name, String desc) {
+ Textifier t = super.visitAnnotation(name, desc);
+ log();
+ return t;
+ }
+
+ @Override
+ public Textifier visitArray(String name) {
+ Textifier t = super.visitArray(name);
+ log();
+ return t;
+ }
+
+ @Override
+ public void visitAnnotationEnd() {
+ super.visitAnnotationEnd();
+ log();
+ }
+
+ @Override
+ public Textifier visitFieldAnnotation(String desc, boolean visible) {
+ Textifier t = super.visitFieldAnnotation(desc, visible);
+ log();
+ return t;
+ }
+
+ @Override
+ public Printer visitFieldTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ Printer t = super.visitFieldTypeAnnotation(typeRef, typePath, desc, visible);
+ log();
+ return t;
+ }
+
+ @Override
+ public void visitFieldAttribute(Attribute attr) {
+ super.visitFieldAttribute(attr);
+ log();
+ }
+
+ @Override
+ public void visitFieldEnd() {
+ super.visitFieldEnd();
+ log();
+ }
+
+ @Override
+ public void visitParameter(String name, int access) {
+ super.visitParameter(name, access);
+ log();
+ }
+
+ @Override
+ public Textifier visitAnnotationDefault() {
+ Textifier t = super.visitAnnotationDefault();
+ log();
+ return t;
+ }
+
+ @Override
+ public Textifier visitMethodAnnotation(String desc, boolean visible) {
+ Textifier t = super.visitMethodAnnotation(desc, visible);
+ log();
+ return t;
+ }
+
+ @Override
+ public Printer visitMethodTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ Printer t = super.visitMethodTypeAnnotation(typeRef, typePath, desc, visible);
+ log();
+ return t;
+ }
+
+ @Override
+ public Textifier visitParameterAnnotation(int parameter, String desc, boolean visible) {
+ Textifier t = super.visitParameterAnnotation(parameter, desc, visible);
+ log();
+ return t;
+ }
+
+ @Override
+ public void visitMethodAttribute(Attribute attr) {
+ super.visitMethodAttribute(attr);
+ log();
+ }
+
+ @Override
+ public void visitCode() {
+ super.visitCode();
+ log();
+ }
+
+ @Override
+ public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
+ super.visitFrame(type, nLocal, local, nStack, stack);
+ log();
+ }
+
+ @Override
+ public void visitInsn(int opcode) {
+ super.visitInsn(opcode);
+ log();
+ }
+
+ @Override
+ public void visitIntInsn(int opcode, int operand) {
+ super.visitIntInsn(opcode, operand);
+ log();
+ }
+
+ @Override
+ public void visitVarInsn(int opcode, int var) {
+ super.visitVarInsn(opcode, var);
+ log();
+ }
+
+ @Override
+ public void visitTypeInsn(int opcode, String type) {
+ super.visitTypeInsn(opcode, type);
+ log();
+ }
+
+ @Override
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ super.visitFieldInsn(opcode, owner, name, desc);
+ log();
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+ super.visitMethodInsn(opcode, owner, name, desc);
+ log();
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
+ super.visitMethodInsn(opcode, owner, name, desc, itf);
+ log();
+ }
+
+ @Override
+ public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
+ super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+ log();
+ }
+
+ @Override
+ public void visitJumpInsn(int opcode, Label label) {
+ super.visitJumpInsn(opcode, label);
+ log();
+ }
+
+ @Override
+ public void visitLabel(Label label) {
+ super.visitLabel(label);
+ log();
+ }
+
+ @Override
+ public void visitLdcInsn(Object cst) {
+ super.visitLdcInsn(cst);
+ log();
+ }
+
+ @Override
+ public void visitIincInsn(int var, int increment) {
+ super.visitIincInsn(var, increment);
+ log();
+ }
+
+ @Override
+ public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
+ super.visitTableSwitchInsn(min, max, dflt, labels);
+ log();
+ }
+
+ @Override
+ public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
+ super.visitLookupSwitchInsn(dflt, keys, labels);
+ log();
+ }
+
+ @Override
+ public void visitMultiANewArrayInsn(String desc, int dims) {
+ super.visitMultiANewArrayInsn(desc, dims);
+ log();
+ }
+
+ @Override
+ public Printer visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ Printer t = super.visitInsnAnnotation(typeRef, typePath, desc, visible);
+ log();
+ return t;
+ }
+
+ @Override
+ public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
+ super.visitTryCatchBlock(start, end, handler, type);
+ log();
+ }
+
+ @Override
+ public Printer visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ Printer t = super.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
+ log();
+ return t;
+ }
+
+ @Override
+ public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
+ super.visitLocalVariable(name, desc, signature, start, end, index);
+ log();
+ }
+
+ @Override
+ public Printer visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible) {
+ Printer t = super.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, desc, visible);
+ log();
+ return t;
+ }
+
+ @Override
+ public void visitLineNumber(int line, Label start) {
+ super.visitLineNumber(line, start);
+ log();
+ }
+
+ @Override
+ public void visitMaxs(int maxStack, int maxLocals) {
+ super.visitMaxs(maxStack, maxLocals);
+ log();
+ }
+
+ @Override
+ public void visitMethodEnd() {
+ super.visitMethodEnd();
+ log();
+ }
+
+ @Override
+ public Textifier visitAnnotation(String desc, boolean visible) {
+ Textifier t = super.visitAnnotation(desc, visible);
+ log();
+ return t;
+ }
+
+ @Override
+ public Textifier visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ Textifier t = super.visitTypeAnnotation(typeRef, typePath, desc, visible);
+ log();
+ return t;
+ }
+
+ @Override
+ public void visitAttribute(Attribute attr) {
+ super.visitAttribute(attr);
+ log();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/package.html b/src/main/java/org/codehaus/groovy/classgen/package.html
new file mode 100644
index 0000000..a72224a
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/package.html
@@ -0,0 +1,28 @@
+<!--
+
+ 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.
+
+-->
+<html>
+ <head>
+ <title>package org.codehaus.groovy.classgen.*</title>
+ </head>
+ <body>
+ <p>Generates Java classes for Groovy classes using ASM.</p>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/cli/GroovyPosixParser.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/cli/GroovyPosixParser.java b/src/main/java/org/codehaus/groovy/cli/GroovyPosixParser.java
new file mode 100644
index 0000000..e583ac9
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/cli/GroovyPosixParser.java
@@ -0,0 +1,281 @@
+/*
+ * 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.cli;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.Parser;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This is a hacked version of Commons CLI 1.2 PosixParser with some bug fixes added.
+ * We aren't aware of any use cases where it isn't now preferable to use the
+ * Commons CLI 1.3 DefaultParser but this class is retained for the time being for
+ * backwards compatibility if someone is relying on this class's exact functionality.
+ *
+ * @author John Keyes (john at integralsource.com)
+ * @author Paul King (Groovy hacks/fixes)
+ * @deprecated use the DefaultParser from Commons CLI
+ */
+@Deprecated
+public class GroovyPosixParser extends Parser
+{
+ /** holder for flattened tokens */
+ private List tokens = new ArrayList();
+
+ /** specifies if bursting should continue */
+ private boolean eatTheRest;
+
+ /** holder for the current option */
+ private Option currentOption;
+
+ /** the command line Options */
+ private Options options;
+
+ /**
+ * Resets the members to their original state i.e. remove
+ * all of <code>tokens</code> entries and set <code>eatTheRest</code>
+ * to false.
+ */
+ private void init()
+ {
+ eatTheRest = false;
+ tokens.clear();
+ }
+
+ /**
+ * An implementation of {@link Parser}'s abstract
+ * {@link Parser#flatten(Options,String[],boolean) flatten} method.
+ * <p>
+ * The following are the rules used by this flatten method.
+ * <ol>
+ * <li>if <code>stopAtNonOption</code> is <b>true</b> then do not
+ * burst anymore of <code>arguments</code> entries, just add each
+ * successive entry without further processing. Otherwise, ignore
+ * <code>stopAtNonOption</code>.</li>
+ * <li>if the current <code>arguments</code> entry is "<b>--</b>"
+ * just add the entry to the list of processed tokens</li>
+ * <li>if the current <code>arguments</code> entry is "<b>-</b>"
+ * just add the entry to the list of processed tokens</li>
+ * <li>if the current <code>arguments</code> entry is two characters
+ * in length and the first character is "<b>-</b>" then check if this
+ * is a valid {@link Option} id. If it is a valid id, then add the
+ * entry to the list of processed tokens and set the current {@link Option}
+ * member. If it is not a valid id and <code>stopAtNonOption</code>
+ * is true, then the remaining entries are copied to the list of
+ * processed tokens. Otherwise, the current entry is ignored.</li>
+ * <li>if the current <code>arguments</code> entry is more than two
+ * characters in length and the first character is "<b>-</b>" then
+ * we need to burst the entry to determine its constituents. For more
+ * information on the bursting algorithm see
+ * {@link GroovyPosixParser#burstToken(String, boolean) burstToken}.</li>
+ * <li>if the current <code>arguments</code> entry is not handled
+ * by any of the previous rules, then the entry is added to the list
+ * of processed tokens.</li>
+ * </ol>
+ *
+ * @param options The command line {@link Options}
+ * @param arguments The command line arguments to be parsed
+ * @param stopAtNonOption Specifies whether to stop flattening when an non option is found.
+ * @return The flattened <code>arguments</code> String array.
+ */
+ protected String[] flatten(Options options, String[] arguments, boolean stopAtNonOption) {
+ init();
+ this.options = options;
+
+ // an iterator for the command line tokens
+ Iterator iter = Arrays.asList(arguments).iterator();
+
+ // process each command line token
+ while (iter.hasNext())
+ {
+ // get the next command line token
+ String token = (String) iter.next();
+
+ // handle long option --foo or --foo=bar
+ if (token.startsWith("--"))
+ {
+ int pos = token.indexOf('=');
+ String opt = pos == -1 ? token : token.substring(0, pos); // --foo
+
+ if (!options.hasOption(opt))
+ {
+ processNonOptionToken(token, stopAtNonOption);
+ }
+ else
+ {
+ tokens.add(opt);
+ if (pos != -1)
+ {
+ tokens.add(token.substring(pos + 1));
+ } else {
+ currentOption = options.getOption(opt);
+ }
+ }
+ }
+
+ // single hyphen
+ else if ("-".equals(token))
+ {
+ tokens.add(token);
+ }
+ else if (token.startsWith("-"))
+ {
+ if (token.length() == 2 || options.hasOption(token))
+ {
+ processOptionToken(token, stopAtNonOption);
+ }
+ // requires bursting
+ else
+ {
+ burstToken(token, stopAtNonOption);
+ }
+ }
+ else
+ {
+ processNonOptionToken(token, stopAtNonOption);
+ }
+
+ gobble(iter);
+ }
+
+ return (String[]) tokens.toArray(new String[tokens.size()]);
+ }
+
+ /**
+ * Adds the remaining tokens to the processed tokens list.
+ *
+ * @param iter An iterator over the remaining tokens
+ */
+ private void gobble(Iterator iter)
+ {
+ if (eatTheRest)
+ {
+ while (iter.hasNext())
+ {
+ tokens.add(iter.next());
+ }
+ }
+ }
+
+ /**
+ * Add the special token "<b>--</b>" and the current <code>value</code>
+ * to the processed tokens list. Then add all the remaining
+ * <code>argument</code> values to the processed tokens list.
+ *
+ * @param value The current token
+ */
+ private void processNonOptionToken(String value, boolean stopAtNonOption)
+ {
+ if (stopAtNonOption && (currentOption == null || !currentOption.hasArg()))
+ {
+ eatTheRest = true;
+ tokens.add("--");
+ }
+
+ tokens.add(value);
+ currentOption = null;
+ }
+
+ /**
+ * If an {@link Option} exists for <code>token</code> then
+ * add the token to the processed list.
+ * <p>
+ * If an {@link Option} does not exist and <code>stopAtNonOption</code>
+ * is set then add the remaining tokens to the processed tokens list
+ * directly.
+ *
+ * @param token The current option token
+ * @param stopAtNonOption Specifies whether flattening should halt at the first non option.
+ */
+ private void processOptionToken(String token, boolean stopAtNonOption) {
+ if (stopAtNonOption && !options.hasOption(token))
+ {
+ eatTheRest = true;
+ }
+
+ if (options.hasOption(token)) {
+ currentOption = options.getOption(token);
+ } else {
+ currentOption = null;
+ }
+
+ tokens.add(token);
+ }
+
+ /**
+ * Breaks <code>token</code> into its constituent parts
+ * using the following algorithm.
+ *
+ * <ul>
+ * <li>ignore the first character ("<b>-</b>")</li>
+ * <li>foreach remaining character check if an {@link Option}
+ * exists with that id.</li>
+ * <li>if an {@link Option} does exist then add that character
+ * prepended with "<b>-</b>" to the list of processed tokens.</li>
+ * <li>if the {@link Option} can have an argument value and there
+ * are remaining characters in the token then add the remaining
+ * characters as a token to the list of processed tokens.</li>
+ * <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b>
+ * <code>stopAtNonOption</code> <b>IS</b> set then add the special token
+ * "<b>--</b>" followed by the remaining characters and also
+ * the remaining tokens directly to the processed tokens list.</li>
+ * <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b>
+ * <code>stopAtNonOption</code> <b>IS NOT</b> set then add that
+ * character prepended with "<b>-</b>".</li>
+ * </ul>
+ *
+ * @param token The current token to be <b>burst</b>
+ * @param stopAtNonOption Specifies whether to stop processing
+ * at the first non-Option encountered.
+ */
+ protected void burstToken(String token, boolean stopAtNonOption)
+ {
+ for (int i = 1; i < token.length(); i++)
+ {
+ String ch = String.valueOf(token.charAt(i));
+
+ if (options.hasOption(ch))
+ {
+ tokens.add("-" + ch);
+ currentOption = options.getOption(ch);
+
+ if (currentOption.hasArg() && (token.length() != (i + 1)))
+ {
+ tokens.add(token.substring(i + 1));
+ break;
+ }
+ }
+ else if (stopAtNonOption)
+ {
+ processNonOptionToken(token.substring(i), true);
+ break;
+ }
+ else
+ {
+ tokens.add(token);
+ break;
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ASTTransformationsContext.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ASTTransformationsContext.java b/src/main/java/org/codehaus/groovy/control/ASTTransformationsContext.java
new file mode 100644
index 0000000..ae95275
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ASTTransformationsContext.java
@@ -0,0 +1,53 @@
+/*
+ * 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.util.HashSet;
+import java.util.Set;
+
+/**
+ * Stores state information about global AST transformations applied to a compilation unit.
+ *
+ * @author Cedric Champeau
+*/
+public class ASTTransformationsContext {
+ protected final GroovyClassLoader transformLoader; // Classloader for global and local transforms
+
+ protected final CompilationUnit compilationUnit; // The compilation unit global AST transformations are applied on
+ protected final Set<String> globalTransformNames = new HashSet<String>(); // collected AST transformation names
+
+ public ASTTransformationsContext(final CompilationUnit compilationUnit, final GroovyClassLoader transformLoader) {
+ this.compilationUnit = compilationUnit;
+ this.transformLoader = transformLoader;
+ }
+
+ public CompilationUnit getCompilationUnit() {
+ return compilationUnit;
+ }
+
+ public Set<String> getGlobalTransformNames() {
+ return globalTransformNames;
+ }
+
+ public GroovyClassLoader getTransformLoader() {
+ return transformLoader;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java b/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java
new file mode 100644
index 0000000..b1610df
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java
@@ -0,0 +1,133 @@
+/*
+ * 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.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.classgen.Verifier;
+
+import java.math.BigDecimal;
+
+/**
+ * Visitor to resolve constants in annotation definitions.
+ *
+ * @author Paul King
+ */
+public class AnnotationConstantsVisitor extends ClassCodeVisitorSupport {
+ private SourceUnit source;
+ private boolean inAnnotationDef;
+
+ public void visitClass(ClassNode node, SourceUnit source) {
+ this.source = source;
+ this.inAnnotationDef = node.isAnnotationDefinition();
+ super.visitClass(node);
+ this.inAnnotationDef = false;
+ }
+
+ @Override
+ protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
+ if (!inAnnotationDef) return;
+ visitStatement(node.getFirstStatement(), node.getReturnType());
+ }
+
+ private static void visitStatement(Statement statement, ClassNode returnType) {
+ if (statement instanceof ReturnStatement) {
+ // normal path
+ ReturnStatement rs = (ReturnStatement) statement;
+ rs.setExpression(transformConstantExpression(rs.getExpression(), returnType));
+ } else if (statement instanceof ExpressionStatement) {
+ // path for JavaStubGenerator
+ ExpressionStatement es = (ExpressionStatement) statement;
+ es.setExpression(transformConstantExpression(es.getExpression(), returnType));
+ }
+ }
+
+ private static Expression transformConstantExpression(Expression val, ClassNode returnType) {
+ ClassNode returnWrapperType = ClassHelper.getWrapper(returnType);
+ if (val instanceof ConstantExpression) {
+ Expression result = revertType(val, returnWrapperType);
+ if (result != null) {
+ return result;
+ }
+ return val;
+ }
+ if (val instanceof CastExpression) {
+ CastExpression castExp = (CastExpression) val;
+ Expression castee = castExp.getExpression();
+ if (castee instanceof ConstantExpression) {
+ if (ClassHelper.getWrapper(castee.getType()).isDerivedFrom(returnWrapperType)) {
+ return castee;
+ }
+ Expression result = revertType(castee, returnWrapperType);
+ if (result != null) {
+ return result;
+ }
+ return castee;
+ }
+ }
+ return val;
+ }
+
+ private static Expression revertType(Expression val, ClassNode returnWrapperType) {
+ ConstantExpression ce = (ConstantExpression) val;
+ if (ClassHelper.Character_TYPE.equals(returnWrapperType) && ClassHelper.STRING_TYPE.equals(val.getType())) {
+ return configure(val, Verifier.transformToPrimitiveConstantIfPossible((ConstantExpression) val));
+ }
+ ClassNode valWrapperType = ClassHelper.getWrapper(val.getType());
+ if (ClassHelper.Integer_TYPE.equals(valWrapperType)) {
+ Integer i = (Integer) ce.getValue();
+ if (ClassHelper.Character_TYPE.equals(returnWrapperType)) {
+ return configure(val, new ConstantExpression((char) i.intValue(), true));
+ }
+ if (ClassHelper.Short_TYPE.equals(returnWrapperType)) {
+ return configure(val, new ConstantExpression(i.shortValue(), true));
+ }
+ if (ClassHelper.Byte_TYPE.equals(returnWrapperType)) {
+ return configure(val, new ConstantExpression(i.byteValue(), true));
+ }
+ }
+ if (ClassHelper.BigDecimal_TYPE.equals(valWrapperType)) {
+ BigDecimal bd = (BigDecimal) ce.getValue();
+ if (ClassHelper.Float_TYPE.equals(returnWrapperType)) {
+ return configure(val, new ConstantExpression(bd.floatValue(), true));
+ }
+ if (ClassHelper.Double_TYPE.equals(returnWrapperType)) {
+ return configure(val, new ConstantExpression(bd.doubleValue(), true));
+ }
+ }
+ return null;
+ }
+
+ private static Expression configure(Expression orig, Expression result) {
+ result.setSourcePosition(orig);
+ return result;
+ }
+
+ protected SourceUnit getSourceUnit() {
+ return source;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/BytecodeProcessor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/BytecodeProcessor.java b/src/main/java/org/codehaus/groovy/control/BytecodeProcessor.java
new file mode 100644
index 0000000..6ef8c30
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/BytecodeProcessor.java
@@ -0,0 +1,23 @@
+/*
+ * 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;
+
+public interface BytecodeProcessor {
+ byte[] processBytecode(String name, byte[] original);
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ClassNodeResolver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ClassNodeResolver.java b/src/main/java/org/codehaus/groovy/control/ClassNodeResolver.java
new file mode 100644
index 0000000..3b64333
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ClassNodeResolver.java
@@ -0,0 +1,345 @@
+/*
+ * 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 org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.decompiled.AsmDecompiler;
+import org.codehaus.groovy.ast.decompiled.AsmReferenceResolver;
+import org.codehaus.groovy.ast.decompiled.DecompiledClassNode;
+import org.codehaus.groovy.classgen.Verifier;
+import org.objectweb.asm.Opcodes;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class is used as a pluggable way to resolve class names.
+ * An instance of this class has to be added to {@link CompilationUnit} using
+ * {@link CompilationUnit#setClassNodeResolver(ClassNodeResolver)}. The
+ * CompilationUnit will then set the resolver on the {@link ResolveVisitor} each
+ * time new. The ResolveVisitor will prepare name lookup and then finally ask
+ * the resolver if the class exists. This resolver then can return either a
+ * SourceUnit or a ClassNode. In case of a SourceUnit the compiler is notified
+ * that a new source is to be added to the compilation queue. In case of a
+ * ClassNode no further action than the resolving is done. The lookup result
+ * is stored in the helper class {@link LookupResult}. This class provides a
+ * class cache to cache lookups. If you don't want this, you have to override
+ * the methods {@link ClassNodeResolver#cacheClass(String, ClassNode)} and
+ * {@link ClassNodeResolver#getFromClassCache(String)}. Custom lookup logic is
+ * supposed to go into the method
+ * {@link ClassNodeResolver#findClassNode(String, CompilationUnit)} while the
+ * entry method is {@link ClassNodeResolver#resolveName(String, CompilationUnit)}
+ *
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class ClassNodeResolver {
+
+ /**
+ * Helper class to return either a SourceUnit or ClassNode.
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+ public static class LookupResult {
+ private final SourceUnit su;
+ private final ClassNode cn;
+ /**
+ * creates a new LookupResult. You are not supposed to supply
+ * a SourceUnit and a ClassNode at the same time
+ */
+ public LookupResult(SourceUnit su, ClassNode cn) {
+ this.su = su;
+ this.cn = cn;
+ if (su==null && cn==null) throw new IllegalArgumentException("Either the SourceUnit or the ClassNode must not be null.");
+ if (su!=null && cn!=null) throw new IllegalArgumentException("SourceUnit and ClassNode cannot be set at the same time.");
+ }
+ /**
+ * returns true if a ClassNode is stored
+ */
+ public boolean isClassNode() { return cn!=null; }
+ /**
+ * returns true if a SourecUnit is stored
+ */
+ public boolean isSourceUnit() { return su!=null; }
+ /**
+ * returns the SourceUnit
+ */
+ public SourceUnit getSourceUnit() { return su; }
+ /**
+ * returns the ClassNode
+ */
+ public ClassNode getClassNode() { return cn; }
+ }
+
+ // Map to store cached classes
+ private final Map<String,ClassNode> cachedClasses = new HashMap();
+ /**
+ * Internal helper used to indicate a cache hit for a class that does not exist.
+ * This way further lookups through a slow {@link #findClassNode(String, CompilationUnit)}
+ * path can be avoided.
+ * WARNING: This class is not to be used outside of ClassNodeResolver.
+ */
+ protected static final ClassNode NO_CLASS = new ClassNode("NO_CLASS", Opcodes.ACC_PUBLIC,ClassHelper.OBJECT_TYPE){
+ public void setRedirect(ClassNode cn) {
+ throw new GroovyBugError("This is a dummy class node only! Never use it for real classes.");
+ }
+ };
+
+ /**
+ * Resolves the name of a class to a SourceUnit or ClassNode. If no
+ * class or source is found this method returns null. A lookup is done
+ * by first asking the cache if there is an entry for the class already available
+ * to then call {@link #findClassNode(String, CompilationUnit)}. The result
+ * of that method call will be cached if a ClassNode is found. If a SourceUnit
+ * is found, this method will not be asked later on again for that class, because
+ * ResolveVisitor will first ask the CompilationUnit for classes in the
+ * compilation queue and it will find the class for that SourceUnit there then.
+ * method return a ClassNode instead of a SourceUnit, the res
+ * @param name - the name of the class
+ * @param compilationUnit - the current CompilationUnit
+ * @return the LookupResult
+ */
+ public LookupResult resolveName(String name, CompilationUnit compilationUnit) {
+ ClassNode res = getFromClassCache(name);
+ if (res==NO_CLASS) return null;
+ if (res!=null) return new LookupResult(null,res);
+ LookupResult lr = findClassNode(name, compilationUnit);
+ if (lr != null) {
+ if (lr.isClassNode()) cacheClass(name, lr.getClassNode());
+ return lr;
+ } else {
+ cacheClass(name, NO_CLASS);
+ return null;
+ }
+ }
+
+ /**
+ * caches a ClassNode
+ * @param name - the name of the class
+ * @param res - the ClassNode for that name
+ */
+ public void cacheClass(String name, ClassNode res) {
+ cachedClasses.put(name, res);
+ }
+
+ /**
+ * returns whatever is stored in the class cache for the given name
+ * @param name - the name of the class
+ * @return the result of the lookup, which may be null
+ */
+ public ClassNode getFromClassCache(String name) {
+ // We use here the class cache cachedClasses to prevent
+ // calls to ClassLoader#loadClass. Disabling this cache will
+ // cause a major performance hit.
+ ClassNode cached = cachedClasses.get(name);
+ return cached;
+ }
+
+ /**
+ * Extension point for custom lookup logic of finding ClassNodes. Per default
+ * this will use the CompilationUnit class loader to do a lookup on the class
+ * path and load the needed class using that loader. Or if a script is found
+ * and that script is seen as "newer", the script will be used instead of the
+ * class.
+ *
+ * @param name - the name of the class
+ * @param compilationUnit - the current compilation unit
+ * @return the lookup result
+ */
+ public LookupResult findClassNode(String name, CompilationUnit compilationUnit) {
+ return tryAsLoaderClassOrScript(name, compilationUnit);
+ }
+
+ /**
+ * This method is used to realize the lookup of a class using the compilation
+ * unit class loader. Should no class be found we fall back to a script lookup.
+ * If a class is found we check if there is also a script and maybe use that
+ * one in case it is newer.<p/>
+ *
+ * Two class search strategies are possible: by ASM decompilation or by usual Java classloading.
+ * The latter is slower but is unavoidable for scripts executed in dynamic environments where
+ * the referenced classes might only be available in the classloader, not on disk.
+ */
+ private LookupResult tryAsLoaderClassOrScript(String name, CompilationUnit compilationUnit) {
+ GroovyClassLoader loader = compilationUnit.getClassLoader();
+
+ Map<String, Boolean> options = compilationUnit.configuration.getOptimizationOptions();
+ boolean useAsm = !Boolean.FALSE.equals(options.get("asmResolving"));
+ boolean useClassLoader = !Boolean.FALSE.equals(options.get("classLoaderResolving"));
+
+ LookupResult result = useAsm ? findDecompiled(name, compilationUnit, loader) : null;
+ if (result != null) {
+ return result;
+ }
+
+ if (!useClassLoader) {
+ return tryAsScript(name, compilationUnit, null);
+ }
+
+ return findByClassLoading(name, compilationUnit, loader);
+ }
+
+ /**
+ * Search for classes using class loading
+ */
+ private static LookupResult findByClassLoading(String name, CompilationUnit compilationUnit, GroovyClassLoader loader) {
+ Class cls;
+ try {
+ // NOTE: it's important to do no lookup against script files
+ // here since the GroovyClassLoader would create a new CompilationUnit
+ cls = loader.loadClass(name, false, true);
+ } catch (ClassNotFoundException cnfe) {
+ LookupResult lr = tryAsScript(name, compilationUnit, null);
+ return lr;
+ } catch (CompilationFailedException cfe) {
+ throw new GroovyBugError("The lookup for "+name+" caused a failed compilaton. There should not have been any compilation from this call.", cfe);
+ }
+ //TODO: the case of a NoClassDefFoundError needs a bit more research
+ // a simple recompilation is not possible it seems. The current class
+ // we are searching for is there, so we should mark that somehow.
+ // Basically the missing class needs to be completely compiled before
+ // we can again search for the current name.
+ /*catch (NoClassDefFoundError ncdfe) {
+ cachedClasses.put(name,SCRIPT);
+ return false;
+ }*/
+ if (cls == null) return null;
+ //NOTE: we might return false here even if we found a class,
+ // because we want to give a possible script a chance to
+ // recompile. This can only be done if the loader was not
+ // the instance defining the class.
+ ClassNode cn = ClassHelper.make(cls);
+ if (cls.getClassLoader() != loader) {
+ return tryAsScript(name, compilationUnit, cn);
+ }
+ return new LookupResult(null,cn);
+ }
+
+ /**
+ * Search for classes using ASM decompiler
+ */
+ private LookupResult findDecompiled(String name, CompilationUnit compilationUnit, GroovyClassLoader loader) {
+ ClassNode node = ClassHelper.make(name);
+ if (node.isResolved()) {
+ return new LookupResult(null, node);
+ }
+
+ DecompiledClassNode asmClass = null;
+ String fileName = name.replace('.', '/') + ".class";
+ URL resource = loader.getResource(fileName);
+ if (resource != null) {
+ try {
+ asmClass = new DecompiledClassNode(AsmDecompiler.parseClass(resource), new AsmReferenceResolver(this, compilationUnit));
+ if (!asmClass.getName().equals(name)) {
+ // this may happen under Windows because getResource is case insensitive under that OS!
+ asmClass = null;
+ }
+ } catch (IOException e) {
+ // fall through and attempt other search strategies
+ }
+ }
+
+ if (asmClass != null) {
+ if (isFromAnotherClassLoader(loader, fileName)) {
+ return tryAsScript(name, compilationUnit, asmClass);
+ }
+
+ return new LookupResult(null, asmClass);
+ }
+ return null;
+ }
+
+ private static boolean isFromAnotherClassLoader(GroovyClassLoader loader, String fileName) {
+ ClassLoader parent = loader.getParent();
+ return parent != null && parent.getResource(fileName) != null;
+ }
+
+ /**
+ * try to find a script using the compilation unit class loader.
+ */
+ private static LookupResult tryAsScript(String name, CompilationUnit compilationUnit, ClassNode oldClass) {
+ LookupResult lr = null;
+ if (oldClass!=null) {
+ lr = new LookupResult(null, oldClass);
+ }
+
+ if (name.startsWith("java.")) return lr;
+ //TODO: don't ignore inner static classes completely
+ if (name.indexOf('$') != -1) return lr;
+
+ // try to find a script from classpath*/
+ GroovyClassLoader gcl = compilationUnit.getClassLoader();
+ URL url = null;
+ try {
+ url = gcl.getResourceLoader().loadGroovySource(name);
+ } catch (MalformedURLException e) {
+ // fall through and let the URL be null
+ }
+ if (url != null && ( oldClass==null || isSourceNewer(url, oldClass))) {
+ SourceUnit su = compilationUnit.addSource(url);
+ return new LookupResult(su,null);
+ }
+ return lr;
+ }
+
+ /**
+ * get the time stamp of a class
+ * NOTE: copied from GroovyClassLoader
+ */
+ private static long getTimeStamp(ClassNode cls) {
+ if (!(cls instanceof DecompiledClassNode)) {
+ return Verifier.getTimestamp(cls.getTypeClass());
+ }
+
+ return ((DecompiledClassNode) cls).getCompilationTimeStamp();
+ }
+
+ /**
+ * returns true if the source in URL is newer than the class
+ * NOTE: copied from GroovyClassLoader
+ */
+ private static boolean isSourceNewer(URL source, ClassNode cls) {
+ try {
+ long lastMod;
+
+ // Special handling for file:// protocol, as getLastModified() often reports
+ // incorrect results (-1)
+ if (source.getProtocol().equals("file")) {
+ // Coerce the file URL to a File
+ String path = source.getPath().replace('/', File.separatorChar).replace('|', ':');
+ File file = new File(path);
+ lastMod = file.lastModified();
+ } else {
+ URLConnection conn = source.openConnection();
+ lastMod = conn.getLastModified();
+ conn.getInputStream().close();
+ }
+ return lastMod > getTimeStamp(cls);
+ } catch (IOException e) {
+ // if the stream can't be opened, let's keep the old reference
+ return false;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/CompilationFailedException.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/CompilationFailedException.java b/src/main/java/org/codehaus/groovy/control/CompilationFailedException.java
new file mode 100644
index 0000000..741b647
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/CompilationFailedException.java
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+
+/**
+ * Thrown when compilation fails from source errors.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public class CompilationFailedException extends GroovyRuntimeException {
+
+ protected int phase; // The phase in which the failures occurred
+ protected ProcessingUnit unit; // The *Unit object this exception wraps
+
+ public CompilationFailedException(int phase, ProcessingUnit unit, Throwable cause) {
+ super(Phases.getDescription(phase) + " failed", cause);
+ this.phase = phase;
+ this.unit = unit;
+ }
+
+
+ public CompilationFailedException(int phase, ProcessingUnit unit) {
+ super(Phases.getDescription(phase) + " failed");
+ this.phase = phase;
+ this.unit = unit;
+ }
+
+
+ /**
+ * Formats the error data as a String.
+ */
+
+ /*public String toString() {
+ StringWriter data = new StringWriter();
+ PrintWriter writer = new PrintWriter(data);
+ Janitor janitor = new Janitor();
+
+ try {
+ unit.getErrorReporter().write(writer, janitor);
+ }
+ finally {
+ janitor.cleanup();
+ }
+
+ return data.toString();
+ }*/
+
+
+ /**
+ * Returns the ProcessingUnit in which the error occurred.
+ */
+
+ public ProcessingUnit getUnit() {
+ return this.unit;
+ }
+
+}