You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2017/12/20 00:56:31 UTC

[34/49] groovy git commit: Move source files to proper packages

http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/NumberRange.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/NumberRange.java b/src/main/groovy/groovy/lang/NumberRange.java
new file mode 100644
index 0000000..52ef856
--- /dev/null
+++ b/src/main/groovy/groovy/lang/NumberRange.java
@@ -0,0 +1,629 @@
+/*
+ * 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 groovy.lang;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.IteratorClosureAdapter;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.AbstractList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import static org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareEqual;
+import static org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareGreaterThan;
+import static org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareGreaterThanEqual;
+import static org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareLessThan;
+import static org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareLessThanEqual;
+import static org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareNotEqual;
+import static org.codehaus.groovy.runtime.ScriptBytecodeAdapter.compareTo;
+import static org.codehaus.groovy.runtime.dgmimpl.NumberNumberMinus.minus;
+import static org.codehaus.groovy.runtime.dgmimpl.NumberNumberMultiply.multiply;
+import static org.codehaus.groovy.runtime.dgmimpl.NumberNumberPlus.plus;
+
+/**
+ * Represents an immutable list of Numbers from a value to a value with a particular step size.
+ *
+ * In general, it isn't recommended using a NumberRange as a key to a map. The range
+ * 0..3 is deemed to be equal to 0.0..3.0 but they have different hashCode values,
+ * so storing a value using one of these ranges couldn't be retrieved using the other.
+ *
+ * @since 2.5.0
+ */
+public class NumberRange extends AbstractList<Comparable> implements Range<Comparable> {
+
+    /**
+     * The first value in the range.
+     */
+    private final Comparable from;
+
+    /**
+     * The last value in the range.
+     */
+    private final Comparable to;
+
+    /**
+     * The step size in the range.
+     */
+    private final Number stepSize;
+
+    /**
+     * The cached size, or -1 if not yet computed
+     */
+    private int size = -1;
+
+    /**
+     * The cached hashCode (once calculated)
+     */
+    private Integer hashCodeCache = null;
+
+    /**
+     * <code>true</code> if the range counts backwards from <code>to</code> to <code>from</code>.
+     */
+    private final boolean reverse;
+
+    /**
+     * <code>true</code> if the range includes the upper bound.
+     */
+    private final boolean inclusive;
+
+    /**
+     * Creates an inclusive {@link NumberRange} with step size 1.
+     * Creates a reversed range if <code>from</code> &lt; <code>to</code>.
+     *
+     * @param from the first value in the range
+     * @param to   the last value in the range
+     */
+    public <T extends Number & Comparable, U extends Number & Comparable>
+    NumberRange(T from, U to) {
+        this(from, to, null, true);
+    }
+
+    /**
+     * Creates a new {@link NumberRange} with step size 1.
+     * Creates a reversed range if <code>from</code> &lt; <code>to</code>.
+     *
+     * @param from start of the range
+     * @param to   end of the range
+     * @param inclusive whether the range is inclusive
+     */
+    public <T extends Number & Comparable, U extends Number & Comparable>
+    NumberRange(T from, U to, boolean inclusive) {
+        this(from, to, null, inclusive);
+    }
+
+    /**
+     * Creates an inclusive {@link NumberRange}.
+     * Creates a reversed range if <code>from</code> &lt; <code>to</code>.
+     *
+     * @param from start of the range
+     * @param to   end of the range
+     * @param stepSize the gap between discrete elements in the range
+     */
+    public <T extends Number & Comparable, U extends Number & Comparable, V extends
+            Number & Comparable<? super Number>>
+    NumberRange(T from, U to, V stepSize) {
+        this(from, to, stepSize, true);
+    }
+
+    /**
+     * Creates a {@link NumberRange}.
+     * Creates a reversed range if <code>from</code> &lt; <code>to</code>.
+     *
+     * @param from start of the range
+     * @param to   end of the range
+     * @param stepSize the gap between discrete elements in the range
+     * @param inclusive whether the range is inclusive
+     */
+    public <T extends Number & Comparable, U extends Number & Comparable, V extends
+            Number & Comparable>
+    NumberRange(T from, U to, V stepSize, boolean inclusive) {
+        if (from == null) {
+            throw new IllegalArgumentException("Must specify a non-null value for the 'from' index in a Range");
+        }
+        if (to == null) {
+            throw new IllegalArgumentException("Must specify a non-null value for the 'to' index in a Range");
+        }
+        reverse = areReversed(from, to);
+        Number tempFrom;
+        Number tempTo;
+        if (reverse) {
+            tempFrom = to;
+            tempTo = from;
+        } else {
+            tempFrom = from;
+            tempTo = to;
+        }
+        if (tempFrom instanceof Short) {
+            tempFrom = tempFrom.intValue();
+        } else if (tempFrom instanceof Float) {
+            tempFrom = tempFrom.doubleValue();
+        }
+        if (tempTo instanceof Short) {
+            tempTo = tempTo.intValue();
+        } else if (tempTo instanceof Float) {
+            tempTo = tempTo.doubleValue();
+        }
+
+        if (tempFrom instanceof Integer && tempTo instanceof Long) {
+            tempFrom = tempFrom.longValue();
+        } else if (tempTo instanceof Integer && tempFrom instanceof Long) {
+            tempTo = tempTo.longValue();
+        }
+
+        this.from = (Comparable) tempFrom;
+        this.to = (Comparable) tempTo;
+        this.stepSize = stepSize == null ? 1 : stepSize;
+        this.inclusive = inclusive;
+    }
+
+    /**
+     * For a NumberRange with step size 1, creates a new NumberRange with the same
+     * <code>from</code> and <code>to</code> as this NumberRange
+     * but with a step size of <code>stepSize</code>.
+     *
+     * @param stepSize the desired step size
+     * @return a new NumberRange
+     */
+    public <T extends Number & Comparable> NumberRange by(T stepSize) {
+        if (!Integer.valueOf(1).equals(this.stepSize)) {
+            throw new IllegalStateException("by only allowed on ranges with original stepSize = 1 but found " + this.stepSize);
+        }
+        return new NumberRange(comparableNumber(from), comparableNumber(to), stepSize, inclusive);
+    }
+
+    @SuppressWarnings("unchecked")
+    /* package private */ static <T extends Number & Comparable> T comparableNumber(Comparable c) {
+        return (T) c;
+    }
+
+    @SuppressWarnings("unchecked")
+    /* package private */ static <T extends Number & Comparable> T comparableNumber(Number n) {
+        return (T) n;
+    }
+
+    private static boolean areReversed(Number from, Number to) {
+        try {
+            return compareGreaterThan(from, to);
+        } catch (ClassCastException cce) {
+            throw new IllegalArgumentException("Unable to create range due to incompatible types: " + from.getClass().getSimpleName() + ".." + to.getClass().getSimpleName() + " (possible missing brackets around range?)", cce);
+        }
+    }
+
+    /**
+     * An object is deemed equal to this NumberRange if it represents a List of items and
+     * those items equal the list of discrete items represented by this NumberRange.
+     *
+     * @param that the object to be compared for equality with this NumberRange
+     * @return {@code true} if the specified object is equal to this NumberRange
+     * @see #fastEquals(NumberRange)
+     */
+    @Override
+    public boolean equals(Object that) {
+        return super.equals(that);
+    }
+
+    /**
+     * A NumberRange's hashCode is based on hashCode values of the discrete items it represents.
+     *
+     * @return the hashCode value
+     */
+    @Override
+    public int hashCode() {
+        if (hashCodeCache == null) {
+            hashCodeCache = super.hashCode();
+        }
+        return hashCodeCache;
+    }
+
+    /*
+     * NOTE: as per the class javadoc, this class doesn't obey the normal equals/hashCode contract.
+     * The following field and method could assist some scenarios which required a similar sort of contract
+     * (but between equals and the custom canonicalHashCode). Currently commented out since we haven't
+     * found a real need. We will likely remove this commented out code if no usage is identified soon.
+     */
+
+    /*
+     * The cached canonical hashCode (once calculated)
+     */
+//    private Integer canonicalHashCodeCache = null;
+
+    /*
+     * A NumberRange's canonicalHashCode is based on hashCode values of the discrete items it represents.
+     * When two NumberRange's are equal they will have the same canonicalHashCode value.
+     * Numerical values which Groovy deems equal have the same hashCode during this calculation.
+     * So currently (0..3).equals(0.0..3.0) yet they have different hashCode values. This breaks
+     * the normal equals/hashCode contract which is a weakness in Groovy's '==' operator. However
+     * the contract isn't broken between equals and canonicalHashCode.
+     *
+     * @return the hashCode value
+     */
+//    public int canonicalHashCode() {
+//        if (canonicalHashCodeCache == null) {
+//            int hashCode = 1;
+//            for (Comparable e : this) {
+//                int value;
+//                if (e == null) {
+//                    value = 0;
+//                } else {
+//                    BigDecimal next = new BigDecimal(e.toString());
+//                    if (next.compareTo(BigDecimal.ZERO) == 0) {
+//                        // workaround on pre-Java8 for http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6480539
+//                        value = BigDecimal.ZERO.hashCode();
+//                    } else {
+//                        value = next.stripTrailingZeros().hashCode();
+//                    }
+//                }
+//                hashCode = 31 * hashCode + value;
+//            }
+//            canonicalHashCodeCache = hashCode;
+//        }
+//        return canonicalHashCodeCache;
+//    }
+
+    /**
+     * Compares a {@link NumberRange} to another {@link NumberRange} using only a strict comparison
+     * of the NumberRange properties. This won't return true for some ranges which represent the same
+     * discrete items, use equals instead for that but will be much faster for large lists.
+     *
+     * @param that the NumberRange to check equality with
+     * @return <code>true</code> if the ranges are equal
+     */
+    public boolean fastEquals(NumberRange that) {
+        return that != null
+                && reverse == that.reverse
+                && inclusive == that.inclusive
+                && compareEqual(from, that.from)
+                && compareEqual(to, that.to)
+                && compareEqual(stepSize, that.stepSize);
+    }
+
+    /*
+     * NOTE: as per the class javadoc, this class doesn't obey the normal equals/hashCode contract.
+     * The following field and method could assist some scenarios which required a similar sort of contract
+     * (but between fastEquals and the custom fastHashCode). Currently commented out since we haven't
+     * found a real need. We will likely remove this commented out code if no usage is identified soon.
+     */
+
+    /*
+     * The cached fast hashCode (once calculated)
+     */
+//    private Integer fastHashCodeCache = null;
+
+    /*
+     * A hashCode function that pairs with fastEquals, following the normal equals/hashCode contract.
+     *
+     * @return the calculated hash code
+     */
+//    public int fastHashCode() {
+//        if (fastHashCodeCache == null) {
+//            int result = 17;
+//            result = result * 31 + (reverse ? 1 : 0);
+//            result = result * 31 + (inclusive ? 1 : 0);
+//            result = result * 31 + new BigDecimal(from.toString()).stripTrailingZeros().hashCode();
+//            result = result * 31 + new BigDecimal(to.toString()).stripTrailingZeros().hashCode();
+//            result = result * 31 + new BigDecimal(stepSize.toString()).stripTrailingZeros().hashCode();
+//            fastHashCodeCache = result;
+//        }
+//        return fastHashCodeCache;
+//    }
+
+    @Override
+    public Comparable getFrom() {
+        return from;
+    }
+
+    @Override
+    public Comparable getTo() {
+        return to;
+    }
+
+    public Comparable getStepSize() {
+        return (Comparable) stepSize;
+    }
+
+    @Override
+    public boolean isReverse() {
+        return reverse;
+    }
+
+    @Override
+    public Comparable get(int index) {
+        if (index < 0) {
+            throw new IndexOutOfBoundsException("Index: " + index + " should not be negative");
+        }
+        final Iterator<Comparable> iter = new StepIterator(this, stepSize);
+
+        Comparable value = iter.next();
+        for (int i = 0; i < index; i++) {
+            if (!iter.hasNext()) {
+                throw new IndexOutOfBoundsException("Index: " + index + " is too big for range: " + this);
+            }
+            value = iter.next();
+        }
+        return value;
+    }
+
+    /**
+     * Checks whether a value is between the from and to values of a Range
+     *
+     * @param value the value of interest
+     * @return true if the value is within the bounds
+     */
+    @Override
+    public boolean containsWithinBounds(Object value) {
+        final int result = compareTo(from, value);
+        return result == 0 || result < 0 && compareTo(to, value) >= 0;
+    }
+
+    /**
+     * protection against calls from Groovy
+     */
+    @SuppressWarnings("unused")
+    private void setSize(int size) {
+        throw new UnsupportedOperationException("size must not be changed");
+    }
+
+    @Override
+    public int size() {
+        if (size == -1) {
+            calcSize(from, to, stepSize);
+        }
+        return size;
+    }
+
+    void calcSize(Comparable from, Comparable to, Number stepSize) {
+        int tempsize = 0;
+        boolean shortcut = false;
+        if (isIntegral(stepSize)) {
+            if ((from instanceof Integer || from instanceof Long)
+                    && (to instanceof Integer || to instanceof Long)) {
+                // let's fast calculate the size
+                final BigInteger fromNum = new BigInteger(from.toString());
+                final BigInteger toTemp = new BigInteger(to.toString());
+                final BigInteger toNum = inclusive ? toTemp : toTemp.subtract(BigInteger.ONE);
+                final BigInteger sizeNum = new BigDecimal(toNum.subtract(fromNum)).divide(new BigDecimal(stepSize.longValue()), BigDecimal.ROUND_DOWN).toBigInteger().add(BigInteger.ONE);
+                tempsize = sizeNum.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) == -1 ? sizeNum.intValue() : Integer.MAX_VALUE;
+                shortcut = true;
+            } else if (((from instanceof BigDecimal || from instanceof BigInteger) && to instanceof Number) ||
+                    ((to instanceof BigDecimal || to instanceof BigInteger) && from instanceof Number)) {
+                // let's fast calculate the size
+                final BigDecimal fromNum = new BigDecimal(from.toString());
+                final BigDecimal toTemp = new BigDecimal(to.toString());
+                final BigDecimal toNum = inclusive ? toTemp : toTemp.subtract(new BigDecimal("1.0"));
+                final BigInteger sizeNum = toNum.subtract(fromNum).divide(new BigDecimal(stepSize.longValue()), BigDecimal.ROUND_DOWN).toBigInteger().add(BigInteger.ONE);
+                tempsize = sizeNum.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) == -1 ? sizeNum.intValue() : Integer.MAX_VALUE;
+                shortcut = true;
+            }
+        }
+        if (!shortcut) {
+            // let's brute-force calculate the size by iterating start to end
+            final Iterator iter = new StepIterator(this, stepSize);
+            while (iter.hasNext()) {
+                tempsize++;
+                // integer overflow
+                if (tempsize < 0) {
+                    break;
+                }
+                iter.next();
+            }
+            // integer overflow
+            if (tempsize < 0) {
+                tempsize = Integer.MAX_VALUE;
+            }
+        }
+        size = tempsize;
+    }
+
+    private boolean isIntegral(Number stepSize) {
+        BigDecimal tempStepSize = new BigDecimal(stepSize.toString());
+        return tempStepSize.equals(new BigDecimal(tempStepSize.toBigInteger()));
+    }
+
+    @Override
+    public List<Comparable> subList(int fromIndex, int toIndex) {
+        if (fromIndex < 0) {
+            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+        }
+        if (fromIndex > toIndex) {
+            throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
+        }
+        if (fromIndex == toIndex) {
+            return new EmptyRange<Comparable>(from);
+        }
+
+        // Performance detail:
+        // not using get(fromIndex), get(toIndex) in the following to avoid stepping over elements twice
+        final Iterator<Comparable> iter = new StepIterator(this, stepSize);
+
+        Comparable value = iter.next();
+        int i = 0;
+        for (; i < fromIndex; i++) {
+            if (!iter.hasNext()) {
+                throw new IndexOutOfBoundsException("Index: " + i + " is too big for range: " + this);
+            }
+            value = iter.next();
+        }
+        final Comparable fromValue = value;
+        for (; i < toIndex - 1; i++) {
+            if (!iter.hasNext()) {
+                throw new IndexOutOfBoundsException("Index: " + i + " is too big for range: " + this);
+            }
+            value = iter.next();
+        }
+        final Comparable toValue = value;
+
+        return new NumberRange(comparableNumber(fromValue), comparableNumber(toValue), comparableNumber(stepSize), true);
+    }
+
+    @Override
+    public String toString() {
+        return getToString(to.toString(), from.toString());
+    }
+
+    @Override
+    public String inspect() {
+        return getToString(InvokerHelper.inspect(to), InvokerHelper.inspect(from));
+    }
+
+    private String getToString(String toText, String fromText) {
+        String sep = inclusive ? ".." : "..<";
+        String base = reverse ? "" + toText + sep + fromText : "" + fromText + sep + toText;
+        return Integer.valueOf(1).equals(stepSize) ? base : base + ".by(" + stepSize + ")";
+    }
+
+    /**
+     * iterates over all values and returns true if one value matches.
+     * Also see containsWithinBounds.
+     */
+    @Override
+    public boolean contains(Object value) {
+        if (value == null) {
+            return false;
+        }
+        final Iterator it = new StepIterator(this, stepSize);
+        while (it.hasNext()) {
+            if (compareEqual(value, it.next())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void step(int numSteps, Closure closure) {
+        if (numSteps == 0 && compareTo(from, to) == 0) {
+            return; // from == to and step == 0, nothing to do, so return
+        }
+        final StepIterator iter = new StepIterator(this, multiply(numSteps, stepSize));
+        while (iter.hasNext()) {
+            closure.call(iter.next());
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Iterator<Comparable> iterator() {
+        return new StepIterator(this, stepSize);
+    }
+
+    /**
+     * convenience class to serve in other methods.
+     * It's not thread-safe, and lazily produces the next element only on calls of hasNext() or next()
+     */
+    private class StepIterator implements Iterator<Comparable> {
+        private final NumberRange range;
+        private final Number step;
+        private final boolean isAscending;
+
+        private boolean isNextFetched = false;
+        private Comparable next = null;
+
+        StepIterator(NumberRange range, Number step) {
+            if (compareEqual(step, 0) && compareNotEqual(range.getFrom(), range.getTo())) {
+                throw new GroovyRuntimeException("Infinite loop detected due to step size of 0");
+            }
+
+            this.range = range;
+            if (compareLessThan(step, 0)) {
+                this.step = multiply(step, -1);
+                isAscending = range.isReverse();
+            } else {
+                this.step = step;
+                isAscending = !range.isReverse();
+            }
+        }
+
+        @Override
+        public boolean hasNext() {
+            fetchNextIfNeeded();
+            return (next != null) && (isAscending
+                    ? (range.inclusive ? compareLessThanEqual(next, range.getTo()) : compareLessThan(next, range.getTo()))
+                    : (range.inclusive ? compareGreaterThanEqual(next, range.getFrom()) : compareGreaterThan(next, range.getFrom())));
+        }
+
+        @Override
+        public Comparable next() {
+            if (!hasNext()) {
+                throw new NoSuchElementException();
+            }
+
+            fetchNextIfNeeded();
+            isNextFetched = false;
+            return next;
+        }
+
+        private void fetchNextIfNeeded() {
+            if (!isNextFetched) {
+                isNextFetched = true;
+
+                if (next == null) {
+                    // make the first fetch lazy too
+                    next = isAscending ? range.getFrom() : range.getTo();
+                } else {
+                    next = isAscending ? increment(next, step) : decrement(next, step);
+                }
+            }
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    @Override
+    public List<Comparable> step(int numSteps) {
+        final IteratorClosureAdapter<Comparable> adapter = new IteratorClosureAdapter<Comparable>(this);
+        step(numSteps, adapter);
+        return adapter.asList();
+    }
+
+    /**
+     * Increments by given step
+     *
+     * @param value the value to increment
+     * @param step the amount to increment
+     * @return the incremented value
+     */
+    @SuppressWarnings("unchecked")
+    private Comparable increment(Object value, Number step) {
+        return (Comparable) plus((Number) value, step);
+    }
+
+    /**
+     * Decrements by given step
+     *
+     * @param value the value to decrement
+     * @param step the amount to decrement
+     * @return the decremented value
+     */
+    @SuppressWarnings("unchecked")
+    private Comparable decrement(Object value, Number step) {
+        return (Comparable) minus((Number) value, step);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/ObjectRange.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/ObjectRange.java b/src/main/groovy/groovy/lang/ObjectRange.java
new file mode 100644
index 0000000..a7e2b05
--- /dev/null
+++ b/src/main/groovy/groovy/lang/ObjectRange.java
@@ -0,0 +1,539 @@
+/*
+ *  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 groovy.lang;
+
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.IteratorClosureAdapter;
+import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.AbstractList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * Represents an inclusive list of objects from a value to a value using
+ * comparators.
+ * <p>
+ * Note: This class is similar to {@link IntRange}. If you make any changes to this
+ * class, you might consider making parallel changes to {@link IntRange}.
+ */
+public class ObjectRange extends AbstractList<Comparable> implements Range<Comparable> {
+    /**
+     * The first value in the range.
+     */
+    private final Comparable from;
+
+    /**
+     * The last value in the range.
+     */
+    private final Comparable to;
+
+    /**
+     * The cached size, or -1 if not yet computed
+     */
+    private int size = -1;
+
+    /**
+     * <code>true</code> if the range counts backwards from <code>to</code> to <code>from</code>.
+     */
+    private final boolean reverse;
+
+    /**
+     * Creates a new {@link ObjectRange}. Creates a reversed range if
+     * <code>from</code> &lt; <code>to</code>.
+     *
+     * @param from the first value in the range.
+     * @param to   the last value in the range.
+     */
+    public ObjectRange(Comparable from, Comparable to) {
+        this(from, to, null);
+    }
+
+    /**
+     * Creates a new {@link ObjectRange} assumes smaller &lt;&#61; larger, else behavior is undefined.
+     * Caution: Prefer the other constructor when in doubt.
+     * <p>
+     * Optimized Constructor avoiding initial computation of comparison.
+     */
+    public ObjectRange(Comparable smaller, Comparable larger, boolean reverse) {
+        this(smaller, larger, (Boolean) reverse);
+    }
+
+    /**
+     * Constructs a Range, computing reverse if not provided. When providing reverse,
+     * 'smaller' must not be larger than 'larger'.
+     *
+     * @param smaller start of the range, must no be larger than to when reverse != null
+     * @param larger  end of the range, must be larger than from when reverse != null
+     * @param reverse direction of the range. If null, causes direction to be computed (can be expensive).
+     */
+    private ObjectRange(Comparable smaller, Comparable larger, Boolean reverse) {
+        if (smaller == null) {
+            throw new IllegalArgumentException("Must specify a non-null value for the 'from' index in a Range");
+        }
+        if (larger == null) {
+            throw new IllegalArgumentException("Must specify a non-null value for the 'to' index in a Range");
+        }
+        if (reverse == null) {
+            final boolean computedReverse = areReversed(smaller, larger);
+            // ensure invariant from <= to
+            if (computedReverse) {
+                final Comparable temp = larger;
+                larger = smaller;
+                smaller = temp;
+            }
+            this.reverse = computedReverse;
+        } else {
+            this.reverse = reverse;
+        }
+
+        if (smaller instanceof Short) {
+            smaller = ((Short) smaller).intValue();
+        } else if (smaller instanceof Float) {
+            smaller = ((Float) smaller).doubleValue();
+        }
+        if (larger instanceof Short) {
+            larger = ((Short) larger).intValue();
+        } else if (larger instanceof Float) {
+            larger = ((Float) larger).doubleValue();
+        }
+
+        if (smaller instanceof Integer && larger instanceof Long) {
+            smaller = ((Integer) smaller).longValue();
+        } else if (larger instanceof Integer && smaller instanceof Long) {
+            larger = ((Integer) larger).longValue();
+        }
+
+        /*
+            areReversed() already does an implicit type compatibility check
+            based on DefaultTypeTransformation.compareToWithEqualityCheck() for mixed classes
+            but it is only invoked if reverse == null.
+            So Object Range has to perform those type checks for consistency even when not calling
+            compareToWithEqualityCheck(), and ObjectRange has
+            to use the normalized value used in a successful comparison in
+            compareToWithEqualityCheck(). Currently that means Chars and single-char Strings
+            are evaluated as the char's charValue (an integer) when compared to numbers.
+            So '7'..'9' should produce ['7', '8', '9'], whereas ['7'..9] and [7..'9'] should produce [55, 56, 57].
+            if classes match, or both numerical, no checks possible / necessary
+        */
+        if (smaller.getClass() == larger.getClass() ||
+                (smaller instanceof Number && larger instanceof Number)) {
+            this.from = smaller;
+            this.to = larger;
+        } else {
+            // Convenience hack: try convert single-char strings to ints
+            final Comparable tempfrom = normaliseStringType(smaller);
+            final Comparable tempto = normaliseStringType(larger);
+            // if after normalizing both are numbers, assume intended range was numbers
+            if (tempfrom instanceof Number && tempto instanceof Number) {
+                this.from = tempfrom;
+                this.to = tempto;
+            } else {
+                // if convenience hack did not make classes match,
+                // throw exception when starting with known class, and thus "from" cannot be advanced over "to".
+                // Note if start is an unusual Object, it could have a next() method
+                // that yields a Number or String to close the range
+                final Comparable start = this.reverse ? larger : smaller;
+                if (start instanceof String || start instanceof Number) {
+                    // starting with number will never reach a non-number, same for string
+                    throw new IllegalArgumentException("Incompatible Argument classes for ObjectRange " + smaller.getClass() + ", " + larger.getClass());
+                }
+                // Since normalizing did not help, use original values at user's risk
+                this.from = smaller;
+                this.to = larger;
+            }
+        }
+        checkBoundaryCompatibility();
+    }
+
+    /**
+     * throws IllegalArgumentException if to and from are incompatible, meaning they e.g. (likely) produce infinite sequences.
+     * Called at construction time, subclasses may override cautiously (using only members to and from).
+     */
+    protected void checkBoundaryCompatibility() {
+        if (from instanceof String && to instanceof String) {
+            // this test depends deeply on the String.next implementation
+            // 009.next is 00:, not 010
+            final String start = from.toString();
+            final String end = to.toString();
+            if (start.length() != end.length()) {
+                throw new IllegalArgumentException("Incompatible Strings for Range: different length");
+            }
+            final int length = start.length();
+            int i;
+            for (i = 0; i < length; i++) {
+                if (start.charAt(i) != end.charAt(i)) {
+                    break;
+                }
+            }
+            // strings must be equal except for the last character
+            if (i < length - 1) {
+                throw new IllegalArgumentException("Incompatible Strings for Range: String#next() will not reach the expected value");
+            }
+        }
+    }
+
+    private static boolean areReversed(Comparable from, Comparable to) {
+        try {
+            return ScriptBytecodeAdapter.compareGreaterThan(from, to);
+        } catch (IllegalArgumentException iae) {
+            throw new IllegalArgumentException("Unable to create range due to incompatible types: " + from.getClass().getSimpleName() + ".." + to.getClass().getSimpleName() + " (possible missing brackets around range?)", iae);
+        }
+    }
+
+    public boolean equals(Object that) {
+        return (that instanceof ObjectRange) ? equals((ObjectRange) that) : super.equals(that);
+    }
+
+    /**
+     * Compares an {@link ObjectRange} to another {@link ObjectRange}.
+     *
+     * @param that the object to check equality with
+     * @return <code>true</code> if the ranges are equal
+     */
+    public boolean equals(ObjectRange that) {
+        return that != null
+                && reverse == that.reverse
+                && DefaultTypeTransformation.compareEqual(from, that.from)
+                && DefaultTypeTransformation.compareEqual(to, that.to);
+    }
+
+    @Override
+    public Comparable getFrom() {
+        return from;
+    }
+
+    @Override
+    public Comparable getTo() {
+        return to;
+    }
+
+    @Override
+    public boolean isReverse() {
+        return reverse;
+    }
+
+    @Override
+    public Comparable get(int index) {
+        if (index < 0) {
+            throw new IndexOutOfBoundsException("Index: " + index + " should not be negative");
+        }
+        final StepIterator iter = new StepIterator(this, 1);
+
+        Comparable value = iter.next();
+        for (int i = 0; i < index; i++) {
+            if (!iter.hasNext()) {
+                throw new IndexOutOfBoundsException("Index: " + index + " is too big for range: " + this);
+            }
+            value = iter.next();
+        }
+        return value;
+    }
+
+    /**
+     * Checks whether a value is between the from and to values of a Range
+     *
+     * @param value the value of interest
+     * @return true if the value is within the bounds
+     */
+    @Override
+    public boolean containsWithinBounds(Object value) {
+        if (value instanceof Comparable) {
+            final int result = compareTo(from, (Comparable) value);
+            return result == 0 || result < 0 && compareTo(to, (Comparable) value) >= 0;
+        }
+        return contains(value);
+    }
+
+    protected int compareTo(Comparable first, Comparable second) {
+        return DefaultGroovyMethods.numberAwareCompareTo(first, second);
+    }
+
+    /**
+     * protection against calls from Groovy
+     */
+    @SuppressWarnings("unused")
+    private void setSize(int size) {
+        throw new UnsupportedOperationException("size must not be changed");
+    }
+
+    @Override
+    public int size() {
+        if (size == -1) {
+            int tempsize = 0;
+            if ((from instanceof Integer || from instanceof Long)
+                    && (to instanceof Integer || to instanceof Long)) {
+                // let's fast calculate the size
+                final BigInteger fromNum = new BigInteger(from.toString());
+                final BigInteger toNum = new BigInteger(to.toString());
+                final BigInteger sizeNum = toNum.subtract(fromNum).add(new BigInteger("1"));
+                tempsize = sizeNum.intValue();
+                if (!BigInteger.valueOf(tempsize).equals(sizeNum)) {
+                    tempsize = Integer.MAX_VALUE;
+                }
+            } else if (from instanceof Character && to instanceof Character) {
+                // let's fast calculate the size
+                final char fromNum = (Character) from;
+                final char toNum = (Character) to;
+                tempsize = toNum - fromNum + 1;
+            } else if (((from instanceof BigDecimal || from instanceof BigInteger) && to instanceof Number) ||
+                    ((to instanceof BigDecimal || to instanceof BigInteger) && from instanceof Number)) {
+                // let's fast calculate the size
+                final BigDecimal fromNum = new BigDecimal(from.toString());
+                final BigDecimal toNum = new BigDecimal(to.toString());
+                final BigInteger sizeNum = toNum.subtract(fromNum).add(new BigDecimal(1.0)).toBigInteger();
+                tempsize = sizeNum.intValue();
+                if (!BigInteger.valueOf(tempsize).equals(sizeNum)) {
+                    tempsize = Integer.MAX_VALUE;
+                }
+            } else {
+                // let's brute-force calculate the size by iterating start to end
+                final Iterator<Comparable> iter = new StepIterator(this, 1);
+                while (iter.hasNext()) {
+                    tempsize++;
+                    // integer overflow
+                    if (tempsize < 0) {
+                        break;
+                    }
+                    iter.next();
+                }
+            }
+            // integer overflow
+            if (tempsize < 0) {
+                tempsize = Integer.MAX_VALUE;
+            }
+            size = tempsize;
+        }
+        return size;
+    }
+
+    @Override
+    public List<Comparable> subList(int fromIndex, int toIndex) {
+        if (fromIndex < 0) {
+            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+        }
+        if (fromIndex > toIndex) {
+            throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
+        }
+        if (fromIndex == toIndex) {
+            return new EmptyRange<Comparable>(from);
+        }
+
+        // Performance detail:
+        // not using get(fromIndex), get(toIndex) in the following to avoid stepping over elements twice
+        final Iterator<Comparable> iter = new StepIterator(this, 1);
+
+        Comparable toValue = iter.next();
+        int i = 0;
+        for (; i < fromIndex; i++) {
+            if (!iter.hasNext()) {
+                throw new IndexOutOfBoundsException("Index: " + i + " is too big for range: " + this);
+            }
+            toValue = iter.next();
+        }
+        final Comparable fromValue = toValue;
+        for (; i < toIndex - 1; i++) {
+            if (!iter.hasNext()) {
+                throw new IndexOutOfBoundsException("Index: " + i + " is too big for range: " + this);
+            }
+            toValue = iter.next();
+        }
+
+        return new ObjectRange(fromValue, toValue, reverse);
+    }
+
+    public String toString() {
+        return reverse ? "" + to + ".." + from : "" + from + ".." + to;
+    }
+
+    @Override
+    public String inspect() {
+        final String toText = InvokerHelper.inspect(to);
+        final String fromText = InvokerHelper.inspect(from);
+        return reverse ? "" + toText + ".." + fromText : "" + fromText + ".." + toText;
+    }
+
+    /**
+     * Iterates over all values and returns true if one value matches.
+     *
+     * @see #containsWithinBounds(Object)
+     */
+    @Override
+    public boolean contains(Object value) {
+        final Iterator<Comparable> iter = new StepIterator(this, 1);
+        if (value == null) {
+            return false;
+        }
+        while (iter.hasNext()) {
+            if (DefaultTypeTransformation.compareEqual(value, iter.next())) return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void step(int step, Closure closure) {
+        if (step == 0 && compareTo(from, to) == 0) {
+            return; // from == to and step == 0, nothing to do, so return
+        }
+        final Iterator<Comparable> iter = new StepIterator(this, step);
+        while (iter.hasNext()) {
+            closure.call(iter.next());
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Iterator<Comparable> iterator() {
+        // non thread-safe iterator
+        return new StepIterator(this, 1);
+    }
+
+    /**
+     * Non-thread-safe iterator which lazily produces the next element only on calls of hasNext() or next()
+     */
+    private static final class StepIterator implements Iterator<Comparable> {
+        // actual step, can be +1 when desired step is -1 and direction is from high to low
+        private final int step;
+        private final ObjectRange range;
+        private int index = -1;
+        private Comparable value;
+        private boolean nextFetched = true;
+
+        private StepIterator(ObjectRange range, final int desiredStep) {
+            if (desiredStep == 0 && range.compareTo(range.getFrom(), range.getTo()) != 0) {
+                throw new GroovyRuntimeException("Infinite loop detected due to step size of 0");
+            }
+            this.range = range;
+            if (range.isReverse()) {
+                step = -desiredStep;
+            } else {
+                step = desiredStep;
+            }
+            if (step > 0) {
+                value = range.getFrom();
+            } else {
+                value = range.getTo();
+            }
+        }
+
+        @Override
+        public void remove() {
+            range.remove(index);
+        }
+
+        @Override
+        public Comparable next() {
+            // not thread safe
+            if (!hasNext()) {
+                throw new NoSuchElementException();
+            }
+            nextFetched = false;
+            index++;
+            return value;
+        }
+
+        @Override
+        public boolean hasNext() {
+            // not thread safe
+            if (!nextFetched) {
+                value = peek();
+                nextFetched = true;
+            }
+            return value != null;
+        }
+
+        private Comparable peek() {
+            if (step > 0) {
+                Comparable peekValue = value;
+                for (int i = 0; i < step; i++) {
+                    peekValue = (Comparable) range.increment(peekValue);
+                    // handle back to beginning due to modulo incrementing
+                    if (range.compareTo(peekValue, range.from) <= 0) return null;
+                }
+                if (range.compareTo(peekValue, range.to) <= 0) {
+                    return peekValue;
+                }
+            } else {
+                final int positiveStep = -step;
+                Comparable peekValue = value;
+                for (int i = 0; i < positiveStep; i++) {
+                    peekValue = (Comparable) range.decrement(peekValue);
+                    // handle back to beginning due to modulo decrementing
+                    if (range.compareTo(peekValue, range.to) >= 0) return null;
+                }
+                if (range.compareTo(peekValue, range.from) >= 0) {
+                    return peekValue;
+                }
+            }
+            return null;
+        }
+    }
+
+    @Override
+    public List<Comparable> step(int step) {
+        final IteratorClosureAdapter<Comparable> adapter = new IteratorClosureAdapter<Comparable>(this);
+        step(step, adapter);
+        return adapter.asList();
+    }
+
+    /**
+     * Increments by one
+     *
+     * @param value the value to increment
+     * @return the incremented value
+     */
+    protected Object increment(Object value) {
+        return InvokerHelper.invokeMethod(value, "next", null);
+    }
+
+    /**
+     * Decrements by one
+     *
+     * @param value the value to decrement
+     * @return the decremented value
+     */
+    protected Object decrement(Object value) {
+        return InvokerHelper.invokeMethod(value, "previous", null);
+    }
+
+    /**
+     * if operand is a Character or a String with one character, return that character's int value.
+     */
+    private static Comparable normaliseStringType(final Comparable operand) {
+        if (operand instanceof Character) {
+            return (int) (Character) operand;
+        }
+        if (operand instanceof String) {
+            final String string = (String) operand;
+
+            if (string.length() == 1) {
+                return (int) string.charAt(0);
+            }
+            return string;
+        }
+        return operand;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/ParameterArray.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/ParameterArray.java b/src/main/groovy/groovy/lang/ParameterArray.java
new file mode 100644
index 0000000..d3a4163
--- /dev/null
+++ b/src/main/groovy/groovy/lang/ParameterArray.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 groovy.lang;
+
+/**
+ * Distinguish a parameter array from Object[].
+ *
+ * @author Pilho Kim
+ */
+public class ParameterArray {
+
+    private final Object parameters;
+
+    public ParameterArray(Object data) {
+        parameters = packArray(data);
+    }
+
+    private static Object packArray(Object object) {
+        if (object instanceof Object[])
+            return (Object[]) object;
+        else
+            return object;
+    }
+
+    public Object get() {
+        return parameters;
+    }
+
+    public String toString() {
+        if (parameters == null)
+            return "<null parameter>";
+        return parameters.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/PropertyAccessInterceptor.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/PropertyAccessInterceptor.java b/src/main/groovy/groovy/lang/PropertyAccessInterceptor.java
new file mode 100644
index 0000000..6d2906e
--- /dev/null
+++ b/src/main/groovy/groovy/lang/PropertyAccessInterceptor.java
@@ -0,0 +1,49 @@
+/*
+ *  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 groovy.lang;
+
+/**
+ * <p>An interface that adds the ability to intercept
+ * property getters/setters
+ *
+ * @author Graeme Rocher
+ * @since Oct 24, 2005
+ */
+public interface PropertyAccessInterceptor extends Interceptor {
+
+    /**
+     * Intercepts a getXXX call and returns a result. The result is replaced by the
+     * real value if doGet() return false
+     *
+     * @param object   The target object
+     * @param property The property to get
+     * @return A value supplied by the interceptor
+     */
+    Object beforeGet(Object object, String property);
+
+    /**
+     * Intercepts a setXXX call
+     *
+     * @param object   The target object
+     * @param property The property to set
+     * @param newValue The new value
+     */
+    void beforeSet(Object object, String property, Object newValue);
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/PropertyValue.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/PropertyValue.java b/src/main/groovy/groovy/lang/PropertyValue.java
new file mode 100644
index 0000000..ac77b54
--- /dev/null
+++ b/src/main/groovy/groovy/lang/PropertyValue.java
@@ -0,0 +1,49 @@
+/*
+ *  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 groovy.lang;
+
+public class PropertyValue {
+    // the owner of the property
+    private final Object bean;
+
+    // the description of the property
+    private final MetaProperty mp;
+
+    public PropertyValue(Object bean, MetaProperty mp) {
+        this.bean = bean;
+        this.mp = mp;
+    }
+
+    public String getName() {
+        return mp.getName();
+    }
+
+    public Class getType() {
+        return mp.getType();
+    }
+
+    public Object getValue() {
+        return mp.getProperty(bean);
+    }
+
+    public void setValue(Object value) {
+        mp.setProperty(bean, value);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/ProxyMetaClass.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/ProxyMetaClass.java b/src/main/groovy/groovy/lang/ProxyMetaClass.java
new file mode 100644
index 0000000..8c41f7d
--- /dev/null
+++ b/src/main/groovy/groovy/lang/ProxyMetaClass.java
@@ -0,0 +1,242 @@
+/*
+ *  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 groovy.lang;
+
+/**
+ * As subclass of MetaClass, ProxyMetaClass manages calls from Groovy Objects to POJOs.
+ * It enriches MetaClass with the feature of making method invocations interceptable by
+ * an Interceptor. To this end, it acts as a decorator (decorator pattern) allowing
+ * to add or withdraw this feature at runtime.
+ * See groovy/lang/InterceptorTest.groovy for details.
+ * <p>
+ * WARNING: This implementation of ProxyMetaClass is NOT thread-safe and hence should only be used for
+ * as a per-instance MetaClass running in a single thread. Do not place this MetaClass in the MetaClassRegistry
+ * as it will result in unpredictable behaviour
+ *
+ * @author Dierk Koenig
+ * @author Graeme Rocher
+ * @see groovy.lang.MetaClassRegistry
+ */
+public class ProxyMetaClass extends MetaClassImpl implements AdaptingMetaClass {
+
+    protected MetaClass adaptee = null;
+    protected Interceptor interceptor = null;
+
+
+    /**
+     * convenience factory method for the most usual case.
+     */
+    public static ProxyMetaClass getInstance(Class theClass) {
+        MetaClassRegistry metaRegistry = GroovySystem.getMetaClassRegistry();
+        MetaClass meta = metaRegistry.getMetaClass(theClass);
+        return new ProxyMetaClass(metaRegistry, theClass, meta);
+    }
+
+    /**
+     * @param adaptee the MetaClass to decorate with interceptability
+     */
+    public ProxyMetaClass(MetaClassRegistry registry, Class theClass, MetaClass adaptee) {
+        super(registry, theClass);
+        this.adaptee = adaptee;
+        if (null == adaptee) throw new IllegalArgumentException("adaptee must not be null");
+        super.initialize();
+    }
+
+    public synchronized void initialize() {
+        this.adaptee.initialize();
+    }
+
+    /**
+     * Use the ProxyMetaClass for the given Closure.
+     * Cares for balanced register/unregister.
+     *
+     * @param closure piece of code to be executed with registered ProxyMetaClass
+     */
+    public Object use(Closure closure) {
+        // grab existing meta (usually adaptee but we may have nested use calls)
+        MetaClass origMetaClass = registry.getMetaClass(theClass);
+        registry.setMetaClass(theClass, this);
+        try {
+            return closure.call();
+        } finally {
+            registry.setMetaClass(theClass, origMetaClass);
+        }
+    }
+
+    /**
+     * Use the ProxyMetaClass for the given Closure.
+     * Cares for balanced setting/unsetting ProxyMetaClass.
+     *
+     * @param closure piece of code to be executed with ProxyMetaClass
+     */
+    public Object use(GroovyObject object, Closure closure) {
+        // grab existing meta (usually adaptee but we may have nested use calls)
+        MetaClass origMetaClass = object.getMetaClass();
+        object.setMetaClass(this);
+        try {
+            return closure.call();
+        } finally {
+            object.setMetaClass(origMetaClass);
+        }
+    }
+
+    /**
+     * @return the interceptor in use or null if no interceptor is used
+     */
+    public Interceptor getInterceptor() {
+        return interceptor;
+    }
+
+    /**
+     * @param interceptor may be null to reset any interception
+     */
+    public void setInterceptor(Interceptor interceptor) {
+        this.interceptor = interceptor;
+    }
+
+    /**
+     * Call invokeMethod on adaptee with logic like in MetaClass unless we have an Interceptor.
+     * With Interceptor the call is nested in its beforeInvoke and afterInvoke methods.
+     * The method call is suppressed if Interceptor.doInvoke() returns false.
+     * See Interceptor for details.
+     */
+    public Object invokeMethod(final Object object, final String methodName, final Object[] arguments) {
+        return doCall(object, methodName, arguments, interceptor, new Callable() {
+            public Object call() {
+                return adaptee.invokeMethod(object, methodName, arguments);
+            }
+        });
+    }
+
+    /**
+     * Call invokeMethod on adaptee with logic like in MetaClass unless we have an Interceptor.
+     * With Interceptor the call is nested in its beforeInvoke and afterInvoke methods.
+     * The method call is suppressed if Interceptor.doInvoke() returns false.
+     * See Interceptor for details.
+     */
+    @Override
+    public Object invokeMethod(final Class sender, final Object object, final String methodName, final Object[] arguments, final boolean isCallToSuper, final boolean fromInsideClass) {
+        return doCall(object, methodName, arguments, interceptor, new Callable() {
+            public Object call() {
+                return adaptee.invokeMethod(sender, object, methodName, arguments, isCallToSuper, fromInsideClass);
+            }
+        });
+    }
+
+    /**
+     * Call invokeStaticMethod on adaptee with logic like in MetaClass unless we have an Interceptor.
+     * With Interceptor the call is nested in its beforeInvoke and afterInvoke methods.
+     * The method call is suppressed if Interceptor.doInvoke() returns false.
+     * See Interceptor for details.
+     */
+    public Object invokeStaticMethod(final Object object, final String methodName, final Object[] arguments) {
+        return doCall(object, methodName, arguments, interceptor, new Callable() {
+            public Object call() {
+                return adaptee.invokeStaticMethod(object, methodName, arguments);
+            }
+        });
+    }
+
+    /**
+     * Call invokeConstructor on adaptee with logic like in MetaClass unless we have an Interceptor.
+     * With Interceptor the call is nested in its beforeInvoke and afterInvoke methods.
+     * The method call is suppressed if Interceptor.doInvoke() returns false.
+     * See Interceptor for details.
+     */
+    public Object invokeConstructor(final Object[] arguments) {
+        return doCall(theClass, "ctor", arguments, interceptor, new Callable() {
+            public Object call() {
+                return adaptee.invokeConstructor(arguments);
+            }
+        });
+    }
+
+    /**
+     * Interceptors the call to getProperty if a PropertyAccessInterceptor is
+     * available
+     *
+     * @param object   the object to invoke the getter on
+     * @param property the property name
+     * @return the value of the property
+     */
+    public Object getProperty(Class aClass, Object object, String property, boolean b, boolean b1) {
+        if (null == interceptor) {
+            return super.getProperty(aClass, object, property, b, b1);
+        }
+        if (interceptor instanceof PropertyAccessInterceptor) {
+            PropertyAccessInterceptor pae = (PropertyAccessInterceptor) interceptor;
+
+            Object result = pae.beforeGet(object, property);
+            if (interceptor.doInvoke()) {
+                result = super.getProperty(aClass, object, property, b, b1);
+            }
+            return result;
+        }
+        return super.getProperty(aClass, object, property, b, b1);
+    }
+
+    /**
+     * Interceptors the call to a property setter if a PropertyAccessInterceptor
+     * is available
+     *
+     * @param object   The object to invoke the setter on
+     * @param property The property name to set
+     * @param newValue The new value of the property
+     */
+    public void setProperty(Class aClass, Object object, String property, Object newValue, boolean b, boolean b1) {
+        if (null == interceptor) {
+            super.setProperty(aClass, object, property, newValue, b, b1);
+        }
+        if (interceptor instanceof PropertyAccessInterceptor) {
+            PropertyAccessInterceptor pae = (PropertyAccessInterceptor) interceptor;
+
+            pae.beforeSet(object, property, newValue);
+            if (interceptor.doInvoke()) {
+                super.setProperty(aClass, object, property, newValue, b, b1);
+            }
+        } else {
+            super.setProperty(aClass, object, property, newValue, b, b1);
+        }
+    }
+
+    public MetaClass getAdaptee() {
+        return this.adaptee;
+    }
+
+    public void setAdaptee(MetaClass metaClass) {
+        this.adaptee = metaClass;
+    }
+
+    // since Java has no Closures...
+    private interface Callable {
+        Object call();
+    }
+
+    private Object doCall(Object object, String methodName, Object[] arguments, Interceptor interceptor, Callable howToInvoke) {
+        if (null == interceptor) {
+            return howToInvoke.call();
+        }
+        Object result = interceptor.beforeInvoke(object, methodName, arguments);
+        if (interceptor.doInvoke()) {
+            result = howToInvoke.call();
+        }
+        result = interceptor.afterInvoke(object, methodName, arguments, result);
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/Range.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/Range.java b/src/main/groovy/groovy/lang/Range.java
new file mode 100644
index 0000000..99f30de
--- /dev/null
+++ b/src/main/groovy/groovy/lang/Range.java
@@ -0,0 +1,109 @@
+/*
+ *  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 groovy.lang;
+
+import java.util.List;
+
+/**
+ * A Range represents the list of discrete items between some starting (or <code>from</code>)
+ * value and <em>working up</em> towards some ending (or <code>to</code>) value.
+ * For a reverse range, the list is obtained by starting at the <code>to</code> value and
+ * <em>working down</em> towards the <code>from</code> value.
+ *
+ * The concept of <em>working up</em> and <em>working down</em> is dependent on the range implementation.
+ * In the general case, working up involves successive calls to the first item's <code>next()</code>
+ * method while working down involves calling the <code>previous()</code> method. Optimized
+ * numerical ranges may apply numeric addition or subtraction of some numerical step size.
+ *
+ * Particular range implementations may also support the notion of inclusivity
+ * and exclusivity with respect to the ending value in the range.
+ * E.g. <code>1..3 == [1, 2, 3]</code>; but <code>1..<3 == [1, 2]</code>.
+ *
+ * In general, the second boundary may not be contained in the range,
+ * and <code>a..b</code> may produce a different set of elements than <code>(b..a).reversed()</code>.
+ * E.g.  <code>1..2.5 == [1, 2]</code>; but <code>2.5..1 == [2.5, 1.5]</code>.
+ *
+ * Implementations can be memory efficient by storing just the <code>from</code> and <code>to</code> boundary
+ * values rather than eagerly creating all discrete items in the conceptual list. The actual discrete items
+ * can be lazily calculated on an as needed basis (e.g. when calling methods from the <code>java.util.List</code>
+ * interface or the additional <code>step</code> methods in the <code>Range</code> interface).
+ *
+ * In addition to the methods related to a Range's "discrete items" abstraction, there is a method,
+ * <code>containsWithinBounds</code> which, for numerical ranges, allows checking within the continuous
+ * interval between the Range's boundary values.
+ */
+public interface Range<T extends Comparable> extends List<T> {
+    /**
+     * The lower value in the range.
+     *
+     * @return the lower value in the range.
+     */
+    T getFrom();
+
+    /**
+     * The upper value in the range.
+     *
+     * @return the upper value in the range
+     */
+    T getTo();
+
+    /**
+     * Indicates whether this is a reverse range which iterates backwards
+     * starting from the to value and ending on the from value
+     *
+     * @return <code>true</code> if this is a reverse range
+     */
+    boolean isReverse();
+
+    /**
+     * Indicates whether an object is greater than or equal to the <code>from</code>
+     * value for the range and less than or equal to the <code>to</code> value.
+     * <p>
+     * This may be true even for values not contained in the range.
+     *
+     * Example: from = 1.5, to = 3, next() increments by 1
+     * containsWithinBounds(2) == true
+     * contains(2) == false
+     *
+     * @param o the object to check against the boundaries of the range
+     * @return <code>true</code> if the object is between the from and to values
+     */
+    boolean containsWithinBounds(Object o);
+
+    /**
+     * Steps through the range, calling a closure for each item.
+     *
+     * @param step    the amount by which to step. If negative, steps through the range backwards.
+     * @param closure the {@link Closure} to call
+     */
+    void step(int step, Closure closure);
+
+    /**
+     * Forms a list by stepping through the range by the indicated interval.
+     *
+     * @param step the amount by which to step. If negative, steps through the range backwards.
+     * @return the list formed by stepping through the range by the indicated interval.
+     */
+    List<T> step(int step);
+
+    /**
+     * @return the verbose {@link String} representation of this {@link Range} as would be typed into a console to create the {@link Range} instance
+     */
+    String inspect();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/ReadOnlyPropertyException.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/ReadOnlyPropertyException.java b/src/main/groovy/groovy/lang/ReadOnlyPropertyException.java
new file mode 100644
index 0000000..342a182
--- /dev/null
+++ b/src/main/groovy/groovy/lang/ReadOnlyPropertyException.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 groovy.lang;
+
+
+/**
+ * This exception is thrown if an attempt is made to set a read only property
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ReadOnlyPropertyException extends MissingPropertyException {
+
+    public ReadOnlyPropertyException(final String property, final Class type) {
+        super("Cannot set readonly property: " + property + " for class: " + type.getName(), property, type);
+    }
+
+    public ReadOnlyPropertyException(final String property, final String classname) {
+        super("Cannot set readonly property: " + property + " for class: " + classname);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/Reference.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/Reference.java b/src/main/groovy/groovy/lang/Reference.java
new file mode 100644
index 0000000..c4bf21d
--- /dev/null
+++ b/src/main/groovy/groovy/lang/Reference.java
@@ -0,0 +1,82 @@
+/*
+ *  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 groovy.lang;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.io.Serializable;
+
+/**
+ * Represents a reference to a value
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class Reference<T> extends GroovyObjectSupport implements Serializable {
+
+    private static final long serialVersionUID = 4963704631487573488L;
+    private T value;
+
+    public Reference() {
+    }
+
+    public Reference(T value) {
+        this.value = value;
+    }
+
+    public Object getProperty(String property) {
+        Object value = get();
+        if (value != null) {
+            return InvokerHelper.getProperty(value, property);
+        }
+        return super.getProperty(property);
+    }
+
+    public void setProperty(String property, Object newValue) {
+        Object value = get();
+        if (value != null) {
+            InvokerHelper.setProperty(value, property, newValue);
+        }
+        else {
+            super.setProperty(property, newValue);
+        }
+    }
+
+    public Object invokeMethod(String name, Object args) {
+        Object value = get();
+        if (value != null) {
+            try {
+                return InvokerHelper.invokeMethod(value, name, args);
+            }
+            catch (Exception e) {
+                return super.invokeMethod(name, args);
+            }
+        }
+        else {
+            return super.invokeMethod(name, args);
+        }
+    }
+
+    public T get() {
+        return value;
+    }
+
+    public void set(T value) {
+        this.value = value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/Script.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/Script.java b/src/main/groovy/groovy/lang/Script.java
new file mode 100644
index 0000000..196c74c
--- /dev/null
+++ b/src/main/groovy/groovy/lang/Script.java
@@ -0,0 +1,231 @@
+/*
+ *  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 groovy.lang;
+
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * This object represents a Groovy script
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Guillaume Laforge
+ */
+public abstract class Script extends GroovyObjectSupport {
+    private Binding binding;
+
+    protected Script() {
+        this(new Binding());
+    }
+
+    protected Script(Binding binding) {
+        this.binding = binding;
+    }
+
+    public Binding getBinding() {
+        return binding;
+    }
+
+    public void setBinding(Binding binding) {
+        this.binding = binding;
+    }
+
+    public Object getProperty(String property) {
+        try {
+            return binding.getVariable(property);
+        } catch (MissingPropertyException e) {
+            return super.getProperty(property);
+        }
+    }
+
+    public void setProperty(String property, Object newValue) {
+        if ("binding".equals(property))
+            setBinding((Binding) newValue);
+        else if("metaClass".equals(property))
+            setMetaClass((MetaClass)newValue);
+        else
+            binding.setVariable(property, newValue);
+    }
+
+    /**
+     * Invoke a method (or closure in the binding) defined.
+     *
+     * @param name method to call
+     * @param args arguments to pass to the method
+     * @return value
+     */
+    public Object invokeMethod(String name, Object args) {
+        try {
+            return super.invokeMethod(name, args);
+        }
+        // if the method was not found in the current scope (the script's methods)
+        // let's try to see if there's a method closure with the same name in the binding
+        catch (MissingMethodException mme) {
+            try {
+                if (name.equals(mme.getMethod())) {
+                    Object boundClosure = getProperty(name);
+                    if (boundClosure != null && boundClosure instanceof Closure) {
+                        return ((Closure) boundClosure).call((Object[])args);
+                    } else {
+                        throw mme;
+                    }
+                } else {
+                    throw mme;
+                }
+            } catch (MissingPropertyException mpe) {
+                throw mme;
+            }
+        }
+    }
+
+    /**
+     * The main instance method of a script which has variables in scope
+     * as defined by the current {@link Binding} instance.
+     */
+    public abstract Object run();
+
+    // println helper methods
+
+    /**
+     * Prints a newline to the current 'out' variable which should be a PrintWriter
+     * or at least have a println() method defined on it.
+     * If there is no 'out' property then print to standard out.
+     */
+    public void println() {
+        Object object;
+
+        try {
+            object = getProperty("out");
+        } catch (MissingPropertyException e) {
+            System.out.println();
+            return;
+        }
+
+        InvokerHelper.invokeMethod(object, "println", ArgumentListExpression.EMPTY_ARRAY);
+    }
+
+    /**
+     * Prints the value to the current 'out' variable which should be a PrintWriter
+     * or at least have a print() method defined on it.
+     * If there is no 'out' property then print to standard out.
+     */
+    public void print(Object value) {
+        Object object;
+
+        try {
+            object = getProperty("out");
+        } catch (MissingPropertyException e) {
+            DefaultGroovyMethods.print(System.out,value);
+            return;
+        }
+
+        InvokerHelper.invokeMethod(object, "print", new Object[]{value});
+    }
+
+    /**
+     * Prints the value and a newline to the current 'out' variable which should be a PrintWriter
+     * or at least have a println() method defined on it.
+     * If there is no 'out' property then print to standard out.
+     */
+    public void println(Object value) {
+        Object object;
+
+        try {
+            object = getProperty("out");
+        } catch (MissingPropertyException e) {
+            DefaultGroovyMethods.println(System.out,value);
+            return;
+        }
+
+        InvokerHelper.invokeMethod(object, "println", new Object[]{value});
+    }
+
+    /**
+     * Prints a formatted string using the specified format string and argument.
+     *
+     * @param format the format to follow
+     * @param value the value to be formatted
+     */
+    public void printf(String format, Object value) {
+        Object object;
+
+        try {
+            object = getProperty("out");
+        } catch (MissingPropertyException e) {
+            DefaultGroovyMethods.printf(System.out, format, value);
+            return;
+        }
+
+        InvokerHelper.invokeMethod(object, "printf", new Object[] { format, value });
+    }
+
+    /**
+     * Prints a formatted string using the specified format string and arguments.
+     *
+     * @param format the format to follow
+     * @param values an array of values to be formatted
+     */
+    public void printf(String format, Object[] values) {
+        Object object;
+
+        try {
+            object = getProperty("out");
+        } catch (MissingPropertyException e) {
+            DefaultGroovyMethods.printf(System.out, format, values);
+            return;
+        }
+
+        InvokerHelper.invokeMethod(object, "printf", new Object[] { format, values });
+    }
+
+    /**
+     * A helper method to allow the dynamic evaluation of groovy expressions using this
+     * scripts binding as the variable scope
+     *
+     * @param expression is the Groovy script expression to evaluate
+     */
+    public Object evaluate(String expression) throws CompilationFailedException {
+        GroovyShell shell = new GroovyShell(getClass().getClassLoader(), binding);
+        return shell.evaluate(expression);
+    }
+
+    /**
+     * A helper method to allow the dynamic evaluation of groovy expressions using this
+     * scripts binding as the variable scope
+     *
+     * @param file is the Groovy script to evaluate
+     */
+    public Object evaluate(File file) throws CompilationFailedException, IOException {
+        GroovyShell shell = new GroovyShell(getClass().getClassLoader(), binding);
+        return shell.evaluate(file);
+    }
+
+    /**
+     * A helper method to allow scripts to be run taking command line arguments
+     */
+    public void run(File file, String[] arguments) throws CompilationFailedException, IOException {
+        GroovyShell shell = new GroovyShell(getClass().getClassLoader(), binding);
+        shell.run(file, arguments);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/Sequence.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/Sequence.java b/src/main/groovy/groovy/lang/Sequence.java
new file mode 100644
index 0000000..2b4316c
--- /dev/null
+++ b/src/main/groovy/groovy/lang/Sequence.java
@@ -0,0 +1,224 @@
+/*
+ *  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 groovy.lang;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Represents a sequence of objects which represents zero or many instances of
+ * of objects of a given type. The type can be omitted in which case any type of
+ * object can be added.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class Sequence extends ArrayList implements GroovyObject {
+
+    private MetaClass metaClass = InvokerHelper.getMetaClass(getClass());
+    private final Class type;
+    private int hashCode;
+
+    public Sequence() {
+        this(null);
+    }
+
+    public Sequence(Class type) {
+        this.type = type;
+    }
+
+    public Sequence(Class type, List content) {
+        super(content.size());
+        this.type = type;
+        addAll(content);
+    }
+
+    /**
+     * Sets the contents of this sequence to that
+     * of the given collection.
+     */
+    public void set(Collection collection) {
+        checkCollectionType(collection);
+        clear();
+        addAll(collection);
+    }
+    
+    public boolean equals(Object that) {
+        if (that instanceof Sequence) {
+            return equals((Sequence) that);
+        }
+        return false;
+    }
+
+    public boolean equals(Sequence that) {
+        if (size() == that.size()) {
+            for (int i = 0; i < size(); i++) {
+                if (!DefaultTypeTransformation.compareEqual(this.get(i), that.get(i))) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public int hashCode() {
+        if (hashCode == 0) {
+            for (int i = 0; i < size(); i++) {
+                Object value = get(i);
+                int hash = (value != null) ? value.hashCode() : 0xbabe;
+                hashCode ^= hash;
+            }
+            if (hashCode == 0) {
+                hashCode = 0xbabe;
+            }
+        }
+        return hashCode;
+    }
+
+    public int minimumSize() {
+        return 0;
+    }
+
+    /**
+     * @return the type of the elements in the sequence or null if there is no
+     * type constraint on this sequence
+     */
+    public Class type() {
+        return type;
+    }
+    
+    public void add(int index, Object element) {
+        checkType(element);
+        hashCode = 0;
+        super.add(index, element);
+    }
+
+    public boolean add(Object element) {
+        checkType(element);
+        hashCode = 0;
+        return super.add(element);
+    }
+
+    public boolean addAll(Collection c) {
+        checkCollectionType(c);
+        hashCode = 0;
+        return super.addAll(c);
+    }
+
+    public boolean addAll(int index, Collection c) {
+        checkCollectionType(c);
+        hashCode = 0;
+        return super.addAll(index, c);
+    }
+
+    public void clear() {
+        hashCode = 0;
+        super.clear();
+    }
+
+    public Object remove(int index) {
+        hashCode = 0;
+        return super.remove(index);
+    }
+
+    protected void removeRange(int fromIndex, int toIndex) {
+        hashCode = 0;
+        super.removeRange(fromIndex, toIndex);
+    }
+
+    public Object set(int index, Object element) {
+        hashCode = 0;
+        return super.set(index, element);
+    }
+
+    // GroovyObject interface
+    //-------------------------------------------------------------------------
+    public Object invokeMethod(String name, Object args) {
+        try {
+        return getMetaClass().invokeMethod(this, name, args);
+        }
+        catch (MissingMethodException e) {
+            // lets apply the method to each item in the collection
+            List answer = new ArrayList(size());
+            for (Iterator iter = iterator(); iter.hasNext(); ) {
+                Object element = iter.next();
+                Object value = InvokerHelper.invokeMethod(element, name, args);
+                answer.add(value);
+            }
+            return answer;
+        }
+    }
+
+    public Object getProperty(String property) {
+        return getMetaClass().getProperty(this, property);
+    }
+
+    public void setProperty(String property, Object newValue) {
+        getMetaClass().setProperty(this, property, newValue);
+    }
+
+    public MetaClass getMetaClass() {
+        return metaClass;
+    }
+
+    public void setMetaClass(MetaClass metaClass) {
+        this.metaClass = metaClass;
+    }
+
+    // Implementation methods
+    //-------------------------------------------------------------------------
+    
+    /**
+     * Checks that each member of the given collection are of the correct
+     * type
+     */
+    protected void checkCollectionType(Collection c) {
+        if (type != null) {
+            for (Iterator iter = c.iterator(); iter.hasNext(); ) {
+                Object element = iter.next();
+                checkType(element);
+            }
+        }
+    }
+
+
+    /** 
+     * Checks that the given object instance is of the correct type
+     * otherwise a runtime exception is thrown
+     */
+    protected void checkType(Object object) {
+        if (object == null) {
+            throw new NullPointerException("Sequences cannot contain null, use a List instead");
+        }
+        if (type != null) {
+            if (!type.isInstance(object)) {
+                throw new IllegalArgumentException(
+                    "Invalid type of argument for sequence of type: "
+                        + type.getName()
+                        + " cannot add object: "
+                        + object);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/10110145/src/main/groovy/groovy/lang/Singleton.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/groovy/lang/Singleton.java b/src/main/groovy/groovy/lang/Singleton.java
new file mode 100644
index 0000000..9b86c8b
--- /dev/null
+++ b/src/main/groovy/groovy/lang/Singleton.java
@@ -0,0 +1,66 @@
+/*
+ *  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 groovy.lang;
+
+import org.codehaus.groovy.transform.GroovyASTTransformationClass;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Class annotation to make a singleton class. The singleton is obtained through normal property access using the singleton property (defaults to "instance").
+ *
+ * Such classes can be initialized during normal static initialization of the class or lazily (on first access).
+ * To make the singleton lazy use {@code @Singleton(lazy=true)}.
+ * Lazy singletons are implemented with double-checked locking and a volatile backing field.
+ * By default, no explicit constructors are allowed. To create one or more explicit constructors
+ * use {@code @Singleton(strict=false)}.
+ * This could be used to:
+ * <ul>
+ * <li>provide your own custom initialization logic in your own no-arg constructor - you
+ * will be responsible for the entire code (the {@code @Singleton} annotation becomes merely documentation)</li>
+ * <li>provide one or more constructors with arguments for a quasi-singleton - these constructors will be used
+ * to create instances that are independent of the singleton instance returned by the singleton property</li>
+ * </ul>
+ *
+ * @author Alex Tkachman
+ * @author Paul King
+ */
+@java.lang.annotation.Documented
+@Retention(RetentionPolicy.SOURCE)
+@Target({ElementType.TYPE})
+@GroovyASTTransformationClass("org.codehaus.groovy.transform.SingletonASTTransformation")
+public @interface Singleton {
+    /**
+     * @return if this singleton should be lazy
+     */
+    boolean lazy() default false;
+
+    /**
+     * @return if this singleton should have strict semantics
+     */
+    boolean strict() default true;
+
+    /**
+     * @return the singleton property name
+     */
+    String property() default "instance";
+}