next 1.0 try

git-svn-id: http://svn.codehaus.org/groovy/tags/GROOVY_1_0@4677 a5544e8c-8a19-0410-ba12-f9af4593a198
diff --git a/groovy-core/.classpath b/groovy-core/.classpath
new file mode 100644
index 0000000..469e791
--- /dev/null
+++ b/groovy-core/.classpath
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src/main"/>
+	<classpathentry excluding="**/.cvsignore" kind="src" path="src/test"/>
+	<classpathentry kind="lib" path="target/test-classes"/>
+	<classpathentry kind="var" path="MAVEN_REPO/ant/jars/ant-1.6.5.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/ant/jars/ant-junit-1.6.5.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/ant/jars/ant-launcher-1.6.5.jar"/>
+	<classpathentry exported="true" kind="var" path="MAVEN_REPO/antlr/jars/antlr-2.7.5.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/asm/jars/asm-2.2.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/asm/jars/asm-analysis-2.2.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/asm/jars/asm-attrs-2.2.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/asm/jars/asm-tree-2.2.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/asm/jars/asm-util-2.2.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/axion/jars/axion-1.0-M3-dev.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/bsf/jars/bsf-2.4.0.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/commons-cli/jars/commons-cli-1.0.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/commons-collections/jars/commons-collections-3.2.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/commons-logging/jars/commons-logging-1.0.3.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/jmock/jars/jmock-cglib-1.1.0.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/jmock/jars/jmock-1.1.0.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/junit/jars/junit-3.8.1.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/mockobjects/jars/mockobjects-core-0.09.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/mx4j/jars/mx4j-3.0.1.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/nekohtml/jars/nekohtml-0.9.5.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/openejb/jars/openejb-loader-1.0.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/qdox/jars/qdox-1.5.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/radeox/jars/radeox-0.9.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/radeox/jars/radeox-oro-0.9.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/regexp/jars/regexp-1.3.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/xerces/jars/xerces-2.4.0.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/xml-apis/jars/xml-apis-1.0.b2.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/xstream/jars/xstream-1.2.jar"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="lib" path="security/GroovyJarTest.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/javax.servlet/jars/servlet-api-2.4.jar"/>
+	<classpathentry kind="var" path="MAVEN_REPO/javax.servlet/jars/jsp-api-2.0.jar"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/groovy-core/.cvsignore b/groovy-core/.cvsignore
new file mode 100644
index 0000000..955090d
--- /dev/null
+++ b/groovy-core/.cvsignore
@@ -0,0 +1,12 @@
+maven.log
+bin
+target
+*.properties
+velocity.log
+logs
+dist
+.externalToolBuilders
+groovy.iml
+groovy.ipr
+groovy.iws
+.DS_Store
diff --git a/groovy-core/.project b/groovy-core/.project
new file mode 100644
index 0000000..4c5aa58
--- /dev/null
+++ b/groovy-core/.project
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<projectDescription>
+  <name>groovy</name>
+  <comment>a powerful and dynamic scripting language for the JVM</comment>
+  <projects>
+  </projects>
+  <buildSpec>
+    <buildCommand>
+      <name>org.eclipse.jdt.core.javabuilder</name>
+      <arguments>
+      </arguments>
+    </buildCommand>
+  </buildSpec>
+  <natures>
+    <nature>org.eclipse.jdt.core.javanature</nature>
+  </natures>
+</projectDescription>
\ No newline at end of file
diff --git a/groovy-core/.settings/.cvsignore b/groovy-core/.settings/.cvsignore
new file mode 100644
index 0000000..7b7a4ea
--- /dev/null
+++ b/groovy-core/.settings/.cvsignore
@@ -0,0 +1 @@
+org.eclipse.jdt.ui.*
diff --git a/groovy-core/.settings/org.eclipse.core.resources.prefs b/groovy-core/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..7785db0
--- /dev/null
+++ b/groovy-core/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+#Tue Jun 06 17:51:41 BST 2006
+eclipse.preferences.version=1
+encoding//src/test/groovy/Base64Test.groovy=UTF-8
diff --git a/groovy-core/.settings/org.eclipse.jdt.core.prefs b/groovy-core/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..1888734
--- /dev/null
+++ b/groovy-core/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,57 @@
+#Sat Jun 11 03:45:36 CEST 2005
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.4
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.4
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=ignore
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=ignore
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.4
diff --git a/groovy-core/ASM-LICENSE.txt b/groovy-core/ASM-LICENSE.txt
new file mode 100644
index 0000000..5f4b794
--- /dev/null
+++ b/groovy-core/ASM-LICENSE.txt
@@ -0,0 +1,31 @@
+/***
+ * http://asm.objectweb.org/
+ *
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000,2002,2003 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
diff --git a/groovy-core/LICENSE.txt b/groovy-core/LICENSE.txt
new file mode 100644
index 0000000..0f6cb23
--- /dev/null
+++ b/groovy-core/LICENSE.txt
@@ -0,0 +1,47 @@
+
+
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
diff --git a/groovy-core/TODO.txt b/groovy-core/TODO.txt
new file mode 100644
index 0000000..c2721d3
--- /dev/null
+++ b/groovy-core/TODO.txt
@@ -0,0 +1,372 @@
+Things to Test
+==============
+
+* test synchronized statement
+
+* test compiler errors when
+	- duplicate methods testno 
+	- duplicate class in module
+	
+* test Button(actionPerformed:{event| event.println() }
+
+	
+Core Groovy Tasks
+=================
+
+* allow maps to be created using identifiers?
+	{name:'James', address:'London'}
+	
+	only issue is the identifiers could conflict.
+	
+	Could use a helper method?
+
+* handling sequences (0-n, 1-n)
+	they are Lists & behave like lists, any methods on the items will
+	be called etc.
+	
+	however how are they assigned / modified.
+	
+		foo.customers += customer
+		
+		foo.customers = [customer1, customer2]
+		
+		so assignment of sequence fields don't really do an assign; they do a set(List) instead
+		
+		- should we allow real assignments. e.g.
+		
+		Address* foo = ...;
+		foo = [1, 2, 3]
+		
+		foo keeps its type so its not a List
+		
+	how about handling mandatory values - 
+		the set we overload to do the non-null checks?
+		this must be a type. e.g.
+		
+			String! x = "hello"
+			x = null // error
+			
+* new GroovyMethods	to be added
+	- File.grep(pattern) -> List
+	- File.grep(pattern) { closure } 
+		allow iteration through a file for each line matching a regex pattern
+		
+	- List.first(), List.last(), pop()
+	- Collection.removeIf { x | x > 0 }
+	- List.eachWithindex { item, idx | ... }
+	- List.reverseEach { ... }
+	- Collection.count(foo) -> returns number of objects that equal foo
+	- Collection.countIf { it > 5 } -> returns number of objects that match closure predicate
+
+	- Map.get(key, defaultValue)
+	- Map.setDefault(key, defaultValue) for things like
+  		 map.setDefault(key, []).add(newValue)
+	
+	- Object.getMetaClass()
+	- Object.eachProperty
+	- Object.eachPropertyName { object.getProperty(it) }
+	- Object.setProperties(foo:'abc', x:123)
+	
+	- Map.eachKey, eachValue
+	- Map.index, Map.indexes
+	- configure method on beans?
+		bean.setProperties(name:'James', location:'London')
+	- some kind of Regexp iterator of strings like Ruby's scan
+	- maybe support Pythons' zip and reduce functions?
+	
+		maybe add the various readonly List APIs to Object[] and *[] types
+		if we ever support the DTD / Xed style type*, type+ then we can do the same
+		there too
+
+* add doesNotUnderstand() method for catching & handling unknown methods	
+		
+* is there a better way to add listeners in Groovy. e.g. how to remove added listeners
+
+	listener = bean.property + { some closure }
+	bean.property - listener
+	
+* BeanBuilder - builder which creates a tree of beans
+	builder.bean(class:SomeClass, x:123, b:'hello') {
+		nestedProperty(a:123)
+		nestedProperty2(class:DerivedClass, b:43)
+	}
+	using adder method as well as setter methods
+
+* MBeanBuilder?
+	builder.mlet {
+		mbean(class:SomeClass) {
+			someAttribute(value)
+		}
+		mbean(class:SomeClass, someAttribute:value) {
+			operation(1, 2)
+		}
+	}
+
+* templating - allow looping & conditionals?
+
+text = "
+<table>
+#for (f in foo)
+<tr>
+<td>${f.name}
+</tr>
+#end
+</table>
+"
+
+* allow if/switch to be the and of a function. i.e.
+	foo() {
+		if (x > 1) {
+			"hello"
+		}
+		else {
+			"cheese"
+		}
+	}
+	ditto for switch? i.e. make return statement optional.
+	
+
+* SQL builder
+
+sql.table("users") {
+ÊÊÊ column('user-id') { autoinc(), primaryKey(), references('foo'), initialValue(1234) }
+ÊÊÊ column('nickname') { varchar(200) }
+	column(name:'foo', type:'varchar(200)', references:['a', 'b'], initialValue:1234)
+  }
+}
+
+* using mixin for adding using style behaviour to any object??
+
+	mixin Using {
+	
+		static using(yield) {
+			object = this.newInstance()
+			try {
+				yield(object)
+				object.close()
+			}
+			catch (Exception e) {
+				try {
+					object.close()
+				}
+				catch (Exception e2)
+					// ignore e2
+					throw e
+				}
+			}
+		}
+		
+		or
+		
+		using(yield) {
+			try {
+				yield(this)
+				close()
+			}
+			catch (Exception e) {
+				try {
+					close()
+				}
+				catch (Exception e2)
+					// ignore e2
+					throw e
+				}
+			}
+		}
+	}
+	
+	then use it as 
+	
+		new FileInputStream().using { in |
+			...
+		}
+
+* looks like a bug on generated methods, should use param name over any field name
+	- also it looks like there's various unnecessary stuff (creation of tuples) when invoking
+	methods
+	
+* groovy thread...
+	foo = new GroovyThread(args) { closure }
+	
+* MetaClass -> add getPropertyDescriptor which has methods
+	- get(), set(), type(), cardinality() etc
+	
+	could use naming conventions to detect cardinality - e.g. addFoo(), getFoos()
+	
+* generate property change listener stuff on properties
+
+* test identity -> hashCode + equals methods
+
+* support for property converters, based on type
+
+* go through all not-working @todo tests in src/test
+	
+* to support dynamic mixins we should use dynamic proxies to allow
+	a groovy object to change metaclass at runtime
+
+* groovy dynamic proxy of any Java object in Java-land?
+	NullObject pattern
+	
+* immutable bean
+
+* MetaClass.deriveMetaClass()
+	MetaClass.addMixin(mixin)
+
+* constructors with map / tuple expressions, named parameter calling
+ 
+* default values for parameters
+
+* test try / catch with multiple exception types
+
+* * support static newInstance() method for constructors
+
+* maybe split up ClassGenerator - do code gen & class gen separately
+
+* mixin support...
+
+	SomeClass.addMixin(Foo);
+	
+	MetaClass.addInterceptor( new Interceptor() {
+		filter(method) {
+			return method.isPublic();
+		}
+		invoke(method, args) {
+			// do something
+			method.invoke(args);
+		}
+	});
+
+	* allow meta classes to be added dynamically using closure syntax?
+	e.g. Map?
+	
+
+STUFF TO PONDER
+===============
+
+* if we allow statements in class declarations, then we could disallow the syntax sugar
+	for method invocation with closures. i.e. foo { code } would have to be foo ({code})
+	otherwise it'd be interpeted as a method declaration.
+	
+	e.g.
+	
+	module MyValidatingModule
+	
+	class Cheese {
+		readOnlyProperty('hello')
+		validatingProperty('name', { it.length > 0 } )
+		
+		lazilyCreatedProperty(:cheese, { new MySpecialCheese() })
+		
+		public(:methodA, :methodB, :methodC)
+	}
+	 
+	for now we could argue that only methods are allowed to be invoked inside the class declaration.
+	We could still do markup but just not as nice
+	
+	class Whatnot {
+		table( {
+			foo {
+			}
+			whatnot {
+			}
+		})
+		
+		blah = { 
+			a(x:1234, b:942) {
+				d()
+			}
+		}
+		
+	
+* Support multiple return values...
+
+	String, Number cheese() {
+		"hello", 7
+	}
+	
+	a, b = cheese()
+	
+	also if we do this we should do assignment / swapping
+	
+		a, b = 1, 2
+		a, b = b, a
+
+* maybe use syntax #[1, 2] to create arrays which behave just like immutable lists?
+		
+* using macros to avoid dependencies on logging stuff (say)
+
+	class GroovyLog {
+		switch (System.getProperty('groovy.log.impl', 'useCommonsLogging')) {
+			case 'useCommonsLogging': {
+				// lets define the new instance method
+				newInstance() {
+					return new CommonsLoggingThingy()
+				}
+			}
+			default {
+				newInstance() {
+					return new SimpleGroovyLog()
+				}
+			}
+		}
+	}
+	
+	doing things like this at compile time means no runtime dependencies. Ditto to do JDK based compiles
+	
+	
+	
+UI WORK
+=======
+
+* tree demo...
+
+* when named method calls are supported with default values, refactor SwingBuilder
+	so that all the creations of widgets occur with SwingFactory which would be 
+	useful in and of itself
+	- plus we should be using normal method call mechanism & for groovy to do the rest to avoid
+	the long laborious Map coding
+	
+* add table layout cell spacing thingy
+
+* FormModel.addPropertyModel(property)
+	FormModel.addClosureModel(readClosure, writeClosure)
+
+* ListModel is-a List but delegates to an underlying list and has events
+
+* rename tableLayout -> table and table -> grid
+
+* add sortableGrid
+
+* create a GroovyUI
+	-> interactive script + allows scripts to be run & objects explored
+
+
+
+
+ECLIPSE WORK
+============
+
+* Run as JUnit support for Groovy! 
+
+* Refactoring support for Groovy and tie it into the Java refactoring
+
+
+JUNIT WORK
+==========
+
+* patch GroovyTestCase so that methods which return Object are included in the test. This avoids us having to
+specify void for method return types.This requires a clever static method when we generate the
+	bytecode which can instantiate a special kind of TestSuite
+	unless there's another way?
+
+
+OPTIMISATIONS
+=============
+* method invocations - if foo instanceof GroovyObject
+then generate bytecode
+
+foo.invokeMethod(method, args);
+
+* could code generate the MetaClass with very efficient dynamic dispatch
+	e.g. could switch() on the method name & then use real method invocation
+	on the method instance
diff --git a/groovy-core/build.gant b/groovy-core/build.gant
new file mode 100644
index 0000000..664331e
--- /dev/null
+++ b/groovy-core/build.gant
@@ -0,0 +1,121 @@
+//  A Gant script for building the Groovy system.
+//
+//  Copyright © 2006 Russel Winder <russel@russel.org.uk>
+//
+//  Licensed 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.
+//
+//  Author : Russel Winder
+//  $Revision$
+//  $Date$
+
+sourceDirectory = 'src'
+mainSourceDirectory = sourceDirectory + '/main'
+testsSourceDirectory = sourceDirectory + '/test'
+targetDirectory = 'target'
+mainClassesDirectory = targetDirectory + '/classes'
+testsClassesDirectory = targetDirectory + '/test-classes'
+reportsDirectory = targetDirectory + '/test-reports'
+
+antlrDirectory = mainSourceDirectory +  '/org/codehaus/groovy/antlr'
+parserDirectory = antlrDirectory + '/parser'
+
+javaVersion = '1.4'
+
+includeTargets << gant.targets.Clean
+cleanDirectory << targetDirectory
+cleanPattern << [ '**.*~' , parserDirectory + '/Groovy*.*' ]
+
+dependencies = 'dependencies'
+Ant.path ( id : dependencies ) {
+  fileset ( dir : System.properties.'groovy.home' + '/lib' , includes : '*.jar' , excludes : 'gant*.jar,*groovy*.jar' )
+}
+
+Ant.taskdef ( name : 'groovyc' , classname : 'org.codehaus.groovy.ant.Groovyc' , classpath : mainClassesDirectory )
+
+task ( ensureAntlr : 'Ensure all the files generated from the Antlr grammar are up to date.' ) {
+  Ant.mkdir ( dir : parserDirectory )
+  //  Need a way of getting this path in a platform independent way.  This is fine fo Ubuntu (and Debian?) but likely fails for all other OSs.
+  def antAntlrJar = '/usr/share/java/ant-antlr.jar'
+  Ant.taskdef ( name : 'antlr' , classname : 'org.apache.tools.ant.taskdefs.optional.ANTLR' , classpath : antAntlrJar )
+  Ant.antlr ( target : antlrDirectory + '/groovy.g' , outputdirectory : parserDirectory ) {
+    classpath ( refid : dependencies )
+  }    
+}
+
+task ( compileMain : 'Compile the Java and Groovy code in the main source.' ) {
+  depends ( ensureAntlr )
+  Ant.mkdir ( dir : mainClassesDirectory )
+  Ant.javac ( srcdir : mainSourceDirectory , destdir : mainClassesDirectory , debug : 'yes' , source : javaVersion , target : javaVersion , classpathref : dependencies , fork : 'true' )
+  Ant.groovyc ( srcdir : mainSourceDirectory , destdir : mainClassesDirectory ) { // , fork : 'true' ) {
+    classpath {
+      pathelement ( location : mainClassesDirectory )
+      path ( refid : dependencies )
+    }
+  } 
+}
+
+task ( compileTest : 'Compile the Java and Groovy code in the test source.' ) {
+  depends ( compileMain )
+  Ant.mkdir ( dir : testsClassesDirectory )
+  Ant.javac ( srcdir : testsSourceDirectory , destdir : testsClassesDirectory , debug : 'yes' , source : javaVersion , target : javaVersion , excludes : 'UberTestCase*.java' , fork : 'true' ) {
+    classpath {
+      pathelement ( location : mainClassesDirectory )
+      path ( refid : dependencies )
+    }
+  }
+  /*
+   *  Compiling the tests appears to require 128M of heap space.  Since the Groovy compiler Ant task doesn't
+   *  yet understand the fork and maxmemory attributes, we have to do things a bit more explicitly so as to
+   *  avoid having to use JAVA_OPTS=-Xmx128M gant on the command line.
+   * 
+  Ant.groovyc ( srcdir : testsSourceDirectory , destdir : testsClassesDirectory ) { // , fork : 'true', maxmemory : '128M'  ) {
+    classpath {
+      pathelement ( location : mainClassesDirectory )
+      pathelement ( location : testsClassesDirectory )
+      path ( refid : dependencies )
+    }
+  }
+  */
+  Ant.java ( classname : 'org.codehaus.groovy.ant.Groovyc' , fork : 'yes' , maxmemory : '128M' ) {
+    arg ( value : testsClassesDirectory )
+    arg ( value : testsSourceDirectory )
+    classpath {
+      pathelement ( location : mainClassesDirectory )
+      pathelement ( location : testsClassesDirectory )
+      path ( refid : dependencies )
+    }
+  }
+  Ant.javac ( srcdir : testsSourceDirectory , destdir : testsClassesDirectory , debug : 'yes' , source : javaVersion , target : javaVersion , includes : 'UberTestCase*.java' , fork : 'true' ) {
+    classpath {
+      pathelement ( location : mainClassesDirectory )
+      pathelement ( location : testsClassesDirectory )
+      path ( refid : dependencies )
+    }
+  }
+}
+
+task ( test : 'Test a build.' ) {
+  depends ( compileTest )
+  Ant.mkdir ( dir : reportsDirectory )
+  Ant.junit ( printsummary : 'true' , fork : 'true' , forkmode : 'once' ) {
+    formatter ( type : 'plain' )
+    batchtest ( todir : reportsDirectory ) {
+      fileset ( dir : testsClassesDirectory , includes : 'UberTest*.class' )
+    }
+    classpath {
+      pathelement ( location : mainClassesDirectory )
+      pathelement ( location : testsClassesDirectory )
+      path ( refid : dependencies )
+    }
+  }
+}
+
+task ( 'default' : 'Default action is currently test.' ) { test ( ) }
diff --git a/groovy-core/build.xml b/groovy-core/build.xml
new file mode 100644
index 0000000..24c3b23
--- /dev/null
+++ b/groovy-core/build.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<project name="tck" default="pretty-test">
+  <!-- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -->
+  <!--                   directories                     -->
+  <!-- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -->
+  <property name="test.reports.dir" value="target/test-reports"/>
+  
+    <target name="cruise" description="to be started by the CruiseControl build server">
+        <echo message="hook for your build"/>
+     </target>
+
+  <target name="pretty-test" 
+          description="HTML output of test cases">
+
+    <junitreport todir="${test.reports.dir}">
+      <fileset dir="${test.reports.dir}">
+        <include name="TEST-*.xml"/>
+      </fileset>
+      <report format="frames" todir="${test.reports.dir}"/>
+    </junitreport>
+  </target>
+
+
+</project>
diff --git a/groovy-core/cruise/build.xml b/groovy-core/cruise/build.xml
new file mode 100644
index 0000000..63e0c04
--- /dev/null
+++ b/groovy-core/cruise/build.xml
@@ -0,0 +1,52 @@
+<project name="groovy-cruisecontrol-starter" default="cruise"> 
+
+
+	<property name="svn.tag" value="https://svn.codehaus.org/groovy/tags/cc"/>
+	<property name="dir.checkout" value=".."/>
+	<property name="svn.user" value="dierk"/>
+
+	<target name="cruise" depends="update, copy-reporting-app, delegate, tagLastBuild"/>
+	
+	<!--
+    	label is given by CruiseControl, provides a default value here for the case where
+    	the admin starts this script manually.
+	-->
+	<property name="label" value="manualBuild"/>
+	
+	<target name="update">
+		<echo message="Getting the detected modifications...."/>
+		<exec executable="svn">
+            <arg line="--username ${svn.user} --non-interactive"/>
+		    <arg line="update ${dir.checkout}"/>
+		</exec>
+	</target>
+	<target name="delegate">
+		<echo message="*** Starting the groovy specific build parts ***"/>
+		<ant dir=".." antfile="build.xml" target="cruise">
+			<property name="buildnumber" value="${label}"/>
+		</ant>
+		<echo message="*** groovy build successfully ended          ***"/>
+	</target>
+
+	<target name="tagLastBuild">
+        <exec executable="svn" failonerror="true">
+            <arg line="--username ${svn.user} --non-interactive"/>
+            <arg line="copy -m '' ${dir.checkout} ${svn.tag}/${label}"/>
+        </exec>
+        <exec executable="svn" failonerror="true">
+            <arg line="--username ${svn.user} --non-interactive"/>
+            <arg line="rm -m '' ${svn.tag}/LAST_BUILD"/>
+        </exec>
+        <exec executable="svn" failonerror="true">
+            <arg line="--username ${svn.user} --non-interactive"/>
+            <arg line="copy -m '' ${svn.tag}/${label} ${svn.tag}/LAST_BUILD"/>
+        </exec>
+	</target>
+	
+	<target name="copy-reporting-app">
+	    <fail unless="reporting-app-dir" message="The property reporting-app-dir must be set from outside!" />
+		<copy todir="${reporting-app-dir}" >  <!-- overwrite="true" can be needed occasionally -->
+		    <fileset dir="reporting-app" />   <!-- only changes to web.xml need context reload -->
+		</copy>
+	</target>
+</project>
diff --git a/groovy-core/cruise/buildstatus.xsl b/groovy-core/cruise/buildstatus.xsl
new file mode 100644
index 0000000..1b2b288
--- /dev/null
+++ b/groovy-core/cruise/buildstatus.xsl
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="us-ascii" ?>
+<!--
+  Excerpted from the book, "Pragmatic Project Automation"
+  ISBN 0-9745140-3-9
+  Copyright 2004 The Pragmatic Programmers, LLC.  All Rights Reserved.
+  Visit www.PragmaticProgrammer.com
+ -->
+
+
+<xsl:stylesheet
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+	version="1.0">
+
+	<xsl:output method="xml" indent="yes"/>
+
+	<xsl:template match="/">
+
+		<rss version="2.0">
+			<channel>
+
+				<title>groovy Build Status</title>
+
+				<link>http://build.canooo.com/groovy/</link>
+
+				<description>CruiseControl build status feed for the groovy project.</description>
+
+				<item>
+
+					<xsl:variable name="project.name"
+						select="cruisecontrol/info/property[@name='projectname']/@value"/>
+					<xsl:variable name="build.date"
+						select="cruisecontrol/info/property[@name='builddate']/@value"/>
+					<xsl:variable name="build.time"
+						select="cruisecontrol/build/@time"/>
+					<xsl:variable name="modification.list"
+						select="cruisecontrol/modifications/modification"/>
+
+					<xsl:variable name="testsuite.list" select="//testsuite"/>
+					<xsl:variable name="testcase.list" select="$testsuite.list/testcase"/>
+					<title>
+						<xsl:choose>
+							<xsl:when test="cruisecontrol/build/@error">BUILD FAILED</xsl:when>
+							<xsl:otherwise>Build Succeeded</xsl:otherwise>
+						</xsl:choose>
+					</title>
+					<link>http://build.canoo.com/groovy/</link>
+					<description>
+						<xsl:choose>
+							<xsl:when test="cruisecontrol/build/@error">
+								<xsl:text>&lt;b&gt;Ant Error Message:&lt;/b&gt;&lt;br/&gt;</xsl:text>
+								<xsl:value-of select="cruisecontrol/build/@error"/>
+							</xsl:when>
+							<xsl:otherwise>
+								<xsl:text>&lt;b&gt;Build:&lt;/b&gt;</xsl:text>
+								<xsl:value-of select="cruisecontrol/info/property[@name='label']/@value"/>
+							</xsl:otherwise>
+						</xsl:choose>
+
+						&lt;br/&gt;
+						&lt;br/&gt;
+
+						&lt;b&gt;Date of build:&lt;/b&gt;
+						<xsl:value-of select="$build.date"/>&lt;br/&gt;
+
+						&lt;b&gt;Time to build:&lt;/b&gt;
+						<xsl:value-of select="$build.time"/>&lt;br/&gt;
+
+						<xsl:apply-templates select="$modification.list">
+							<xsl:sort select="date" order="descending" data-type="text"/>
+						</xsl:apply-templates>
+
+						&lt;br/&gt;
+
+						&lt;b&gt;Unit Tests:&lt;/b&gt;
+						<xsl:value-of select="count($testcase.list)"/>
+
+					</description>
+				</item>
+			</channel>
+		</rss>
+	</xsl:template>
+
+	<xsl:template match="modification">
+		<xsl:if test="position() = 1">
+
+			&lt;br/&gt;
+
+			&lt;b&gt;Last changed:&lt;/b&gt;
+			<xsl:value-of select="date"/>&lt;br/&gt;
+
+			&lt;b&gt;Last changed by:&lt;/b&gt;
+			<xsl:value-of select="user"/>&lt;br/&gt;
+
+			&lt;b&gt;Last log entry:&lt;/b&gt;
+			<xsl:value-of select="comment"/>&lt;br/&gt;
+
+		</xsl:if>
+	</xsl:template>
+
+</xsl:stylesheet>
diff --git a/groovy-core/cruise/cc.xsl b/groovy-core/cruise/cc.xsl
new file mode 100644
index 0000000..4879363
--- /dev/null
+++ b/groovy-core/cruise/cc.xsl
@@ -0,0 +1,380 @@
+<?xml version="1.0"?>
+<!DOCTYPE xsl:stylesheet [
+	<!ENTITY space "&#32;">
+	<!ENTITY nbsp "&#160;">
+	<!ENTITY bullet "&#8226;">]>
+
+<xsl:stylesheet
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+   xmlns:xslt="http://xml.apache.org/xslt"
+	>
+	<xsl:output method="html"/>
+
+	<!-- collects all task nodes with parent target into the variable $tasklist -->
+	<xsl:variable name="tasklist" select="//task"/>
+
+	<!-- collects all task nodes from $tasklist with attribute name="Javac" etc. -->
+	<xsl:variable name="javac.tasklist" select="$tasklist[@name='javac']"/>
+	<xsl:variable name="ejbjar.tasklist" select="$tasklist[@name='ejbjar']"/>
+	<xsl:variable name="jar.tasklist" select="$tasklist[@name='jar']"/>
+	<xsl:variable name="war.tasklist" select="$tasklist[@name='war']"/>
+
+	<!-- count elements in sublists -->
+	<xsl:variable name="dist.count" select="count($jar.tasklist) + count($war.tasklist)"/>
+
+	<!-- collect all testsuite nodes in build, regardless of depth -->
+	<xsl:variable name="testsuite.list" select="//testsuite"/>
+	<!-- count error nodes directly under testsuite -->
+	<xsl:variable name="testsuite.error.count" select="count($testsuite.list/error)"/>
+
+	<xsl:variable name="testcase.list" select="$testsuite.list/testcase"/>
+	<xsl:variable name="testcase.error.list" select="$testcase.list/error"/>
+	<xsl:variable name="testcase.failure.list" select="$testcase.list/failure"/>
+	<xsl:variable name="totalErrorsAndFailures" select="count($testcase.error.list) + count($testcase.failure.list)"/>
+
+	<!-- 1: /build/modifications, 2: /cruisecontrol/modifications -->
+	<xsl:variable name="modification.list" select="//modifications/modification"/>
+	<!-- collects all the modification sets -->
+	<xsl:key name="modificationSet" match="//modifications/modification" use="concat(user,':',comment)"/>
+
+	<!-- long template for the whole page, this ensures sequence -->
+	<xsl:template match="/">
+		<!-- Header Part -->
+
+		<xsl:choose>
+			<xsl:when test="//build/@error"> <!-- build tag contains attribute error -->
+				<h1>BUILD FAILED</h1>
+			</xsl:when>
+			<xsl:otherwise>
+				<h1>
+					<xsl:text>BUILD COMPLETE -&space;</xsl:text>
+					<!-- support CruiseControl 1.0 and 2.0 -->
+					<xsl:value-of select="build/label | //info/property[@name='label']/@value"/>
+				</h1>
+			</xsl:otherwise>
+		</xsl:choose>
+
+		<table>
+			<tr>
+				<th>Date of build</th>
+				<td>
+					<!-- support CruiseControl 1.0 and 2.0 -->
+					<xsl:value-of select="build/today | //info/property[@name='builddate']/@value"/>
+				</td>
+			</tr>
+			<tr>
+				<th>Time to build</th>
+				<td>
+					<xsl:value-of select="//build/@time"/>
+				</td>
+			</tr>
+			<tr>
+				<th>Last changed</th>
+				<td>
+					<xsl:value-of select="//modifications/modification/date"/>
+				</td>
+			</tr>
+			<tr>
+				<th>Last log entry</th>
+				<td>
+					<xsl:value-of select="//modifications/modification/comment"/>
+				</td>
+			</tr>
+		</table>
+
+		<xsl:if test="//build/@error">
+			<h2>Ant Error Message</h2>
+			<pre>
+				<xsl:value-of select="//build/@error"/>
+			</pre>
+			<pre>
+				<xsl:value-of select="//stacktrace"/>
+			</pre>
+		</xsl:if>
+
+		<!-- Compilation Messages -->
+
+		<xsl:variable name="javac.warn.messages" select="$javac.tasklist/message[@priority='warn']"/>
+		<xsl:variable name="ejbjar.warn.messages" select="$ejbjar.tasklist/message[@priority='warn']"/>
+		<xsl:variable name="total.errorMessage.count"
+		              select="count($javac.warn.messages) + count($ejbjar.warn.messages)"/>
+
+		<!-- NOTE: total.errorMessage.count is actually the number of lines of error
+									  messages. This accurately represents the number of errors ONLY if the Ant property
+									  build.compiler.emacs is set to "true" -->
+		<xsl:if test="$total.errorMessage.count > 0">
+			<h2>
+				<xsl:text>Error-/Warning- Lines:&space;</xsl:text>
+				<xsl:value-of select="$total.errorMessage.count"/>
+			</h2>
+
+			<pre>
+				<xsl:apply-templates select="$javac.warn.messages"/>
+			</pre>
+		</xsl:if>
+
+		<!-- Unit Tests -->
+		<xsl:variable name="unit.passed" select="count($testcase.list)-$totalErrorsAndFailures"/>
+
+		<h2>Unit Tests</h2>
+		<p>
+			<xsl:text>Test cases:&space;</xsl:text>
+			<b>
+				<xsl:value-of select="count($testcase.list)"/>
+			</b>
+			<xsl:text>, passed:&space;</xsl:text>
+			<b>
+				<xsl:value-of select="$unit.passed"/>
+			</b>
+			<xsl:text>, failures:&space;</xsl:text>
+			<b>
+				<xsl:value-of select="count($testcase.failure.list)"/>
+			</b>
+			<xsl:text>, errors:&space;</xsl:text>
+			<b>
+				<xsl:value-of select="count($testcase.error.list)"/>
+			</b>
+			<xsl:text>.</xsl:text>
+		</p>
+
+		<xsl:call-template name="colorBar">
+			<xsl:with-param name="success.count" select="$unit.passed"/>
+			<xsl:with-param name="failed.count" select="$totalErrorsAndFailures"/>
+			<xsl:with-param name="total.count" select="count($testcase.list)"/>
+			<xsl:with-param name="tableID">utests</xsl:with-param>
+		</xsl:call-template>
+
+		<xsl:if test="count($testcase.error.list) > 0">
+			<h3>Errors</h3>
+			<ul>
+				<xsl:apply-templates select="$testcase.error.list"/>
+			</ul>
+		</xsl:if>
+
+		<xsl:if test="count($testcase.failure.list) > 0">
+			<h3>Failures</h3>
+			<ul>
+				<xsl:apply-templates select="$testcase.failure.list"/>
+			</ul>
+		</xsl:if>
+
+		<xsl:if test="$totalErrorsAndFailures > 0">
+			<h3>
+				<xsl:text>Unit Test Error Details:&space;(</xsl:text>
+				<xsl:value-of select="$totalErrorsAndFailures"/>
+				<xsl:text>)</xsl:text>
+			</h3>
+			<xsl:apply-templates select="//testsuite/testcase[.//error]"/>
+			<xsl:apply-templates select="//testsuite/testcase[.//failure]"/>
+		</xsl:if>
+
+		<!-- Functional Tests -->
+
+		<!-- functional testing vars -->
+		<xsl:variable name="cases" select="//summary/testresult"/>
+		<xsl:variable name="steps" select="//summary/testresult/results/step"/>
+		<xsl:variable name="passed" select="$cases[@successful='yes']"/>
+		<xsl:variable name="failed" select="$cases[@successful='no']"/>
+
+		<h2>Functional Tests</h2>
+		<p>
+			<xsl:text>Szenarios:&space;</xsl:text>
+			<b>
+				<xsl:value-of select="count($cases)"/>
+			</b>
+			<xsl:text>, passed:&space;</xsl:text>
+			<b>
+				<xsl:value-of select="count($passed)"/>
+			</b>
+			<xsl:text>, failed:&space;</xsl:text>
+			<b>
+				<xsl:value-of select="count($failed)"/>
+			</b>
+			<xsl:text>, including&space;</xsl:text>
+			<b>
+				<xsl:value-of select="count($steps)"/>
+			</b>
+			<xsl:text>&space;single steps.</xsl:text>
+		</p>
+
+		<xsl:call-template name="colorBar">
+			<xsl:with-param name="success.count" select="count($passed)"/>
+			<xsl:with-param name="failed.count" select="count($failed)"/>
+			<xsl:with-param name="total.count" select="count($cases)"/>
+			<xsl:with-param name="tableID">ftests</xsl:with-param>
+		</xsl:call-template>
+
+		<h2>Modifications</h2>
+		<p>
+			<xsl:value-of select="count($modification.list)"/>
+			<xsl:text>&space;modifications since last build.</xsl:text>
+		</p>
+
+		<xsl:for-each select="$modification.list[count(.|key('modificationSet',concat(user,':',comment))[1])=1]">
+			<h3>
+				<xsl:value-of select="user"/>
+				<xsl:text>:&space;</xsl:text>
+				<xsl:value-of select="comment"/>
+				<xsl:text>&space;(</xsl:text>
+				<xsl:value-of select="date"/>
+				<xsl:text>)</xsl:text>
+			</h3>
+			<ul>
+				<xsl:apply-templates select="key('modificationSet',concat(user,':',comment))"/>
+			</ul>
+		</xsl:for-each>
+
+
+		<xsl:if test="$dist.count > 0">
+			<h2>Deployments</h2>
+			<p>
+				<xsl:value-of select="$dist.count"/>
+				<xsl:text>&space;files deployed by this build.</xsl:text>
+			</p>
+
+			<ul>
+				<xsl:apply-templates select="$jar.tasklist | $war.tasklist"/>
+			</ul>
+		</xsl:if>
+
+	</xsl:template>
+
+	<xsl:template name="colorBar">
+		<xsl:param name="success.count"/>
+		<xsl:param name="failed.count"/>
+		<xsl:param name="total.count"/>
+		<xsl:param name="tableID"/>
+
+		<table bgcolor="white" cellspacing="0" cellpadding="0">
+			<xsl:attribute name="id">
+				<xsl:value-of select="$tableID"/>
+			</xsl:attribute>
+			<tr>
+				<xsl:if test="$success.count > 0">
+					<td bgcolor="green">
+						<xsl:attribute name="width">
+							<xsl:value-of select="concat($success.count * 100 div $total.count, '%')"/>
+						</xsl:attribute>
+						&nbsp;
+					</td>
+				</xsl:if>
+
+				<xsl:if test="$failed.count > 0">
+					<td bgcolor="#FFFFA0">
+						<xsl:attribute name="width">
+							<xsl:value-of select="concat($failed.count * 100 div $total.count, '%')"/>
+						</xsl:attribute>
+						&nbsp;
+					</td>
+				</xsl:if>
+
+				<xsl:if test="($total.count = 0) or ($total.count > ($success.count + $failed.count))">
+					<td>&nbsp;</td>
+				</xsl:if>
+			</tr>
+		</table>
+	</xsl:template>
+
+
+	<!-- UnitTest Errors/Failures -->
+	<xsl:template match="error|failure">
+		<li>
+			<xsl:call-template name="colorOddEvenRow"/>
+			<xsl:value-of select="../@name"/>
+		</li>
+	</xsl:template>
+
+	<!-- UnitTest Errors And Failures Detail Template -->
+	<xsl:template match="//testsuite/testcase">
+		<h4>
+			<xsl:text>Test:&space;</xsl:text>
+			<xsl:value-of select="@name"/>
+		</h4>
+
+		<p>
+			<xsl:text>Type:</xsl:text>
+			<xsl:value-of select="node()/@type"/>
+		</p>
+		<p>
+			<xsl:text>Message:</xsl:text>
+			<xsl:value-of select="node()/@message"/>
+		</p>
+
+		<PRE>
+			<xsl:value-of select="node()"/>
+		</PRE>
+	</xsl:template>
+
+	<!-- Compilation Error Details -->
+	<xsl:template match="message[@priority='warn']">
+		<xsl:value-of select="text()"/>
+		<br/>
+	</xsl:template>
+	<!-- Test Execution Stacktrace -->
+	<xsl:template match="stacktrace">
+		<pre>
+			<xsl:value-of select="text()"/>
+		</pre>
+	</xsl:template>
+
+	<!-- Modifications template -->
+	<xsl:template match="modification[file/filename]">
+		<!-- CC 2.0 -->
+		<li>
+			<xsl:call-template name="colorOddEvenRow"/>
+			<xsl:call-template name="modificationType">
+				<xsl:with-param name="type" select="file/@action"/>
+			</xsl:call-template>
+
+			<xsl:value-of select="file/project"/>
+			<xsl:if test="string-length(normalize-space(file/project))">
+				<xsl:text>/</xsl:text>
+			</xsl:if>
+			<xsl:value-of select="file/filename"/>
+		</li>
+	</xsl:template>
+
+	<xsl:template match="modification">
+		<!-- CC 1.0 -->
+		<li>
+			<xsl:call-template name="colorOddEvenRow"/>
+			<xsl:call-template name="modificationType">
+				<xsl:with-param name="type" select="@type"/>
+			</xsl:call-template>
+
+			<xsl:value-of select="filename"/>
+		</li>
+	</xsl:template>
+
+	<xsl:template name="modificationType">
+		<xsl:param name="type"/>
+
+		<span class="modifificationType">
+			<xsl:choose>
+				<xsl:when test="$type='modified'">&gt;</xsl:when>
+				<xsl:when test="$type='added'">+</xsl:when>
+				<xsl:when test="$type='deleted'">-</xsl:when>
+				<xsl:otherwise><xsl:value-of select="$type"/></xsl:otherwise>
+			</xsl:choose>
+		</span>
+
+		&nbsp;
+	</xsl:template>
+
+	<!-- jar and war template -->
+	<xsl:template match="task[translate(string(@name),'jJwW','')='ar']">
+		<li>
+			<xsl:call-template name="colorOddEvenRow"/>
+			<xsl:value-of select="message"/>
+		</li>
+	</xsl:template>
+
+	<xsl:template name="colorOddEvenRow">
+		<xsl:attribute name="class">
+			<xsl:choose>
+				<xsl:when test="position() mod 2 = 0">evenrow</xsl:when>
+				<xsl:otherwise>oddrow</xsl:otherwise>
+			</xsl:choose>
+		</xsl:attribute>
+	</xsl:template>
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/groovy-core/cruise/emailmap.properties b/groovy-core/cruise/emailmap.properties
new file mode 100644
index 0000000..4f94d45
--- /dev/null
+++ b/groovy-core/cruise/emailmap.properties
@@ -0,0 +1,9 @@
+#
+# Maps cvs user id to e-mail adress.
+#
+# these team members get notified on builds
+# of what they have commited to the CVS
+#
+
+dierk=dierk.koenig@canoo.com
+graeme=graemerocher@yahoo.co.uk
\ No newline at end of file
diff --git a/groovy-core/cruise/htmlmail.xsl b/groovy-core/cruise/htmlmail.xsl
new file mode 100644
index 0000000..b24fb27
--- /dev/null
+++ b/groovy-core/cruise/htmlmail.xsl
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="us-ascii" ?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+	<xsl:import href="cc.xsl"/>
+	<xsl:output method="html"/>
+
+	<xsl:template match="/">
+		<html>
+			<head>
+				<title>CruiseControl Build Result</title>
+			</head>
+			<body>
+				<xsl:apply-imports/>
+			</body>
+		</html>
+	</xsl:template>
+</xsl:stylesheet>
diff --git a/groovy-core/cruise/project.xml b/groovy-core/cruise/project.xml
new file mode 100644
index 0000000..8e1f750
--- /dev/null
+++ b/groovy-core/cruise/project.xml
@@ -0,0 +1,52 @@
+<!-- 
+This file is referenced from cruisecontrol's config.xml and contains the project definition.
+
+Available entities are:
+basedir
+hostname
+defaultmailhost
+-->
+
+
+<project name="groovy" buildafterfailed="false">
+		<modificationset quietperiod="120">
+			<svn localworkingcopy="&basedir;/groovy/cruisecontrol/checkout"/>
+		</modificationset>
+		<schedule>
+			<!-- buildfile is relative to checkout dir -->
+			<ant
+				buildfile="&basedir;/groovy/cruisecontrol/checkout/cruise/build.xml"
+				antWorkingDir="&basedir;/groovy/cruisecontrol/checkout"
+				usedebug="false"
+				uselogger="true"
+				>
+                            <property name="reporting-app-dir" value="&basedir;/groovy/&hostname;/groovy/"/>
+                        </ant>
+		</schedule>
+		<listeners>
+                    <currentbuildstatuslistener file="&basedir;/groovy/cruisecontrol/logs/status.txt"/>
+                </listeners>
+                <log dir="&basedir;/groovy/cruisecontrol/logs">
+			<!--merge dir="&basedir;/groovy/cruisecontrol/checkout/target/test-reports/"/-->
+		</log>
+		<publishers>
+			<!-- htmlemail is used only for explicit subscribers -->
+			<htmlemail
+				buildresultsurl="http://&hostname;/groovy/"
+				mailhost="&defaultmailhost;"
+				returnaddress="build-support@canoo.com"
+				spamwhilebroken="false"
+				skipusers="true"
+				logdir="&basedir;/groovy/cruisecontrol/logs"
+				xslfile="&basedir;/groovy/cruisecontrol/checkout/cruise/htmlmail.xsl"
+				>
+				<!--propertiesmapper file="&basedir;/groovy/cruisecontrol/checkout/cruise/emailmap.properties"/-->
+				<always address="dierk.koenig@canoo.com"/>
+			</htmlemail>
+			<XSLTLogPublisher
+				directory="&basedir;/groovy/&hostname;/groovy/"
+				outfilename="buildstatus.rss"
+				xsltfile="&basedir;/groovy/cruisecontrol/checkout/cruise/buildstatus.xsl"
+				/>
+		</publishers>
+</project>
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/BuildInfo.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/BuildInfo.class
new file mode 100644
index 0000000..ada309a
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/BuildInfo.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/BuildInfoSummary.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/BuildInfoSummary.class
new file mode 100644
index 0000000..9f8d53b
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/BuildInfoSummary.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/CruiseControlWebAppException.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/CruiseControlWebAppException.class
new file mode 100644
index 0000000..36f565d
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/CruiseControlWebAppException.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/StatusHelper.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/StatusHelper.class
new file mode 100644
index 0000000..3fc96c5
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/StatusHelper.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/chart/AbstractCruiseControlChartData.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/chart/AbstractCruiseControlChartData.class
new file mode 100644
index 0000000..ef6a3a0
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/chart/AbstractCruiseControlChartData.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/chart/PieChartData.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/chart/PieChartData.class
new file mode 100644
index 0000000..b10ba0e
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/chart/PieChartData.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/chart/TimeChartData.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/chart/TimeChartData.class
new file mode 100644
index 0000000..27329ab
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/chart/TimeChartData.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/servlet/FileServlet.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/servlet/FileServlet.class
new file mode 100644
index 0000000..6ba43da
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/servlet/FileServlet.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/servlet/WebFile.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/servlet/WebFile.class
new file mode 100644
index 0000000..49a8c86
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/servlet/WebFile.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/ArtifactsLinkTag.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/ArtifactsLinkTag.class
new file mode 100644
index 0000000..e34df35
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/ArtifactsLinkTag.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/ArtifactsLinkTagExtraInfo.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/ArtifactsLinkTagExtraInfo.class
new file mode 100644
index 0000000..414dda7
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/ArtifactsLinkTagExtraInfo.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/BuildInfoTag.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/BuildInfoTag.class
new file mode 100644
index 0000000..d44b402
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/BuildInfoTag.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/BuildInfoTagExtraInfo.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/BuildInfoTagExtraInfo.class
new file mode 100644
index 0000000..8f495ad
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/BuildInfoTagExtraInfo.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/CruiseControlBodyTagSupport.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/CruiseControlBodyTagSupport.class
new file mode 100644
index 0000000..2fb7861
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/CruiseControlBodyTagSupport.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/CruiseControlLogFileFilter.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/CruiseControlLogFileFilter.class
new file mode 100644
index 0000000..8925392
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/CruiseControlLogFileFilter.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/CruiseControlTagSupport$1.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/CruiseControlTagSupport$1.class
new file mode 100644
index 0000000..6c38ff5
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/CruiseControlTagSupport$1.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/CruiseControlTagSupport.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/CruiseControlTagSupport.class
new file mode 100644
index 0000000..ec3110f
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/CruiseControlTagSupport.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/CurrentBuildStatusTag.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/CurrentBuildStatusTag.class
new file mode 100644
index 0000000..a6eb815
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/CurrentBuildStatusTag.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/LinkTag.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/LinkTag.class
new file mode 100644
index 0000000..0974be9
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/LinkTag.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/LinkTagExtraInfo.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/LinkTagExtraInfo.class
new file mode 100644
index 0000000..cd51562
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/LinkTagExtraInfo.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/NavigationTag.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/NavigationTag.class
new file mode 100644
index 0000000..43dac85
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/NavigationTag.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/NavigationTagExtraInfo.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/NavigationTagExtraInfo.class
new file mode 100644
index 0000000..81a62ef
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/NavigationTagExtraInfo.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/ReversedComparator.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/ReversedComparator.class
new file mode 100644
index 0000000..d7bcc2d
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/ReversedComparator.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/Tab.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/Tab.class
new file mode 100644
index 0000000..8d70a1a
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/Tab.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/TabSheetTag.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/TabSheetTag.class
new file mode 100644
index 0000000..14dd51e
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/TabSheetTag.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/TabTag.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/TabTag.class
new file mode 100644
index 0000000..3dd906f
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/TabTag.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/XSLTag$1.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/XSLTag$1.class
new file mode 100644
index 0000000..951562e
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/XSLTag$1.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/XSLTag.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/XSLTag.class
new file mode 100644
index 0000000..e78d42a
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/taglib/XSLTag.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/util/DateUtil.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/util/DateUtil.class
new file mode 100644
index 0000000..ed4a4e2
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/util/DateUtil.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/util/TimeNumberFormat.class b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/util/TimeNumberFormat.class
new file mode 100644
index 0000000..72ea257
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/classes/net/sourceforge/cruisecontrol/util/TimeNumberFormat.class
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/cruisecontrol-jsp11.tld b/groovy-core/cruise/reporting-app/WEB-INF/cruisecontrol-jsp11.tld
new file mode 100644
index 0000000..cea2d11
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/cruisecontrol-jsp11.tld
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>

+<!DOCTYPE taglib

+        PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"

+	"http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">

+

+<!--********************************************************************************

+ * CruiseControl, a Continuous Integration Toolkit

+ * Copyright (c) 2001, ThoughtWorks, Inc.

+ * 651 W Washington Ave. Suite 600

+ * Chicago, IL 60661 USA

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ *

+ *     + Redistributions of source code must retain the above copyright

+ *       notice, this list of conditions and the following disclaimer.

+ *

+ *     + Redistributions in binary form must reproduce the above

+ *       copyright notice, this list of conditions and the following

+ *       disclaimer in the documentation and/or other materials provided

+ *       with the distribution.

+ *

+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the

+ *       names of its contributors may be used to endorse or promote

+ *       products derived from this software without specific prior

+ *       written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR

+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,

+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR

+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF

+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING

+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS

+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ ********************************************************************************-->

+<taglib>

+    <tlibversion>1.0</tlibversion>

+    <jspversion>1.1</jspversion>

+    <shortname>simple</shortname>

+    <uri></uri>

+    <info>

+        A simple tab library for the examples

+    </info>

+    <tag>

+        <name>xsl</name>

+        <tagclass>net.sourceforge.cruisecontrol.taglib.XSLTag</tagclass>

+        <bodycontent>JSP</bodycontent>

+        <info>

+            Transforms the xml build log using XSL.

+        </info>

+        <attribute>

+            <name>xslFile</name>

+            <required>true</required>

+        </attribute>

+        <attribute>

+            <name>xslRootContext</name>

+            <required>false</required>

+        </attribute>

+    </tag>

+    <tag>

+        <name>currentbuildstatus</name>

+        <tagclass>net.sourceforge.cruisecontrol.taglib.CurrentBuildStatusTag</tagclass>

+        <bodycontent>empty</bodycontent>

+        <info>

+            Report when the build started, or when it will start again.

+        </info>

+    </tag>

+    <tag>

+        <name>nav</name>

+        <tagclass>net.sourceforge.cruisecontrol.taglib.NavigationTag</tagclass>

+        <teiclass>net.sourceforge.cruisecontrol.taglib.NavigationTagExtraInfo</teiclass>

+        <bodycontent>JSP</bodycontent>

+        <info>

+            Builds the navigation

+        </info>

+        <attribute>

+            <name>dateFormat</name>

+            <required>false</required>

+        </attribute>

+        <attribute>

+            <name>startingBuildNumber</name>

+            <required>false</required>

+        </attribute>

+        <attribute>

+            <name>finalBuildNumber</name>

+            <required>false</required>

+        </attribute>

+    </tag>

+    <tag>

+        <name>artifactsLink</name>

+        <tagclass>net.sourceforge.cruisecontrol.taglib.ArtifactsLinkTag</tagclass>

+        <teiclass>net.sourceforge.cruisecontrol.taglib.ArtifactsLinkTagExtraInfo</teiclass>

+        <bodycontent>JSP</bodycontent>

+        <info>

+            Inserts link to the artifacts FileServlet

+        </info>

+    </tag>

+    <tag>

+        <name>buildInfo</name>

+        <tagclass>net.sourceforge.cruisecontrol.taglib.BuildInfoTag</tagclass>

+        <teiclass>net.sourceforge.cruisecontrol.taglib.BuildInfoTagExtraInfo</teiclass>

+        <bodycontent>empty</bodycontent>

+        <info>

+            Inserts information about the various builds into the page scope.

+        </info>

+    </tag>

+    <tag>

+        <name>tabsheet</name>

+        <tagclass>net.sourceforge.cruisecontrol.taglib.TabSheetTag</tagclass>

+        <bodycontent>JSP</bodycontent>

+        <info>

+            Creates a tab sheet that tabs can be placed into.

+        </info>

+    </tag>

+    <tag>

+        <name>tab</name>

+        <tagclass>net.sourceforge.cruisecontrol.taglib.TabTag</tagclass>

+        <bodycontent>JSP</bodycontent>

+        <info>Creates a tab that selected content gets put into.</info>

+        <attribute>

+            <name>name</name>

+            <required>true</required>

+        </attribute>

+        <attribute>

+            <name>label</name>

+            <required>true</required>

+        </attribute>

+    </tag>

+    <tag>

+        <name>link</name>

+        <tagclass>net.sourceforge.cruisecontrol.taglib.LinkTag</tagclass>

+        <teiclass>net.sourceforge.cruisecontrol.taglib.LinkTagExtraInfo</teiclass>

+        <bodycontent>empty</bodycontent>

+        <info>Builds up a link URL</info>

+        <attribute>

+            <name>id</name>

+            <required>true</required>

+        </attribute>

+        <attribute>

+            <name>exclude</name>

+            <required>false</required>

+        </attribute>

+    </tag>

+</taglib>

diff --git a/groovy-core/cruise/reporting-app/WEB-INF/cruisecontrol-jsp12.tld b/groovy-core/cruise/reporting-app/WEB-INF/cruisecontrol-jsp12.tld
new file mode 100644
index 0000000..3ca20d6
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/cruisecontrol-jsp12.tld
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>

+<!DOCTYPE taglib

+  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"

+  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">

+

+<!--********************************************************************************

+ * CruiseControl, a Continuous Integration Toolkit

+ * Copyright (c) 2001, ThoughtWorks, Inc.

+ * 651 W Washington Ave. Suite 600

+ * Chicago, IL 60661 USA

+ * All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ *

+ *     + Redistributions of source code must retain the above copyright

+ *       notice, this list of conditions and the following disclaimer.

+ *

+ *     + Redistributions in binary form must reproduce the above

+ *       copyright notice, this list of conditions and the following

+ *       disclaimer in the documentation and/or other materials provided

+ *       with the distribution.

+ *

+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the

+ *       names of its contributors may be used to endorse or promote

+ *       products derived from this software without specific prior

+ *       written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR

+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,

+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR

+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF

+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING

+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS

+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ ********************************************************************************-->

+<taglib>

+    <tlib-version>1.0</tlib-version>

+    <jsp-version>1.2</jsp-version>

+    <short-name>cruisecontrol</short-name>

+    <uri>http://cruisecontrol.sourceforge.net/taglibs/cruisecontrol-1.0</uri>

+    <tag>

+        <name>xsl</name>

+        <tag-class>net.sourceforge.cruisecontrol.taglib.XSLTag</tag-class>

+        <body-content>JSP</body-content>

+        <description>

+            Transforms the xml build log using XSL.

+        </description>

+        <attribute>

+            <name>xslFile</name>

+            <required>true</required>

+        </attribute>

+        <attribute>

+            <name>xslRootContext</name>

+            <required>false</required>

+        </attribute>

+    </tag>

+    <tag>

+        <name>currentbuildstatus</name>

+        <tag-class>net.sourceforge.cruisecontrol.taglib.CurrentBuildStatusTag</tag-class>

+        <body-content>empty</body-content>

+        <description>

+            Report when the build started, or when it will start again.

+        </description>

+    </tag>

+    <tag>

+        <name>nav</name>

+        <tag-class>net.sourceforge.cruisecontrol.taglib.NavigationTag</tag-class>

+        <tei-class>net.sourceforge.cruisecontrol.taglib.NavigationTagExtraInfo</tei-class>

+        <body-content>JSP</body-content>

+        <description>

+            Builds the navigation

+        </description>

+        <attribute>

+            <name>dateFormat</name>

+            <required>false</required>

+        </attribute>

+        <attribute>

+            <name>startingBuildNumber</name>

+            <required>false</required>

+        </attribute>

+        <attribute>

+            <name>finalBuildNumber</name>

+            <required>false</required>

+        </attribute>

+    </tag>

+    <tag>

+        <name>artifactsLink</name>

+        <tag-class>net.sourceforge.cruisecontrol.taglib.ArtifactsLinkTag</tag-class>

+        <tei-class>net.sourceforge.cruisecontrol.taglib.ArtifactsLinkTagExtraInfo</tei-class>

+        <body-content>JSP</body-content>

+        <description>

+            Inserts link to the artifacts FileServlet

+        </description>

+    </tag>

+     <tag>

+        <name>buildInfo</name>

+        <tag-class>net.sourceforge.cruisecontrol.taglib.BuildInfoTag</tag-class>

+        <tei-class>net.sourceforge.cruisecontrol.taglib.BuildInfoTagExtraInfo</tei-class>

+        <body-content>empty</body-content>

+        <description>

+            Inserts information about the various builds into the page scope.

+        </description>

+    </tag>

+    <tag>

+        <name>tabsheet</name>

+        <tag-class>net.sourceforge.cruisecontrol.taglib.TabSheetTag</tag-class>

+        <body-content>JSP</body-content>

+        <description>Creates a tab sheet that tabs can be placed into.</description>

+    </tag>

+    <tag>

+        <name>tab</name>

+        <tag-class>net.sourceforge.cruisecontrol.taglib.TabTag</tag-class>

+        <body-content>JSP</body-content>

+        <description>Creates a tab that selected content gets put into.</description>

+        <attribute>

+            <name>name</name>

+            <required>true</required>

+        </attribute>

+        <attribute>

+            <name>label</name>

+            <required>true</required>

+        </attribute>

+    </tag>

+    <tag>

+        <name>link</name>

+        <tag-class>net.sourceforge.cruisecontrol.taglib.LinkTag</tag-class>

+        <tei-class>net.sourceforge.cruisecontrol.taglib.LinkTagExtraInfo</tei-class>

+        <body-content>empty</body-content>

+        <description>Builds up a link URL</description>

+        <attribute>

+            <name>id</name>

+            <required>true</required>

+        </attribute>

+        <attribute>

+            <name>exclude</name>

+            <required>false</required>

+        </attribute>

+    </tag>

+</taglib>

diff --git a/groovy-core/cruise/reporting-app/WEB-INF/lib/batik-awt-util.jar b/groovy-core/cruise/reporting-app/WEB-INF/lib/batik-awt-util.jar
new file mode 100644
index 0000000..943a536
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/lib/batik-awt-util.jar
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/lib/batik-svggen.jar b/groovy-core/cruise/reporting-app/WEB-INF/lib/batik-svggen.jar
new file mode 100644
index 0000000..e11e86c
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/lib/batik-svggen.jar
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/lib/batik-util.jar b/groovy-core/cruise/reporting-app/WEB-INF/lib/batik-util.jar
new file mode 100644
index 0000000..af3d81b
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/lib/batik-util.jar
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/lib/cewolf.jar b/groovy-core/cruise/reporting-app/WEB-INF/lib/cewolf.jar
new file mode 100644
index 0000000..dda5a9e
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/lib/cewolf.jar
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/lib/commons-logging.jar b/groovy-core/cruise/reporting-app/WEB-INF/lib/commons-logging.jar
new file mode 100644
index 0000000..a4d5563
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/lib/commons-logging.jar
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/lib/jcommon-0.8.0.jar b/groovy-core/cruise/reporting-app/WEB-INF/lib/jcommon-0.8.0.jar
new file mode 100644
index 0000000..90bbb30
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/lib/jcommon-0.8.0.jar
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/lib/jfreechart-0.9.8.jar b/groovy-core/cruise/reporting-app/WEB-INF/lib/jfreechart-0.9.8.jar
new file mode 100644
index 0000000..a9e6081
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/lib/jfreechart-0.9.8.jar
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/WEB-INF/web.xml b/groovy-core/cruise/reporting-app/WEB-INF/web.xml
new file mode 100644
index 0000000..5efdbc2
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/WEB-INF/web.xml
@@ -0,0 +1,139 @@
+<!DOCTYPE web-app
+    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
+    "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
+
+<!--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************-->
+<web-app>
+    <display-name>groovy CruiseControl Reporting App</display-name>
+    <description>The reporting application for CruiseControl. Provides a simple but rich
+        interface for viewing CruiseControl build reports.
+    </description>
+
+    <context-param>
+        <param-name>singleProject</param-name>
+        <param-value>true</param-value>
+        <description>Indicates if the CruiseControl instance is to report on only one project.
+            If it is, then you should set this to true.
+        </description>
+    </context-param>
+
+    <context-param>
+      <!-- You can set this value via the user.log.dir property in Ant, when building the WAR file. -->
+      <param-name>logDir</param-name>
+      <param-value>/opt/groovy/cruisecontrol/logs/</param-value>
+      <description> This should be the full path to your CruiseControl log directory. If you
+          are in single project mode, this will contain only the logs for your project. If you
+          are in multi-project mode, it is expected that you will have multiple sub-directories
+          inside this log directory, one for each project.
+      </description>
+    </context-param>
+
+    <context-param>
+      <!-- You can set this value via the user.build.status.file property in Ant, when building the WAR file. -->
+      <param-name>currentBuildStatusFile</param-name>
+      <param-value>status.txt</param-value>
+      <description>This should be the path to your current build status file, which is relative
+          to the log directory (or, in single-project mode, relative to the project's log
+          directory)
+      </description>
+    </context-param>
+
+    <servlet>
+      <servlet-name>buildresults</servlet-name>
+      <display-name>Build Result Reporter</display-name>
+      <description>Presents build results in a human-readable and intuitive format.</description>
+      <jsp-file>/main.jsp</jsp-file>
+    </servlet>
+
+    <servlet>
+        <servlet-name>index</servlet-name>
+        <display-name>Index/Summary page</display-name>
+        <description>Presents a summary of all projects, allowing easy navigation to each.</description>
+        <jsp-file>/index.jsp</jsp-file>
+    </servlet>
+
+    <servlet>
+        <servlet-name>ArtifactServlet</servlet-name>
+        <servlet-class>net.sourceforge.cruisecontrol.servlet.FileServlet</servlet-class>
+        <init-param>
+            <param-name>rootDir</param-name>
+            <param-value>/opt/groovy/cruisecontrol/checkout/dist/</param-value>
+        </init-param>
+    </servlet>
+
+    <servlet>
+        <servlet-name>LogServlet</servlet-name>
+        <servlet-class>net.sourceforge.cruisecontrol.servlet.FileServlet</servlet-class>
+    </servlet>
+
+    <!-- Used for charting... -->
+    <servlet>
+        <servlet-name>CewolfServlet</servlet-name>
+        <servlet-class>de.laures.cewolf.CewolfRenderer</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>CewolfServlet</servlet-name>
+        <url-pattern>/cewolf/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>LogServlet</servlet-name>
+        <url-pattern>/logs/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>ArtifactServlet</servlet-name>
+        <url-pattern>/artifacts/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+      <servlet-name>buildresults</servlet-name>
+      <!-- Strictly speaking, this should be /buildresults for single-project mode. But it works anyway. -->
+      <url-pattern>/buildresults/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>index</servlet-name>
+        <url-pattern>/index</url-pattern>
+    </servlet-mapping>
+
+    <welcome-file-list>
+    	<welcome-file>index.jsp</welcome-file>
+    </welcome-file-list>
+</web-app>
diff --git a/groovy-core/cruise/reporting-app/buildresults.jsp b/groovy-core/cruise/reporting-app/buildresults.jsp
new file mode 100644
index 0000000..1044a29
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/buildresults.jsp
@@ -0,0 +1,58 @@
+<%--********************************************************************************
+* CruiseControl, a Continuous Integration Toolkit
+* Copyright (c) 2001, ThoughtWorks, Inc.
+* 651 W Washington Ave. Suite 600
+* Chicago, IL 60661 USA
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+*     + Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*
+*     + Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*
+*     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+*       names of its contributors may be used to endorse or promote
+*       products derived from this software without specific prior
+*       written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+********************************************************************************--%>
+<%@ taglib uri="/WEB-INF/cruisecontrol-jsp11.tld" prefix="cruisecontrol"%>
+<cruisecontrol:xsl xslFile="/xsl/header.xsl"/>
+
+<cruisecontrol:artifactsLink>
+  <table width="98%" border="0" cellspacing="0" cellpadding="2" align="center">
+    <tr><td class="header-label"><!--<a href="<%= artifacts_url %>">--><a href="http://build.canoo.com/groovy/artifacts/">Build Artifacts</a></td></tr>
+  </table>
+</cruisecontrol:artifactsLink>
+
+<cruisecontrol:xsl xslFile="/xsl/maven.xsl"/>
+<p>
+<cruisecontrol:xsl xslFile="/xsl/checkstyle.xsl"/>
+<p>
+<cruisecontrol:xsl xslFile="/xsl/compile.xsl"/>
+<p>
+<cruisecontrol:xsl xslFile="/xsl/javadoc.xsl"/>
+<p>
+<cruisecontrol:xsl xslFile="/xsl/unittests.xsl"/>
+<p>
+<cruisecontrol:xsl xslFile="/xsl/modifications.xsl"/>
+<p>
+<cruisecontrol:xsl xslFile="/xsl/distributables.xsl"/>
diff --git a/groovy-core/cruise/reporting-app/checkstyle.xml b/groovy-core/cruise/reporting-app/checkstyle.xml
new file mode 100644
index 0000000..2d3bc69
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/checkstyle.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+<!DOCTYPE module PUBLIC
+    "-//Puppy Crawl//DTD Check Configuration 1.1//EN"
+    "http://www.puppycrawl.com/dtds/configuration_1_1.dtd">
+
+<module name="Checker">
+    <module name="Translation"/>   
+    <module name="TreeWalker">
+        <property name="cacheFile" value="target/checkstyle.cache"/>
+        <property name="tabWidth" value="4"/>
+
+        <!-- Naming conventions -->
+        <module name="ConstantName"/>
+        <module name="LocalFinalVariableName"/>
+        <module name="LocalVariableName"/>
+        <module name="MemberName"/>
+        <module name="MethodName"/>
+        <module name="PackageName">
+            <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
+        </module>
+        <module name="ParameterName"/>
+        <module name="StaticVariableName"/>
+        <module name="TypeName"/>
+
+        <!-- Imports -->
+        <module name="AvoidStarImport"/>
+        <module name="IllegalImport"/>
+        <module name="RedundantImport"/>
+        <module name="UnusedImports"/>
+
+        <!-- Size violations -->
+        <module name="FileLength"/>
+        <module name="LineLength">
+            <property name="max" value="120"/>
+        </module>
+        <module name="MethodLength"/>
+        <module name="ParameterNumber"/>
+
+        <!-- Whitespace -->
+        <module name="NoWhitespaceAfter">
+            <property name="tokens"
+                value="BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS, UNARY_PLUS"/>
+        </module>
+        <module name="NoWhitespaceBefore"/>
+        <module name="OperatorWrap"/>
+        <module name="ParenPad"/>
+        <module name="TabCharacter"/>
+        <module name="WhitespaceAfter"/>
+        <module name="WhitespaceAround"/>
+
+        <!-- Modifiers -->
+        <module name="ModifierOrder"/>
+
+        <!-- Blocks -->
+        <module name="EmptyBlock">
+            <property name="tokens"
+                value="LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_TRY, LITERAL_WHILE, STATIC_INIT"/>
+        </module>
+        <module name="LeftCurly"/>
+        <module name="NeedBraces"/>
+        <module name="RightCurly"/>
+        <module name="AvoidNestedBlocks"/>
+
+        <!-- Checks for coding problems -->
+        <module name="DoubleCheckedLocking"/>
+        <module name="HiddenField">
+            <property name="tokens" value="VARIABLE_DEF"/>
+        </module>
+        <module name="InnerAssignment"/>
+        <module name="MissingSwitchDefault"/>
+        <module name="SimplifyBooleanExpression"/>
+        <module name="SimplifyBooleanReturn"/>
+        
+        <!-- Design checks -->
+        <module name="VisibilityModifier">
+            <property name="publicMemberPattern" value="^[a-zA-Z0-9]*$"/>
+        </module>
+        <module name="FinalClass"/>
+        <module name="InterfaceIsType"/>
+        <module name="HideUtilityClassConstructor"/>
+
+        <!-- Miscellaneous -->
+        <module name="UpperEll"/>
+        <module name="ArrayTypeStyle"/>        
+    </module>
+</module>
diff --git a/groovy-core/cruise/reporting-app/controlpanel.jsp b/groovy-core/cruise/reporting-app/controlpanel.jsp
new file mode 100644
index 0000000..04c7836
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/controlpanel.jsp
@@ -0,0 +1,63 @@
+<%--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************--%>
+<%@ taglib uri="/WEB-INF/cruisecontrol-jsp11.tld" prefix="cruisecontrol"%>
+<%@page import="java.net.*,java.io.*"%>
+<%
+    String hostname = "";
+    try
+    {
+        hostname = InetAddress.getLocalHost().getHostName();
+    }
+    catch(IOException e)
+    {
+        hostname = "localhost";
+    }
+%>
+<p>
+<table width="600" align="center" cellpadding="0" cellspacing="0">
+    <tr>
+        <td align="center">
+            <h2>JMX Control Panel</h2>
+        </td>
+    </tr>
+    <tr>
+        <td>
+            <iframe name="controlPanelFrame" id="controlPanelFrame" height="520" marginheight="0" frameborder="1" marginwidth="0" src="http://build.canoo.com:37980" width="605"></iframe>
+        </td>
+    </tr>
+</table>
+</p>
diff --git a/groovy-core/cruise/reporting-app/cruisecontrol.header b/groovy-core/cruise/reporting-app/cruisecontrol.header
new file mode 100644
index 0000000..88205c9
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/cruisecontrol.header
@@ -0,0 +1,36 @@
+/********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2003, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************/
diff --git a/groovy-core/cruise/reporting-app/css/cruisecontrol.css b/groovy-core/cruise/reporting-app/css/cruisecontrol.css
new file mode 100644
index 0000000..c1b5a58
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/css/cruisecontrol.css
@@ -0,0 +1,135 @@
+.host {
+	BACKGROUND-POSITION: 0px -25px; FONT-SIZE: 80%; BACKGROUND-IMAGE: url(/groovy/images/yellowGreenBack.png); BACKGROUND-REPEAT: repeat-x; FONT-FAMILY: verdana, helvetica, arial, sans-serif; HEIGHT: 75px; BACKGROUND-COLOR: #ffffaa; TEXT-ALIGN: right
+}
+.canoo {
+	RIGHT: 20px; POSITION: absolute; TOP: 4px
+}
+.logo {
+    LEFT: 20px; POSITION: relative; TOP: -84px
+}
+
+.white {
+	COLOR: #ffffff
+}
+.navigation {
+    padding-top: 20px;
+    padding-left: 10px;
+	BACKGROUND-COLOR: #ffffaa
+}
+.index {
+	BACKGROUND-COLOR: #ffffff
+}
+.index-passed {
+	COLOR: #004400
+}
+.index-failed {
+	FONT-WEIGHT: bold; COLOR: #ff0000
+}
+.index-header {
+	FONT-WEIGHT: bold
+}
+.link {
+	FONT-SIZE: 10pt; COLOR: #336699; FONT-FAMILY: arial,helvetica,sans-serif; TEXT-DECORATION: none
+}
+.tab-table {
+	MARGIN: 0em 0em 0.5em
+}
+.tabs {
+	PADDING-RIGHT: 2em; PADDING-LEFT: 2em; FONT-WEIGHT: bold; FONT-SIZE: 8pt; PADDING-BOTTOM: 0em; COLOR: #000000; PADDING-TOP: 0em; FONT-FAMILY: arial,helvetica,sans-serif; BACKGROUND-COLOR: #ccccff
+}
+.tabs-link {
+	COLOR: #000000; TEXT-DECORATION: none
+}
+.tabs-link:visited {
+	COLOR: #000000; TEXT-DECORATION: none
+}
+.tabs-selected {
+	PADDING-RIGHT: 2em; PADDING-LEFT: 2em; FONT-WEIGHT: bold; FONT-SIZE: 8pt; PADDING-BOTTOM: 0em; COLOR: #000000; PADDING-TOP: 0em; FONT-FAMILY: arial,helvetica,sans-serif
+}
+.tabs-selected {
+	BORDER-RIGHT: inset; BORDER-TOP: inset; BORDER-LEFT: inset; BORDER-BOTTOM: inset
+}
+.header-title {
+	FONT-WEIGHT: bold; FONT-SIZE: 12pt; COLOR: #336699; FONT-FAMILY: arial,helvetica,sans-serif
+}
+.header-label {
+	FONT-WEIGHT: bold
+}
+.header-data {
+	FONT-SIZE: 10pt; COLOR: #336699; FONT-FAMILY: arial,helvetica,sans-serif
+}
+.modifications-data {
+	FONT-SIZE: 8pt; COLOR: #000000; FONT-FAMILY: arial,helvetica,sans-serif
+}
+.modifications-sectionheader {
+	FONT-SIZE: 10pt; COLOR: #336699; FONT-FAMILY: arial,helvetica,sans-serif; BACKGROUND-COLOR: #ffffaa
+}
+.modifications-oddrow {
+	BACKGROUND-COLOR: #ccccff
+}
+.modifications-evenrow {
+	BACKGROUND-COLOR: #ffffcc
+}
+.changelists-oddrow {
+	BACKGROUND-COLOR: #ccccff
+}
+.changelists-evenrow {
+	BACKGROUND-COLOR: #ffffcc
+}
+.changelists-file-spacer {
+	BACKGROUND-COLOR: #ffffff
+}
+.changelists-file-evenrow {
+	BACKGROUND-COLOR: #eeeeee
+}
+.changelists-file-oddrow {
+	BACKGROUND-COLOR: #ffffee
+}
+.changelists-file-header {
+	FONT-SIZE: 8pt; COLOR: #ffffff; FONT-FAMILY: arial,helvetica,sans-serif; BACKGROUND-COLOR: #666666
+}
+.compile-data {
+	FONT-SIZE: 8pt; COLOR: #000000; FONT-FAMILY: arial,helvetica,sans-serif
+}
+.compile-error-data {
+	FONT-SIZE: 8pt; COLOR: #ff0000; FONT-FAMILY: arial,helvetica,sans-serif
+}
+.compile-warn-data {
+	FONT-SIZE: 8pt; COLOR: #cc9900; FONT-FAMILY: arial,helvetica,sans-serif
+}
+.compile-sectionheader {
+	FONT-SIZE: 10pt; COLOR: #336699; FONT-FAMILY: arial,helvetica,sans-serif; BACKGROUND-COLOR: #ffffaa
+}
+.distributables-data {
+	FONT-SIZE: 8pt; COLOR: #000000; FONT-FAMILY: arial,helvetica,sans-serif
+}
+.distributables-sectionheader {
+	FONT-SIZE: 10pt; COLOR: #336699; FONT-FAMILY: arial,helvetica,sans-serif; BACKGROUND-COLOR: #ffffaa
+}
+.distributables-oddrow {
+	BACKGROUND-COLOR: #ccccff
+}
+.unittests-sectionheader {
+	FONT-SIZE: 10pt; COLOR: #336699; FONT-FAMILY: arial,helvetica,sans-serif; BACKGROUND-COLOR: #ffffaa
+}
+.unittests-oddrow {
+	BACKGROUND-COLOR: #ccccff
+}
+.unittests-data {
+	FONT-SIZE: 8pt; COLOR: #000000; FONT-FAMILY: arial,helvetica,sans-serif
+}
+.unittests-error {
+	FONT-SIZE: 8pt; COLOR: #901090; FONT-FAMILY: arial,helvetica,sans-serif
+}
+.unittests-failure {
+	FONT-SIZE: 8pt; COLOR: #ff0000; FONT-FAMILY: arial,helvetica,sans-serif
+}
+.checkstyle-oddrow {
+	BACKGROUND-COLOR: #ccccff
+}
+.checkstyle-data {
+	FONT-SIZE: 8pt; COLOR: #000000; FONT-FAMILY: arial,helvetica,sans-serif
+}
+.checkstyle-sectionheader {
+	FONT-SIZE: 10pt; COLOR: #336699; FONT-FAMILY: arial,helvetica,sans-serif; BACKGROUND-COLOR: #ffffaa
+}
diff --git a/groovy-core/cruise/reporting-app/images/backhead2.png b/groovy-core/cruise/reporting-app/images/backhead2.png
new file mode 100644
index 0000000..d8e06eb
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/backhead2.png
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/blank35.gif b/groovy-core/cruise/reporting-app/images/blank35.gif
new file mode 100644
index 0000000..d60dd2e
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/blank35.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/blank8.gif b/groovy-core/cruise/reporting-app/images/blank8.gif
new file mode 100644
index 0000000..9cbf371
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/blank8.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/bluebg.gif b/groovy-core/cruise/reporting-app/images/bluebg.gif
new file mode 100644
index 0000000..02711ce
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/bluebg.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/bluestripesbottom.gif b/groovy-core/cruise/reporting-app/images/bluestripesbottom.gif
new file mode 100644
index 0000000..6bbea1c
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/bluestripesbottom.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/bluestripestop.gif b/groovy-core/cruise/reporting-app/images/bluestripestop.gif
new file mode 100644
index 0000000..6bbea1c
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/bluestripestop.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/buildResultsTab-off.gif b/groovy-core/cruise/reporting-app/images/buildResultsTab-off.gif
new file mode 100644
index 0000000..77aa777
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/buildResultsTab-off.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/buildResultsTab-on.gif b/groovy-core/cruise/reporting-app/images/buildResultsTab-on.gif
new file mode 100644
index 0000000..6322f78
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/buildResultsTab-on.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/canoo_rgb_pos.gif b/groovy-core/cruise/reporting-app/images/canoo_rgb_pos.gif
new file mode 100644
index 0000000..2504f28
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/canoo_rgb_pos.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/continuousintegration.gif b/groovy-core/cruise/reporting-app/images/continuousintegration.gif
new file mode 100644
index 0000000..2040e5e
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/continuousintegration.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/controlPanelTab-off.gif b/groovy-core/cruise/reporting-app/images/controlPanelTab-off.gif
new file mode 100644
index 0000000..8a01d18
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/controlPanelTab-off.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/controlPanelTab-on.gif b/groovy-core/cruise/reporting-app/images/controlPanelTab-on.gif
new file mode 100644
index 0000000..25acd52
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/controlPanelTab-on.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/logo.gif b/groovy-core/cruise/reporting-app/images/logo.gif
new file mode 100644
index 0000000..79abe20
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/logo.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/testResultsTab-off.gif b/groovy-core/cruise/reporting-app/images/testResultsTab-off.gif
new file mode 100644
index 0000000..2c7b0da
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/testResultsTab-off.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/testResultsTab-on.gif b/groovy-core/cruise/reporting-app/images/testResultsTab-on.gif
new file mode 100644
index 0000000..563140e
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/testResultsTab-on.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/xmlLogFileTab-off.gif b/groovy-core/cruise/reporting-app/images/xmlLogFileTab-off.gif
new file mode 100644
index 0000000..0a4c8ed
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/xmlLogFileTab-off.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/xmlLogFileTab-on.gif b/groovy-core/cruise/reporting-app/images/xmlLogFileTab-on.gif
new file mode 100644
index 0000000..fec9104
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/xmlLogFileTab-on.gif
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/images/yellowGreenBack.png b/groovy-core/cruise/reporting-app/images/yellowGreenBack.png
new file mode 100644
index 0000000..6b2395b
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/images/yellowGreenBack.png
Binary files differ
diff --git a/groovy-core/cruise/reporting-app/index.jsp b/groovy-core/cruise/reporting-app/index.jsp
new file mode 100644
index 0000000..d2caeab
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/index.jsp
@@ -0,0 +1,155 @@
+<%@ page import="java.io.File,
+                 java.util.Arrays,
+                 java.util.Calendar"%>
+ <%--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************--%>
+<jsp:useBean id="statusHelper" scope="page" class="net.sourceforge.cruisecontrol.StatusHelper" />
+<%
+    String singleProjectMode = application.getInitParameter("singleProject");
+    if (Boolean.valueOf(singleProjectMode).booleanValue()) {
+       %><jsp:forward page="buildresults" /><%
+        return;
+    }
+
+    StringBuffer reportTime = new StringBuffer();
+    Calendar now = Calendar.getInstance();
+    reportTime.append(now.get(Calendar.HOUR_OF_DAY));
+    reportTime.append(":");
+    String minutes = String.valueOf(now.get(Calendar.MINUTE));
+    if (minutes.length() == 1) {
+        minutes = 0 + minutes;
+    }
+    reportTime.append(minutes);
+
+    boolean autoRefresh = "true".equals(request.getParameter("auto_refresh"));
+%>
+<html>
+<head>
+  <title>CruiseControl Status Page</title>
+  <base href="<%=request.getScheme()%>://<%=request.getServerName()%>:<%=request.getServerPort()%><%=request.getContextPath()%>/" />
+  <link type="text/css" rel="stylesheet" href="css/cruisecontrol.css"/>
+  <%
+     if (autoRefresh) { 
+  %>
+  <META HTTP-EQUIV="Refresh" CONTENT="10">
+  <%
+     }
+  %>
+</head>
+<body background="images/bluebg.gif" topmargin="0" leftmargin="0" marginheight="0" marginwidth="0">
+<p>&nbsp;</p>
+
+<h1 class="white" align="center">CruiseControl Status Page</h1>
+
+<table align="center" border="0" cellpadding="0" cellspacing="0" width="70%">
+<tfoot>
+  <tr><td class="link">listing generated at <%=reportTime.toString()%></td></tr>
+</tfoot>
+<tbody>
+<tr><td align="right">
+  <%
+     if (autoRefresh) {
+  %>
+    <a class="white" href="?auto_refresh=false">Turn autorefresh off</a>
+  <%
+     } else {
+  %>
+    <a class="white" href="?auto_refresh=true">Turn autorefresh on</a>
+  <%
+     }
+  %>
+  </td></tr>
+  <tr><td>&nbsp;</td></tr>
+  <tr><td bgcolor="#FFFFFF"><img border="0" src="images/bluestripestop.gif"></td></tr>
+  <tr><td><table class="index" width="100%">
+<%
+   String logDirPath = application.getInitParameter("logDir");
+   if (logDirPath == null) {
+       %><tr><td>You need to provide a value for the context parameter <code>&quot;logDir&quot;</code></td></tr><%
+   } else {
+       java.io.File logDir = new java.io.File(logDirPath);
+       if (logDir.isDirectory() == false) {
+           %><tr><td>Context parameter logDir needs to be set to a directory. Currently set to &quot;<%=logDirPath%>&quot;</td></tr><%
+       } else {
+           String[] projectDirs = logDir.list(new java.io.FilenameFilter() {
+               public boolean accept(File dir, String name) {
+                   return (new File(dir, name).isDirectory());
+               }
+           });
+
+           if (projectDirs.length == 0) {
+               %><tr><td>no project directories found under <%=logDirPath%></td></tr><%
+           }
+           else {
+%>    <thead class="index-header">
+      <tr>
+        <td>Project</td>
+        <td align="center">Last build result</td>
+        <td align="center">Last build time</td>
+        <td align="center">Last successful build time</td>
+        <td align="center">Last label</td>
+    </tr>
+    </thead>
+    <tbody>
+ <%
+               Arrays.sort(projectDirs);
+             for (int i = 0; i < projectDirs.length; i++) {
+                   String project = projectDirs[i];
+                   File projectDir = new File(logDir, project);
+                   statusHelper.setProjectDirectory(projectDir);
+                 final String result = statusHelper.getLastBuildResult();
+         %>        <tr><td><a href="buildresults/<%=project%>"><%=project%></a></td><%
+                 %><td class="index-<%=result%>" align="center"><%=result%></td><%
+                 %><td align="center"><%=statusHelper.getLastBuildTimeString(request.getLocale())%></td><%
+                 %><td align="center"><%=statusHelper.getLastSuccessfulBuildTimeString(request.getLocale())%></td><%
+                 %><td><%=statusHelper.getLastSuccessfulBuildLabel()%></td>
+                   </tr>
+ <%
+               }
+         %>    </tbody>
+<%
+           }
+       }
+   }
+%></table></td></tr>
+  <tr><td bgcolor="#FFFFFF"><img border="0" src="images/bluestripesbottom.gif"></td></tr>
+  <tr><td>&nbsp;</td></tr>
+</tbody>
+</table>
+</body>
+</html>
+
diff --git a/groovy-core/cruise/reporting-app/main.jsp b/groovy-core/cruise/reporting-app/main.jsp
new file mode 100644
index 0000000..6cdbdde
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/main.jsp
@@ -0,0 +1,85 @@
+<%--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************--%>
+<%@page contentType="text/html"%>
+<%@ taglib uri="/WEB-INF/cruisecontrol-jsp11.tld" prefix="cruisecontrol"%>
+<html>
+<head>
+  <title>groovy: CruiseControl Build Results</title>
+  <base href="<%=request.getScheme()%>://<%=request.getServerName()%>:<%=request.getServerPort()%><%=request.getContextPath()%>/" />
+  <link type="text/css" rel="stylesheet" href="css/cruisecontrol.css"/>
+</head>
+<body topmargin="0" leftmargin="0" marginheight="0" marginwidth="0">
+  <table border="0" align="center" cellpadding="0" cellspacing="0" width="100%">
+    <tr><td colspan="2" class="host">
+        <div class="canoo">hosted by<br><a href="http://www.canoo.com"><img border="0" height="20" width="112" src="images/canoo_rgb_pos.gif"></a>
+        </div></td></tr>
+    <tr>
+      <td valign="top" class="navigation">
+        <%@ include file="navigation.jsp" %>
+      </td>
+      <td valign="top">
+        &nbsp;<br>
+        <cruisecontrol:tabsheet>
+          <tr>
+            <td bgcolor="white" >
+              <cruisecontrol:tab name="buildResults" label="Build Results" >
+                <%@ include file="buildresults.jsp" %>
+              </cruisecontrol:tab>
+
+              <cruisecontrol:tab name="testResults" label="Test Results" >
+                <%@ include file="testdetails.jsp" %>
+              </cruisecontrol:tab>
+
+              <cruisecontrol:tab name="xmlLogFile" label="XML Log File" >
+                <%@ include file="xmllog.jsp" %>
+              </cruisecontrol:tab>
+
+              <cruisecontrol:tab name="metrics" label="Metrics" >
+                <%@ include file="metrics.jsp" %>
+              </cruisecontrol:tab>
+
+              <cruisecontrol:tab name="controlPanel" label="Control Panel" >
+                <%@ include file="controlpanel.jsp" %>
+              </cruisecontrol:tab>
+            </td>
+          </tr>
+        </cruisecontrol:tabsheet>
+      </td>
+    </tr>
+  </table>
+</body>
+</html>
diff --git a/groovy-core/cruise/reporting-app/metrics.jsp b/groovy-core/cruise/reporting-app/metrics.jsp
new file mode 100644
index 0000000..d1f531f
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/metrics.jsp
@@ -0,0 +1,35 @@
+<%@page import="net.sourceforge.cruisecontrol.*, net.sourceforge.cruisecontrol.chart.*"%>
+<%@taglib uri='WEB-INF/lib/cewolf.jar' prefix='cewolf' %>
+<%@ taglib uri="/WEB-INF/cruisecontrol-jsp11.tld" prefix="cruisecontrol"%>
+
+<cruisecontrol:buildInfo />
+
+<table>
+  <tr><td>Number of Build Attempts</td><td><%=build_info.size() %></td></tr>
+  <tr><td>Number of Broken Builds</td><td><%=build_info.getNumBrokenBuilds() %></td></tr>
+  <tr><td>Number of Successful Builds</td><td><%=build_info.getNumSuccessfulBuilds() %></td></tr>
+</table>
+
+<hr />
+<jsp:useBean id="pieData" class="net.sourceforge.cruisecontrol.chart.PieChartData" />
+<cewolf:chart id="pie" title="Breakdown of build types" type="pie" >
+    <cewolf:data>
+        <cewolf:producer id="pieData">
+          <cewolf:param name="buildInfo" value="<%=build_info%>" />
+        </cewolf:producer>
+    </cewolf:data>
+</cewolf:chart>
+<cewolf:img chartid="pie" renderer="cewolf" width="400" height="300"/>
+
+<hr />
+<jsp:useBean id="chartData" class="net.sourceforge.cruisecontrol.chart.TimeChartData" />
+<cewolf:chart id="chart" title="Breakdown of build types" type="timeseries"  xaxislabel="date" yaxislabel="time">
+    <cewolf:data>
+        <cewolf:producer id="chartData">
+          <cewolf:param name="buildInfo" value="<%=build_info%>" />
+        </cewolf:producer>
+    </cewolf:data>
+    <cewolf:chartpostprocessor id="chartData" />
+</cewolf:chart>
+<cewolf:img chartid="chart" renderer="cewolf" width="400" height="300"/>
+
diff --git a/groovy-core/cruise/reporting-app/navigation.jsp b/groovy-core/cruise/reporting-app/navigation.jsp
new file mode 100644
index 0000000..75817a1
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/navigation.jsp
@@ -0,0 +1,57 @@
+<%--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************--%>
+<%@ taglib uri="/WEB-INF/cruisecontrol-jsp11.tld" prefix="cruisecontrol"%>
+        
+        <DIV class=logo><h1><a href="http://build.canoo.com/groovy" border="0">groovy</a></h1><div><p>
+        <table border="0" align="center" width="98%">
+            <tr><td><cruisecontrol:currentbuildstatus/></td></tr>
+            <tr><td>&nbsp;</td></tr>
+            <cruisecontrol:link id="baseUrl" />
+            <tr><td><a class="link" href="<%=baseUrl%>">Latest Build</a></td></tr>
+            <cruisecontrol:nav startingBuildNumber="0" finalBuildNumber="10" >
+                <tr><td><a class="link" href="<%= url %>"><%= linktext %></a></td></tr>
+            </cruisecontrol:nav>
+            <tr><td>
+              <form method="GET" action="<%=baseUrl%>" >
+                <select name="log" onchange="form.submit()">
+                  <cruisecontrol:nav startingBuildNumber="10">
+                    <option value="<%=logfile%>"><%= linktext %></option>
+                  </cruisecontrol:nav>
+                </select>
+              </form>
+            </td></tr>
+        </table>
diff --git a/groovy-core/cruise/reporting-app/testdetails.jsp b/groovy-core/cruise/reporting-app/testdetails.jsp
new file mode 100644
index 0000000..9e68af6
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/testdetails.jsp
@@ -0,0 +1,39 @@
+<%--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************--%>
+<%@ taglib uri="/WEB-INF/cruisecontrol-jsp11.tld" prefix="cruisecontrol"%>
+
+<cruisecontrol:xsl xslFile="/xsl/testdetails.xsl"/>
diff --git a/groovy-core/cruise/reporting-app/xmllog.jsp b/groovy-core/cruise/reporting-app/xmllog.jsp
new file mode 100644
index 0000000..626fe91
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/xmllog.jsp
@@ -0,0 +1,38 @@
+<%--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************--%>
+<%@ taglib uri="/WEB-INF/cruisecontrol-jsp11.tld" prefix="cruisecontrol"%>
+<pre class="modifications-data"><cruisecontrol:xsl xslFile="/xsl/logfile.xsl"/></pre>
diff --git a/groovy-core/cruise/reporting-app/xsl/changelists/header.xsl b/groovy-core/cruise/reporting-app/xsl/changelists/header.xsl
new file mode 100644
index 0000000..8fb61b5
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/xsl/changelists/header.xsl
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+<!--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************-->
+<xsl:stylesheet
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+    xmlns:lxslt="http://xml.apache.org/xslt">
+
+    <xsl:output method="html"/>
+
+    <xsl:template match="/">
+        <table align="center" cellpadding="2" cellspacing="0" border="0" width="98%">
+
+            <xsl:if test="cruisecontrol/build/@error">
+                <tr><td class="header-title">BUILD FAILED</td></tr>
+                <tr><td class="header-data">
+                    <span class="header-label">Error Message:&#160;</span>
+                    <xsl:value-of select="cruisecontrol/build/@error"/>
+                </td></tr>
+            </xsl:if>
+
+            <xsl:if test="not (cruisecontrol/build/@error)">
+                <tr><td class="header-title">BUILD COMPLETE&#160;-&#160;
+                    <xsl:value-of select="cruisecontrol/info/property[@name='label']/@value"/>
+                </td></tr>
+            </xsl:if>
+
+            <tr><td class="header-data">
+                <span class="header-label">Date of build:&#160;</span>
+                <xsl:value-of select="cruisecontrol/info/property[@name='lastbuild']/@value"/>
+            </td></tr>
+            <tr><td class="header-data">
+                <span class="header-label">Time to build:&#160;</span>
+                <xsl:value-of select="cruisecontrol/build/@time"/>
+            </td></tr>
+            <tr>
+                <td class="header-data">
+                    <span class="header-label">Last changed:&#160;</span>
+                    <xsl:value-of select="cruisecontrol/modifications/changelist/@dateOfSubmission"/>
+                </td>
+            </tr>
+            <tr>
+                <td class="header-data">
+                    <span class="header-label">Last log entry:&#160;</span>
+                    <xsl:value-of select="cruisecontrol/modifications/changelist/description"/>
+                </td>
+            </tr>
+        </table>
+    </xsl:template>
+
+</xsl:stylesheet>
diff --git a/groovy-core/cruise/reporting-app/xsl/checkstyle.xsl b/groovy-core/cruise/reporting-app/xsl/checkstyle.xsl
new file mode 100644
index 0000000..f0dac4b
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/xsl/checkstyle.xsl
@@ -0,0 +1,68 @@
+<?xml version="1.0"?>
+<!--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+    <xsl:output method="html"/>
+
+    <xsl:template match="/">
+        <xsl:apply-templates select="cruisecontrol/checkstyle"/>
+    </xsl:template>
+
+    <xsl:template match="checkstyle[file/error]">
+        <xsl:variable name="file.error.count" select="count(file[error])" />
+        <xsl:variable name="total.error.count" select="count(file/error)" />
+        <table align="center" cellpadding="2" cellspacing="0" border="0" width="98%">
+          <tr>
+            <td class="checkstyle-sectionheader" colspan="3">
+                Checkstyle errors (<xsl:value-of select="$total.error.count" />)
+            </td>
+          </tr>
+          <xsl:for-each select="file/error" >
+            <tr>
+              <xsl:if test="position() mod 2 = 1">
+                <xsl:attribute name="class">checkstyle-oddrow</xsl:attribute>
+              </xsl:if>
+              <td class="checkstyle-data"><xsl:value-of select="../@name" /></td>
+              <td class="checkstyle-data"><xsl:value-of select="@line" /></td>
+              <td class="checkstyle-data"><xsl:value-of select="@message" /></td>
+            </tr>
+          </xsl:for-each>
+        </table>
+    </xsl:template>
+
+<!--    <xsl:template match="*|@*|text()" />-->
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/groovy-core/cruise/reporting-app/xsl/compile.xsl b/groovy-core/cruise/reporting-app/xsl/compile.xsl
new file mode 100644
index 0000000..a402a0e
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/xsl/compile.xsl
@@ -0,0 +1,119 @@
+<?xml version="1.0"?>
+<!--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************-->
+<xsl:stylesheet
+    version="1.0"
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns="http://www.w3.org/TR/html4/strict.dtd" >
+
+    <xsl:output method="html"/>
+
+    <xsl:variable name="tasklist" select="/cruisecontrol/build//target/task"/>
+    <xsl:variable name="javac.tasklist" select="$tasklist[@name='Javac'] | $tasklist[@name='javac'] | $tasklist[@name='compilewithwalls']"/>
+    <xsl:variable name="ejbjar.tasklist" select="$tasklist[@name='EjbJar'] | $tasklist[@name='ejbjar']"/>
+
+    <xsl:template match="/">
+
+        <xsl:variable name="javac.error.messages" select="$javac.tasklist/message[@priority='error'][text() != '']"/>
+        <xsl:variable name="javac.warn.messages" select="$javac.tasklist/message[@priority='warn'][text() != '']"/>
+        <xsl:variable name="ejbjar.error.messages" select="$ejbjar.tasklist/message[@priority='error'][text() != '']"/>
+        <xsl:variable name="ejbjar.warn.messages" select="$ejbjar.tasklist/message[@priority='warn'][text() != '']"/>
+        <xsl:variable name="total.errorMessage.count" select="count($javac.warn.messages) + count($ejbjar.warn.messages) + count($javac.error.messages) + count($ejbjar.error.messages)"/>
+
+        <xsl:if test="$total.errorMessage.count > 0">
+            <table align="center" cellpadding="2" cellspacing="0" border="0" width="98%">
+                <tr>
+                    <!-- NOTE: total.errorMessage.count is actually the number of lines of error
+                     messages. This accurately represents the number of errors ONLY if the Ant property
+                     build.compiler.emacs is set to "true" -->
+                    <td class="compile-sectionheader">
+                        &#160;Errors/Warnings: (<xsl:value-of select="$total.errorMessage.count"/>)
+                    </td>
+                </tr>
+                <xsl:if test="count($javac.error.messages) > 0">
+                    <tr>
+                        <td>
+                           <pre class="compile-error-data">
+                            <xsl:apply-templates select="$javac.error.messages"/>
+                           </pre>
+                        </td>
+                    </tr>
+                </xsl:if>
+                <xsl:if test="count($javac.warn.messages) > 0">
+                    <tr>
+                        <td>
+                           <pre class="compile-data">
+                            <xsl:apply-templates select="$javac.warn.messages"/>
+                           </pre>
+                        </td>
+                    </tr>
+                </xsl:if>
+                <xsl:if test="count($ejbjar.error.messages) > 0">
+                    <tr>
+                        <td>
+                           <pre class="compile-error-data">
+                            <xsl:apply-templates select="$ejbjar.error.messages"/>
+                           </pre>
+                        </td>
+                    </tr>
+                </xsl:if>
+                <xsl:if test="count($ejbjar.warn.messages) > 0">
+                    <tr>
+                        <td>
+                           <pre class="compile-warn-data">
+                            <xsl:apply-templates select="$ejbjar.warn.messages"/>
+                           </pre>
+                        </td>
+                    </tr>
+                </xsl:if>
+            </table>
+        </xsl:if>
+
+    </xsl:template>
+
+    <xsl:template match="message[@priority='error']">
+        <xsl:value-of select="text()"/>
+        <xsl:if test="count(./../message[@priority='error']) != position()">
+            <br class="none"/>
+        </xsl:if>
+    </xsl:template>
+
+    <xsl:template match="message[@priority='warn']">
+        <xsl:value-of select="text()"/><br class="none"/>
+    </xsl:template>
+
+</xsl:stylesheet>
diff --git a/groovy-core/cruise/reporting-app/xsl/distributables.xsl b/groovy-core/cruise/reporting-app/xsl/distributables.xsl
new file mode 100644
index 0000000..c954b9d
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/xsl/distributables.xsl
@@ -0,0 +1,77 @@
+<?xml version="1.0"?>
+<!--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************-->
+
+<xsl:stylesheet
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+    xmlns:lxslt="http://xml.apache.org/xslt">
+
+    <xsl:output method="html"/>
+    <xsl:variable name="tasklist" select="/cruisecontrol/build//target/task"/>
+    <xsl:variable name="jar.tasklist" select="$tasklist[@name='Jar']/message[@priority='info'] | $tasklist[@name='jar']/message[@priority='info']"/>
+    <xsl:variable name="war.tasklist" select="$tasklist[@name='War']/message[@priority='info'] | $tasklist[@name='war']/message[@priority='info']"/>
+    <xsl:variable name="ejbjar.tasklist" select="$tasklist[@name='ejbjar']/message[@priority='info']"/>
+    <xsl:variable name="ear.tasklist" select="$tasklist[@name='ear']/message[@priority='info']"/>
+    <xsl:variable name="dist.count" select="count($jar.tasklist) + count($war.tasklist) + count($ejbjar.tasklist) + count($ear.tasklist)"/>
+
+    <xsl:template match="/">
+        <table align="center" cellpadding="2" cellspacing="0" border="0" width="98%">
+
+            <xsl:if test="$dist.count > 0">
+                <tr>
+                    <td class="distributables-sectionheader">
+                        &#160;Deployments by this build:&#160;(<xsl:value-of select="$dist.count"/>)
+                    </td>
+                </tr>
+                <xsl:apply-templates select="$jar.tasklist | $war.tasklist | $ejbjar.tasklist | $ear.tasklist" />
+            </xsl:if>
+
+        </table>
+    </xsl:template>
+
+    <xsl:template match="task[@name='Jar']/message[@priority='info'] | task[@name='War']/message[@priority='info'] | task[@name='jar']/message[@priority='info'] | task[@name='war']/message[@priority='info'] | task[@name='ejbjar']/message[@priority='info'] | task[@name='ear']/message[@priority='info']">
+        <tr>
+            <xsl:if test="position() mod 2 = 0">
+                <xsl:attribute name="class">distributables-oddrow</xsl:attribute>
+            </xsl:if>
+            <td class="distributables-data">
+                <xsl:value-of select="text()"/>
+            </td>
+        </tr>
+    </xsl:template>
+
+</xsl:stylesheet>
diff --git a/groovy-core/cruise/reporting-app/xsl/header.xsl b/groovy-core/cruise/reporting-app/xsl/header.xsl
new file mode 100644
index 0000000..585a0b8
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/xsl/header.xsl
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<!--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************-->
+<xsl:stylesheet
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+    xmlns:lxslt="http://xml.apache.org/xslt">
+
+    <xsl:output method="html"/>
+
+    <xsl:template match="/">
+        <xsl:variable name="modification.list" select="cruisecontrol/modifications/modification"/>
+
+        <table align="center" cellpadding="2" cellspacing="0" border="0" width="98%">
+
+            <xsl:if test="cruisecontrol/build/@error">
+                <tr><td class="header-title">BUILD FAILED</td></tr>
+                <tr><td class="header-data">
+                    <span class="header-label">Ant Error Message:&#160;</span>
+                    <xsl:value-of select="cruisecontrol/build/@error"/>
+                </td></tr>
+            </xsl:if>
+
+            <xsl:if test="not (cruisecontrol/build/@error)">
+                <tr><td class="header-title">BUILD COMPLETE&#160;-&#160;
+                    <xsl:value-of select="cruisecontrol/info/property[@name='label']/@value"/>
+                </td></tr>
+            </xsl:if>
+
+            <tr><td class="header-data">
+                <span class="header-label">Date of build:&#160;</span>
+                <xsl:value-of select="cruisecontrol/info/property[@name='builddate']/@value"/>
+            </td></tr>
+            <tr><td class="header-data">
+                <span class="header-label">Time to build:&#160;</span>
+                <xsl:value-of select="cruisecontrol/build/@time"/>
+            </td></tr>
+            <xsl:apply-templates select="$modification.list">
+                <xsl:sort select="date" order="descending" data-type="text" />
+            </xsl:apply-templates>
+        </table>
+    </xsl:template>
+
+    <!-- Last Modification template -->
+    <xsl:template match="modification">
+        <xsl:if test="position() = 1">
+            <tr><td class="header-data">
+                <span class="header-label">Last changed:&#160;</span>
+                <xsl:value-of select="date"/>
+            </td></tr>
+            <tr><td class="header-data">
+                <span class="header-label">Last log entry:&#160;</span>
+                <xsl:value-of select="comment"/>
+            </td></tr>
+        </xsl:if>
+    </xsl:template>
+</xsl:stylesheet>
diff --git a/groovy-core/cruise/reporting-app/xsl/javadoc.xsl b/groovy-core/cruise/reporting-app/xsl/javadoc.xsl
new file mode 100644
index 0000000..38e1b57
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/xsl/javadoc.xsl
@@ -0,0 +1,98 @@
+<?xml version="1.0"?>
+<!--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************-->
+<xsl:stylesheet
+    version="1.0"
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns="http://www.w3.org/TR/html4/strict.dtd" >
+
+    <xsl:output method="html"/>
+
+    <xsl:variable name="tasklist" select="/cruisecontrol/build//target/task"/>
+    <xsl:variable name="javadoc.tasklist" select="$tasklist[@name='Javadoc'] | $tasklist[@name='javadoc']"/>
+
+    <xsl:template match="/">
+
+        <xsl:variable name="javadoc.error.messages" select="$javadoc.tasklist/message[@priority='error']"/>
+        <xsl:variable name="javadoc.warn.messages" select="$javadoc.tasklist/message[@priority='warn']"/>
+        <xsl:variable name="total.errorMessage.count" select="count($javadoc.warn.messages)  + count($javadoc.error.messages)"/>
+
+        <xsl:if test="$total.errorMessage.count > 0">
+            <table align="center" cellpadding="2" cellspacing="0" border="0" width="98%">
+                <tr>
+                    <!-- NOTE: total.errorMessage.count is actually the number of lines of error
+                     messages. This accurately represents the number of errors ONLY if the Ant property
+                     build.compiler.emacs is set to "true" -->
+                    <td class="compile-sectionheader">
+                        &#160;Javadoc Errors/Warnings: (<xsl:value-of select="$total.errorMessage.count"/>)
+                    </td>
+                </tr>
+                <xsl:if test="count($javadoc.error.messages) > 0">
+                    <tr>
+                        <td>
+                           <pre class="compile-error-data">
+                            <xsl:apply-templates select="$javadoc.error.messages"/>
+                           </pre>
+                        </td>
+                    </tr>
+                </xsl:if>
+                <xsl:if test="count($javadoc.warn.messages) > 0">
+                    <tr>
+                        <td>
+                           <pre class="compile-data">
+                            <xsl:apply-templates select="$javadoc.warn.messages"/>
+                           </pre>
+                        </td>
+                    </tr>
+                </xsl:if>
+            </table>
+        </xsl:if>
+
+    </xsl:template>
+
+    <xsl:template match="message[@priority='error']">
+        <xsl:value-of select="text()"/>
+        <xsl:if test="count(./../message[@priority='error']) != position()">
+            <br/>
+        </xsl:if>
+    </xsl:template>
+
+    <xsl:template match="message[@priority='warn']">
+        <xsl:value-of select="text()"/><br/>
+    </xsl:template>
+
+</xsl:stylesheet>
diff --git a/groovy-core/cruise/reporting-app/xsl/logfile.xsl b/groovy-core/cruise/reporting-app/xsl/logfile.xsl
new file mode 100644
index 0000000..d97708b
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/xsl/logfile.xsl
@@ -0,0 +1,313 @@
+<!--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************-->
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:output omit-xml-declaration="yes" method="html"/>
+
+  <xsl:param name="use-empty-syntax" select="true()"/>
+  <xsl:param name="exclude-unused-prefixes" select="true()"/>
+
+  <xsl:param name="start-tag-start"     select="'&lt;'"/>
+  <xsl:param name="start-tag-end"       select="'>'"/>
+  <xsl:param name="empty-tag-end"       select="'/>'"/>
+  <xsl:param name="end-tag-start"       select="'&lt;/'"/>
+  <xsl:param name="end-tag-end"         select="'>'"/>
+  <xsl:param name="space"               select="' '"/>
+  <xsl:param name="ns-decl"             select="'xmlns'"/>
+  <xsl:param name="colon"               select="':'"/>
+  <xsl:param name="equals"              select="'='"/>
+  <xsl:param name="attribute-delimiter" select="'&quot;'"/>
+  <xsl:param name="comment-start"       select="'&lt;!--'"/>
+  <xsl:param name="comment-end"         select="'-->'"/>
+  <xsl:param name="pi-start"            select="'&lt;?'"/>
+  <xsl:param name="pi-end"              select="'?>'"/>
+
+  <xsl:template name="xml-to-string">
+    <xsl:param name="node-set" select="."/>
+    <xsl:apply-templates select="$node-set" mode="xml-to-string">
+      <xsl:with-param name="depth" select="1"/>
+    </xsl:apply-templates>
+  </xsl:template>
+
+  <xsl:template match="/" name="xml-to-string-root-rule">
+    <xsl:call-template name="xml-to-string"/>
+  </xsl:template>
+
+  <xsl:template match="/" mode="xml-to-string">
+    <xsl:param name="depth"/>
+    <xsl:apply-templates mode="xml-to-string">
+      <xsl:with-param name="depth" select="$depth"/>
+    </xsl:apply-templates>
+  </xsl:template>
+
+  <xsl:template match="*" mode="xml-to-string">
+    <xsl:param name="depth"/>
+    <xsl:variable name="element" select="."/>
+    <xsl:value-of select="$start-tag-start"/>
+    <xsl:call-template name="element-name">
+      <xsl:with-param name="text" select="name()"/>
+    </xsl:call-template>
+    <xsl:apply-templates select="@*" mode="xml-to-string"/>
+    <xsl:for-each select="namespace::*">
+      <xsl:call-template name="process-namespace-node">
+        <xsl:with-param name="element" select="$element"/>
+        <xsl:with-param name="depth" select="$depth"/>
+      </xsl:call-template>
+    </xsl:for-each>
+    <xsl:choose>
+      <xsl:when test="node() or not($use-empty-syntax)">
+        <xsl:value-of select="$start-tag-end"/>
+        <xsl:apply-templates mode="xml-to-string">
+          <xsl:with-param name="depth" select="$depth + 1"/>
+        </xsl:apply-templates>
+        <xsl:value-of select="$end-tag-start"/>
+        <xsl:call-template name="element-name">
+          <xsl:with-param name="text" select="name()"/>
+        </xsl:call-template>
+        <xsl:value-of select="$end-tag-end"/>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="$empty-tag-end"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="process-namespace-node">
+    <xsl:param name="element"/>
+    <xsl:param name="depth"/>
+    <xsl:variable name="declaredAbove">
+      <xsl:call-template name="isDeclaredAbove">
+        <xsl:with-param name="depth" select="$depth - 1"/>
+        <xsl:with-param name="element" select="$element/.."/>
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:if test="(not($exclude-unused-prefixes) or ($element | $element//@* | $element//*)[namespace-uri()=current()]) and not(string($declaredAbove)) and name()!='xml'">
+      <xsl:value-of select="$space"/>
+      <xsl:value-of select="$ns-decl"/>
+      <xsl:if test="name()">
+        <xsl:value-of select="$colon"/>
+        <xsl:call-template name="ns-prefix">
+          <xsl:with-param name="text" select="name()"/>
+        </xsl:call-template>
+      </xsl:if>
+      <xsl:value-of select="$equals"/>
+      <xsl:value-of select="$attribute-delimiter"/>
+      <xsl:call-template name="ns-uri">
+        <xsl:with-param name="text" select="string(.)"/>
+      </xsl:call-template>
+      <xsl:value-of select="$attribute-delimiter"/>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template name="isDeclaredAbove">
+    <xsl:param name="element"/>
+    <xsl:param name="depth"/>
+    <xsl:if test="$depth > 0">
+      <xsl:choose>
+        <xsl:when test="$element/namespace::*[name(.)=name(current()) and .=current()]">1</xsl:when>
+        <xsl:when test="$element/namespace::*[name(.)=name(current())]"/>
+        <xsl:otherwise>
+          <xsl:call-template name="isDeclaredAbove">
+            <xsl:with-param name="depth" select="$depth - 1"/>
+            <xsl:with-param name="element" select="$element/.."/>
+          </xsl:call-template>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template match="@*" mode="xml-to-string">
+    <xsl:value-of select="$space"/>
+    <xsl:call-template name="attribute-name">
+      <xsl:with-param name="text" select="name()"/>
+    </xsl:call-template>
+    <xsl:value-of select="$equals"/>
+    <xsl:value-of select="$attribute-delimiter"/>
+    <xsl:call-template name="attribute-value">
+      <xsl:with-param name="text" select="string(.)"/>
+    </xsl:call-template>
+    <xsl:value-of select="$attribute-delimiter"/>
+  </xsl:template>
+
+  <xsl:template match="comment()" mode="xml-to-string">
+    <xsl:value-of select="$comment-start"/>
+    <xsl:call-template name="comment-text">
+      <xsl:with-param name="text" select="string(.)"/>
+    </xsl:call-template>
+    <xsl:value-of select="$comment-end"/>
+  </xsl:template>
+
+  <xsl:template match="processing-instruction()" mode="xml-to-string">
+    <xsl:value-of select="$pi-start"/>
+    <xsl:call-template name="pi-target">
+      <xsl:with-param name="text" select="name()"/>
+    </xsl:call-template>
+    <xsl:value-of select="$space"/>
+    <xsl:call-template name="pi-text">
+      <xsl:with-param name="text" select="string(.)"/>
+    </xsl:call-template>
+    <xsl:value-of select="$pi-end"/>
+  </xsl:template>
+
+  <xsl:template match="text()" mode="xml-to-string">
+    <xsl:call-template name="text-content">
+      <xsl:with-param name="text" select="string(.)"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template name="element-name">
+    <xsl:param name="text"/>
+    <xsl:value-of select="$text"/>
+  </xsl:template>
+
+  <xsl:template name="attribute-name">
+    <xsl:param name="text"/>
+    <xsl:value-of select="$text"/>
+  </xsl:template>
+
+  <xsl:template name="attribute-value">
+    <xsl:param name="text"/>
+    <xsl:variable name="escaped-markup">
+      <xsl:call-template name="escape-markup-characters">
+        <xsl:with-param name="text" select="$text"/>
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$attribute-delimiter = &quot;'&quot;">
+        <xsl:call-template name="replace-string">
+          <xsl:with-param name="text" select="$escaped-markup"/>
+          <xsl:with-param name="replace" select="&quot;'&quot;"/>
+          <xsl:with-param name="with" select="'&amp;apos;'"/>
+        </xsl:call-template>
+      </xsl:when>
+      <xsl:when test="$attribute-delimiter = '&quot;'">
+        <xsl:call-template name="replace-string">
+          <xsl:with-param name="text" select="$escaped-markup"/>
+          <xsl:with-param name="replace" select="'&quot;'"/>
+          <xsl:with-param name="with" select="'&amp;quot;'"/>
+        </xsl:call-template>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:call-template name="replace-string">
+          <xsl:with-param name="text" select="$escaped-markup"/>
+          <xsl:with-param name="replace" select="$attribute-delimiter"/>
+          <xsl:with-param name="with" select="''"/>
+        </xsl:call-template>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="ns-prefix">
+    <xsl:param name="text"/>
+    <xsl:value-of select="$text"/>
+  </xsl:template>
+
+  <xsl:template name="ns-uri">
+    <xsl:param name="text"/>
+    <xsl:call-template name="attribute-value">
+      <xsl:with-param name="text" select="$text"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template name="text-content">
+    <xsl:param name="text"/>
+    <xsl:call-template name="escape-markup-characters">
+      <xsl:with-param name="text" select="$text"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template name="pi-target">
+    <xsl:param name="text"/>
+    <xsl:value-of select="$text"/>
+  </xsl:template>
+
+  <xsl:template name="pi-text">
+    <xsl:param name="text"/>
+    <xsl:value-of select="$text"/>
+  </xsl:template>
+
+  <xsl:template name="comment-text">
+    <xsl:param name="text"/>
+    <xsl:value-of select="$text"/>
+  </xsl:template>
+
+  <xsl:template name="escape-markup-characters">
+    <xsl:param name="text"/>
+    <xsl:variable name="ampEscaped">
+      <xsl:call-template name="replace-string">
+        <xsl:with-param name="text" select="$text"/>
+        <xsl:with-param name="replace" select="'&amp;'"/>
+        <xsl:with-param name="with" select="'&amp;amp;'"/>
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:variable name="ltEscaped">
+      <xsl:call-template name="replace-string">
+        <xsl:with-param name="text" select="$ampEscaped"/>
+        <xsl:with-param name="replace" select="'&lt;'"/>
+        <xsl:with-param name="with" select="'&amp;lt;'"/>
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:call-template name="replace-string">
+      <xsl:with-param name="text" select="$ltEscaped"/>
+      <xsl:with-param name="replace" select="']]>'"/>
+      <xsl:with-param name="with" select="']]&amp;gt;'"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template name="replace-string">
+    <xsl:param name="text"/>
+    <xsl:param name="replace"/>
+    <xsl:param name="with"/>
+    <xsl:variable name="stringText" select="string($text)"/>
+    <xsl:choose>
+      <xsl:when test="contains($stringText,$replace)">
+        <xsl:value-of select="substring-before($stringText,$replace)"/>
+        <xsl:value-of select="$with"/>
+        <xsl:call-template name="replace-string">
+          <xsl:with-param name="text" select="substring-after($stringText,$replace)"/>
+          <xsl:with-param name="replace" select="$replace"/>
+          <xsl:with-param name="with" select="$with"/>
+        </xsl:call-template>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="$stringText"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+</xsl:stylesheet>
diff --git a/groovy-core/cruise/reporting-app/xsl/maven.xsl b/groovy-core/cruise/reporting-app/xsl/maven.xsl
new file mode 100644
index 0000000..9a38092
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/xsl/maven.xsl
@@ -0,0 +1,101 @@
+<?xml version="1.0"?>
+<!--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2003, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************-->
+<xsl:stylesheet
+    version="1.0"
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns="http://www.w3.org/TR/html4/strict.dtd" >
+
+    <xsl:output method="html"/>
+
+    <xsl:variable name="mavengoal" select="/cruisecontrol/build//mavengoal"/>
+
+    <xsl:template match="/">
+
+        <xsl:variable name="maven.messages" select="$mavengoal/message"/>
+        <xsl:variable name="maven.error.messages" select="$mavengoal/message[@priority='error']"/>
+        <xsl:variable name="maven.warn.messages" select="$mavengoal/message[@priority='warn']"/>
+        <xsl:variable name="maven.info.messages" select="$mavengoal/message[@priority='info']"/>
+
+        <xsl:if test="count($maven.messages) > 0">
+            <table align="center" cellpadding="2" cellspacing="0" border="0" width="98%">
+                 <!-- Style download notifications first -->
+                 <tr class="compile-sectionheader">
+                     <td>Initial Messages</td>
+                 </tr>
+                 <tr>
+                     <td>
+                         <xsl:apply-templates select="cruisecontrol/build/message"/>
+                     </td>
+                 </tr>
+                 <xsl:apply-templates select="$mavengoal"/>
+            </table>
+        </xsl:if>
+    </xsl:template>
+
+    <xsl:template match="mavengoal">
+       <tr class="compile-sectionheader">
+       		<td>
+            	<xsl:value-of select="@name"/>
+            </td>
+       </tr>
+       <tr>
+       		<td>
+            	<xsl:apply-templates select="./message"/>
+            </td>
+       </tr>
+    </xsl:template>
+
+    <xsl:template match="message[@priority='error']">
+    	  <span class="compile-error-data">
+        <xsl:value-of select="text()"/><xsl:text disable-output-escaping="yes"><![CDATA[<br/>]]></xsl:text>
+        </span>
+    </xsl:template>
+
+    <xsl:template match="message[@priority='warn']">
+    	  <span class="compile-data">
+        <xsl:value-of select="text()"/><xsl:text disable-output-escaping="yes"><![CDATA[<br/>]]></xsl:text>
+        </span>
+    </xsl:template>
+
+    <xsl:template match="message[@priority='info']">
+    	  <span class="compile-data">
+        <xsl:value-of select="text()"/><xsl:text disable-output-escaping="yes"><![CDATA[<br/>]]></xsl:text>
+        </span>
+    </xsl:template>
+
+</xsl:stylesheet>
diff --git a/groovy-core/cruise/reporting-app/xsl/modifications.xsl b/groovy-core/cruise/reporting-app/xsl/modifications.xsl
new file mode 100644
index 0000000..3eb887c
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/xsl/modifications.xsl
@@ -0,0 +1,205 @@
+<?xml version="1.0"?>
+<!--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************-->
+<xsl:stylesheet
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+
+    <xsl:output method="html"/>
+    <xsl:variable name="modification.list" select="cruisecontrol/modifications/modification"/>
+
+    <xsl:template match="/">
+        <table align="center" cellpadding="2" cellspacing="1" border="0" width="98%">
+            <!-- Modifications -->
+            <tr>
+                <td class="modifications-sectionheader" colspan="6">
+                    &#160;Modifications since last build:&#160;
+                    (<xsl:value-of select="count($modification.list)"/>)
+                </td>
+            </tr>
+
+            <xsl:apply-templates select="$modification.list">
+                <xsl:sort select="date" order="descending" data-type="text" />
+            </xsl:apply-templates>
+
+        </table>
+    </xsl:template>
+
+    <!-- P4 changelist template
+    <modification type="p4" revision="15">
+       <revision>15</revision>
+       <user>non</user>
+       <client>non:all</client>
+       <date>2002/05/02 10:10:10</date>
+       <file action="add">
+          <filename>myfile</filename>
+          <revision>10</revision>
+       </file>
+    </modification>
+    -->
+    <xsl:template match="modification[@type='p4']">
+        <tr valign="top">
+            <xsl:if test="position() mod 2=0">
+                <xsl:attribute name="class">changelists-oddrow</xsl:attribute>
+            </xsl:if>
+            <xsl:if test="position() mod 2!=0">
+                <xsl:attribute name="class">changelists-evenrow</xsl:attribute>
+            </xsl:if>
+            <td class="modifications-data">
+                <xsl:value-of select="revision"/>
+            </td>
+            <td class="modifications-data">
+                <xsl:value-of select="user"/>
+            </td>
+            <td class="modifications-data">
+                <xsl:value-of select="client"/>
+            </td>
+            <td class="modifications-data">
+                <xsl:value-of select="date"/>
+            </td>
+            <td class="modifications-data">
+                <xsl:value-of select="comment"/>
+            </td>
+        </tr>
+        <xsl:if test="count(file) > 0">
+            <tr valign="top">
+                <xsl:if test="position() mod 2=0">
+                    <xsl:attribute name="class">changelists-oddrow</xsl:attribute>
+                </xsl:if>
+                <xsl:if test="position() mod 2!=0">
+                    <xsl:attribute name="class">changelists-evenrow</xsl:attribute>
+                </xsl:if>
+                <td class="modifications-data" colspan="6">
+                    <table align="right" cellpadding="1" cellspacing="0" border="0" width="95%">
+                        <tr>
+                            <td class="changelists-file-header" colspan="3">
+                                &#160;Files affected by this changelist:&#160;
+                                (<xsl:value-of select="count(file)"/>)
+                            </td>
+                        </tr>
+                        <xsl:apply-templates select="file"/>
+                    </table>
+                </td>
+            </tr>
+        </xsl:if>
+    </xsl:template>
+
+    <!-- used by P4 -->
+    <xsl:template match="file">
+        <tr valign="top" >
+            <xsl:if test="position() mod 2=0">
+                <xsl:attribute name="class">changelists-file-oddrow</xsl:attribute>
+            </xsl:if>
+            <xsl:if test="position() mod 2!=0">
+                <xsl:attribute name="class">changelists-file-evenrow</xsl:attribute>
+            </xsl:if>
+
+            <td class="changelists-file-spacer">
+                &#160;
+            </td>
+
+            <td class="modifications-data">
+                <b>
+                    <xsl:value-of select="@action"/>
+                </b>
+            </td>
+            <td class="modifications-data" width="100%">
+                <xsl:value-of select="filename"/>&#160;
+                <xsl:value-of select="revision"/>
+            </td>
+        </tr>
+    </xsl:template>
+
+    <!-- Modifications template -->
+    <xsl:template match="modification[file]">
+        <tr>
+            <xsl:if test="position() mod 2=0">
+                <xsl:attribute name="class">modifications-oddrow</xsl:attribute>
+            </xsl:if>
+            <xsl:if test="position() mod 2!=0">
+                <xsl:attribute name="class">modifications-evenrow</xsl:attribute>
+            </xsl:if>
+
+            <td class="modifications-data">
+                <xsl:value-of select="file/@action"/>
+            </td>
+            <td class="modifications-data">
+                <xsl:value-of select="user"/>
+            </td>
+            <td class="modifications-data">
+                <xsl:if test="file/project">
+                    <xsl:value-of select="file/project"/>
+                    <xsl:value-of select="system-property('file.separator')"/>
+                </xsl:if>
+                <xsl:value-of select="file/filename"/>
+            </td>
+            <td class="modifications-data">
+                <xsl:value-of select="comment"/>
+            </td>
+        </tr>
+    </xsl:template>
+
+    <!-- Up to version 2.1.6 the modification set format did not
+         include the file node -->
+    <xsl:template match="modification">
+        <tr>
+            <xsl:if test="position() mod 2=0">
+                <xsl:attribute name="class">modifications-oddrow</xsl:attribute>
+            </xsl:if>
+            <xsl:if test="position() mod 2!=0">
+                <xsl:attribute name="class">modifications-evenrow</xsl:attribute>
+            </xsl:if>
+
+            <td class="modifications-data">
+                <xsl:value-of select="@type"/>
+            </td>
+            <td class="modifications-data">
+                <xsl:value-of select="user"/>
+            </td>
+            <td class="modifications-data">
+                <xsl:if test="project">
+                    <xsl:value-of select="project"/>
+                    <xsl:value-of select="system-property('file.separator')"/>
+                </xsl:if>
+                <xsl:value-of select="filename"/>
+            </td>
+            <td class="modifications-data">
+                <xsl:value-of select="comment"/>
+            </td>
+        </tr>
+    </xsl:template>
+
+</xsl:stylesheet>
diff --git a/groovy-core/cruise/reporting-app/xsl/testdetails.xsl b/groovy-core/cruise/reporting-app/xsl/testdetails.xsl
new file mode 100644
index 0000000..79f7008
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/xsl/testdetails.xsl
@@ -0,0 +1,313 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<!--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************-->
+<xsl:output method="html"/>
+<xsl:decimal-format decimal-separator="." grouping-separator="," />
+
+<!-- ================================================================== -->
+<!-- Write a package level report                                       -->
+<!-- It creates a table with values from the document:                  -->
+<!-- Name | Tests | Errors | Failures | Time                            -->
+<!-- ================================================================== -->
+<xsl:template match="cruisecontrol" priority="1">
+    <script type="text/javascript" language="JavaScript">
+        var TestCases = new Array();
+        var SystemOut = new Array();
+        var SystemErr = new Array();
+        var Problem = new Array();
+        var cur;
+      <!--xsl:apply-templates select="//testsuite" mode="js.props" /-->
+      <xsl:apply-templates select="//testsuite" mode="js.props" />
+    </script>
+    <script type="text/javascript" language="JavaScript"><![CDATA[
+        function displayProperties (name) {
+          var win = window.open('','JUnitSystemProperties','scrollbars=1,resizable=1');
+          var doc = win.document.open();
+          doc.write("<html><head><title>Properties of " + name + "</title>");
+          doc.write("<style>")
+          doc.write("body {font:normal 68% verdana,arial,helvetica; color:#000000; }");
+          doc.write("table tr td, table tr th { font-size: 68%; }");
+          doc.write("table.properties { border-collapse:collapse; border-left:solid 1 #cccccc; border-top:solid 1 #cccccc; padding:5px; }");
+          doc.write("table.properties th { text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#eeeeee; }");
+          doc.write("table.properties td { font:normal; text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#fffffff; }");
+          doc.write("h3 { margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica }");
+          doc.write("</style>");
+          doc.write("</head><body>");
+          doc.write("<h3>Properties of " + name + "</h3>");
+          doc.write("<div align=\"right\"><a href=\"javascript:window.close();\">Close</a></div>");
+          doc.write("<table class='properties'>");
+          doc.write("<tr><th>Name</th><th>Value</th></tr>");
+          for (prop in TestCases[name]) {
+            doc.write("<tr><th>" + prop + "</th><td>" + TestCases[name][prop] + "</td></tr>");
+          }
+          doc.write("</table>");
+          doc.write("</body></html>");
+          doc.close();
+          win.focus();
+        }
+    ]]>  
+    </script>
+    <script type="text/javascript" language="JavaScript"><![CDATA[
+    function displayMessage(name) {
+        var win = window.open('','Message','scrollbars=1,resizable=1');
+        var doc = win.document.open();
+        doc.write("<html><head><title>Message</title></head>");
+        doc.write("<body><pre>");
+        doc.write(Problem[name]);
+        doc.write("</pre></body></html>");
+        doc.close();
+        win.focus();
+    }
+    ]]>
+    </script>
+    <script type="text/javascript" language="JavaScript"><![CDATA[
+    function displayOut(name) {
+        var win = window.open('','Out','scrollbars=1,resizable=1');
+        var doc = win.document.open();
+        doc.write("<html><head><title>Out</title></head>");
+        doc.write("<body><pre>");
+        doc.write(SystemOut[name]);
+        doc.write("</pre></body></html>");
+        doc.close();
+        win.focus();
+    }
+    ]]>
+    </script>
+    <script type="text/javascript" language="JavaScript"><![CDATA[
+    function displayErr(name) {
+        var win = window.open('','Err','scrollbars=1,resizable=1');
+        var doc = win.document.open();
+        doc.write("<html><head><title>Err</title></head>");
+        doc.write("<body><pre>");
+        doc.write(SystemErr[name]);
+        doc.write("</pre></body></html>");
+        doc.close();
+        win.focus();
+    }
+    ]]>
+    </script>
+    <table border="0" cellspacing="0" width="100%">
+    <xsl:call-template name="table.header" />
+    <xsl:for-each select="//testsuite">
+        <xsl:sort select="count(testcase/error)" data-type="number" order="descending" />
+        <xsl:sort select="count(testcase/failure)" data-type="number" order="descending" />
+        <xsl:sort select="@package"/>
+        <xsl:sort select="@name"/>
+
+        <xsl:call-template name="print.class" />
+        <xsl:apply-templates select="." mode="print.test" />
+        <xsl:call-template name="print.properties" />
+    </xsl:for-each>
+    </table>
+</xsl:template>
+    
+<xsl:template match="system-out|system-err" mode="print.test"/>
+
+<xsl:template match="testcase" mode="print.test">
+    <tr>
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="error">unittests-error</xsl:when>
+                <xsl:when test="failure">unittests-error</xsl:when>
+                <xsl:otherwise>unittests-data</xsl:otherwise>
+            </xsl:choose>
+        </xsl:attribute>
+        <td />
+        <td colspan="2">
+            <xsl:value-of select="@name"/>
+        </td>
+        <td>
+            <xsl:choose>
+                <xsl:when test="error">
+                    <a>
+                        <xsl:attribute name="href">javascript:displayMessage('<xsl:value-of select="../@package"/>.<xsl:value-of select="../@name"/>.<xsl:value-of select='@name'/>');</xsl:attribute>
+                        Error &#187;
+                    </a>
+                </xsl:when>
+                <xsl:when test="failure">
+                    <a>
+                        <xsl:attribute name="href">javascript:displayMessage('<xsl:value-of select="../@package"/>.<xsl:value-of select="../@name"/>.<xsl:value-of select='@name'/>');</xsl:attribute>
+                        Failure &#187;
+                    </a>
+                </xsl:when>
+                <xsl:otherwise>Success</xsl:otherwise>
+            </xsl:choose>
+        </td>
+        <xsl:if test="not(failure|error)">
+            <td>
+                <xsl:value-of select="format-number(@time,'0.000')"/>
+            </td>
+        </xsl:if>
+    </tr>
+</xsl:template>
+
+<xsl:template name="table.header" >
+    <colgroup>
+        <col width="10%"></col>
+        <col width="45%"></col>
+        <col width="25%"></col>
+        <col width="10%"></col>
+        <col width="10%"></col>
+    </colgroup>
+    <tr valign="top" class="unittests-sectionheader" align="left" >
+        <th colspan="3">Name</th>
+        <th>Status</th>
+        <th nowrap="nowrap">Time(s)</th>
+    </tr>
+</xsl:template>
+
+<xsl:template name="print.properties" >
+    <tr class="unittests-data">
+        <td colspan="2">
+            <a>
+                <xsl:attribute name="href">javascript:displayProperties('<xsl:value-of select="@package"/>.<xsl:value-of select="@name"/>');</xsl:attribute>
+                Properties &#187;
+            </a>
+        </td>
+        <td>
+            <xsl:if test="system-out/text()">
+              <a style="float:center" >
+                <xsl:attribute name="href">javascript:displayOut('<xsl:value-of select="@package"/>.<xsl:value-of select="@name"/>');</xsl:attribute>
+                System.out &#187;
+              </a>
+            </xsl:if>
+        </td>
+        <td>
+            <xsl:if test="system-err/text()">
+              <a>
+                <xsl:attribute name="href">javascript:displayErr('<xsl:value-of select="@package"/>.<xsl:value-of select="@name"/>');</xsl:attribute>
+                System.err &#187;
+              </a>
+            </xsl:if>
+        </td>
+    </tr>
+</xsl:template>
+
+<xsl:template name="print.class" >
+    <tr>
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="testcase/error">unittests-error</xsl:when>
+                <xsl:when test="testcase/failure">unittests-error</xsl:when>
+                <xsl:otherwise>unittests-data</xsl:otherwise>
+            </xsl:choose>
+        </xsl:attribute>
+        <td colspan="5"><xsl:value-of select="@package"/>.<xsl:value-of select="@name"/></td>
+    </tr>
+</xsl:template>
+
+<!--
+  Write output and err into a JavaScript data structure.
+  This is based on the original idea by Erik Hatcher (ehatcher@apache.org)
+-->
+<!--xsl:template match="system-out" mode="js.props" >
+    SystemOut['<xsl:value-of select="../@package"/>.<xsl:value-of select="../@name"/>'] = '<xsl:call-template name="JS-escape"><xsl:with-param select="." name="string"/></xsl:call-template>';
+</xsl:template>
+
+<xsl:template match="system-err" mode="js.props" >
+    SystemErr['<xsl:value-of select="../@package"/>.<xsl:value-of select="../@name"/>'] = '<xsl:call-template name="JS-escape"><xsl:with-param select="." name="string"/></xsl:call-template>';
+</xsl:template-->
+
+<xsl:template match="error|failure" mode="js.props" >
+    Problem['<xsl:value-of select="../../@package"/>.<xsl:value-of select="../../@name"/>.<xsl:value-of select="../@name"/>'] = '<xsl:call-template name="JS-escape"><xsl:with-param select="." name="string"/></xsl:call-template>';
+</xsl:template>
+
+<!--
+  Write properties into a JavaScript data structure.
+  This is based on the original idea by Erik Hatcher (ehatcher@apache.org)
+-->
+<xsl:template match="properties" mode="js.props" >
+    cur = TestCases['<xsl:value-of select="../@package"/>.<xsl:value-of select="../@name"/>'] = new Array();
+    <xsl:for-each select="property">
+        <xsl:sort select="@name"/>
+        cur['<xsl:value-of select="@name"/>'] = '<xsl:call-template name="JS-escape"><xsl:with-param name="string" select="@value"/></xsl:call-template>';
+    </xsl:for-each>
+</xsl:template>
+    
+<xsl:template name="JS-escape">
+    <xsl:param name="string"/>		
+    <xsl:variable name="CR" select="'&#xD;'"/>					
+    <xsl:variable name="LF" select="'&#xA;'"/>
+    <xsl:variable name="CRLF" select="concat($CR, $LF)"/>			
+    <xsl:choose>
+        <!-- crlf -->
+        <xsl:when test="contains($string,$CRLF)">
+            <xsl:call-template name="JS-escape">
+                <xsl:with-param name="string" select="substring-before($string,$CRLF)"/>
+            </xsl:call-template><br/><xsl:call-template name="JS-escape">
+                <xsl:with-param name="string" select="substring-after($string,$CRLF)"/>
+            </xsl:call-template>
+        </xsl:when>
+        <!-- carriage return -->
+        <xsl:when test="contains($string,$CR)">
+            <xsl:call-template name="JS-escape">
+                <xsl:with-param name="string" select="substring-before($string,$CR)"/>
+            </xsl:call-template><br/><xsl:call-template name="JS-escape">
+                <xsl:with-param name="string" select="substring-after($string,$CR)"/>
+            </xsl:call-template>
+        </xsl:when>
+        <!-- line feed -->
+        <xsl:when test="contains($string,$LF)">
+            <xsl:call-template name="JS-escape">
+                <xsl:with-param name="string" select="substring-before($string,$LF)"/>
+            </xsl:call-template><br/><xsl:call-template name="JS-escape">
+                <xsl:with-param name="string" select="substring-after($string,$LF)"/>
+            </xsl:call-template>
+        </xsl:when>
+        <!-- single quote -->
+        <xsl:when test="contains($string,&quot;'&quot;)">
+            <xsl:call-template name="JS-escape">
+                <xsl:with-param name="string" select="substring-before($string,&quot;'&quot;)"/>
+            </xsl:call-template>\&apos;<xsl:call-template name="JS-escape">
+                <xsl:with-param name="string" select="substring-after($string,&quot;'&quot;)"/>
+            </xsl:call-template>
+        </xsl:when>
+        <!-- escape -->
+        <xsl:when test="contains($string,'\')">
+            <xsl:call-template name="JS-escape">
+                <xsl:with-param name="string" select="substring-before($string,'\')"/>
+            </xsl:call-template>\\<xsl:call-template name="JS-escape">
+                <xsl:with-param name="string" select="substring-after($string,'\')"/>
+            </xsl:call-template>
+        </xsl:when>
+        <xsl:otherwise>
+            <xsl:value-of select="$string"/>
+        </xsl:otherwise>
+    </xsl:choose>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/groovy-core/cruise/reporting-app/xsl/unittests.xsl b/groovy-core/cruise/reporting-app/xsl/unittests.xsl
new file mode 100644
index 0000000..a964aaf
--- /dev/null
+++ b/groovy-core/cruise/reporting-app/xsl/unittests.xsl
@@ -0,0 +1,243 @@
+<?xml version="1.0"?>
+<!--********************************************************************************
+ * CruiseControl, a Continuous Integration Toolkit
+ * Copyright (c) 2001, ThoughtWorks, Inc.
+ * 651 W Washington Ave. Suite 600
+ * Chicago, IL 60661 USA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     + Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     + Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************************-->
+<xsl:stylesheet
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+    xmlns:lxslt="http://xml.apache.org/xslt">
+
+    <xsl:output method="html"/>
+
+    <xsl:variable name="testsuite.list" select="//testsuite"/>
+    <xsl:variable name="testsuite.error.count" select="count($testsuite.list/error)"/>
+    <xsl:variable name="testcase.list" select="$testsuite.list/testcase"/>
+    <xsl:variable name="testcase.error.list" select="$testcase.list/error"/>
+    <xsl:variable name="testcase.failure.list" select="$testcase.list/failure"/>
+    <xsl:variable name="totalErrorsAndFailures" select="count($testcase.error.list) + count($testcase.failure.list) + $testsuite.error.count"/>
+
+    <xsl:template match="/">
+        <table align="center" cellpadding="2" cellspacing="0" border="0" width="98%">
+
+            <!-- Unit Tests -->
+            <tr>
+                <td class="unittests-sectionheader" colspan="4">
+                   &#160;Unit Tests: (<xsl:value-of select="count($testcase.list)"/>)
+                </td>
+            </tr>
+
+            <xsl:choose>
+                <xsl:when test="count($testsuite.list) = 0">
+                    <tr>
+                        <td colspan="2" class="unittests-data">
+                            No Tests Run
+                        </td>
+                    </tr>
+                    <tr>
+                        <td colspan="2" class="unittests-error">
+                            This project doesn't have any tests
+                        </td>
+                    </tr>
+                </xsl:when>
+
+                <xsl:when test="$totalErrorsAndFailures = 0">
+                    <tr>
+                        <td colspan="2" class="unittests-data">
+                            All Tests Passed
+                        </td>
+                    </tr>
+                </xsl:when>
+            </xsl:choose>
+            <tr>
+              <td>
+                 <table align="center" cellpadding="2" cellspacing="0" border="0" width="98%">
+                    <xsl:apply-templates select="$testcase.error.list"/>
+                    <xsl:apply-templates select="$testcase.failure.list"/>
+                 </table>
+              </td>
+            </tr>
+            <tr/>
+            <tr><td colspan="2">&#160;</td></tr>
+
+            <xsl:if test="$totalErrorsAndFailures > 0">
+
+              <tr>
+                <td class="unittests-sectionheader" colspan="4">
+                    &#160;Unit Test Error Details:&#160;(<xsl:value-of select="$totalErrorsAndFailures"/>)
+                </td>
+              </tr>
+
+              <!-- (PENDING) Why doesn't this work if set up as variables up top? -->
+              <xsl:call-template name="testdetail">
+                <xsl:with-param name="detailnodes" select="//testsuite/testcase[.//error]"/>
+              </xsl:call-template>
+
+              <xsl:call-template name="testdetail">
+                <xsl:with-param name="detailnodes" select="//testsuite/testcase[.//failure]"/>
+              </xsl:call-template>
+
+
+              <tr><td colspan="2">&#160;</td></tr>
+            </xsl:if>
+
+
+        </table>
+    </xsl:template>
+
+    <!-- UnitTest Errors -->
+    <xsl:template match="error">
+        <tr>
+            <xsl:if test="position() mod 2 = 0">
+                <xsl:attribute name="class">unittests-oddrow</xsl:attribute>
+            </xsl:if>
+
+            <td class="unittests-data">
+                error
+            </td>
+            <td class="unittests-data" width="40%">
+                <xsl:value-of select="../@name"/>
+            </td>
+            <td class="unittests-data" width="40%">
+                <xsl:value-of select="..//..//@name"/>
+            </td>
+        </tr>
+    </xsl:template>
+
+    <!-- UnitTest Failures -->
+    <xsl:template match="failure">
+        <tr>
+            <xsl:if test="($testsuite.error.count + position()) mod 2 = 0">
+                <xsl:attribute name="class">unittests-oddrow</xsl:attribute>
+            </xsl:if>
+
+            <td class="unittests-data">
+                failure
+            </td>
+            <td class="unittests-data" width="40%">
+                <xsl:value-of select="../@name"/>
+            </td>
+            <td class="unittests-data" width="40%">
+                <xsl:value-of select="..//..//@name"/>
+            </td>
+        </tr>
+    </xsl:template>
+
+    <!-- UnitTest Errors And Failures Detail Template -->
+    <xsl:template name="testdetail">
+      <xsl:param name="detailnodes"/>
+
+      <xsl:for-each select="$detailnodes">
+
+        <tr>
+            <td colspan="2" class="unittests-data">
+                Test:&#160;<xsl:value-of select="@name"/>
+            </td>
+        </tr>
+        <tr>
+            <td colspan="2" class="unittests-data">
+                Class:&#160;<xsl:value-of select="..//@name"/>
+            </td>
+        </tr>
+
+        <xsl:if test="error">
+            <tr>
+                <td colspan="2" class="unittests-data">
+                    Type: <xsl:value-of select="error/@type" />
+                </td>
+            </tr>
+        <tr>
+            <td colspan="2" class="unittests-data">
+                Message: <xsl:value-of select="error/@message" />
+            </td>
+        </tr>
+
+        <tr>
+            <td colspan="2" class="unittests-error">
+                <PRE>
+                    <xsl:call-template name="br-replace">
+                        <xsl:with-param name="word" select="error" />
+                    </xsl:call-template>
+                </PRE>
+            </td>
+        </tr>
+        </xsl:if>
+
+        <xsl:if test="failure">
+        <tr>
+            <td colspan="2" class="unittests-data">
+                Type: <xsl:value-of select="failure/@type" />
+            </td>
+        </tr>
+        <tr>
+            <td colspan="2" class="unittests-data">
+                Message: <xsl:value-of select="failure/@message" />
+            </td>
+        </tr>
+
+        <tr>
+            <td colspan="2" class="unittests-failure">
+                <pre>
+                    <xsl:call-template name="br-replace">
+                        <xsl:with-param name="word" select="failure"/>
+                    </xsl:call-template>
+                </pre>
+            </td>
+        </tr>
+        </xsl:if>
+
+      </xsl:for-each>
+    </xsl:template>
+
+    <xsl:template name="br-replace">
+        <xsl:param name="word"/>
+<!-- </xsl:text> on next line on purpose to get newline -->
+<xsl:variable name="cr"><xsl:text>
+</xsl:text></xsl:variable>
+        <xsl:choose>
+            <xsl:when test="contains($word,$cr)">
+                <xsl:value-of select="substring-before($word,$cr)"/>
+                <br/>
+                <xsl:call-template name="br-replace">
+                <xsl:with-param name="word" select="substring-after($word,$cr)"/>
+                </xsl:call-template>
+            </xsl:when>
+            <xsl:otherwise>
+                <xsl:value-of select="$word"/>
+            </xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
+
+</xsl:stylesheet>
diff --git a/groovy-core/experimental/TestMeta.java b/groovy-core/experimental/TestMeta.java
new file mode 100644
index 0000000..8874d99
--- /dev/null
+++ b/groovy-core/experimental/TestMeta.java
@@ -0,0 +1,80 @@
+import groovy.lang.MetaClass;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.MetaClassActions;
+import org.codehaus.groovy.runtime.MetaClassActionsGenerator;
+
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.
+ *
+ */
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class TestMeta {
+  
+  /**
+   * @param args
+   */
+  public static void main(String[] args) throws Exception {   
+    final MetaClassActions a1 = MetaClassActionsGenerator.getActions(ArrayList.class);
+    final MetaClassActions a2 = MetaClassActionsGenerator.getActions(HashMap.class);
+    final MetaClass m1 = InvokerHelper.getInstance().getMetaRegistry().getMetaClass(ArrayList.class);
+    final MetaClass m2 = InvokerHelper.getInstance().getMetaRegistry().getMetaClass(HashMap.class);
+    final ArrayList i1 = new ArrayList();
+    final HashMap i2 = new HashMap();
+    final Integer zero = new Integer(0);
+    
+    i1.add(new Integer(0));
+    i1.add(new Integer(1));
+    i1.add(new Integer(0));
+    i1.add(new Integer(3));
+    
+    System.out.println(m1.invokeMethod(i1, "count", new Object[]{zero}));
+    System.out.println(a1.doInvokeMethod(i1, "count", new Object[]{zero}));
+    
+    final String method = "toArray";
+    
+    long start = System.currentTimeMillis();
+    
+    for (int i = 0; i != 10000000; i++) {
+      m1.invokeMethod(i1, method, new Object[]{});
+    }
+    
+    System.out.println("Time taken via MetaClass: " + (System.currentTimeMillis() - start));
+    
+    start = System.currentTimeMillis();
+    
+    for (int i = 0; i != 10000000; i++) {
+      a1.doInvokeMethod(i1, method, new Object[]{});
+    }
+    
+    System.out.println("Time taken via MetaClassActions: " + (System.currentTimeMillis() - start));
+    
+    start = System.currentTimeMillis();
+    
+    for (int i = 0; i != 10000000; i++) {
+      i1.toArray();
+    }
+    
+    System.out.println("Time taken via direct call: " + (System.currentTimeMillis() - start));
+  }
+}
\ No newline at end of file
diff --git a/groovy-core/experimental/groovy/lang/MOP.java b/groovy-core/experimental/groovy/lang/MOP.java
new file mode 100644
index 0000000..ab8e1db
--- /dev/null
+++ b/groovy-core/experimental/groovy/lang/MOP.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+/**
+ * This inteface defines thew Meta Object Protocol implemented by the MetaClass
+ * Note that this inteface is purely for documantation purposes
+ * An object implementing this interface is not neccesarily a vaild MetaClass
+ * A MetaClass needs to implement may more methods
+ *
+ */
+public interface MOP {
+    static final Object NOT_CALLED = new Object();
+    static final Object NO_PROPERTY = new Object();
+    static final Object NO_ATTRIBUTE = new Object();
+
+    /**
+     * Invoke a public method on an object.
+     * Public methods are those declared public in the class and those added via mechanisms like DefaultGroovyMethods.
+     * If no suitable method is found a groovy.lang.MissingMethodException is thrown.
+     * @param object
+     * The object on which the call is to be made
+     * @param objectType
+     * If objectType is not null then method to be called is selected as though the object was cast to this type before making the call.
+     * @param methodName
+     * The name of the method to be called
+     * @param arguments
+     * The arguments to the call.
+     * If NOT_CALLED is returned and there is a private or protected method which
+     * should be called then this array will contain the parameters to that method. The MetaClass will have done any conversions
+     * (e.g. GString to String) needed to allow the call to suceed.
+     * If any other value is returned then the values in this array are undefined. In this case the MetaClass may or may not
+     * change these values. DO NOT use these values unless NOT_CALLED is returned.
+     * @param argumentTypes
+     * This array must be the same length as the arguments arguments array.
+     * It contains the type of each parameter if known or null if unknown.
+     * The if there are multiple methods with the same name and number of parameters then this information
+     * contributes to the selection of the correct method to call.
+     * If NOT_CALLED is returned and there is a private or protected method which
+     * should be called then this array will contain the classes which represent the types of the parameters to that method.
+     * If any other value is returned then the values in this array are undefined. In this case the MetaClass may or may not
+     * change these values. DO NOT use these values unless NOT_CALLED is returned.
+     * @return
+     * The result of calling the method (null is returned if the method returns void).
+     */
+    Object invokeMethod( Object object,  Class objectType,  String methodName,  Object[] arguments,  Class[] argumentTypes);
+    
+    Object getProperty( Object object,  Class objectType,  String property);
+    
+    void setProperty( Object object,  Class objectType,  String property,  Object newValue,  Class newValueType);
+    
+    Object getAttribute( Object object,  Class objectType,  String attribute);
+    
+    void setAttribute( Object object,  Class objectType,  String attribute,  Object newValue,  Class newValueType);
+    
+    /**
+     * Invoke a public method on an object.
+     * These public methods are those declared public in the class and those added via mechanisms like DefaultGroovyMethods.
+     * If no public method can be found but there exists protected or private methods which would match the name, number and type
+     * of the parameters then the value NOT_CALLED is returned.
+     * Oherwise a groovy.lang.MissingMethodException is thrown.
+     * @param object
+     * The object on which the call is to be made
+     * @param thisType
+     * The type of the class in which this call was made. This must never be null.
+     * Note this type valie may not be the same as object.getClass() as it my be a superclass of that class.
+     * @param methodName
+     * The name of the method to be called
+     * @param arguments
+     * The arguments to the call.
+     * If NOT_CALLED is returned and there is a private or protected method which
+     * should be called then this array will contain the parameters to that method. The MetaClass will have done any conversions
+     * (e.g. GString to String) needed to allow the call to succeed.
+     * If any other value is returned then the values in this array are undefined. In this case the MetaClass may or may not
+     * change these values. DO NOT use these values unless NOT_CALLED is returned.
+     * @param argumentTypes
+     * This array must be the same length as the arguments arguments array.
+     * It contains the type of each parameter if known or null if unknown.
+     * The if there are multiple methods with the same name and number of parameters then this information
+     * contributes to the selection of the correct method to call.
+     * If NOT_CALLED is returned and there is a private or protected method which
+     * should be called then this array will contain the classes which represent the types of the parameters to that method.
+     * If any other value is returned then the values in this array are undefined. In this case the MetaClass may or may not
+     * change these values. DO NOT use these values unless NOT_CALLED is returned.
+     * @return
+     * Either the result of calling the method (null is returned if the method returns void) or the value NOT_CALLED.
+     * NOT_CALLED is returned if a suitable method exists but the MetaClass did not call it because it is not public.
+     * In this case the caller is free to try to invoke the method itself (e.g. by executing generated bytecode).
+     * If there are multiple methods with the same name and number of parameters then the values on the array passed
+     * as argumentTypes should be used to choose the correct one to call.
+     */
+    Object invokeThisMethod( Object object,  Class thisType,  String methodName,  Object[] arguments,  Class[] argumentTypes);
+    
+    Object getThisProperty( Object object,  Class thisType,  String property);
+    
+    boolean setThisProperty( Object object,  Class thisType,  String property,  Object newValue,  Class newValueType);
+    
+    Object getThisAttribute( Object object,  Class thisType,  String attribute);
+    
+    boolean setThisAttribute( Object object,  Class thisType,  String attribute,  Object newValue,  Class newValueType);
+    
+    /**
+     * Invoke an added method on an object. Methods are added via mechanisms like DefaultGroovyMethods.
+     * If no added method can be found but there exists public, protected or private methods on the specified superclass
+     * which would match the name, number and type of the parameters then the value NOT_CALLED is returned.
+     * Oherwise a groovy.lang.MissingMethodException is thrown.
+     * @param object
+     * The object on which the call is to be made
+     * @param superclassType
+     * The type of the superclass. This must never be null.
+     * @param methodName
+     * The name of the method to be called
+     * @param arguments
+     * The arguments to the call.
+     * If NOT_CALLED is returned and there is a private or protected method which
+     * should be called then this array will contain the parameters to that method. The MetaClass will have done any conversions
+     * (e.g. GString to String) needed to allow the call to succeed.
+     * If any other value is returned then the values in this array are undefined. In this case the MetaClass may or may not
+     * change these values. DO NOT use these values unless NOT_CALLED is returned.
+     * @param argumentTypes
+     * This array must be the same length as the arguments arguments array.
+     * It contains the type of each parameter if known or null if unknown.
+     * The if there are multiple methods with the same name and number of parameters then this information
+     * contributes to the selection of the correct method to call.
+     * If NOT_CALLED is returned and there is a method which
+     * should be called then this array will contain the classes which represent the types of the parameters to that method.
+     * If any other value is returned then the values in this array are undefined. In this case the MetaClass may or may not
+     * change these values. DO NOT use these values unless NOT_CALLED is returned.
+     * @return
+     * Either the result of calling the method (null is returned if the method returns void) or the value NOT_CALLED.
+     * NOT_CALLED is returned if a suitable method exists but the MetaClass did not call it because it is not added.
+     * In this case the caller is free to try to invoke the method itself (e.g. by executing generated bytecode).
+     * If there are multiple methods with the same name and number of parameters then the values on the array passed
+     * as argumentTypes should be used to choose the correct one to call.
+     */  
+    Object invokeSuperMethod( Object object,  Class superclassType,  String methodName,  Object[] arguments,  Class[] argumentTypes);
+    
+    Object getSuperProperty( Object object,  Class superclassType,  String property);
+    
+    boolean setSuperProperty( Object object,  Class superclassType,  String property,  Object newValue,  Class newValueType);
+    
+    Object getSuperAttribute( Object object,  Class superclassType,  String attribute);
+    
+    boolean setSuperAttribute( Object object,  Class superclassType,  String attribute,  Object newValue,  Class newValueType);
+
+}
diff --git a/groovy-core/experimental/groovy/lang/NewMetaClass.java b/groovy-core/experimental/groovy/lang/NewMetaClass.java
new file mode 100644
index 0000000..56a3f13
--- /dev/null
+++ b/groovy-core/experimental/groovy/lang/NewMetaClass.java
@@ -0,0 +1,341 @@
+package groovy.lang;
+
+
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.
+ *
+ */
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public abstract class NewMetaClass implements MOP {
+    public static final Object NOT_CONSTRUCTED = new Object();
+    
+    protected static final Object[] NO_PARAMETERS = new Object[0];
+    protected static final Class[] NO_PARAMETER_TYPES = new Class[0];
+    
+    //
+    // The methods forming the Meta Object Protocol
+    
+    //
+    /* (non-Javadoc)
+     * @see groovy.lang.MOP#invokeMethod(java.lang.Object, java.lang.Class, java.lang.String, java.lang.Object[], java.lang.Class[])
+     */
+    public abstract Object invokeMethod(final Object object, final Class objectType, final String methodName, final Object[] arguments, final Class[] argumentTypes);
+    
+    /* (non-Javadoc)
+     * @see groovy.lang.MOP#getProperty(java.lang.Object, java.lang.Class, java.lang.String)
+     */
+    public abstract Object getProperty(final Object object, final Class objectType, final String property);
+    
+    /* (non-Javadoc)
+     * @see groovy.lang.MOP#setProperty(java.lang.Object, java.lang.Class, java.lang.String, java.lang.Object, java.lang.Class)
+     */
+    public abstract void setProperty(final Object object, final Class objectType, final String property, final Object newValue, final Class newValueType);
+    
+    /* (non-Javadoc)
+     * @see groovy.lang.MOP#getAttribute(java.lang.Object, java.lang.Class, java.lang.String)
+     */
+    public abstract Object getAttribute(final Object object, final Class objectType, final String attribute);
+    
+    /* (non-Javadoc)
+     * @see groovy.lang.MOP#setAttribute(java.lang.Object, java.lang.Class, java.lang.String, java.lang.Object, java.lang.Class)
+     */
+    public abstract void setAttribute(final Object object, final Class objectType, final String attribute, final Object newValue, final Class newValueType);
+    
+    /* (non-Javadoc)
+     * @see groovy.lang.MOP#invokeThisMethod(java.lang.Object, java.lang.Class, java.lang.String, java.lang.Object[], java.lang.Class[])
+     */
+    public abstract Object invokeThisMethod(final Object object, final Class thisType, final String methodName, final Object[] arguments, final Class[] argumentTypes);
+    
+    /* (non-Javadoc)
+     * @see groovy.lang.MOP#getThisProperty(java.lang.Object, java.lang.Class, java.lang.String)
+     */
+    public abstract Object getThisProperty(final Object object, final Class thisType, final String property);
+    
+    /* (non-Javadoc)
+     * @see groovy.lang.MOP#setThisProperty(java.lang.Object, java.lang.Class, java.lang.String, java.lang.Object, java.lang.Class)
+     */
+    public abstract boolean setThisProperty(final Object object, final Class thisType, final String property, final Object newValue, final Class newValueType);
+    
+    /* (non-Javadoc)
+     * @see groovy.lang.MOP#getThisAttribute(java.lang.Object, java.lang.Class, java.lang.String)
+     */
+    public abstract Object getThisAttribute(final Object object, final Class thisType, final String attribute);
+    
+    /* (non-Javadoc)
+     * @see groovy.lang.MOP#setThisAttribute(java.lang.Object, java.lang.Class, java.lang.String, java.lang.Object, java.lang.Class)
+     */
+    public abstract boolean setThisAttribute(final Object object, final Class thisType, final String attribute, final Object newValue, final Class newValueType);
+
+    /* (non-Javadoc)
+     * @see groovy.lang.MOP#invokeSuperMethod(java.lang.Object, java.lang.Class, java.lang.String, java.lang.Object[], java.lang.Class[])
+     */
+    public abstract Object invokeSuperMethod(final Object object, final Class superclassType, final String methodName, final Object[] arguments, final Class[] argumentTypes);
+    
+    /* (non-Javadoc)
+     * @see groovy.lang.MOP#getSuperProperty(java.lang.Object, java.lang.Class, java.lang.String)
+     */
+    public abstract Object getSuperProperty(final Object object, final Class superclassType, final String property);
+    
+    /* (non-Javadoc)
+     * @see groovy.lang.MOP#setSuperProperty(java.lang.Object, java.lang.Class, java.lang.String, java.lang.Object, java.lang.Class)
+     */
+    public abstract boolean setSuperProperty(final Object object, final Class superclassType, final String property, final Object newValue, final Class newValueType);
+    
+    /* (non-Javadoc)
+     * @see groovy.lang.MOP#getSuperAttribute(java.lang.Object, java.lang.Class, java.lang.String)
+     */
+    public abstract Object getSuperAttribute(final Object object, final Class superclassType, final String attribute);
+    
+    /* (non-Javadoc)
+     * @see groovy.lang.MOP#setSuperAttribute(java.lang.Object, java.lang.Class, java.lang.String, java.lang.Object, java.lang.Class)
+     */
+    public abstract boolean setSuperAttribute(final Object object, final Class superclassType, final String attribute, final Object newValue, final Class newValueType);
+
+    //
+    // Methods which may migrate to the MOP at some time in the future
+    //
+    
+    /**
+     * Construct an instance of the class represented by this instance of the MetaClass.
+     * Only public constructors may be called. There is currently no way of dynamically adding constructors but
+     * if one is introduced then this method will use them.
+     * If no suitable constuctor is found then a groovy.lang.MissingConstructorException is thrown
+     * @param arguments
+     * The arguments to the constructor call. The values in this array are undefined after the call is made.
+     * The MetaClass may or may not change these vaues. DO NOT use these vaules after the call.
+     * @param argumentTypes
+     * This array must be the same length as the arguments array.
+     * It contains the type of each parameter if known or null if unknown.
+     * The if there are overloaded constructors then this information contributes to the selection of the correct constructor to call.
+     * The MetaClass may or may not change these vaues. DO NOT use these values after the call.
+     * @return
+     * A new instance of the class represented by this instance of MetaClass.
+     */
+    public abstract Object invokeConstructor(final Object[] arguments, final Class[] argumentTypes);
+    
+    /**
+     * Construct an instance of the class represented by this instance of the MetaClass.
+     * Only public constructors will be called directly. There is currently no way of dynamically adding constructors but
+     * if one is introduced then this method will use them.
+     * If a protected or private constructor is the best match for the parameters then NOT_CONSTRUCTED is returned
+     * otherwise a groovy.lang.MissingConstructorException is thrown
+     * @param arguments
+     * The arguments to the constructor.
+     * If NOT_CONSTUCTED is returned and there is a private or protected constuctor which
+     * should be called then this array will contain the parameters to that constructor. The MetaClass will have done any conversions
+     * (e.g. GString to String) needed to allow the constuctor call to suceed.
+     * If any other value is returned then the values in this array are undefined. In this case the MetaClass may or may not
+     * change these values. DO NOT use these values unless NOT_CONSTUCTED is returned.
+     * @param argumentTypes
+     * This array must be the same length as the arguments arguments array.
+     * It contains the type of each parameter if known or null if unknown.
+     * The if there are multiple constructors with the same name and number of parameters then this information
+     * contributes to the selection of the correct method to call.
+     * If NOT_CONSTUCTED is returned and there is a private or protected constuctor which
+     * should be called then this array will contain the classes which represent the types of the parameters to that constructor.
+     * If any other value is returned then the values in this array are undefined. In this case the MetaClass may or may not
+     * change these values. DO NOT use these values unless NOT_CALLED is returned.
+     * @return
+     * Either a new instance of the class represented by this instance of MetaClass or NOT_CONSTRUCTED.
+     * NOT_CONSTRUCTED is returned if a suitable constructor exists but the MetaClass did not call it because it is not public.
+     * In this case the caller is free to try to invoke the constuctor itself (e.g. by executing generated bytecode). 
+     * If there are multiple constuctors with the same name and number of parameters then the values on the array passed
+     * as argumentTypes should be used to choose the correct one to call.
+     */
+    public abstract Object invokeThisConstructor(final Object[] arguments, final Class[] argumentTypes);
+    
+    //
+    // Additional methods for use when some or all of the type information is not available
+    // We don't bother doing this with super calls properety and attribute acess as they are far less common
+    //
+    
+    public Object invokeConstructor(final Object[] arguments) {
+        return invokeConstructor(arguments, new Class[arguments.length]);
+    }
+    
+    public Object invokeMethod(final Object object, final Class objectType, final String methodName, final Object[] arguments) {
+        return invokeMethod(object, objectType, methodName, arguments, new Class[arguments.length]);
+    }
+    
+    public Object invokeMethod(final Object object, final String methodName, final Object[] arguments, final Class[] argumentTypes) {
+        return invokeMethod(object, (Class)null, methodName, arguments, argumentTypes);
+    }
+    
+    public Object invokeMethod(final Object object, final String methodName, final Object[] arguments) {
+        return invokeMethod(object, (Class)null, methodName, arguments, new Class[arguments.length]);
+    }
+    
+    public Object getProperty(final Object object, final String property) {
+        return getProperty(object, (Class)null, property);
+    }
+    
+    public void setProperty(final Object object, final Class objectType, final String property, final Object newValue) {
+        setProperty(object, objectType, property, newValue, (Class)null);
+    }
+    
+    public void setProperty(final Object object, final String property, final Object newValue, final Class newValueType) {
+        setProperty(object, (Class)null, property, newValue, newValueType);
+    }
+    
+    public void setProperty(final Object object, final String property, final Object newValue) {
+        setProperty(object, (Class)null, property, newValue, (Class)null);
+    }
+    
+    public Object getAttribute(final Object object, final String attribute) {
+        return getAttribute(object, (Class)null, attribute);
+    }
+    
+    public void setAttribute(final Object object, final Class objectType, final String attribute, final Object newValue) {
+        setAttribute(object, objectType, attribute, newValue, (Class)null);
+    }
+    
+    public void setAttribute(final Object object, final String attribute, final Object newValue, final Class newValueType) {
+        setAttribute(object, (Class)null, attribute, newValue, newValueType);
+    }
+    
+    public void setAttribute(final Object object, final String attribute, final Object newValue) {
+        setAttribute(object, (Class)null, attribute, newValue, (Class)null);
+    }
+    
+    public Object invokeThisMethod(final Object object, final Class thisType, final String methodName, final Object[] arguments) {
+        return invokeThisMethod(object, thisType, methodName, arguments, new Class[arguments.length]);
+    }
+    
+    public boolean setThisProperty(final Object object, final Class thisType, final String property, final Object newValue) {
+        return setThisProperty(object, thisType, property, newValue, (Class)null);
+    }
+    
+    public boolean setThisProperty(final Object object, final String property, final Object newValue) {
+        return setThisProperty(object, (Class)null, property, newValue, (Class)null);
+    }
+    
+    //
+    // Methods used to optimise method calling when there are 0, 1, 2, 3 or 4 parameters
+    // We don't bother doing this with super calls as they are far less common
+    //
+       
+    public Object invokeMethod(final Object object, final String methodName) {
+        return invokeMethod(object, (Class)null, methodName, NO_PARAMETERS, NO_PARAMETER_TYPES);
+    }
+       
+    public Object invokeMethod(final Object object, final Class objectType, final String methodName) {
+        return invokeMethod(object, objectType, methodName, NO_PARAMETERS, NO_PARAMETER_TYPES);
+    }
+       
+    public Object invokeMethod(final Object object, final String methodName, final Object p1, final Class c1) {
+        return invokeMethod(object, (Class)null, methodName, new Object[] {p1}, new Class[] {c1});
+    }
+       
+    public Object invokeMethod(final Object object, final Class objectType, final String methodName, final Object p1, final Class c1) {
+        return invokeMethod(object, objectType, methodName, new Object[] {p1}, new Class[] {c1});
+    }
+       
+    public Object invokeMethod(final Object object, final String methodName, final Object p1) {
+        return invokeMethod(object, (Class)null, methodName, new Object[] {p1}, new Class[1]);
+    }
+       
+    public Object invokeMethod(final Object object, final Class objectType, final String methodName, final Object p1) {
+        return invokeMethod(object, objectType, methodName, new Object[] {p1}, new Class[1]);
+    }
+       
+    public Object invokeMethod(final Object object, final String methodName, final Object p1, final Object p2, final Class c1, final Class c2) {
+        return invokeMethod(object, (Class)null, methodName, new Object[] {p1, p2}, new Class[] {c1, c2});
+    }
+       
+    public Object invokeMethod(final Object object, final Class objectType, final String methodName, final Object p1, final Object p2, final Class c1, final Class c2) {
+        return invokeMethod(object, objectType, methodName, new Object[] {p1, p2}, new Class[] {c1, c2});
+    }
+       
+    public Object invokeMethod(final Object object, final String methodName, final Object p1, final Object p2) {
+        return invokeMethod(object, (Class)null, methodName, new Object[] {p1, p2}, new Class[2]);
+    }
+       
+    public Object invokeMethod(final Object object, final Class objectType, final String methodName, final Object p1, final Object p2) {
+        return invokeMethod(object, objectType, methodName, new Object[] {p1, p2}, new Class[2]);
+    }
+       
+    public Object invokeMethod(final Object object, final String methodName, final Object p1, final Object p2, final Object p3, final Class c1, final Class c2, final Class c3) {
+        return invokeMethod(object, (Class)null, methodName, new Object[] {p1, p2, p3}, new Class[] {c1, c2, c3});
+    }
+       
+    public Object invokeMethod(final Object object, final Class objectType, final String methodName, final Object p1, final Object p2, final Object p3, final Class c1, final Class c2, final Class c3) {
+        return invokeMethod(object, objectType, methodName, new Object[] {p1, p2, p3}, new Class[] {c1, c2, c3});
+    }
+       
+    public Object invokeMethod(final Object object, final String methodName, final Object p1, final Object p2, final Object p3) {
+        return invokeMethod(object, (Class)null, methodName, new Object[] {p1, p2, p3}, new Class[3]);
+    }
+       
+    public Object invokeMethod(final Object object, final Class objectType, final String methodName, final Object p1, final Object p2, final Object p3) {
+        return invokeMethod(object, objectType, methodName, new Object[] {p1, p2, p3}, new Class[3]);
+    }
+       
+    public Object invokeMethod(final Object object, final String methodName, final Object p1, final Object p2, final Object p3, final Object p4, final Class c1, final Class c2, final Class c3, final Class c4) {
+        return invokeMethod(object, (Class)null, methodName, new Object[] {p1, p2, p3, p4}, new Class[] {c1, c2, c3, c4});
+    }
+       
+    public Object invokeMethod(final Object object, final Class objectType, final String methodName, final Object p1, final Object p2, final Object p3, final Object p4, final Class c1, final Class c2, final Class c3, final Class c4) {
+        return invokeMethod(object, objectType, methodName, new Object[] {p1, p2, p3, p4}, new Class[] {c1, c2, c3, c4});
+    }
+       
+    public Object invokeMethod(final Object object, final String methodName, final Object p1, final Object p2, final Object p3, final Object p4) {
+        return invokeMethod(object, (Class)null, methodName, new Object[] {p1, p2, p3, p4}, new Class[4]);
+    }
+       
+    public Object invokeMethod(final Object object, final Class objectType, final String methodName, final Object p1, final Object p2, final Object p3, final Object p4) {
+        return invokeMethod(object, objectType, methodName, new Object[] {p1, p2, p3, p4}, new Class[4]);
+    }
+       
+    public Object invokeThisMethod(final Object object, final Class thisType, final String methodName) {
+        return invokeThisMethod(object, thisType, methodName, NO_PARAMETERS, NO_PARAMETER_TYPES);
+    }
+       
+    public Object invokeThisMethod(final Object object, final Class thisType, final String methodName, final Object p1, final Class c1) {
+        return invokeThisMethod(object, thisType, methodName, new Object[] {p1}, new Class[] {c1});
+    }
+       
+    public Object invokeThisMethod(final Object object, final Class thisType, final String methodName, final Object p1) {
+        return invokeThisMethod(object, thisType, methodName, new Object[] {p1}, new Class[1]);
+    }
+
+    public Object invokeThisMethod(final Object object, final Class thisType, final String methodName, final Object p1, final Object p2, final Class c1, final Class c2) {
+        return invokeThisMethod(object, thisType, methodName, new Object[] {p1, p2}, new Class[] {c1, c2});
+    }
+
+    public Object invokeThisMethod(final Object object, final Class thisType, final String methodName, final Object p1, final Object p2) {
+        return invokeThisMethod(object, thisType, methodName, new Object[] {p1, p2}, new Class[2]);
+    }
+
+    public Object invokeThisMethod(final Object object, final Class thisType, final String methodName, final Object p1, final Object p2, final Object p3, final Class c1, final Class c2, final Class c3) {
+        return invokeThisMethod(object, thisType, methodName, new Object[] {p1, p2, p3}, new Class[] {c1, c2, c3});
+    }
+
+    public Object invokeThisMethod(final Object object, final Class thisType, final String methodName, final Object p1, final Object p2, final Object p3) {
+        return invokeThisMethod(object, thisType, methodName, new Object[] {p1, p2, p3}, new Class[3]);
+    }
+
+    public Object invokeThisMethod(final Object object, final Class thisType, final String methodName, final Object p1, final Object p2, final Object p3, final Object p4, final Class c1, final Class c2, final Class c3, final Class c4) {
+        return invokeThisMethod(object, thisType, methodName, new Object[] {p1, p2, p3, p4}, new Class[] {c1, c2, c3, c4});
+    }
+
+    public Object invokeThisMethod(final Object object, final Class thisType, final String methodName, final Object p1, final Object p2, final Object p3, final Object p4) {
+        return invokeThisMethod(object, thisType, methodName, new Object[] {p1, p2, p3, p4}, new Class[4]);
+    }
+}
diff --git a/groovy-core/experimental/org/codehaus/groovy/runtime/MetaClassActions.java b/groovy-core/experimental/org/codehaus/groovy/runtime/MetaClassActions.java
new file mode 100644
index 0000000..cb2bd9a
--- /dev/null
+++ b/groovy-core/experimental/org/codehaus/groovy/runtime/MetaClassActions.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.runtime;
+
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public abstract class MetaClassActions {
+  protected int chooseMethod(final Class[][] formalParameterLists, final Object[] actualParameters) {
+    return 0; // TODO: implement parameter choosing code
+  }
+  
+  public abstract Object doInvokeMethod(Object target, String name, Object[] args) throws Exception;
+}
diff --git a/groovy-core/experimental/org/codehaus/groovy/runtime/MetaClassActionsGenerator.java b/groovy-core/experimental/org/codehaus/groovy/runtime/MetaClassActionsGenerator.java
new file mode 100644
index 0000000..146544c
--- /dev/null
+++ b/groovy-core/experimental/org/codehaus/groovy/runtime/MetaClassActionsGenerator.java
@@ -0,0 +1,382 @@
+package org.codehaus.groovy.runtime;
+import groovy.lang.MetaMethod;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import org.codehaus.groovy.runtimemetaclassactionssupport.DefaultGroovyInstanceMethodGenerator;
+import org.codehaus.groovy.runtimemetaclassactionssupport.DefaultGroovyStaticMethodGenerator;
+import org.codehaus.groovy.runtimemetaclassactionssupport.InstanceMethodGenerator;
+import org.codehaus.groovy.runtimemetaclassactionssupport.MethodGenerator;
+import org.codehaus.groovy.runtimemetaclassactionssupport.ReflectionMethodGenerator;
+import org.codehaus.groovy.runtimemetaclassactionssupport.StaticMethodGenerator;
+
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.
+ *
+ */
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class MetaClassActionsGenerator {
+  private static final Map actionsInfoMap = new WeakHashMap();
+  
+  static {
+    actionsInfoMap.put(Object.class, new ActionsInfo(Object.class));
+  }
+
+  public static MetaClassActions getActions(final Class claz) {
+    return getActionsInfo(claz).getActions();
+  }
+  
+  protected static ActionsInfo getActionsInfo(final Class claz) {
+  ActionsInfo classInfo = (ActionsInfo)actionsInfoMap.get(claz);
+  
+    if (classInfo == null) {
+    final Class superClass = claz.getSuperclass();
+    
+      if (superClass != null) {
+        getActionsInfo(superClass); // ensure that the superclass information has been created
+      }
+      
+      classInfo = new ActionsInfo(claz);
+      actionsInfoMap.put(claz, classInfo);
+    }
+    
+    return classInfo;
+  }
+}
+
+class ActionsInfo {
+  private static Map defaultGroovyMethodsMap = new HashMap();
+  static {
+    try {
+      final Method[] defaultGroovyMethods = Class.forName("org.codehaus.groovy.runtime.DefaultGroovyMethods").getDeclaredMethods();
+      
+      for (int i = 0; i != defaultGroovyMethods.length; i++) {
+        final Method method = defaultGroovyMethods[i];
+        
+        if ((method.getModifiers() & (Modifier.PUBLIC | Modifier.STATIC)) == (Modifier.PUBLIC | Modifier.STATIC)) {
+        final Class[] parameterTypes = method.getParameterTypes();
+        
+          if (parameterTypes.length != 0) {
+          List methodList = (List)defaultGroovyMethodsMap.get(parameterTypes[0]);
+          
+            if (methodList == null) {
+              methodList = new LinkedList();
+              defaultGroovyMethodsMap.put(parameterTypes[0], methodList);
+            }
+
+            methodList.add(new DefaultGroovyInstanceMethodGenerator(method));
+          }
+        }
+      }
+    } catch (SecurityException e) {
+      e.printStackTrace();
+    } catch (ClassNotFoundException e) {
+      e.printStackTrace();
+    }
+  }
+  
+  private static Map defaultGroovyStaticMethodsMap = new HashMap();
+  static {
+    try {
+      final Method[] defaultGroovyStaticMethods = Class.forName("org.codehaus.groovy.runtime.DefaultGroovyStaticMethods").getDeclaredMethods();
+      
+      for (int i = 0; i != defaultGroovyStaticMethods.length; i++) {
+        final Method method = defaultGroovyStaticMethods[i];
+        
+        if ((method.getModifiers() & (Modifier.PUBLIC | Modifier.STATIC)) == (Modifier.PUBLIC | Modifier.STATIC)) {
+        final Class[] parameterTypes = method.getParameterTypes();
+        
+          if (parameterTypes.length != 0) {
+          List methodList = (List)defaultGroovyStaticMethodsMap.get(parameterTypes[0]);
+          
+            if (methodList == null) {
+              methodList = new LinkedList();
+              defaultGroovyStaticMethodsMap.put(parameterTypes[0], methodList);
+            }
+
+            methodList.add(new DefaultGroovyStaticMethodGenerator(method));
+          }
+        }
+      }
+    } catch (SecurityException e) {
+      e.printStackTrace();
+    } catch (ClassNotFoundException e) {
+      e.printStackTrace();
+    }
+  }
+  
+  private MetaClassActions actions = null;
+  private final List generators = new LinkedList();
+
+  public ActionsInfo(final Class claz) {
+  final Package pack = claz.getPackage();
+  final String packageName = "groovy.runtime.metaclassactions." + ((pack == null) ? "" : pack.getName() + ".");
+  
+    setUpGenerators(claz);  // Need to do this even if the class is already generated
+  
+    try {
+    final Class actionsClass = Class.forName(packageName + claz.getSimpleName() + "MetaClassActions");
+    
+      this.actions = (MetaClassActions)actionsClass.newInstance();
+    } catch (final Exception e1) {
+    final File generatedFile = new File("generated/" + packageName.replace('.', '/'));
+      
+      generatedFile.mkdirs();
+      
+      try {
+      final Writer out = new FileWriter(new File(generatedFile,  claz.getSimpleName() + "MetaClassActions.java"));
+      
+        try {
+          out.write(generateJavaFile(claz));
+        } finally {    
+          out.close();
+        }
+      } catch (final IOException e) {
+         e.printStackTrace();
+      }
+    }  
+  }
+  
+  public MetaClassActions getActions() {
+    return this.actions;
+  }
+  
+  private void setUpGenerators(final Class claz) {
+  final Method[] methods = claz.getDeclaredMethods();
+  final List defaultMethods = (List)defaultGroovyMethodsMap.get(claz);
+  final List defaultStaticMethods = (List)defaultGroovyStaticMethodsMap.get(claz);
+  
+    if (defaultMethods != null) {
+      this.generators.addAll(defaultMethods);
+    }
+    
+    if (defaultStaticMethods != null) {
+      this.generators.addAll(defaultStaticMethods);
+    }
+    
+    for (int i = 0; i != methods.length; i++) {
+    final Method method = methods[i];
+    final int methodModifiers = method.getModifiers();
+    
+      if ((methodModifiers & Modifier.PUBLIC) != 0) {        
+        if ((methodModifiers & Modifier.STATIC) != 0) {
+          this.generators.add(new StaticMethodGenerator(method));
+        } else {
+          this.generators.add(new InstanceMethodGenerator(method));
+        }
+      } else if ((methodModifiers & Modifier.PROTECTED) != 0) {
+        this.generators.add(new ReflectionMethodGenerator(method));
+      }
+    }
+    
+    if (claz != Object.class) {
+    final Class superClass = claz.getSuperclass();
+    
+      if (superClass != null) {
+        this.generators.addAll(MetaClassActionsGenerator.getActionsInfo(superClass).generators);
+      }
+      
+      final Class[] interfaces = claz.getInterfaces();
+      
+      for (int i = 0; i != interfaces.length; i++) {
+        this.generators.addAll(MetaClassActionsGenerator.getActionsInfo(interfaces[i]).generators);
+      }
+    }
+    
+    Collections.sort(this.generators, new Comparator() {
+      public int compare(final Object lhs, final Object rhs) {
+      final int lhsNumberOfParameters = ((MethodGenerator)lhs).getNumberOfParameters();
+      final int rhsNumberOfParameters = ((MethodGenerator)rhs).getNumberOfParameters();
+      
+        if (lhsNumberOfParameters  == rhsNumberOfParameters) {
+        final String lhsName = ((MethodGenerator)lhs).getName();
+        final String rhsName = ((MethodGenerator)rhs).getName();
+        
+          return lhsName.compareTo(rhsName);
+        } else if (lhsNumberOfParameters  < rhsNumberOfParameters) {
+          return -1;
+        } else {
+          return 1;
+        }
+      }
+    });
+    
+    if (this.generators.size() > 1) {
+    MethodGenerator g1 = (MethodGenerator)this.generators.get(this.generators.size() - 1);
+      
+      for (int i = this.generators.size() - 2; i > -1 ; i--) {
+      final MethodGenerator g2 = (MethodGenerator)this.generators.get(i);
+      
+        if (g1.isOverloaded(g2)) {
+          this.generators.remove(i + 1);
+          g1 = g1.processOverloaded(claz, g2);
+          this.generators.set(i, g1);
+        } else {
+          g1 = g2;
+        }
+      }
+    }
+  }
+  
+  private String generateJavaFile(final Class claz) {
+  final StringBuffer code = new StringBuffer();
+    
+    generateStartOfFile(claz, code);
+    
+    final Iterator iter = this.generators.iterator();
+    int methodIndex = 0;
+    while (iter.hasNext()) {
+    final MethodGenerator gen = (MethodGenerator)iter.next();
+    
+      code.append(gen.generateDeclaration(methodIndex++));
+    }
+    
+    generateInvokemethod(claz, code);
+    
+    generateEndOfFile(claz, code);
+    
+    return code.toString();
+  }
+  
+  private void addMethod(final Set methodSet, final Map methodMap, final List methods) {
+  final Iterator methodIterator = methods.iterator();
+    
+    while (methodIterator.hasNext()) {
+      final MetaMethod method = (MetaMethod)methodIterator.next();
+      final String name = method.getName();
+      
+      methodSet.add(name);
+      
+      List methodList = (List)methodMap.get(name);
+      if (methodList == null) {
+        methodList = new LinkedList();
+        
+        methodMap.put(name, methodList);
+      }
+      methodList.add(method);
+    }
+  }
+  
+  private void generateStartOfFile(final Class claz, final StringBuffer code) {
+  final Package pack = claz.getPackage();
+  final String packageName = (pack == null) ? "" : "." + pack.getName();
+  
+    code.append("package groovy.runtime.metaclassactions").append(packageName).append(";\n");
+    code.append("import java.lang.reflect.Method;\n");
+    code.append("import java.security.AccessController;\n");
+    code.append("import java.security.PrivilegedAction;\n");
+    code.append("public class ").append(claz.getSimpleName()).append("MetaClassActions extends org.codehaus.groovy.runtime.MetaClassActions {\n");
+  }
+  
+  private void generateInvokemethod(final Class claz, final StringBuffer code) {
+    
+    code.append("public Object doInvokeMethod(final Object target, final String name, final Object[] args) ");
+    code.append("throws Exception {\n");
+    
+    if (this.generators.size() != 0) {
+    final List generatorSubset = new LinkedList();
+    MethodGenerator firstGenerator = (MethodGenerator)this.generators.get(0);
+    int currentArgsLength = firstGenerator.getNumberOfParameters();
+    char firstChar = firstGenerator.getName().charAt(0);
+    final Iterator iter = this.generators.iterator();
+    
+      while (iter.hasNext()) {
+      final MethodGenerator generator = (MethodGenerator)iter.next();
+      
+        if (currentArgsLength == generator.getNumberOfParameters()) {
+          generatorSubset.add(generator);
+        } else {
+          generateCalls(claz, code, currentArgsLength, generatorSubset);
+          currentArgsLength = generator.getNumberOfParameters();
+        }
+      }
+      
+      generateCalls(claz, code, currentArgsLength, generatorSubset);
+      
+      code.setLength(code.length() - 6);  // chop the trailing " else "     
+    }
+    
+    code.append("\nreturn groovy.lang.MetaClass.NO_METHOD_FOUND;");
+    code.append("\n}\n");
+  }
+  
+  private void generateCalls(final Class claz, final StringBuffer code, final int currentArgsLength, final List generatorSubset) {
+    if (generatorSubset.size() != 0) {
+      code.append("if (args.length == ").append(currentArgsLength).append(") {\n");
+      code.append("switch(name.charAt(0)) {");
+      
+      boolean firstCase = true;
+      final Iterator iter1 = generatorSubset.iterator();
+      char fc = 0;
+      
+      while (iter1.hasNext()) {
+      final MethodGenerator generator1 = (MethodGenerator)iter1.next();
+      final String name = generator1.getName();
+      
+        if (fc != name.charAt(0)) {
+          if (firstCase) {
+            firstCase = false;
+          } else {
+            code.append(" else {\n");
+            code.append("return groovy.lang.MetaClass.NO_METHOD_FOUND;\n");
+            code.append("}");
+          }
+          fc = name.charAt(0);
+          code.append("\ncase '").append(fc).append("' :\n");
+          code.append("if (\"").append(generator1.getName()).append("\".equals(name)) {\n");
+          code.append(generator1.generateCall(claz));
+          code.append("}");
+        } else {
+          code.append(" else if (\"").append(generator1.getName()).append("\".equals(name)) {\n");
+          code.append(generator1.generateCall(claz));
+          code.append("}");
+        }
+      }
+      
+      code.append(" else {\n");
+      code.append("return groovy.lang.MetaClass.NO_METHOD_FOUND;\n");
+      code.append("}\n");
+      code.append("default:\n");
+      code.append("return groovy.lang.MetaClass.NO_METHOD_FOUND;\n");
+      code.append("}\n");
+      code.append("} else ");
+      
+      generatorSubset.clear();
+    }
+  }
+  
+  private void generateEndOfFile(final Class claz, final StringBuffer code) {
+    code.append("}\n");
+  }
+}
diff --git a/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/DefaultGroovyInstanceMethodGenerator.java b/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/DefaultGroovyInstanceMethodGenerator.java
new file mode 100644
index 0000000..30b4666
--- /dev/null
+++ b/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/DefaultGroovyInstanceMethodGenerator.java
@@ -0,0 +1,70 @@
+package org.codehaus.groovy.runtimemetaclassactionssupport;
+import java.lang.reflect.Method;
+
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.
+ *
+ */
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class DefaultGroovyInstanceMethodGenerator extends MethodGenerator {
+
+  /**
+   * @param method
+   */
+  public DefaultGroovyInstanceMethodGenerator(Method method) {
+    super(method);
+  }
+  
+  public int getNumberOfParameters() {
+    return this.method.getParameterTypes().length - 1;
+  }
+  
+  /* (non-Javadoc)
+   * @see MethodGenerator#getParameterTypes()
+   */
+  public Class[] getParameterTypes() {
+  final Class[] parameterTypes = this.method.getParameterTypes();
+  final Class[] result = new Class[parameterTypes.length - 1];
+  
+    System.arraycopy(parameterTypes, 1, result, 0, result.length);
+    return result;
+  }
+
+  protected void startCall(final StringBuffer code) {
+    code.append(DEFAULT_GROOVY_METHODS).append('.').append(this.method.getName()).append('(');
+  }
+  
+  protected StringBuffer addParameters(final StringBuffer code, final Class[] parameterTypes) {   
+  final Class[] newParameterTypes = new Class[parameterTypes.length - 1];
+    
+    System.arraycopy(parameterTypes, 1, newParameterTypes, 0, newParameterTypes.length);
+    
+    code.append('(');
+    getFullName(parameterTypes[0], code);
+    
+    if (newParameterTypes.length == 0) {
+      code.append(")target");
+    } else {
+      code.append(")target, ");
+    }
+    
+    return super.addParameters(code, newParameterTypes);
+  }
+}
diff --git a/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/DefaultGroovyStaticMethodGenerator.java b/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/DefaultGroovyStaticMethodGenerator.java
new file mode 100644
index 0000000..8a156c6
--- /dev/null
+++ b/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/DefaultGroovyStaticMethodGenerator.java
@@ -0,0 +1,41 @@
+package org.codehaus.groovy.runtimemetaclassactionssupport;
+import java.lang.reflect.Method;
+
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.
+ *
+ */
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class DefaultGroovyStaticMethodGenerator extends MethodGenerator {
+
+  /**
+   * @param method
+   */
+  public DefaultGroovyStaticMethodGenerator(Method method) {
+    super(method);
+  }
+
+  /* (non-Javadoc)
+   * @see MethodGenerator#startCall(java.lang.StringBuffer)
+   */
+  protected void startCall(StringBuffer code) {
+    code.append(DEFAULT_STATIC_GROOVY_METHODS).append('.').append(this.method.getName()).append('(');
+  }
+}
diff --git a/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/InstanceMethodGenerator.java b/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/InstanceMethodGenerator.java
new file mode 100644
index 0000000..863d970
--- /dev/null
+++ b/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/InstanceMethodGenerator.java
@@ -0,0 +1,35 @@
+package org.codehaus.groovy.runtimemetaclassactionssupport;
+
+import java.lang.reflect.Method;
+
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.
+ *
+ */
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class InstanceMethodGenerator extends MethodGenerator {
+  public InstanceMethodGenerator(final Method method) {
+    super(method);
+  }
+  
+  protected void startCall(final StringBuffer code) {
+    code.append("((").append(this.method.getDeclaringClass().getName()).append(")target).").append(this.method.getName()).append('(');
+  }
+}
diff --git a/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/MethodGenerator.java b/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/MethodGenerator.java
new file mode 100644
index 0000000..7d67444
--- /dev/null
+++ b/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/MethodGenerator.java
@@ -0,0 +1,193 @@
+package org.codehaus.groovy.runtimemetaclassactionssupport;
+import groovy.lang.GString;
+
+import java.lang.reflect.Method;
+
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.
+ *
+ */
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public abstract class MethodGenerator {
+  protected final static String DEFAULT_GROOVY_METHODS = "org.codehaus.groovy.runtime.DefaultGroovyMethods";
+  protected final static String DEFAULT_STATIC_GROOVY_METHODS = "org.codehaus.groovy.runtime.DefaultGroovyStaticMethods";
+  
+  protected final Method method;
+    
+  /**
+   * @param method
+   */
+  public MethodGenerator(Method method) {
+    this.method = method;
+  }
+  
+  public String getName() {
+    return this.method.getName();
+  }
+  
+  public int getNumberOfParameters() {
+    return this.method.getParameterTypes().length;
+  }
+  
+  public Class[] getParameterTypes() {
+    return this.method.getParameterTypes();
+  }
+  
+  public boolean isOverloaded(final MethodGenerator other) {
+    return getName().equals(other.getName()) && getNumberOfParameters() == other.getNumberOfParameters();
+  }
+  
+  public MethodGenerator processOverloaded(final Class claz, final MethodGenerator other) {
+  final Class[] p1 = getParameterTypes();
+  final Class[] p2 = other.getParameterTypes();
+  
+    for (int i = 0; i != p1.length; i++) {
+      if (p1[i] != p2[i]) {
+        return new OverloadedMethodsGenerator(this, other); // We have an overloaded method 
+      }
+    }
+    
+    // We have a duplicate - return the one which has its declaring class as the current class
+    
+    if (this.method.getDeclaringClass() == claz) {
+      return this;
+    } else {
+      return other;
+    }
+  }
+   
+  public String generateDeclaration(int methodIndex) {
+    return "";
+  }
+  
+  public String generateCall(final Class claz) {
+  final StringBuffer code = new StringBuffer();
+  final Class returnType = method.getReturnType();
+    
+    if (returnType.isPrimitive()) {
+      if (returnType == void.class) {
+        makeCall(code).append(";\nreturn null;\n");
+      } else if (returnType == int.class) {
+        code.append("return new Integer(");
+        makeCall(code).append(");\n");  
+      } else if (returnType == long.class) {
+        code.append("return new Long(");
+        makeCall(code).append(");\n");  
+      } else if (returnType == short.class) {
+        code.append("return new Short(");
+        makeCall(code).append(");\n");  
+      } else if (returnType == char.class) {
+        code.append("return new Char(");
+        makeCall(code).append(");\n");  
+      } else if (returnType == byte.class) {
+        code.append("return new Byte(");
+        makeCall(code).append(");\n");  
+      } else if (returnType == boolean.class) {
+        code.append("return new Boolean(");
+        makeCall(code).append(");\n");  
+      } else if (returnType == float.class) {
+        code.append("return new Float(");
+        makeCall(code).append(");\n");  
+      } else if (returnType == double.class) {
+        code.append("return new Double(");
+        makeCall(code).append(");\n");  
+      } else {
+        code.append("**** ERROR ***** found primitive return type: " + returnType.getName());
+      }
+    } else {
+      code.append("return ");
+      makeCall(code).append(";\n");  
+    }
+    
+    return code.toString();
+  }
+  
+  private StringBuffer makeCall(final StringBuffer code) {
+    startCall(code);
+    addParameters(code, this.method.getParameterTypes()).append(')');
+    
+    return code;
+  }
+  
+  protected abstract void startCall(StringBuffer code);
+  
+  protected StringBuffer addParameters(final StringBuffer code, final Class[] parameterTypes) {
+    if (parameterTypes.length != 0) {
+      for (int i = 0; i != parameterTypes.length; i++) {
+      final Class parameterType = parameterTypes[i]; 
+        
+        if (parameterType.isPrimitive()) {
+          if (parameterType == int.class) {
+            code.append("((Number)").append("args[");
+            code.append(i).append("]).intValue(), ");
+          } else if (parameterType == long.class) {
+            code.append("((Number)").append("args[");
+            code.append(i).append("]).longValue(), ");
+          } else if (parameterType == short.class) {
+            code.append("((Number)").append("args[");
+            code.append(i).append("]).shortValue(), ");
+          } else if (parameterType == char.class) {
+            code.append("((Character)").append("args[");
+            code.append(i).append("]).charValue(), ");
+          } else if (parameterType == byte.class) {
+            code.append("((Number)").append("args[");
+            code.append(i).append("]).byteValue(), ");
+          } else if (parameterType == boolean.class) {
+            code.append("((Boolean)").append("args[");
+            code.append(i).append("]).booleanValue(), ");
+          } else if (parameterType == float.class) {
+            code.append("((Number)").append("args[");
+            code.append(i).append("]).floatValue(), ");
+          } else if (parameterType == double.class) {
+            code.append("((Number)").append("args[");
+            code.append(i).append("]).doubleValue(), ");
+          } else {
+            code.append("**** ERROR ***** found primative parameter type: " + parameterType.getName());
+          }
+        } else if (parameterType == String.class) {
+          code.append("args[").append(i).append("].toString(), ");
+        } else if (parameterType == GString.class) {
+          code.append("(groovy.lang.GString)((args[").append(i).append("] instanceof groovy.lang.GString) ? ");
+          code.append("args[").append(i).append("] : ");
+          code.append("new groovy.lang.GString(args[").append(i).append("].toString()){public String[] getStrings() {return (String [])this.getValues();}}), ");
+        } else {
+          code.append('(');
+          getFullName(parameterType, code);
+          code.append(")args[").append(i).append("], ");
+        }
+      }
+      
+      code.setLength(code.length() - 2);  // trim the last "' " off
+    }
+    
+    return code;
+  }
+  
+  protected StringBuffer getFullName(final Class claz, final StringBuffer code) {
+  final Package classPackage = (claz.isArray()) ? claz.getComponentType().getPackage() : claz.getPackage(); 
+  
+    if (classPackage != null) {
+      code.append(classPackage.getName()).append('.') ;
+    }
+
+    return code.append(claz.getSimpleName());
+  }
+}
+
diff --git a/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/OverloadedMethodsGenerator.java b/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/OverloadedMethodsGenerator.java
new file mode 100644
index 0000000..a7c0a60
--- /dev/null
+++ b/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/OverloadedMethodsGenerator.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.runtimemetaclassactionssupport;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class OverloadedMethodsGenerator extends MethodGenerator {
+  private final MethodGenerator firstMethod;
+  private final List generatorList = new LinkedList();
+  private int methodIndex = 0;
+  
+  public OverloadedMethodsGenerator(final MethodGenerator firstMethod, final MethodGenerator secondMethod) {
+    super(null);
+    
+    this.firstMethod = firstMethod;
+    this.generatorList.add(firstMethod);
+    this.generatorList.add(secondMethod);
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.runtimemetaclassactionssupport.MethodGenerator#generateCall(java.lang.Class)
+   */
+  public String generateCall(final Class claz) {
+  final StringBuffer code = new StringBuffer();
+  final Iterator iter = this.generatorList.iterator();
+  int i = 0;
+  
+    code.append("switch(chooseMethod(possible").append(getName()).append("Parameters").append(this.methodIndex).append(", args)) {\n");
+    while (iter.hasNext()) {
+    final MethodGenerator generator = (MethodGenerator)iter.next();
+      
+      code.append("case ").append(i++).append(": \n");
+      code.append(generator.generateCall(claz));
+    }
+    code.append("default:\n");
+    code.append("return groovy.lang.MetaClass.NO_METHOD_FOUND;\n");
+    code.append("}\n");
+
+    return code.toString();
+  }
+  
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.runtimemetaclassactionssupport.MethodGenerator#startCall(java.lang.StringBuffer)
+   */
+  protected void startCall(final StringBuffer code) {
+
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.runtimemetaclassactionssupport.MethodGenerator#generateDeclaration(int)
+   */
+  public String generateDeclaration(final int methodIndex) {
+  final StringBuffer code = new StringBuffer();
+  final Iterator iter = this.generatorList.iterator();
+  int i = 1;
+  
+    this.methodIndex = methodIndex;
+  
+    while (iter.hasNext()) {
+    final MethodGenerator generator = (MethodGenerator)iter.next();
+    
+      code.append(generator.generateDeclaration((methodIndex << 16) | i )); // TODO: find a better way of getting unique indexes
+    }
+    
+    code.append("private final Class[][] possible").append(getName()).append("Parameters").append(methodIndex).append(" = new Class[][]{\n");
+    final Iterator iter1 = this.generatorList.iterator();
+
+    while (iter1.hasNext()) {
+    final MethodGenerator generator = (MethodGenerator)iter1.next();
+    final Class[] parameterTypes = generator.getParameterTypes();
+    
+      code.append("new Class[] {");
+      
+      for (int j = 0; j != parameterTypes.length; j++) {
+      final Class parameterType = parameterTypes[j];
+      
+        if (parameterType.isPrimitive()) {
+          if (parameterType == int.class) {
+            code.append("int");
+          } else if (parameterType == long.class) {
+            code.append("long");
+          } else if (parameterType == short.class) {
+            code.append("short");
+          } else if (parameterType == char.class) {
+            code.append("char");
+          } else if (parameterType == byte.class) {
+            code.append("byte");
+          } else if (parameterType == boolean.class) {
+            code.append("boolean");
+          } else if (parameterType == float.class) {
+            code.append("float");
+          } else if (parameterType == double.class) {
+            code.append("double");
+          } else {
+            code.append("**** ERROR ***** found primative parameter type: " + parameterType.getName());
+          }
+        } else {
+          getFullName(parameterType, code);
+        }
+        code.append(".class, ");
+      }
+      
+      code.setLength(code.length() - 2);  // Trim the trailing ", "
+      code.append("},\n ");
+    }
+    
+    code.setLength(code.length() - 3);  // Trim the trailing ",\n "
+    code.append("\n};\n");
+    return code.toString();
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.runtimemetaclassactionssupport.MethodGenerator#getName()
+   */
+  public String getName() {
+    return firstMethod.getName();
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.runtimemetaclassactionssupport.MethodGenerator#getNumberOfParameters()
+   */
+  public int getNumberOfParameters() {
+    return firstMethod.getNumberOfParameters();
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.runtimemetaclassactionssupport.MethodGenerator#getParameterTypes()
+   */
+  public Class[] getParameterTypes() {
+    return firstMethod.getParameterTypes();
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.runtimemetaclassactionssupport.MethodGenerator#isOverloaded(org.codehaus.groovy.runtimemetaclassactionssupport.MethodGenerator)
+   */
+  public boolean isOverloaded(final MethodGenerator other) {
+     return firstMethod.isOverloaded(other);
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.runtimemetaclassactionssupport.MethodGenerator#processOverloaded(java.lang.Class, org.codehaus.groovy.runtimemetaclassactionssupport.MethodGenerator)
+   */
+  public MethodGenerator processOverloaded(final Class claz, final MethodGenerator other) {
+    if (other instanceof OverloadedMethodsGenerator) {
+    final Iterator iter = ((OverloadedMethodsGenerator)other).generatorList.iterator();
+    
+      while (iter.hasNext()) {
+        processOverloaded(claz, (MethodGenerator)iter.next());
+      }
+    } else {
+    final Class[] p1 = other.getParameterTypes();
+  
+      for (int i = 0; i != this.generatorList.size(); i++) {
+      final MethodGenerator generator = (MethodGenerator)this.generatorList.get(i);
+      final Class[] p2 = generator.getParameterTypes();
+      int j = 0;
+      
+        while (p1[j] == p2[j] && ++j != p1.length);
+        
+        if (j == p1.length) {
+          // other is a duplicate of this method
+          if (other.method.getDeclaringClass() == claz) {
+            this.generatorList.add(i, other);
+          }
+          
+          return this;
+        }
+      }
+      
+      this.generatorList.add(other);
+    }
+    
+    return this;
+  }
+}
diff --git a/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/ReflectionMethodGenerator.java b/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/ReflectionMethodGenerator.java
new file mode 100644
index 0000000..d751c1a
--- /dev/null
+++ b/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/ReflectionMethodGenerator.java
@@ -0,0 +1,106 @@
+package org.codehaus.groovy.runtimemetaclassactionssupport;
+import java.lang.reflect.Method;
+
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.
+ *
+ */
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class ReflectionMethodGenerator extends MethodGenerator {
+  private int methodIndex;
+  
+  /**
+   * @param method
+   */
+  public ReflectionMethodGenerator(Method method) {
+    super(method);
+  }
+
+  /* (non-Javadoc)
+   * @see MethodGenerator#generateCall()
+   */
+  public String generateCall(final Class claz) {
+  final StringBuffer code = new StringBuffer();
+    
+    code.append("return ").append(this.method.getName() + this.methodIndex).append("Method.invoke(target, args);\n");
+
+    return code.toString();
+  }
+
+  public String generateDeclaration(final int methodIndex) {
+  final StringBuffer code = new StringBuffer();
+    
+    this.methodIndex = methodIndex;
+    
+    code.append("private Method ").append(this.method.getName() + this.methodIndex).append("Method;\n");
+    code.append("{\ntry {\n").append(this.method.getName() + this.methodIndex).append("Method = ");
+    code.append(this.method.getDeclaringClass().getName()).append(".class.getDeclaredMethod(\"").append(this.method.getName()).append("\", new Class[] {");
+    
+    final Class[] parameterTypes = this.method.getParameterTypes();
+    if (parameterTypes.length != 0){
+      for (int i = 0; i != parameterTypes.length; i++) {
+      final Class parameterType = parameterTypes[i];
+      
+        if (parameterType.isPrimitive()) {
+          if (parameterType == void.class) {
+            code.append("void.class, ");
+          } else if (parameterType == int.class) {
+            code.append("void.class, ");
+          } else if (parameterType == long.class) {
+            code.append("void.class, ");
+          } else if (parameterType == short.class) {
+            code.append("void.class, ");
+          } else if (parameterType == char.class) {
+            code.append("void.class, ");
+          } else if (parameterType == byte.class) {
+            code.append("void.class, ");
+          } else if (parameterType == boolean.class) {
+            code.append("void.class, ");
+          } else if (parameterType == float.class) {
+            code.append("void.class, ");
+          } else if (parameterType == double.class) {
+            code.append("void.class, ");
+          } else {
+            code.append("**** ERROR ***** found primative return type: " + parameterType.getName());
+          }
+        } else {
+          getFullName(parameterType, code);
+          code.append(".class, ");
+        }
+      }
+      
+      code.setLength(code.length() - 2);   // trim the last ", " off
+    }
+    
+    code.append("});\n");
+    code.append("AccessController.doPrivileged(new PrivilegedAction() {\npublic Object run() {\n");
+    code.append(this.method.getName() + this.methodIndex).append("Method.setAccessible(true);\nreturn null;\n}\n});\n");
+    code.append("} catch (final NoSuchMethodException e) {}\n}\n");
+    
+    return code.toString();
+  }
+  
+  /* (non-Javadoc)
+   * @see MethodGenerator#startCall(java.lang.StringBuffer)
+   */
+  protected void startCall(StringBuffer code) {
+  }
+
+}
diff --git a/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/StaticMethodGenerator.java b/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/StaticMethodGenerator.java
new file mode 100644
index 0000000..2cae3ce
--- /dev/null
+++ b/groovy-core/experimental/org/codehaus/groovy/runtimemetaclassactionssupport/StaticMethodGenerator.java
@@ -0,0 +1,38 @@
+package org.codehaus.groovy.runtimemetaclassactionssupport;
+import java.lang.reflect.Method;
+
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.
+ *
+ */
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class StaticMethodGenerator extends MethodGenerator {
+
+  /**
+   * @param method
+   */
+  public StaticMethodGenerator(final Method method) {
+    super(method);
+  }
+
+  protected void startCall(final StringBuffer code) {
+    code.append(this.method.getDeclaringClass().getName()).append('.').append(this.method.getName()).append('(');
+  }
+}
diff --git a/groovy-core/maven.xml b/groovy-core/maven.xml
new file mode 100644
index 0000000..bffa373
--- /dev/null
+++ b/groovy-core/maven.xml
@@ -0,0 +1,686 @@
+<project default="default" xmlns:j="jelly:core" xmlns:u="jelly:util" xmlns:maven="jelly:maven">
+
+  <goal name="default" prereqs="clean, groovy:make-install"/>
+
+  <goal name="dc" prereqs="clean">
+    <attainGoal name="jar:deploy-snapshot"/>
+
+    <j:set var="maven.test.skip" value="true"/>
+
+    <attainGoal name="site:deploy"/>
+  </goal>
+
+  <goal name="modules" description="Builds related modules">
+    <maven:reactor
+       basedir="${basedir}/../modules"
+       includes="xmlrpc/project.xml" 
+       banner="Executing build:"
+       ignoreFailures="false"
+       postProcessing="true"
+       goals="jar"
+       />
+  </goal>
+
+  <preGoal name="java:compile">
+    <attainGoal name="generate"/>
+  </preGoal>
+
+  <postGoal name="dist:prepare-src-filesystem">
+    <!-- lets zap the build.xml -->
+    <delete file="${maven.dist.src.assembly.dir}/build.xml"/>
+
+  </postGoal>
+  
+  <goal name="generate" description="Regenerates the groovy grammar from antlr sources">
+    <j:set var="maven.antlr.grammars" value="groovy.g"/>
+    <j:set var="maven.antlr.src.dir" value="${basedir}/src/main/org/codehaus/groovy/antlr"/>
+    <j:set var="maven.antlr.target.dir" value="${basedir}/src/main"/>
+
+    <delete file="${basedir}/src/main/org/codehaus/groovy/antlr/parser/GroovyRecognizer.java"/>
+    <delete file="${basedir}/src/main/org/codehaus/groovy/antlr/parser/GroovyLexer.java"/>
+    <delete file="${basedir}/src/main/org/codehaus/groovy/antlr/parser/GroovyTokenTypes.java"/>
+    <delete file="${basedir}/src/main/org/codehaus/groovy/antlr/parser/GroovyTokenTypes.txt"/>
+
+<!--    <attainGoal name="antlr:generate"/> -->
+
+    <mkdir dir="${maven.antlr.target.dir}/org/codehaus/groovy/antlr/parser"/>
+
+    <antlr target="${maven.antlr.src.dir}/${maven.antlr.grammars}"
+           outputdirectory="${maven.antlr.target.dir}/org/codehaus/groovy/antlr/parser">
+      <classpath refid="maven.dependency.classpath"/>
+    </antlr>
+
+
+
+    <j:set var="maven.antlr.grammars" value="java.g"/>
+    <j:set var="maven.antlr.src.dir" value="${basedir}/src/main/org/codehaus/groovy/antlr/java"/>
+    <j:set var="maven.antlr.target.dir" value="${basedir}/src/main"/>
+
+    <delete file="${basedir}/src/main/org/codehaus/groovy/antlr/java/JavaRecognizer.java"/>
+    <delete file="${basedir}/src/main/org/codehaus/groovy/antlr/java/JavaLexer.java"/>
+    <delete file="${basedir}/src/main/org/codehaus/groovy/antlr/java/JavaTokenTypes.java"/>
+    <delete file="${basedir}/src/main/org/codehaus/groovy/antlr/java/JavaTokenTypes.txt"/>
+
+    <mkdir dir="${maven.antlr.target.dir}/org/codehaus/groovy/antlr/java"/>
+    
+    <antlr target="${maven.antlr.src.dir}/${maven.antlr.grammars}"
+           outputdirectory="${maven.antlr.target.dir}/org/codehaus/groovy/antlr/java">
+      <classpath refid="maven.dependency.classpath"/>
+    </antlr>
+  </goal>
+
+  <goal name="rebuild" prereqs="clean" description="Rebuilds the groovy install without running the unit tests">
+   <j:set var="maven.test.skip" value="true"/>
+   <echo>Rebuilding the binary distro of Groovy without running the unit test cases</echo>
+   <attainGoal name="groovy:make-install"/>
+  </goal>
+  
+  <goal name="groovy:release" prereqs="clean, jar:install, release, groovy:disable-unittests, site, dist:deploy-bin, dist:deploy-src, jar:deploy"
+    description="Performs a release of the source, binary and jar distros">
+  </goal>
+
+  <goal name="groovy:disable-unittests" description="Disables the running of the unit test cases">
+   <!-- we've run the tests by now once already, lets avoid it again -->
+   <j:set var="maven.test.skip" value="true"/>
+  </goal>
+
+  <preGoal name="groovy:release">
+   <!-- we've run the tests by now once already, lets avoid it again -->
+   <j:set var="maven.test.skip" value="true"/>
+  </preGoal>
+
+  <goal name="groovy:test-wiki" description="Generates the test cases for the wiki and runs the tests">
+   <attainGoal name="clean"/>
+   <attainGoal name="groovy:compile"/>
+   <j:set var="testcase" value="org.codehaus.groovy.wiki.RunWikiTest"/>
+   <attainGoal name="test:single"/>
+  </goal>
+  
+  <goal name="groovy:test-single" prereqs="groovy:compile" description="Runs a named groovy test case using the 'test' property">
+    <java classname="groovy.util.GroovyTestSuite" fork="yes">
+      <classpath refid="test.classpath"/>
+      <sysproperty key="test" value="${test}"/>
+    </java>
+  </goal>
+  
+
+  <goal name="groovy:test-quick" prereqs="clean" description="Tries running all the unit test cases in the same JVM">
+   <attainGoal name="clean"/>
+   <attainGoal name="groovy:compile"/>
+   <j:set var="testcase" value="org.codehaus.groovy.tools.FindAllTestsSuite"/>
+   <j:set var="maven.junit.usefile" value="false"/>
+   <attainGoal name="test:single"/>
+  </goal>
+  
+  <postGoal name="dist:prepare-bin-filesystem">
+    <attainGoal name="groovy:make-full-install"/>
+    <echo>Copying groovy install to ${maven.dist.bin.assembly.dir}</echo>
+    <copy toDir="${maven.dist.bin.assembly.dir}">
+      <fileset dir="${groovy.install.staging.dest}">
+        <include name="**/*"/>
+        <exclude name="**/*.groovy"/>
+      </fileset>
+    </copy>
+    <chmod perm="ugo+x">
+      <fileset dir="${maven.dist.bin.assembly.dir}/bin">
+        <include name="*"/>
+        <include name="*.*"/>
+      </fileset>
+    </chmod>
+  </postGoal>
+
+  <goal
+    name="dist:build-bin"
+    prereqs="dist:build-setup,dist:prepare-bin-filesystem"
+    description="Build the binary distribution.">
+
+    <!-- Create a tar.gz file -->
+    <tar longfile="gnu" tarfile="${maven.dist.dir}/${maven.final.name}.tar">
+      <tarfileset dir="${maven.dist.bin.archive.dir}" >
+        <exclude name="groovy-${pom.currentVersion}/bin/**" />
+      </tarfileset>
+      <tarfileset dir="${maven.dist.bin.archive.dir}" mode ="0755">
+        <include name="groovy-${pom.currentVersion}/bin/**"  />
+      </tarfileset>
+    </tar>
+
+
+    <gzip
+      zipfile="${maven.dist.dir}/${maven.final.name}.tar.gz"
+      src="${maven.dist.dir}/${maven.final.name}.tar"
+    />
+
+    <delete file="${maven.dist.dir}/${maven.final.name}.tar"/>
+
+    <!-- Create a zip file -->
+    <zip zipfile="${maven.dist.dir}/${maven.final.name}.zip">
+      <zipfileset dir="${maven.dist.bin.archive.dir}"/>
+    </zip>
+  </goal>
+
+
+  <goal name="run" prereqs="test:compile"
+    description="Runs the given compiled Groovy class">
+    <j:if test="${empty(name)}">
+      <j:set var="name" value="HelloWorld"/>
+    </j:if>
+    <echo>Running class $$name = ${name}</echo>
+    <java classname="${name}" fork="yes">
+      <classpath refid="test.classpath"/>
+      <arg value="${args}"/>
+    </java>
+  </goal>
+
+  <goal name="script" prereqs="test:compile"
+    description="Runs the given Groovy script file">
+
+    <j:if test="${empty(name)}">
+      <j:set var="name" value="src/test/groovy/script/HelloWorld.groovy"/>
+    </j:if>
+
+    <echo>Running class $$name = ${name}</echo>
+    <java classname="groovy.lang.GroovyShell" fork="yes">
+      <classpath refid="test.classpath"/>
+      <arg value="${name}"/>
+      <arg value="${args}"/>
+    </java>
+  </goal>
+
+
+  <goal name="console" prereqs="test:compile"
+    description="Runs the Groovy command console">
+    <java classname="groovy.ui.Console" fork="yes">
+      <classpath refid="test.classpath"/>
+    </java>
+<!--
+    <java classname="groovy.lang.GroovyShell" fork="yes">
+      <arg value="src/main/groovy/ui/Console.groovy"/>
+      <classpath refid="test.classpath"/>
+    </java>
+-->    
+  </goal>
+
+  <goal name="swing:demo" prereqs="test:compile"
+    description="Runs the GroovySwing demo">
+    <java classname="groovy.swing.Demo" fork="yes">
+      <classpath refid="test.classpath"/>
+    </java>
+  </goal>
+
+
+
+  <preGoal name="xdoc:jelly-transform">
+    <attainGoal name="groovy:xdoc-stuff"/>
+  </preGoal>
+
+  <goal name="groovy:xdoc-stuff" prereqs="java:compile, setclasspath, groovy:make-new-javadoc">
+    <mkdir dir="${maven.html2xdoc.dir}"/>
+    <!--
+    <copy toDir="${maven.html2xdoc.dir}">
+      <fileset dir="${basedir}/xdocs">
+        <include name="**/*.html"/>
+      </fileset>
+    </copy>
+    -->
+
+    <!-- now lets run the wiki plugin -->
+    <!--
+    <attainGoal name="java:compile"/>
+    <attainGoal name="setclasspath"/>
+    -->
+
+    <wiki2html srcdir="${basedir}/xdocs" destdir="${maven.html2xdoc.dir}"/>
+
+    <!-- lets generate the HTML docs -->
+    <attainGoal name="groovy:make-new-javadoc"/>
+
+    <attainGoal name="html2xdoc"/>
+    <attainGoal name="faq"/>
+  </goal>
+
+  <goal name="groovy:make-new-javadoc" prereqs="java:compile, setclasspath"
+    description="Generates the HTML of the new JavaDoc added to the JDK">
+    <mkdir dir="${maven.html2xdoc.dir}"/>
+    <java classname="org.codehaus.groovy.tools.DocGenerator" fork="yes">
+      <classpath refid="test.classpath"/>
+    </java>
+  </goal>
+
+  <postGoal name="test:compile">
+    <attainGoal name="setclasspath"/>
+    <j:if test="${unitTestSourcesPresent == 'true' and context.getVariable('maven.test.skip') != 'true'}">
+      <attainGoal name="groovy:compile-tests"/>
+    </j:if>
+    ${context.setVariable('java.awt.headless', true)}
+  </postGoal>
+    
+  <goal name="setclasspath">
+    <path id="test.classpath">
+      <pathelement path="${maven.build.dest}"/>
+      <pathelement path="target/classes"/>
+      <pathelement path="target/test-classes"/>
+      <path refid="maven.dependency.classpath"/>
+    </path>
+    
+    <taskdef name="rootLoaderRef" classname="org.codehaus.groovy.ant.RootLoaderRef" classpathref="test.classpath"/>
+    <rootLoaderRef ref="tmp.groovy.groovyc">     
+      <classpath refid="test.classpath"/>
+    </rootLoaderRef>
+        
+    <taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc" classpathref="test.classpath" loaderRef="tmp.groovy.groovyc"/> 
+    <taskdef name="wiki2html" classname="org.codehaus.groovy.wiki.Wiki2Markup" classpathref="test.classpath"/> 
+    <taskdef name="wiki2testcase" classname="org.codehaus.groovy.wiki.Wiki2TestCase" classpathref="test.classpath"/> 
+  </goal>
+  
+  
+  <goal name="asm:verify" prereqs="test:compile"
+    description="verifies the bytecode of every class">
+    <taskdef name="verifyclasses" classname="org.codehaus.groovy.ant.VerifyClass" classpathref="test.classpath"/> 
+    
+    <verifyclasses dir="${basedir}/target/classes"/>
+    <verifyclasses dir="${basedir}/target/test-classes"/>
+  </goal>
+
+  <goal name="asm:dump" prereqs="test:compile"
+    description="Dumps the ASM instructions to generate the given class using the name property">
+
+    <j:if test="${empty(name)}">
+      <j:set var="name" value="org.codehaus.groovy.classgen.DumpClass"/>
+    </j:if>
+
+    <echo>Dumping class $$name = ${name}</echo>
+    <java classname="org.objectweb.asm.util.DumpClassVisitor" fork="yes">
+      <classpath refid="test.classpath"/>
+      <arg value="${name}"/>
+    </java>
+  </goal>
+
+  <goal name="groovy:compile" prereqs="java:compile, setclasspath"
+    description="Compiles the Groovy code">
+
+    <!-- lets create the test cases from the wiki documentation -->
+    <mkdir dir="${basedir}/target/test-classes/wiki"/>
+    <wiki2testcase srcdir="${basedir}/xdocs" destdir="${basedir}/target/test-classes/wiki"/>
+    
+    <copy todir="${basedir}/target/classes">
+      <fileset dir="${basedir}/src/main">
+        <include name="**/*.groovy"/>
+        <exclude name="CVS/*"/>
+      </fileset>
+    </copy>
+
+    <groovyc destdir="${basedir}/target/classes" srcdir="${basedir}/target/classes" listfiles="true">
+      <classpath refid="test.classpath"/>
+    </groovyc>
+
+  </goal>
+
+  <goal name="groovy:tck-test-generation" prereqs="setclasspath"
+        description="Generates the Groovy TCK tests">
+    <ant dir="src/tck" inheritRefs="true">
+      <reference refid="test.classpath" torefid="passed.classpath"/>
+    </ant>
+    <mkdir dir="${basedir}/target/test-classes"/>
+    <copy todir="${basedir}/target/test-classes">
+      <!-- TCK classes and sources -->
+      <fileset dir="${basedir}/src/tck/build/test/classes">
+        <include name="**/*.class"/>
+      </fileset>
+      <fileset dir="${basedir}/src/tck/gentest">
+        <include name="**/*.java"/>
+      </fileset>
+
+      <!-- helper classes for TCK tests -->
+      <fileset dir="${basedir}/src/tck/build/classes">
+        <include name="**/*Helper.class"/>
+      </fileset>
+    </copy>
+  </goal>
+
+  <goal name="groovy:compile-tests" prereqs="groovy:compile, setclasspath, groovy:tck-test-generation"
+    description="Compiles the Groovy unit test cases">
+    <!-- lets copy and touch all the groovy files to ensure they all recompile -->
+    <mkdir dir="${basedir}/target/test-classes"/>
+    <copy todir="${basedir}/target/test-classes">
+      <fileset dir="${basedir}/src/test">
+        <include name="**/*.groovy"/>
+
+        <exclude name="**/notworking/*.groovy"/>
+        <exclude name="**/parser/*.groovy"/>
+        <exclude name="**/ant/*/GroovyTest*.groovy"/> <!-- should not get compiled here as test has to define by itself his classpath -->
+        <exclude name="CVS/*"/>
+      </fileset>
+    </copy>
+    <!--
+    <touch>
+    <fileset dir="${basedir}/target/test-classes" includes="**/*.groovy"/>
+    </touch>
+    -->
+
+    <groovyc destdir="${basedir}/target/test-classes" srcdir="${basedir}/target/test-classes" listfiles="true">
+      <classpath refid="test.classpath"/>
+    </groovyc>
+
+      <!-- Re compile java, so that UberTests are now built -->
+      <javac srcdir="${basedir}/src/test"
+             destdir="${basedir}/target/test-classes"
+             classpathref="test.classpath">
+        <include name="**/Uber*.java" />   
+      </javac>
+
+  </goal>
+
+<!--
+  <goal name="test" 
+        description="Test the application"
+        prereqs="">
+    <attainGoal name="groovy:test"/>
+  </goal>
+
+  <goal name="test:test" 
+        description="Test the application"
+        prereqs="">
+    <attainGoal name="groovy:test"/>
+  </goal>
+-->
+
+
+  <goal name="groovy:fails"
+        description="Test the application with any former failing tests"
+        prereqs="test:compile"
+  >
+    <path id="test.classpath">
+      <pathelement path="${maven.build.dest}"/>
+	  <pathelement path="target/classes"/>
+	  <pathelement path="target/test-fails"/>
+	  <path refid="maven.dependency.classpath"/>
+    </path> 
+
+      <taskdef name="junit" classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTask" /> 
+	
+      <delete dir="${basedir}/target/test-fails-reports" />
+      <delete dir="${basedir}/target/test-fails" />
+
+      <mkdir dir="${basedir}/target/test-fails"/>
+      <mkdir dir="${basedir}/target/test-fails-reports"/>
+
+      <copy todir="${basedir}/target/test-fails" >
+        <fileset dir="${basedir}/src/test-fails">
+          <include name="**/*.groovy"/>  
+        </fileset> 
+      </copy>
+
+
+      <javac srcdir="${basedir}/src/test-fails"
+             destdir="${basedir}/target/test-fails"
+             classpathref="test.classpath" >
+        <include name="**/*.java" />   
+      </javac>
+      
+      <java classname="org.codehaus.groovy.ant.Groovyc" fork="yes" failsonerror="true">
+        <classpath refid="test.classpath"/>
+        <arg value="${basedir}/target/test-fails"/>
+        <arg value="${basedir}/target/test-fails"/>
+      </java>
+      
+    <junit printsummary="yes">
+      <classpath>
+          <path refid="maven.dependency.classpath"/>
+          <pathelement location="${basedir}/target/classes"/>
+          <pathelement location="${basedir}/target/test-fails"/>
+          <pathelement path="${plugin.getDependencyPath('junit')}"/>
+      </classpath>
+      <formatter type="xml"/>
+      <batchtest todir="${basedir}/target/test-fails-reports">
+        <fileset dir="${basedir}/target/test-fails">
+          <exclude name="**/*AbstractTestCase.*"/>
+        </fileset>
+      </batchtest>
+    </junit>
+  </goal>
+
+
+  <goal name="groovy:test"
+        description="Test the application with any Java or Groovy unit tests"
+        prereqs="test:compile">
+
+    <j:if test="${unitTestSourcesPresent == 'true' and context.getVariable('maven.test.skip') != 'true'}">
+      
+      <taskdef
+        name="junit"
+        classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTask"
+      />
+
+      <j:set var="testPlugin" value="${pom.getPluginContext('maven-test-plugin')}"/>
+      <j:set var="reportsDirectory">${testPlugin.findVariable('maven.test.reportsDirectory')}</j:set>
+
+      <mkdir dir="${reportsDirectory}"/>
+
+      <junit printSummary="yes" 
+             failureProperty="maven.test.failure"
+             fork="${maven.junit.fork}"
+             dir="${maven.junit.dir}">
+        <sysproperty key="basedir" value="${basedir}"/>
+        
+        <!-- use headless for AWT stuff -->
+        <u:replace var="headless" oldChar="_" newChar=".">java_awt_headless</u:replace>
+        <echo>Setting property ${headless} to true</echo>
+        <sysproperty key="${headless}" value="true"/>
+        
+        <u:tokenize var="listOfProperties" delim=" ">${maven.junit.sysproperties}</u:tokenize>
+        <j:forEach var="someProperty" items="${listOfProperties}">
+          <sysproperty key="${someProperty}" value="${context.getVariable(someProperty)}"/>
+        </j:forEach>
+        <u:tokenize var="listOfJvmArgs" delim=" ">${maven.junit.jvmargs}</u:tokenize>
+        <j:forEach var="somejvmarg" items="${listOfJvmArgs}">
+          <jvmarg value="${somejvmarg}"/>
+        </j:forEach>
+        <formatter type="xml"/>
+        <formatter type="plain" usefile="${maven.junit.usefile}"/>
+        <classpath>
+          <path refid="maven.dependency.classpath"/>
+          <pathelement location="${basedir}/target/classes"/>
+          <pathelement location="${basedir}/target/test-classes"/>
+          <pathelement path="${plugin.getDependencyPath('junit')}"/>
+        </classpath>
+        <batchtest todir="${reportsDirectory}">
+          <fileset dir="${basedir}/target/test-classes">
+            <j:forEach var="pat" items="${pom.build.unitTest.includes}">
+              <include name="${pat}"/>
+            </j:forEach>
+            <j:forEach var="pat" items="${pom.build.unitTest.excludes}">
+              <exclude name="${pat}"/>
+            </j:forEach>
+              <exclude name="**/*AbstractTestCase.*"/>
+          </fileset>
+        </batchtest>
+      </junit>
+
+      <j:if test="${maven.test.failure}">
+        <j:set var="ignore__" value="${maven.test.failure.ignore}X"/>
+        <j:if test="${ignore__ == 'X'}">
+          <fail message="There were test failures."/>
+        </j:if>
+      </j:if>
+
+    </j:if>
+    
+    <j:if test="${!unitTestSourcesPresent}">
+      <echo>No tests to run.</echo>
+    </j:if>
+
+  </goal>
+
+  <goal name="groovy-eclipse:copyjars">
+    <j:if test="${empty(groovy.eclipse.dir)}">
+      <j:set var="groovy.eclipse.dir" value="../groovy-eclipse"/>
+    </j:if>
+    
+    <copy file="${maven.build.dir}/${maven.final.name}.jar" tofile="${groovy.eclipse.dir}/lib/groovy.jar"/>
+
+    <j:forEach var="lib" items="${pom.artifacts}">
+      <echo>Processing ${lib.name}</echo>
+      <j:choose>
+        <j:when test="${lib.name.startsWith('commons-log')}">
+          <copy file="${lib.path}" tofile="${groovy.eclipse.dir}/lib/commons-logging.jar"/>
+        </j:when>
+        <j:when test="${lib.name.startsWith('asm-util')}">
+        </j:when>
+        <j:when test="${lib.name.startsWith('asm')}">
+          <copy file="${lib.groovypath}" tofile="${groovy.eclipse.dir}/lib/asm.jar"/>
+        </j:when>
+      </j:choose>
+    </j:forEach>
+    
+  </goal>
+
+  <preGoal name="jar:jar">
+     <attainGoal name="groovy:compile"/>
+  </preGoal>
+	
+  <goal name="war:notests">
+   <j:set var="maven.test.skip" value="true"/>
+   <echo>Rebuilding groovlet-examples.war without running the unit test cases</echo>
+   <attainGoal name="war"/>
+  </goal>	
+	
+  <postGoal name="war:webapp">
+  	<echo>Replacing class folder with Groovy.jar...</echo>
+  	<copy file="${maven.build.dir}/${maven.final.name}.jar" toDir="${maven.war.build.dir}/WEB-INF/lib"/>
+  </postGoal>
+    
+  <goal name="groovy:make-install" prereqs="jar:jar">
+    <echo>${groovy.install.staging.dest}</echo>
+    <mkdir dir="${groovy.install.staging.dest}"/>
+    <mkdir dir="${groovy.install.staging.dest}/lib"/>
+    <mkdir dir="${groovy.install.staging.dest}/bin"/>
+    <mkdir dir="${groovy.install.staging.dest}/conf"/>
+    <j:forEach var="lib" items="${pom.artifacts}">
+      <copy file="${lib.path}" toDir="${groovy.install.staging.dest}/lib"/>
+    </j:forEach>
+    <copy file="${maven.build.dir}/${maven.final.name}.jar" toDir="${groovy.install.staging.dest}/lib"/>
+    <copy toDir="${groovy.install.staging.dest}/conf">
+      <fileset dir="${maven.src.dir}/conf">
+        <include name="*"/>
+      </fileset>
+    </copy>
+    <copy toDir="${groovy.install.staging.dest}/bin">
+      <fileset dir="${maven.src.dir}/bin">
+        <include name="*"/>
+      </fileset>
+    </copy>
+    
+    <!-- fix crlf-->
+    <fixcrlf srcdir="${groovy.install.staging.dest}/bin"
+       eol="lf" excludes="*.bat" 
+    />
+    <fixcrlf srcdir="${groovy.install.staging.dest}/bin"
+       eol="crlf" includes="*.bat"
+    />
+    
+    <chmod perm="ugo+x">
+      <fileset dir="${groovy.install.staging.dest}/bin">
+        <include name="*"/>
+        <include name="*.*"/>
+      </fileset>
+    </chmod>
+    <attainGoal name="groovy:embeddable-jar"/>
+    <attainGoal name="groovy:groovy-starter-jar"/>
+  </goal>
+
+  <goal name="groovy:make-full-install" prereqs="groovy:make-install">
+    <!-- lets copy xmlrpc into the release -->
+    <!-- attainGoal name="modules"/ -->
+    <!--
+    <echo>Copying the xmlrpc jar into the install directory ${groovy.install.staging.dest}/lib</echo>
+    -->
+
+    <copy toDir="${groovy.install.staging.dest}/lib">
+      <fileset dir="../modules/xmlrpc/target">
+        <include name="groovy*.jar"/>
+      </fileset>
+    </copy>
+  </goal>
+
+  <goal name="groovy:groovy-starter-jar">
+     <jar destfile="${groovy.install.staging.dest}/lib/groovy-starter.jar" >
+       <fileset dir="${maven.build.dir}/classes" casesensitive="yes">
+         <include name="org/codehaus/groovy/tools/RootLoader*.class" />
+         <include name="org/codehaus/groovy/tools/GroovyStarter*.class" />
+         <include name="org/codehaus/groovy/tools/LoaderConfiguration*.class" />
+       </fileset>
+     </jar>
+  </goal>
+
+  <goal name="groovy:embeddable-jar">
+  	<mkdir dir="${groovy.embeddable.working.dir}"/>
+	<unzip dest="${groovy.embeddable.working.dir}">
+		<fileset dir="${groovy.install.staging.dest}/lib">
+			<include name="antlr*.jar"/>
+			<include name="asm*.jar"/>
+			<exclude name="asm-attr*.jar"/>
+			<exclude name="asm-util*.jar"/>
+			<exclude name="asm-analysis*.jar"/>
+			<include name="groovy*.jar"/>
+		</fileset>
+	</unzip>
+	<copy toDir="${groovy.embeddable.working.dir}/META-INF">
+		<fileset dir="${basedir}">
+			<include name="ASM-LICENSE.txt"/>
+		</fileset>
+	</copy>
+	<mkdir dir="${groovy.install.staging.dest}/embeddable"/>
+	<taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask" classpath="${groovy.install.staging.dest}/lib/jarjar-0.6.jar"/>
+	<jarjar jarfile="${groovy.install.staging.dest}/embeddable/groovy-all-${pom.currentVersion}.jar" 
+                                                        manifest="${groovy.embeddable.working.dir}/META-INF/MANIFEST.MF">
+		<fileset dir="${groovy.embeddable.working.dir}"/>
+		<rule pattern="antlr.**"         result="groovyjarjarantlr.@1"/>
+		<rule pattern="org.objectweb.**" result="groovyjarjarasm.@1"/>
+	</jarjar>
+<!--	<delete dir="${groovy.embeddable.working.dir}"/>-->
+  </goal>
+
+  <goal name="groovy:exe">
+    <echo>Building a Groovy executable</echo>
+    <property name="groovy.build.native" value="${maven.build.dir}/native"/>
+    <property name="groovy.src.native" value="${maven.src.dir}/native"/>
+    <mkdir dir="${groovy.build.native}"/>
+    <exec executable="gcc">
+      <arg value='-DJAVA_CLASS_NAME="groovy.lang.GroovyShell"'/>
+      <arg value="-g"/>
+      <arg value="-o"/>
+      <arg value="${groovy.build.native}/groovybase"/>
+      <arg value="${groovy.src.native}/base.c"/>
+    </exec>
+    <exec executable="gcc">
+      <arg value='-DJAVA_CLASS_NAME="org.codehaus.groovy.tools.FileSystemCompiler"'/>
+      <arg value="-g"/>
+      <arg value="-o"/>
+      <arg value="${groovy.build.native}/groovycbase"/>
+      <arg value="${groovy.src.native}/base.c"/>
+    </exec>
+    <jar destfile="${groovy.build.native}/groovy.jar" manifest="${groovy.embeddable.working.dir}/META-INF/MANIFEST.MF">
+      <zipfileset src="${maven.build.dir}/${maven.final.name}.jar"/>
+      <zipfileset src="${groovy.install.staging.dest}/lib/antlr-2.7.5.jar"/>
+      <zipfileset src="${groovy.install.staging.dest}/lib/asm-2.2.jar"/>
+      <zipfileset src="${groovy.install.staging.dest}/lib/asm-util-2.2.jar"/>
+      <zipfileset src="${groovy.install.staging.dest}/lib/asm-attrs-2.2.jar"/>
+      <zipfileset src="${groovy.install.staging.dest}/lib/asm-analysis-2.2.jar"/>
+      <zipfileset src="${groovy.install.staging.dest}/lib/commons-cli-1.0.jar"/>
+      <zipfileset src="${groovy.install.staging.dest}/lib/xerces-2.4.0.jar"/>
+      <zipfileset src="${groovy.install.staging.dest}/lib/xml-apis-1.0.b2.jar"/>
+        <!--<zipfileset src="${groovy.install.staging.dest}/lib/xercesImpl-2.6.2.jar"/>-->
+        <!--<zipfileset src="${groovy.install.staging.dest}/lib/xmlParserAPIs-2.6.2.jar"/>-->
+        <!--<zipfileset src="${groovy.install.staging.dest}/lib/xml-resolver-1.1.jar"/>-->
+    </jar>
+    <concat destfile="${groovy.build.native}/groovy">
+      <filelist dir="${groovy.build.native}" files="groovybase,groovy.jar"/>
+    </concat>
+    <concat destfile="${groovy.build.native}/groovyc">
+      <filelist dir="${groovy.build.native}" files="groovycbase,groovy.jar"/>
+    </concat>
+    <chmod file="${groovy.build.native}/groovy" perm="ugo+rx"/>
+    <chmod file="${groovy.build.native}/groovyc" perm="ugo+rx"/>
+  </goal>
+ 
+</project>
diff --git a/groovy-core/pom.xml b/groovy-core/pom.xml
new file mode 100644
index 0000000..e171c33
--- /dev/null
+++ b/groovy-core/pom.xml
@@ -0,0 +1,814 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project
+  xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
+>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>groovy</groupId>
+  <artifactId>groovy</artifactId>
+  <name>Groovy</name>
+  <version>1.0-RC-02-SNAPSHOT</version>
+  <packaging>jar</packaging>
+  <organization>
+    <name>The Codehaus</name>
+    <url>http://codehaus.org</url>
+  </organization>
+  <inceptionYear>2003</inceptionYear>
+  <url>http://groovy.codehaus.org/</url>
+  <description>Groovy: A powerful dynamic scripting language for the JVM</description>
+  
+  <scm>
+    <connection>scm:svn:http://svn.codehaus.org/groovy/groovy-core</connection>
+    <developerConnection>scm:svn:https://${maven.username}@svn.codehaus.org/groovy/groovy-core</developerConnection>
+    <url>http://svn.codehaus.org/groovy/groovy-core</url>
+  </scm>
+
+<!--
+  <packageGroups>
+    <packageGroup>
+      <title>Groovy Development Kit API used in the Groovy language</title>
+      <packages>groovy.*</packages>
+    </packageGroup>
+    <packageGroup>
+      <title>Groovy compiler and runtime implementation</title>
+      <packages>org.codehaus.*</packages>
+    </packageGroup>
+  </packageGroups>
+  -->
+  
+<!--
+  <versions>
+    <version>
+      <id>b1</id>
+      <name>1.0-beta1</name>
+      <tag>GROOVY_1_0_BETA_1</tag>
+    </version>
+    <version>
+      <id>b2</id>
+      <name>1.0-beta2</name>
+      <tag>GROOVY_1_0_BETA_2</tag>
+    </version>
+    <version>
+      <id>b3</id>
+      <name>1.0-beta3</name>
+      <tag>GROOVY_1_0_BETA_3</tag>
+    </version>
+    <version>
+      <id>b4</id>
+      <name>1.0-beta4</name>
+      <tag>GROOVY_1_0_BETA_4</tag>
+    </version>
+    <version>
+      <id>b5</id>
+      <name>1.0-beta5</name>
+      <tag>GROOVY_1_0_BETA_5</tag>
+    </version>
+    <version>
+      <id>b6</id>
+      <name>1.0-beta6</name>
+      <tag>GROOVY_1_0_BETA_6</tag>
+    </version>
+    <version>
+      <id>b7</id>
+      <name>1.0-beta7</name>
+      <tag>GROOVY_1_0_BETA_7</tag>
+    </version>
+    <version>
+      <id>b8</id>
+      <name>1.0-beta8</name>
+      <tag>GROOVY_1_0_BETA_8</tag>
+    </version>
+    <version>
+      <id>b9</id>
+      <name>1.0-beta9</name>
+      <tag>GROOVY_1_0_BETA_9</tag>
+    </version>
+    <version>
+      <id>b10</id>
+      <name>1.0-beta10</name>
+      <tag>GROOVY_1_0_BETA_10</tag>
+    </version>
+    <version>
+      <id>jsr01</id>
+      <name>1.0-JSR-01</name>
+      <tag>GROOVY_1_0_JSR_01</tag>
+    </version>
+    <version>
+      <id>jsr02</id>
+      <name>1.0-JSR-02</name>
+      <tag>GROOVY_1_0_JSR_02</tag>
+    </version>
+    <version>
+      <id>jsr03</id>
+      <name>1.0-JSR-03</name>
+      <tag>GROOVY_1_0_JSR_03</tag>
+    </version>
+    <version>
+      <id>jsr04</id>
+      <name>1.0-JSR-04</name>
+      <tag>GROOVY_1_0_JSR_04</tag>
+    </version>
+      <version>
+        <id>jsr05</id>
+        <name>1.0-JSR-05</name>
+        <tag>GROOVY_1_0_JSR_05</tag>
+      </version>
+      <version>
+        <id>jsr06</id>
+        <name>1.0-JSR-06</name>
+        <tag>GROOVY_1_0_JSR_06</tag>
+      </version>
+  </versions>
+-->
+
+  <mailingLists>
+    <mailingList>
+      <name>Groovy JSR Discussion List</name>
+      <subscribe>jsr-subscribe@groovy.codehaus.org</subscribe>
+      <unsubscribe>jsr-unsubscribe@groovy.codehaus.org</unsubscribe>
+      <archive>http://dir.gmane.org/gmane.comp.lang.groovy.jsr</archive>
+    </mailingList>
+    <mailingList>
+      <name>Groovy Developer List</name>
+      <subscribe>dev-subscribe@groovy.codehaus.org</subscribe>
+      <unsubscribe>dev-unsubscribe@groovy.codehaus.org</unsubscribe>
+      <archive>http://dir.gmane.org/gmane.comp.lang.groovy.devel</archive>
+    </mailingList>
+    <mailingList>
+      <name>Groovy User List</name>
+      <subscribe>user-subscribe@groovy.codehaus.org</subscribe>
+      <unsubscribe>user-unsubscribe@groovy.codehaus.org</unsubscribe>
+      <archive>http://dir.gmane.org/gmane.comp.lang.groovy.user</archive>
+    </mailingList>
+    <mailingList>
+      <name>Groovy SCM List</name>
+      <subscribe>scm-subscribe@groovy.codehaus.org</subscribe>
+      <unsubscribe>scm-unsubscribe@groovy.codehaus.org</unsubscribe>
+      <archive>http://archive.groovy.codehaus.org/scm/</archive>
+    </mailingList>
+  </mailingLists>
+
+  <developers>
+    <developer>
+      <name>Guillaume Laforge</name>
+      <id>glaforge</id>
+      <email></email>
+      <organization>Octo Technology</organization>
+      <roles>
+        <role>Project Manager</role>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>bob mcwhirter</name>
+      <id>bob</id>
+      <email>bob@werken.com</email>
+      <organization>The Werken Company</organization>
+      <roles>
+        <role>Founder</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>James Strachan</name>
+      <id>jstrachan</id>
+      <email>james@coredevelopers.com</email>
+      <organization>Core Developers Network</organization>
+      <roles>
+        <role>Founder</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Joe Walnes</name>
+      <id>joe</id>
+      <email></email>
+      <organization>ThoughtWorks</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Chris Stevenson</name>
+      <id>skizz</id>
+      <email></email>
+      <organization>ThoughtWorks</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Jamie McCrindle</name>
+      <id>jamiemc</id>
+      <email></email>
+      <organization>Three</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Matt Foemmel</name>
+      <id>mattf</id>
+      <email></email>
+      <organization>ThoughtWorks</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Sam Pullara</name>
+      <id>spullara</id>
+      <email>sam@sampullara.com</email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Kasper Nielsen</name>
+      <id>kasper</id>
+      <email></email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Travis Kay</name>
+      <id>travis</id>
+      <email></email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Zohar Melamed</name>
+      <id>zohar</id>
+      <email></email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>John Wilson</name>
+      <id>jwilson</id>
+      <email>tug@wilson.co.uk</email>
+      <organization>The Wilson Partnership</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Chris Poirier</name>
+      <id>cpoirier</id>
+      <email>cpoirier@dreaming.org</email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Christiaan ten Klooster</name>
+      <id>ckl</id>
+      <email>ckl@dacelo.nl</email>
+      <organization>Dacelo WebDevelopment</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Steve Goetze</name>
+      <id>goetze</id>
+      <email>goetze@dovetail.com</email>
+      <organization>Dovetailed Technologies, LLC</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+        <name>Bing Ran</name>
+        <id>bran</id>
+        <email>b55r@sina.com</email>
+        <organization>Leadingcare</organization>
+        <roles>
+          <role>Developer</role>
+        </roles>
+    </developer>
+    <developer>
+        <name>Jeremy Rayner</name>
+        <id>jez</id>
+        <email>jeremy.rayner@gmail.com</email>
+        <organization>javanicus</organization>
+        <roles>
+          <role>Developer</role>
+        </roles>
+   </developer>
+    <developer>
+        <name>John Stump</name>
+        <id>jstump</id>
+        <email>johnstump2@yahoo.com</email>
+        <organization></organization>
+        <roles>
+          <role>Developer</role>
+        </roles>
+   </developer>
+    <developer>
+        <name>Jochen Theodorou</name>
+        <id>blackdrag</id>
+        <email>blackdrag@gmx.org</email>
+        <organization></organization>
+        <roles>
+          <role>Developer</role>
+        </roles>
+   </developer>
+    <developer>
+      <name>Russel Winder</name>
+      <id>russel</id>
+      <email>russel@itzinteractive.com</email>
+      <organization>It'z Interactive Ltd</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+   </developer>
+    <developer>
+        <name>Pilho Kim</name>
+        <id>phk</id>
+        <email>phkim@cluecom.co.kr</email>
+        <organization></organization>
+        <roles>
+          <role>Developer</role>
+        </roles>
+   </developer>
+    <developer>
+        <name>Christian Stein</name>
+        <id>cstein</id>
+        <email>sormuras@gmx.de</email>
+        <organization>CTSR.de</organization>
+        <roles>
+          <role>Developer</role>
+        </roles>
+   </developer>
+   <developer>
+      <name>Dierk Koenig</name>
+      <id>mittie</id>
+      <email>dierk.koenig@canoo.com</email>
+      <organization>Canoo Engineering AG</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+   <developer>
+      <name>Paul King</name>
+      <id>paulk</id>
+      <email>paulk@asert.com.au</email>
+      <organization>ASERT, Australia</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+  </developers>
+
+  <contributors>
+    <contributor>
+      <name>Joern Eyrich</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Robert Kuzelj</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Rod Cope</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Yuri Schimke</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>James Birchfield</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Robert Fuller</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Sergey Udovenko</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Hallvard Traetteberg</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Peter Reilly</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Brian McCallister</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Richard Monson-Haefel</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Brian Larson</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Artur Biesiadowski</name>
+      <email>abies@pg.gda.pl</email>
+    </contributor>
+    <contributor>
+      <name>Ivan Z. Ganza</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Arjun Nayyar</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Mark Chu-Carroll</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Mark Turansky</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Jean-Louis Berliet</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Graham Miller</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Marc Palmer</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Tugdual Grall</name>
+      <email></email>
+    </contributor>
+  </contributors>
+
+  <dependencies>
+
+    <!-- core dependencies -->
+    <dependency>
+      <groupId>antlr</groupId>
+      <artifactId>antlr</artifactId>
+      <version>2.7.6</version>
+    </dependency>
+    <dependency>
+      <groupId>asm</groupId>
+      <artifactId>asm</artifactId>
+      <version>2.2</version>
+    </dependency>
+
+    <!-- dependencies used by optional features -->
+      <dependency>
+        <groupId>xerces</groupId>
+        <artifactId>xercesImpl</artifactId>
+        <version>2.8.0</version>
+      </dependency>
+      <dependency>
+        <groupId>xml-apis</groupId>
+        <artifactId>xml-apis</artifactId>
+        <version>1.3.03</version>
+      </dependency>
+      <dependency>
+        <groupId>xml-resolver</groupId>
+        <artifactId>xml-resolver</artifactId>
+        <version>1.1</version>
+      </dependency>
+
+    <!-- only used for command line tools -->
+    <dependency>
+      <groupId>commons-cli</groupId>
+      <artifactId>commons-cli</artifactId>    
+      <version>1.0</version>
+    </dependency>
+
+    <!-- only used for Ant tasks & scripting tools -->
+    <dependency>
+      <groupId>ant</groupId>
+      <artifactId>ant</artifactId>    
+      <version>1.6.5</version>
+    </dependency>
+    <dependency>
+      <groupId>ant</groupId>
+      <artifactId>ant-junit</artifactId>    
+      <version>1.6.5</version>
+    </dependency>
+    <dependency>
+      <groupId>ant</groupId>
+      <artifactId>ant-launcher</artifactId>    
+      <version>1.6.5</version>
+    </dependency>
+
+    <!-- only used for testing helper classes -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.2</version>
+    </dependency>
+    <dependency>
+      <groupId>jmock</groupId>
+      <artifactId>jmock</artifactId>
+      <version>1.1.0</version>
+    </dependency>
+    <dependency>
+      <groupId>jmock</groupId>
+      <artifactId>jmock-cglib</artifactId>
+      <version>1.1.0</version>
+      <!-- This pulls in an incompatible version of ASM, so it must be excluded.  -->
+      <exclusions>
+        <exclusion>
+          <groupId>cglib</groupId>
+          <artifactId>cglib-full</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>cglib</groupId>
+      <artifactId>cglib-nodep</artifactId>
+      <version>2.1_3</version>
+    </dependency>
+
+    <!-- only used for testing/debugging-->
+    <dependency>
+      <groupId>asm</groupId>
+      <artifactId>asm-util</artifactId>    
+      <version>2.2</version>
+    </dependency>
+    <dependency>
+      <groupId>asm</groupId>
+      <artifactId>asm-attrs</artifactId>    
+      <version>2.2</version>
+    </dependency>
+    <dependency>
+      <groupId>asm</groupId>
+      <artifactId>asm-analysis</artifactId>    
+      <version>2.2</version>
+    </dependency>
+    <dependency>
+      <groupId>asm</groupId>
+      <artifactId>asm-tree</artifactId>    
+      <version>2.2</version>
+    </dependency>
+
+    <!-- only used for BSF adapter-->
+
+    <!-- 2.4.0 POM not in the repository, yields warning but OK -->
+    <dependency>
+      <groupId>bsf</groupId>
+      <artifactId>bsf</artifactId>    
+      <version>2.4.0</version>
+    </dependency>
+
+    <!-- only used for JMX utilities -->
+    <dependency>
+      <groupId>mx4j</groupId>
+      <artifactId>mx4j</artifactId>    
+      <version>3.0.1</version>
+    </dependency>
+
+    <!-- only used for GroovyMock tools -->
+    <dependency>
+      <groupId>mockobjects</groupId>
+      <artifactId>mockobjects-core</artifactId>
+      <version>0.09</version>
+    </dependency>
+
+    <!-- only used for EJB browser -->
+      <dependency>
+          <groupId>castor</groupId>
+          <artifactId>castor</artifactId>
+          <version>1.0</version>
+      </dependency>
+      <dependency>
+          <groupId>openejb</groupId>
+          <artifactId>openejb-loader</artifactId>
+          <version>1.0</version>
+          <!-- This pulls in an incompatible version of castor, so it must be excluded.  -->
+          <exclusions>
+              <exclusion>
+                  <groupId>castor</groupId>
+                  <artifactId>castor</artifactId>
+              </exclusion>
+              <exclusion>
+                  <groupId>org.apache.geronimo.specs</groupId>
+                  <artifactId>geronimo-jta_1.0.1B_spec</artifactId>
+              </exclusion>
+              <exclusion>
+                  <groupId>org.apache.geronimo.specs</groupId>
+                  <artifactId>geronimo-ejb_2.1_spec</artifactId>
+              </exclusion>
+              <exclusion>
+                  <groupId>org.apache.geronimo.specs</groupId>
+                  <artifactId>geronimo-j2ee-connector_1.5_spec</artifactId>
+              </exclusion>
+          </exclusions>
+      </dependency>
+
+    <!-- only used for SQL library -->
+    <dependency>
+      <groupId>axion</groupId>
+      <artifactId>axion</artifactId>    
+      <version>1.0-M3-dev</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-logging</groupId>
+      <artifactId>commons-logging</artifactId>    
+      <version>1.0.4</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-collections</groupId>
+      <artifactId>commons-collections</artifactId>    
+      <version>3.2</version>
+    </dependency>
+    <dependency>
+      <groupId>regexp</groupId>
+      <artifactId>regexp</artifactId>    
+      <version>1.3</version>
+    </dependency>
+  
+    <!-- only used for servlet / gsp -->
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>servlet-api</artifactId>    
+      <version>2.4</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>jsp-api</artifactId>
+      <version>2.0</version>
+    </dependency>
+
+    <!-- only used for the Wiki Ant tasks -->
+    <dependency>
+      <groupId>radeox</groupId>
+      <artifactId>radeox</artifactId>    
+      <version>0.9</version><!-- later version based on Java 5 -->
+    </dependency>
+    <dependency>
+      <groupId>radeox</groupId>
+      <artifactId>radeox-oro</artifactId>    
+      <version>0.9</version>
+    </dependency>
+
+    <!-- only used for the HTML to Wiki script -->
+    <dependency>
+      <groupId>nekohtml</groupId>
+      <artifactId>nekohtml</artifactId>    
+      <version>0.9.5</version>
+    </dependency>
+
+    <!-- only used for the JavaDoc generator script -->
+    <dependency>
+      <groupId>qdox</groupId>
+      <artifactId>qdox</artifactId>    
+      <version>1.5</version>
+    </dependency>
+
+    <!-- only used in the samples (BlogLines client) -->
+    <!-- Also needed for Ivy when Gant pulls Ivy in? -->
+    <dependency>
+      <groupId>commons-httpclient</groupId>
+      <artifactId>commons-httpclient</artifactId>
+      <version>3.0.1</version>
+    </dependency>
+
+    <!-- used to dump out the AST -->
+    <dependency>
+      <groupId>xstream</groupId>
+      <artifactId>xstream</artifactId>
+      <version>1.2</version>
+    </dependency>
+
+    <!-- used to build embeddable jar -->
+    <dependency>
+      <groupId>com.tonicsystems</groupId>
+      <artifactId>jarjar</artifactId>
+      <version>0.6</version>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <defaultGoal>test</defaultGoal>
+
+    <!-- Maven 1 repository structure is different to Maven 2 structure, so we manually set the top of the
+    source hierarchy -->
+    <sourceDirectory>src/main</sourceDirectory>
+
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.4</source>
+          <target>1.4</target>
+          <debug>on</debug>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-antlr-plugin</artifactId>
+        <configuration>
+          <grammars>groovy.g</grammars>
+          <sourceDirectory>src/main/org/codehaus/groovy/antlr</sourceDirectory>
+          <outputDirectory>src/main</outputDirectory>
+        </configuration>
+        <executions>
+          <execution>
+            <goals>
+              <goal>generate</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>2.2</version>
+        <configuration>
+          <includes>
+            <include>**/*Test.*</include>
+            <include>**/*Bug.*</include>
+            <include>**/Uber*.*</include>
+          </includes>          
+          <excludes>
+            <exclude>**/SignedJarTest.*</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+
+<!--
+    <unitTest>
+      <resources> 
+        <!- - security test files - ->
+        <resource>
+          <directory>src/security</directory>
+          <includes>
+            <include>**/*.*</include>
+            <include>**/groovy*</include>
+          </includes>
+        </resource>
+    </resources>  
+  </unitTest>
+-->
+
+  </build>
+
+  <reports>
+    <report>maven-license-plugin</report>
+    <!-- very large and offers no real value, it just slows us down!
+    <report>maven-checkstyle-plugin</report>
+    -->
+    <report>maven-pmd-plugin</report>
+    <!-- <report>maven-simian-plugin</report> -->
+    <report>maven-jdepend-plugin</report>
+    <report>maven-changelog-plugin</report>
+  	<!--
+    <report>maven-statcvs-plugin</report>
+    -->
+    <report>maven-file-activity-plugin</report>
+    <report>maven-developer-activity-plugin</report>
+    <report>maven-jxr-plugin</report>
+    <!--
+    <report>maven-javadoc-plugin</report>
+    -->
+    <report>maven-junit-report-plugin</report>
+    <report>maven-faq-plugin</report>
+    <!--
+    <report>maven-clover-plugin</report>
+    -->
+    <report>maven-changes-plugin</report>
+    
+    <!-- prepare for EMMA
+    <report>maven-emma-plugin</report>
+    -->
+  </reports>
+
+<!--
+  <reporting>
+    <plugins>
+      <plugin> 
+       <groupId>org.apache.maven.plugins</groupId> 
+         <artifactId>maven-surefire-report-plugin</artifactId> 
+      </plugin>
+    </plugins>    
+  </reporting>
+-->
+
+</project>
diff --git a/groovy-core/project.properties b/groovy-core/project.properties
new file mode 100644
index 0000000..9cef436
--- /dev/null
+++ b/groovy-core/project.properties
@@ -0,0 +1,94 @@
+# -------------------------------------------------------------------
+# Build Properties
+# -------------------------------------------------------------------
+maven.repo.remote=\
+http://repo1.maven.org/maven,\
+http://dist.codehaus.org
+
+maven.compile.source=1.4
+maven.compile.target=1.4
+maven.test.source=1.4
+maven.compile.deprecation=true
+maven.compile.debug=true
+maven.compile.optimize=true
+
+maven.javadoc.links=http://java.sun.com/j2se/1.4.2/docs/api/
+maven.javadoc.source=1.4
+maven.javadoc.additionalparam = -linksource
+
+maven.test.search.classdir = true
+
+maven.junit.fork=true
+maven.junit.usefile=true
+
+groovy.install.staging.dest=${maven.build.dir}/install/
+groovy.embeddable.working.dir=${maven.build.dir}/embeddable-temp
+maven.html2xdoc.dir=${maven.build.dir}/html
+
+maven.xdoc.date = left
+
+maven.war.src = ${basedir}/src/examples/webapps/groovlet-examples
+maven.war.classes.excludes = **/*
+maven.war.build.dir = ${maven.build.dir}/war-groovlet-examples
+maven.war.webapp.dir = ${maven.war.build.dir}
+maven.war.final.name = ../groovlet-examples.war
+maven.war.index = false
+
+#####################################################
+# codehaus theme
+#####################################################
+maven.xdoc.theme.url=http://codehaus.org/codehaus-style.css
+
+#####################################################
+# Where the jars are uploaded
+#####################################################
+maven.repo.central = beaver.codehaus.org
+maven.repo.central.directory = /dist
+
+maven.junit.sysproperties = java.awt.headless
+
+maven.remote.group = groovy
+
+# Deployment properties
+maven.repo.list=codehaus
+
+maven.repo.codehaus=scp://${pom.distributionSite}
+maven.repo.codehaus.directory=${pom.distributionDirectory}
+maven.repo.codehaus.group=groovy
+
+# The following properties must be set in your build.properties or on the command line
+#maven.repo.codehaus.username=
+#maven.repo.codehaus.privatekey=
+#maven.repo.codehaus.passphrase=
+
+#####################################################
+# emma code coverage
+#####################################################
+# maven.emma.mode.product: replace_classes
+# maven.emma.mode.testing: replace_classes
+
+#####################################################
+# clover code coverage
+#####################################################
+#maven.clover.license.path=${basedir}/clover.license
+
+#####################################################
+# cobertura code coverage
+#
+# This variable seems to need to be set and needs to
+# be set to this value.  If you omit it or set it to
+# some other value, two .ser files end up generated.
+# One is in ${basedir}/cobertura.ser and one in
+# ${maven.cobertura.datafile}.  This results in a report
+# of 0% coverage.  This issue hinted at in the cobertura FAQ.
+#
+# You can download this plugin using (all on one line):
+#
+# maven -DartifactId=maven-cobertura-plugin -DgroupId=maven-plugins -Dversion=1.2 plugin:download \
+#  -Dmaven.repo.remote=http://www.ibiblio.org/maven,http://maven-plugins.sourceforge.net/repository
+#
+# Then to use it:
+#
+# maven cobertura:report
+#####################################################
+maven.cobertura.datafile = ${basedir}/cobertura.ser
diff --git a/groovy-core/project.xml b/groovy-core/project.xml
new file mode 100644
index 0000000..92da1f0
--- /dev/null
+++ b/groovy-core/project.xml
@@ -0,0 +1,810 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project>
+  <pomVersion>3</pomVersion>
+  <id>groovy</id>
+  <name>groovy</name>
+  <groupId>groovy</groupId>
+  <currentVersion>1.0</currentVersion>
+  <organization>
+    <name>The Codehaus</name>
+    <url>http://codehaus.org</url>
+    <logo>http://codehaus.org/codehaus-small.gif</logo>
+  </organization>
+  <inceptionYear>2003</inceptionYear>
+  
+  <!-- package>groovy,org.codehaus.groovy</package -->
+  <packageGroups>
+    <packageGroup>
+      <title>Groovy Development Kit API used in the Groovy language</title>
+      <packages>groovy.*</packages>
+    </packageGroup>
+    <packageGroup>
+      <title>Groovy compiler and runtime implementation</title>
+      <packages>org.codehaus.*</packages>
+    </packageGroup>
+  </packageGroups>
+  
+  
+  <shortDescription>groovy: a powerful and dynamic scripting language for the JVM</shortDescription>
+  <logo>/images/groovy-logo.png</logo>
+
+  <description>
+    a powerful and dynamic scripting language for the JVM
+  </description>
+
+  <url>http://groovy.codehaus.org/</url>
+  
+  <!-- siteAddress>beaver.codehaus.org</siteAddress>
+  <siteDirectory>/home/projects/groovy/public_html</siteDirectory -->
+  <issueTrackingUrl>http://jira.codehaus.org/browse/GROOVY</issueTrackingUrl>
+
+  <!-- distributionDirectory>/dist/</distributionDirectory>
+  <distributionSite>beaver.codehaus.org</distributionSite -->
+
+  <repository>
+    <connection>scm:svn:http://svn.codehaus.org/groovy/groovy-core</connection>
+    <developerConnection>scm:svn:https://${maven.username}@svn.codehaus.org/groovy/groovy-core</developerConnection>
+    <url>http://svn.groovy.codehaus.org/</url>
+  </repository>
+  
+  <versions>
+    <version>
+      <id>b1</id>
+      <name>1.0-beta1</name>
+      <tag>GROOVY_1_0_BETA_1</tag>
+    </version>
+    <version>
+      <id>b2</id>
+      <name>1.0-beta2</name>
+      <tag>GROOVY_1_0_BETA_2</tag>
+    </version>
+    <version>
+      <id>b3</id>
+      <name>1.0-beta3</name>
+      <tag>GROOVY_1_0_BETA_3</tag>
+    </version>
+    <version>
+      <id>b4</id>
+      <name>1.0-beta4</name>
+      <tag>GROOVY_1_0_BETA_4</tag>
+    </version>
+    <version>
+      <id>b5</id>
+      <name>1.0-beta5</name>
+      <tag>GROOVY_1_0_BETA_5</tag>
+    </version>
+    <version>
+      <id>b6</id>
+      <name>1.0-beta6</name>
+      <tag>GROOVY_1_0_BETA_6</tag>
+    </version>
+    <version>
+      <id>b7</id>
+      <name>1.0-beta7</name>
+      <tag>GROOVY_1_0_BETA_7</tag>
+    </version>
+    <version>
+      <id>b8</id>
+      <name>1.0-beta8</name>
+      <tag>GROOVY_1_0_BETA_8</tag>
+    </version>
+    <version>
+      <id>b9</id>
+      <name>1.0-beta9</name>
+      <tag>GROOVY_1_0_BETA_9</tag>
+    </version>
+    <version>
+      <id>b10</id>
+      <name>1.0-beta10</name>
+      <tag>GROOVY_1_0_BETA_10</tag>
+    </version>
+    <version>
+      <id>jsr01</id>
+      <name>1.0-JSR-01</name>
+      <tag>GROOVY_1_0_JSR_01</tag>
+    </version>
+    <version>
+      <id>jsr02</id>
+      <name>1.0-JSR-02</name>
+      <tag>GROOVY_1_0_JSR_02</tag>
+    </version>
+    <version>
+      <id>jsr03</id>
+      <name>1.0-JSR-03</name>
+      <tag>GROOVY_1_0_JSR_03</tag>
+    </version>
+    <version>
+      <id>jsr04</id>
+      <name>1.0-JSR-04</name>
+      <tag>GROOVY_1_0_JSR_04</tag>
+    </version>
+    <version>
+        <id>jsr05</id>
+        <name>1.0-JSR-05</name>
+        <tag>GROOVY_1_0_JSR_05</tag>
+    </version>
+    <version>
+        <id>jsr06</id>
+        <name>1.0-JSR-06</name>
+        <tag>GROOVY_1_0_JSR_06</tag>
+    </version>
+    <version>
+        <id>rc1</id>
+        <name>1.0-RC-1</name>
+        <tag>GROOVY_1_0_RC_1</tag>
+    </version>
+  </versions>
+
+  <mailingLists>
+    <mailingList>
+      <name>Groovy JSR Discussion List</name>
+      <subscribe>jsr-subscribe@groovy.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email</unsubscribe>
+      <archive>http://dir.gmane.org/gmane.comp.lang.groovy.jsr</archive>
+    </mailingList>
+    <mailingList>
+      <name>Groovy Developer List</name>
+      <subscribe>dev-subscribe@groovy.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email</unsubscribe>
+      <archive>http://dir.gmane.org/gmane.comp.lang.groovy.devel</archive>
+    </mailingList>
+    <mailingList>
+      <name>Groovy User List</name>
+      <subscribe>user-subscribe@groovy.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email</unsubscribe>
+      <archive>http://dir.gmane.org/gmane.comp.lang.groovy.user</archive>
+    </mailingList>
+    <mailingList>
+      <name>Groovy SCM List</name>
+      <subscribe>scm-subscribe@groovy.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email</unsubscribe>
+      <archive>http://archive.groovy.codehaus.org/scm/</archive>
+    </mailingList>
+  </mailingLists>
+
+  <developers>
+    <developer>
+      <name>Guillaume Laforge</name>
+      <id>glaforge</id>
+      <email></email>
+      <organization>Octo Technology</organization>
+      <roles>
+        <role>Project Manager</role>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>bob mcwhirter</name>
+      <id>bob</id>
+      <email>bob@werken.com</email>
+      <organization>The Werken Company</organization>
+      <roles>
+        <role>Founder</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>James Strachan</name>
+      <id>jstrachan</id>
+      <email>james@coredevelopers.com</email>
+      <organization>Core Developers Network</organization>
+      <roles>
+        <role>Founder</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Joe Walnes</name>
+      <id>joe</id>
+      <email></email>
+      <organization>ThoughtWorks</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Chris Stevenson</name>
+      <id>skizz</id>
+      <email></email>
+      <organization>ThoughtWorks</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Jamie McCrindle</name>
+      <id>jamiemc</id>
+      <email></email>
+      <organization>Three</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Matt Foemmel</name>
+      <id>mattf</id>
+      <email></email>
+      <organization>ThoughtWorks</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Sam Pullara</name>
+      <id>spullara</id>
+      <email>sam@sampullara.com</email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Kasper Nielsen</name>
+      <id>kasper</id>
+      <email></email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Travis Kay</name>
+      <id>travis</id>
+      <email></email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Zohar Melamed</name>
+      <id>zohar</id>
+      <email></email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>John Wilson</name>
+      <id>jwilson</id>
+      <email>tug@wilson.co.uk</email>
+      <organization>The Wilson Partnership</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Chris Poirier</name>
+      <id>cpoirier</id>
+      <email>cpoirier@dreaming.org</email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Christiaan ten Klooster</name>
+      <id>ckl</id>
+      <email>ckl@dacelo.nl</email>
+      <organization>Dacelo WebDevelopment</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Steve Goetze</name>
+      <id>goetze</id>
+      <email>goetze@dovetail.com</email>
+      <organization>Dovetailed Technologies, LLC</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+        <name>Bing Ran</name>
+        <id>bran</id>
+        <email>b55r@sina.com</email>
+        <organization>Leadingcare</organization>
+        <roles>
+          <role>Developer</role>
+        </roles>
+    </developer>
+    <developer>
+        <name>Jeremy Rayner</name>
+        <id>jez</id>
+        <email>jeremy.rayner@gmail.com</email>
+        <organization>javanicus</organization>
+        <roles>
+          <role>Developer</role>
+        </roles>
+   </developer>
+    <developer>
+        <name>John Stump</name>
+        <id>jstump</id>
+        <email>johnstump2@yahoo.com</email>
+        <organization></organization>
+        <roles>
+          <role>Developer</role>
+        </roles>
+   </developer>
+    <developer>
+        <name>Jochen Theodorou</name>
+        <id>blackdrag</id>
+        <email>blackdrag@gmx.org</email>
+        <organization></organization>
+        <roles>
+          <role>Developer</role>
+        </roles>
+   </developer>
+    <developer>
+      <name>Russel Winder</name>
+      <id>russel</id>
+      <email>russel@itzinteractive.com</email>
+      <organization>It'z Interactive Ltd</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+   </developer>
+    <developer>
+        <name>Pilho Kim</name>
+        <id>phk</id>
+        <email>phkim@cluecom.co.kr</email>
+        <organization></organization>
+        <roles>
+          <role>Developer</role>
+        </roles>
+   </developer>
+    <developer>
+        <name>Christian Stein</name>
+        <id>cstein</id>
+        <email>sormuras@gmx.de</email>
+        <organization>CTSR.de</organization>
+        <roles>
+          <role>Developer</role>
+        </roles>
+   </developer>
+   <developer>
+      <name>Dierk Koenig</name>
+      <id>mittie</id>
+      <email>dierk.koenig@canoo.com</email>
+      <organization>Canoo Engineering AG</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+   <developer>
+      <name>Paul King</name>
+      <id>paulk</id>
+      <email>paulk@asert.com.au</email>
+      <organization>ASERT, Australia</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+  </developers>
+
+  <contributors>
+    <contributor>
+      <name>Joern Eyrich</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Robert Kuzelj</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Rod Cope</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Yuri Schimke</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>James Birchfield</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Robert Fuller</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Sergey Udovenko</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Hallvard Traetteberg</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Peter Reilly</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Brian McCallister</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Richard Monson-Haefel</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Brian Larson</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Artur Biesiadowski</name>
+      <email>abies@pg.gda.pl</email>
+    </contributor>
+    <contributor>
+      <name>Ivan Z. Ganza</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Arjun Nayyar</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Mark Chu-Carroll</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Mark Turansky</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Jean-Louis Berliet</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Graham Miller</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Marc Palmer</name>
+      <email></email>
+    </contributor>
+    <contributor>
+      <name>Tugdual Grall</name>
+      <email></email>
+    </contributor>
+  </contributors>
+
+  <dependencies>
+
+    <!-- core dependencies -->
+    <dependency>
+      <groupId>antlr</groupId>
+      <artifactId>antlr</artifactId>
+      <version>2.7.5</version>
+      <properties>
+         <war.bundle>true</war.bundle>
+      </properties>
+    </dependency>    
+    <dependency>
+      <groupId>asm</groupId>
+      <artifactId>asm</artifactId>
+      <version>2.2</version>
+      <properties>
+         <war.bundle>true</war.bundle>
+      </properties>      
+    </dependency>
+
+    <!-- dependencies used by optional features -->
+    <dependency>
+      <groupId>xerces</groupId>
+      <artifactId>xerces</artifactId>
+      <version>2.4.0</version>
+    </dependency>
+    <dependency>
+      <groupId>xml-apis</groupId>
+      <artifactId>xml-apis</artifactId>
+      <version>1.0.b2</version>
+    </dependency>
+<!-- TODO upgrade to recent Xerces but maven 1.0.2 issues holding us back
+      <dependency>
+        <groupId>xerces</groupId>
+        <artifactId>xercesImpl</artifactId>
+        <version>2.6.2</version>
+      </dependency>
+      <dependency>
+        <groupId>xerces</groupId>
+        <artifactId>xmlParserAPIs</artifactId>
+        <version>2.6.2</version>
+      </dependency>
+      <dependency>
+        <groupId>xml-resolver</groupId>
+        <artifactId>xml-resolver</artifactId>
+        <version>1.1</version>
+      </dependency>-->
+
+    <!-- only used for command line tools -->
+    <dependency>
+      <groupId>commons-cli</groupId>
+      <artifactId>commons-cli</artifactId>    
+      <version>1.0</version>
+    </dependency>
+
+    <!-- only used for Ant tasks & scripting tools -->
+    <dependency>
+      <groupId>ant</groupId>
+      <artifactId>ant</artifactId>
+      <version>1.6.5</version>
+    </dependency>
+    <dependency>
+      <groupId>ant</groupId>
+      <artifactId>ant-junit</artifactId>    
+      <version>1.6.5</version>
+    </dependency>
+    <dependency>
+      <groupId>ant</groupId>
+      <artifactId>ant-launcher</artifactId>    
+      <version>1.6.5</version>
+    </dependency>
+
+    <!-- only used for testing helper classes -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>    
+      <version>3.8.2</version>
+    </dependency>    
+    <dependency>
+      <groupId>jmock</groupId>
+      <artifactId>jmock</artifactId>
+      <version>1.1.0</version>
+    </dependency>
+    <dependency>
+      <groupId>jmock</groupId>
+      <artifactId>jmock-cglib</artifactId>
+      <version>1.1.0</version>
+    </dependency>
+    <dependency>
+        <groupId>cglib</groupId>
+        <artifactId>cglib-nodep</artifactId>
+        <version>2.1_3</version>
+    </dependency>
+
+    <!-- only used for testing/debugging-->
+    <dependency>
+      <groupId>asm</groupId>
+      <artifactId>asm-util</artifactId>    
+      <version>2.2</version>
+    </dependency>
+    <dependency>
+      <groupId>asm</groupId>
+      <artifactId>asm-attrs</artifactId>    
+      <version>2.2</version>
+    </dependency>
+    <dependency>
+      <groupId>asm</groupId>
+      <artifactId>asm-analysis</artifactId>    
+      <version>2.2</version>
+    </dependency>
+    <dependency>
+      <groupId>asm</groupId>
+      <artifactId>asm-tree</artifactId>    
+      <version>2.2</version>
+    </dependency>
+
+    <!-- only used for BSF adapter-->
+    <dependency>
+      <groupId>bsf</groupId>
+      <artifactId>bsf</artifactId>    
+      <version>2.4.0</version>
+    </dependency>
+
+    <!-- only used for JMX utilities -->
+    <dependency>
+      <groupId>mx4j</groupId>
+      <artifactId>mx4j</artifactId>    
+      <version>3.0.1</version>
+      <properties>
+          <bootstrap>true</bootstrap>
+      </properties>
+    </dependency>
+
+    <!-- only used for GroovyMock tools -->
+    <dependency>
+      <groupId>mockobjects</groupId>
+      <artifactId>mockobjects-core</artifactId>
+      <version>0.09</version>
+    </dependency>
+
+    <!-- only used for EJB browser -->
+    <dependency>
+      <groupId>openejb</groupId>
+      <artifactId>openejb-loader</artifactId>
+      <version>1.0</version>
+    </dependency>
+
+    <!-- only used for SQL library -->
+    <dependency>
+      <groupId>axion</groupId>
+      <artifactId>axion</artifactId>    
+      <version>1.0-M3-dev</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-logging</groupId>
+      <artifactId>commons-logging</artifactId>    
+      <version>1.0.4</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-collections</groupId>
+      <artifactId>commons-collections</artifactId>    
+      <version>3.2</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-primitives</groupId>
+      <artifactId>commons-primitives</artifactId>
+      <version>1.0</version>
+    </dependency>
+    <dependency>
+      <groupId>regexp</groupId>
+      <artifactId>regexp</artifactId>    
+      <version>1.3</version>
+    </dependency>
+  
+    <!-- only used for servlet / gsp -->
+      <dependency>
+        <groupId>javax.servlet</groupId>
+        <artifactId>servlet-api</artifactId>
+        <version>2.4</version>
+      </dependency>
+      <dependency>
+        <groupId>javax.servlet</groupId>
+        <artifactId>jsp-api</artifactId>
+        <version>2.0</version>
+      </dependency>
+  
+    <!-- only used for the Wiki Ant tasks -->
+    <dependency>
+      <groupId>radeox</groupId>
+      <artifactId>radeox</artifactId>    
+      <version>0.9</version><!-- later version based on Java 5 -->
+    </dependency>
+    <dependency>
+      <groupId>radeox</groupId>
+      <artifactId>radeox-oro</artifactId>    
+      <version>0.9</version>
+    </dependency>
+
+    <!-- only used for the HTML to Wiki script -->
+    <dependency>
+      <groupId>nekohtml</groupId>
+      <artifactId>nekohtml</artifactId>    
+      <version>0.9.5</version>
+    </dependency>
+
+    <!-- only used for the JavaDoc generator script -->
+    <dependency>
+      <groupId>qdox</groupId>
+      <artifactId>qdox</artifactId>    
+      <version>1.5</version>
+    </dependency>
+
+    <!-- only used in the samples (BlogLines client) -->
+    <dependency>
+      <groupId>commons-httpclient</groupId>
+      <artifactId>commons-httpclient</artifactId>
+      <version>3.0.1</version>
+    </dependency>
+
+    <!-- used to dump out the AST -->
+    <dependency>
+      <groupId>xstream</groupId>
+      <artifactId>xstream</artifactId>
+      <version>1.2</version>
+    </dependency>
+
+    <!-- used by xstream -->
+    <dependency>
+      <groupId>xpp3</groupId>
+      <artifactId>xpp3</artifactId>
+      <version>1.1.3.4.O</version>
+    </dependency>
+
+    <!-- used to build embeddable jar -->
+    <dependency>
+      <groupId>com.tonicsystems</groupId>
+      <artifactId>jarjar</artifactId>
+      <version>0.6</version>
+    </dependency>
+
+    <!-- prepare for EMMA
+    <dependency>
+            <id>emma</id>
+            <version>2.0.latest</version>
+            <url>http://emma.sourceforge.net</url>
+        </dependency>
+        <dependency>
+            <id>emma_ant</id>
+            <groupId>emma</groupId>
+            <version>2.0.latest</version>
+            <url>http://emma.sourceforge.net</url>
+        </dependency>
+    -->
+
+  </dependencies>
+
+    <build>
+        <nagEmailAddress>groovy-scm@groovy.codehaus.org</nagEmailAddress>
+        <sourceDirectory>src/main</sourceDirectory>
+        <sourceModifications>
+            <sourceModification>
+                <!-- a random test from the groovy test suite, exclude javac of UberTests if groovy tests not available -->
+                <className>CastTest</className>
+                <excludes>
+                    <exclude>**/Uber*.java</exclude>
+                </excludes>
+            </sourceModification>
+        </sourceModifications>
+        <unitTestSourceDirectory>src/test</unitTestSourceDirectory>
+        <aspectSourceDirectory/>
+        <unitTest>
+            <resources>
+                <resource>
+                    <directory>src/test</directory>
+                    <includes>
+                        <include>**/*.properties</include>
+                        <include>**/*.xml</include>
+                        <include>**/*.xsd</include>
+                    </includes>
+                </resource>
+                <!-- security test files -->
+                <resource>
+                    <directory>src/security</directory>
+                    <includes>
+                        <include>**/*.*</include>
+                        <include>**/groovy*</include>
+                    </includes>
+                </resource>
+            </resources>
+            <!--      <includes>
+              <include>**/*Test.*</include>
+              <include>**/*Bug.*</include>
+            </includes>-->
+            <includes>
+                <include>**/Uber*.*</include>
+            </includes>
+            <excludes>
+                <exclude>**/SignedJarTest.*</exclude>
+            </excludes>
+        </unitTest>
+        <resources>
+            <resource>
+                <directory>src/main</directory>
+                <includes>
+                    <include>**/*.properties</include>
+                    <include>**/*.xml</include>
+                </includes>
+            </resource>
+        </resources>
+    </build>  
+   
+  <reports>
+    <report>maven-license-plugin</report>
+
+    <!-- very large and offers no real value, it just slows us down!
+    <report>maven-checkstyle-plugin</report>
+    -->
+
+    <report>maven-pmd-plugin</report>
+    <!-- <report>maven-simian-plugin</report> -->
+    <report>maven-jdepend-plugin</report>
+    <!-- <report>maven-changelog-plugin</report> -->
+  	<!-- <report>maven-statcvs-plugin</report>   -->
+    <!-- <report>maven-file-activity-plugin</report> -->
+    <!--<report>maven-developer-activity-plugin</report> -->
+    <report>maven-jxr-plugin</report>
+    <!-- <report>maven-javadoc-plugin</report> -->
+    <report>maven-junit-report-plugin</report>
+    <report>maven-faq-plugin</report>
+    <!-- <report>maven-clover-plugin</report> -->
+    <report>maven-changes-plugin</report>
+    <!-- <report>maven-cobertura-plugin</report> -->
+    <!-- prepare for EMMA
+    <report>maven-emma-plugin</report>
+    -->
+  </reports>
+
+</project>
diff --git a/groovy-core/security/GroovyJarTest.jar b/groovy-core/security/GroovyJarTest.jar
new file mode 100644
index 0000000..eb59c7d
--- /dev/null
+++ b/groovy-core/security/GroovyJarTest.jar
Binary files differ
diff --git a/groovy-core/security/groovy.policy b/groovy-core/security/groovy.policy
new file mode 100644
index 0000000..a08df0f
--- /dev/null
+++ b/groovy-core/security/groovy.policy
@@ -0,0 +1,234 @@
+/* Notes on the contents of this policy file:
+ *
+ * The following methods in groovy have privileged operations wrapping
+ * setAccessible.  If these wrappers are not provided, most codebases below
+ * must have the following grant: 
+ * permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
+ *  MetaMethod.createMetaMethod
+ *  MetaMethod.invoke(Object Object[])
+ *  ReflectionMetaMethod.invoke(Object Object[])
+ *  DefaultGoovyMethods.dump(Object)
+ */
+
+/*
+ * This keystore contains the public key of the pair used to sign GroovyTestJar.jar
+ * See SecurityTest.testReadSignedJar()
+ */
+keystore "file:${user.dir}/security/groovykeys";
+
+/*
+ * ================= Codebases requiring java.security.AllPermission ===============
+ * The following codebases require java.security.AllPermission.  They are considered trusted
+ * for purposes of groovy security enforcement.  In a deployed groovy environment, these classes
+ * would all be in a set of jars.  If these jars are signed, the grants could be strengthened to
+ * by adding a signedBy clause to the grant.
+ */
+ 
+//spg:  Looks like james switched the output destination to bin from target/classes
+//in his 7/13/04 update to the eclipse .classpath.  This permission allows the 
+//Security tests to run properly in eclipse (they were unaffected when running from maven)
+grant codeBase "file:${user.dir}/bin/-" {
+	permission java.security.AllPermission;
+};
+
+grant codeBase "file:${user.dir}/target/classes/-" {
+	permission java.security.AllPermission;
+};
+
+grant codeBase "file:${user.dir}/target/test-classes/-" {
+	permission java.security.AllPermission;
+};
+
+grant codeBase "file:${groovy.lib}/-" {
+	permission java.security.AllPermission;
+};
+
+/*
+ * When running from maven, this codebase is required.
+ * If not running from maven, the codesource will not be found, but will not cause an error.
+ */
+grant codeBase "file:${maven.home}/-" {
+	permission java.security.AllPermission;
+};
+
+/*
+ * When running the junit plugin from within eclipse, this codebase is required.
+ * If not running from eclipse, the codesource will not be found, but will not cause an error.
+ */
+grant codeBase "file:${user.dir}/../../plugins/-" {
+	permission java.security.AllPermission;
+};
+
+/*
+ * ================= Default codebases created by groovy. ===============
+ * The following codebases are assigned when groovy parses a groovy script
+ */
+
+/* 
+ * GroovyShell.parse(InputStream,...) is given a codebase of "groovy.shell" because no actual
+ * codebase can be determined.  The other forms of parse(File) and parse(GroovyCodeSource) allow
+ * for more control.  These permission should be set to control scripts that are passed into
+ * the shell in the form of a string or other groovy code of unknown provenance.
+ */
+grant codeBase "file:/groovy/shell" {
+	permission java.lang.RuntimePermission "accessDeclaredMembers";
+};
+
+/*
+ * Similar to "file:/groovy/shell", but implying a direct call to GroovyClassLoader.parse() without
+ * passing through GroovyShell.
+ */
+grant codeBase "file:/groovy/script" {
+	permission java.lang.RuntimePermission "accessDeclaredMembers";
+	//permission java.util.PropertyPermission "groovy.output.dir", "read";
+};
+
+/*
+ * The TestSupport class has a loadClass method that takes a ClassNode and runs it
+ * through defineClass() of the class loader.  The codebase for this operation is
+ * set to "/groovy/testSupport".
+ */
+grant codeBase "file:/groovy/testSupport" {
+	permission java.lang.RuntimePermission "accessDeclaredMembers";
+};
+
+/*
+ * ================= SecurityTest codebases  ===============
+ * The following grants are for individual security test cases where the
+ * codebase is explicity specified (e.g. the script is a raw string rather
+ * than read from a file).  Note that even though the codebases conform to
+ * the file URL syntax, they are not physical files: they represent virtual
+ * codebases.
+ * The permission grant that is commented out is the permission that is 
+ * expected to be missing by the test case.  It is here as a comment for
+ * information.
+ */
+ 
+//Since a codebase is a URL, we can make use of the natural hierarchy permission implications
+//to grant a 'global' accessDeclaredPermission here.
+grant codeBase "file:/groovy/security/-" {
+	permission java.lang.RuntimePermission "accessDeclaredMembers";
+};
+
+grant codeBase "file:/groovy/security/testForbiddenPackage" {
+	//permission java.lang.RuntimePermission "accessClassInPackage.sun.*";
+};
+
+grant codeBase "file:/groovy/security/javax/print/deny" {
+	//permission java.lang.RuntimePermission "accessClassInPackage.javax.print";
+};
+
+grant codeBase "file:/groovy/security/javax/print/allow" {
+	permission java.lang.RuntimePermission "accessClassInPackage.javax.print";
+};
+
+/*
+ * ================= .groovy script file codebases  ===============
+ * The following grants are for individual security test cases.
+ * The permission grant that is commented out is the permission that is 
+ * expected to be missing by the test case.  It is here as a comment for
+ * information.
+ */
+grant codeBase "file:${user.dir}/src/test/-" {
+	// Required by most groovy scripts during execution because of the heavy use of reflection/
+ 	// introspection.  The groovy code could potentially be changed to eliminate this requirement
+ 	// by adding privileged operations in many places.
+	permission java.lang.RuntimePermission "accessDeclaredMembers";
+
+	// SHOULD NOT HAVE TO DO THIS! - Level.getLocalizedName() should have a doPrivileged block.
+	// Any test that logs, will encounter this (although it will be masked by the method
+	permission java.lang.RuntimePermission "accessClassInPackage.sun.util.logging.resources";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/security/forbiddenCodeBase.gvy" {
+	//The following grant is commented out so that the test case will throw an AccessControlException
+	permission groovy.security.GroovyCodeSourcePermission "groovy/security/forbiddenCodeBase";
+};
+
+// Grant permission to .groovy files extracted from a signed jar that has been signedBy "Groovy"
+grant signedBy "Groovy" {
+	permission java.lang.RuntimePermission "accessDeclaredMembers";
+	permission java.util.PropertyPermission "user.home", "read";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/bugs/BadScriptNameBug.groovy" {
+	permission java.util.PropertyPermission "java.class.path", "read";
+	permission java.io.FilePermission "<<ALL FILES>>", "read";
+	permission java.lang.RuntimePermission "createClassLoader";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/ClosureListenerTest.groovy" {
+	permission java.util.PropertyPermission "java.awt.headless", "read";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/ClosureMethodTest.groovy" {
+	permission java.io.FilePermission "${user.dir}${/}src${/}test${/}-", "read";
+	permission java.util.PropertyPermission "file.encoding", "read";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/GroovyMethodsTest.groovy" {
+	permission java.util.PropertyPermission "*", "read,write";
+	//spg 2006-02-09 added ALL FILES execute because a test case 
+	//invokes Runtime.exec().  This is OK and permission should be granted here.
+	permission java.io.FilePermission "<<ALL FILES>>", "execute";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/ClosureWithDefaultParamTest.groovy" {
+	permission java.io.FilePermission "src${/}test${/}-", "read";
+	permission java.util.PropertyPermission "file.encoding", "read";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/bugs/ConstructorBug.groovy" {
+	permission java.lang.RuntimePermission "createClassLoader";
+	permission java.io.FilePermission "src${/}test${/}groovy${/}bugs${/}TestBase.groovy", "read";
+	permission java.io.FilePermission "src${/}test${/}groovy${/}bugs${/}TestDerived.groovy", "read";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/bugs/ForAndSqlBug.groovy" {
+	permission java.io.FilePermission "target${/}test-classes${/}*", "read, write";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/bugs/ForLoopBug.groovy" {
+	permission java.io.FilePermission "target${/}test-classes${/}*", "read, write";
+	permission java.io.FilePermission "target${/}test-classes${/}*", "read, write";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/bugs/Groovy303_Bug.groovy" {
+	permission java.awt.AWTPermission "showWindowWithoutWarningBanner";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/script/ScriptTest.groovy" {
+	permission java.io.FilePermission "src${/}test${/}groovy${/}-", "read";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/script/EvalInScript.groovy" {
+	permission java.io.FilePermission "src${/}test${/}groovy${/}script${/}HelloWorld.groovy", "read";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/sql/PersonTest.groovy" {
+	permission java.io.FilePermission "target${/}test-classes${/}groovy${/}sql${/}-", "read";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/sql/SqlCompleteTest.groovy" {
+	permission java.io.FilePermission "target${/}test-classes${/}groovy${/}sql${/}-", "read";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/sql/SqlCompleteWithoutDataSourceTest.groovy" {
+	permission java.util.PropertyPermission "axiondb.database.*", "read";
+	permission java.util.PropertyPermission "org.apache.commons.logging.*", "read";
+	permission java.util.PropertyPermission "org.axiondb.engine.*", "read";
+	permission java.io.FilePermission "${groovy.lib}${/}axion${/}jars${/}axion-1.0-M3-dev.jar", "read";	
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/sql/SqlTest.groovy" {
+	permission java.io.FilePermission "target${/}test-classes${/}groovy${/}sql${/}-", "read";
+};
+
+grant codeBase "file:${user.dir}/src/test/groovy/util/AntTest.groovy" {
+	permission java.security.AllPermission;
+};
+
+grant codeBase "file:${user.dir}/src/test/org/codehaus/groovy/classgen/MetaClassTest.groovy" {
+	permission java.io.FilePermission "target${/}test-classes${/}-", "read";
+};
+
diff --git a/groovy-core/security/groovykeys b/groovy-core/security/groovykeys
new file mode 100644
index 0000000..4fc24da
--- /dev/null
+++ b/groovy-core/security/groovykeys
Binary files differ
diff --git a/groovy-core/src/bin/grok b/groovy-core/src/bin/grok
new file mode 100644
index 0000000..7903f36
--- /dev/null
+++ b/groovy-core/src/bin/grok
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+##############################################################################
+##                                                                          ##
+##  Groovy JVM Bootstrap for UN*X                                           ##
+##                                                                          ##
+##############################################################################
+
+##
+## $Revision$
+## $Date$
+##
+
+DIRNAME=`dirname "$0"`
+. "$DIRNAME/startGroovy"
+
+startGroovy org.codehaus.groovy.tools.Grok "$@"
+
diff --git a/groovy-core/src/bin/grok.bat b/groovy-core/src/bin/grok.bat
new file mode 100644
index 0000000..cc4a1eb
--- /dev/null
+++ b/groovy-core/src/bin/grok.bat
@@ -0,0 +1,18 @@
+@if "%DEBUG%" == "" @echo off
+
+@rem 
+@rem $Revision$ $Date$
+@rem 
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+:begin
+@rem Determine what directory it is in.
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.\
+
+"%DIRNAME%\startGroovy.bat" "%DIRNAME%" org.codehaus.groovy.tools.Grok %*
+
+@rem End local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" endlocal
\ No newline at end of file
diff --git a/groovy-core/src/bin/groovy b/groovy-core/src/bin/groovy
new file mode 100644
index 0000000..b1208df
--- /dev/null
+++ b/groovy-core/src/bin/groovy
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+##############################################################################
+##                                                                          ##
+##  Groovy JVM Bootstrap for UN*X                                           ##
+##                                                                          ##
+##  use -cp or -classpath just as in java to use a custom classpath         ##
+##                                                                          ##
+##############################################################################
+
+##
+## $Revision$
+## $Date$
+##
+
+DIRNAME=`dirname "$0"`
+. "$DIRNAME/startGroovy"
+
+startGroovy groovy.ui.GroovyMain "$@"
diff --git a/groovy-core/src/bin/groovy.bat b/groovy-core/src/bin/groovy.bat
new file mode 100644
index 0000000..4f480af
--- /dev/null
+++ b/groovy-core/src/bin/groovy.bat
@@ -0,0 +1,18 @@
+@if "%DEBUG%" == "" @echo off
+
+@rem 
+@rem $Revision$ $Date$
+@rem 
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+:begin
+@rem Determine what directory it is in.
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.\
+
+"%DIRNAME%\startGroovy.bat" "%DIRNAME%" groovy.ui.GroovyMain %*
+
+@rem End local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" endlocal
\ No newline at end of file
diff --git a/groovy-core/src/bin/groovyConsole b/groovy-core/src/bin/groovyConsole
new file mode 100644
index 0000000..bd4a2cf
--- /dev/null
+++ b/groovy-core/src/bin/groovyConsole
@@ -0,0 +1,15 @@
+#!/bin/sh
+##############################################################################
+##                                                                          ##
+##  Groovy Console script for UN*X                                          ##
+##                                                                          ##
+##############################################################################
+
+##
+## $Revision$ $Date$
+##
+
+DIRNAME=`dirname "$0"`
+. "$DIRNAME/startGroovy"
+
+startGroovy groovy.ui.Console "$@"
diff --git a/groovy-core/src/bin/groovyConsole.bat b/groovy-core/src/bin/groovyConsole.bat
new file mode 100644
index 0000000..34a0989
--- /dev/null
+++ b/groovy-core/src/bin/groovyConsole.bat
@@ -0,0 +1,18 @@
+@if "%DEBUG%" == "" @echo off
+
+@rem 
+@rem $Revision$ $Date$
+@rem 
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+:begin
+@rem Determine what directory it is in.
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.\
+
+"%DIRNAME%\startGroovy.bat" "%DIRNAME%" groovy.ui.Console %*
+
+@rem End local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" endlocal
\ No newline at end of file
diff --git a/groovy-core/src/bin/groovyc b/groovy-core/src/bin/groovyc
new file mode 100644
index 0000000..21f9257
--- /dev/null
+++ b/groovy-core/src/bin/groovyc
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+##############################################################################
+##                                                                          ##
+##  Groovy JVM Bootstrap for UN*X                                           ##
+##                                                                          ##
+##############################################################################
+
+##
+## $Revision$
+## $Date$
+##
+
+DIRNAME=`dirname "$0"`
+. "$DIRNAME/startGroovy"
+
+startGroovy org.codehaus.groovy.tools.FileSystemCompiler "$@"
diff --git a/groovy-core/src/bin/groovyc.bat b/groovy-core/src/bin/groovyc.bat
new file mode 100644
index 0000000..92fc041
--- /dev/null
+++ b/groovy-core/src/bin/groovyc.bat
@@ -0,0 +1,18 @@
+@if "%DEBUG%" == "" @echo off
+
+@rem 
+@rem $Revision$ $Date$
+@rem 
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+:begin
+@rem Determine what directory it is in.
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.\
+
+"%DIRNAME%\startGroovy.bat" "%DIRNAME%" org.codehaus.groovy.tools.FileSystemCompiler %*
+
+@rem End local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" endlocal
\ No newline at end of file
diff --git a/groovy-core/src/bin/groovysh b/groovy-core/src/bin/groovysh
new file mode 100644
index 0000000..2f54544
--- /dev/null
+++ b/groovy-core/src/bin/groovysh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+##############################################################################
+##                                                                          ##
+##  Groovy Console script for UN*X                                          ##
+##                                                                          ##
+##############################################################################
+
+##
+## $Revision$
+## $Date$
+##
+
+DIRNAME=`dirname "$0"`
+. "$DIRNAME/startGroovy"
+
+startGroovy groovy.ui.InteractiveShell "$@"
diff --git a/groovy-core/src/bin/groovysh.bat b/groovy-core/src/bin/groovysh.bat
new file mode 100644
index 0000000..b5bc20f
--- /dev/null
+++ b/groovy-core/src/bin/groovysh.bat
@@ -0,0 +1,18 @@
+@if "%DEBUG%" == "" @echo off
+
+@rem 
+@rem $Revision$ $Date$
+@rem 
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+:begin
+@rem Determine what directory it is in.
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.\
+
+"%DIRNAME%\startGroovy.bat" "%DIRNAME%" groovy.ui.InteractiveShell %*
+
+@rem End local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" endlocal
\ No newline at end of file
diff --git a/groovy-core/src/bin/java2groovy b/groovy-core/src/bin/java2groovy
new file mode 100644
index 0000000..a0e9f43
--- /dev/null
+++ b/groovy-core/src/bin/java2groovy
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+##############################################################################
+##                                                                          ##
+##  Groovy JVM Bootstrap for UN*X                                           ##
+##                                                                          ##
+##############################################################################
+
+##
+## $Revision: 4241 $
+## $Date: 2006-11-16 17:30:40 +0000 (Thu, 16 Nov 2006) $
+##
+
+DIRNAME=`dirname "$0"`
+. "$DIRNAME/startGroovy"
+
+startGroovy org.codehaus.groovy.antlr.java.Java2GroovyMain "$@"
diff --git a/groovy-core/src/bin/java2groovy.bat b/groovy-core/src/bin/java2groovy.bat
new file mode 100644
index 0000000..f529c4f
--- /dev/null
+++ b/groovy-core/src/bin/java2groovy.bat
@@ -0,0 +1,18 @@
+@if "%DEBUG%" == "" @echo off
+
+@rem 
+@rem $Revision: 2770 $ $Date: 2005-08-29 11:49:42 +0100 (Mon, 29 Aug 2005) $
+@rem 
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+:begin
+@rem Determine what directory it is in.
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.\
+
+"%DIRNAME%\startGroovy.bat" "%DIRNAME%" org.codehaus.groovy.antlr.java.Java2Groovy %*
+
+@rem End local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" endlocal
diff --git a/groovy-core/src/bin/startGroovy b/groovy-core/src/bin/startGroovy
new file mode 100644
index 0000000..4db01a2
--- /dev/null
+++ b/groovy-core/src/bin/startGroovy
@@ -0,0 +1,245 @@
+# -*- mode:sh -*-
+
+##############################################################################
+##                                                                          ##
+##  Groovy JVM Bootstrap for UN*X                                           ##
+##                                                                          ##
+##############################################################################
+
+##
+## $Revision$
+## $Date$
+##
+
+PROGNAME=`basename "$0"`
+
+#DIRNAME=`dirname "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "${PROGNAME}: $*"
+}
+
+die ( ) {
+    warn "$*"
+    exit 1
+}
+
+earlyInit ( ) {
+    return
+}
+
+lateInit ( ) {
+    return
+}
+
+GROOVY_STARTUP="$HOME/.groovy/startup"
+if [ -r "$GROOVY_STARTUP" ] ; then
+    . "$GROOVY_STARTUP"
+fi
+
+earlyInit
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;; 
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+if [ "$1" = "-cp" -o "$1" = "-classpath" ] ; then
+    CP=$2
+    shift 2
+fi
+
+# Attempt to set JAVA_HOME if it's not already set.
+if [ -z "$JAVA_HOME" ] ; then
+    if $darwin ; then 
+        [ -z "$JAVA_HOME" -a -d "/Library/Java/Home" ] && export JAVA_HOME="/Library/Java/Home"
+        [ -z "$JAVA_HOME" -a -d "/System/Library/Frameworks/JavaVM.framework/Home" ] && export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Home"
+    else
+        javaExecutable="`which javac`"
+        [ -z "$javaExecutable" -o "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ] && die "JAVA_HOME not set and cannot find javac to deduce location, please set JAVA_HOME."
+        # readlink(1) is not available as standard on Solaris 10.
+        readLink=`which readlink`
+        [ `expr "$readLink" : '\([^ ]*\)'` = "no" ] && die "JAVA_HOME not set and readlink not available, please set JAVA_HOME."
+        javaExecutable="`readlink -f \"$javaExecutable\"`"
+        javaHome="`dirname \"$javaExecutable\"`"
+        javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+        export JAVA_HOME="$javaHome"
+    fi
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$GROOVY_HOME" ] && GROOVY_HOME=`cygpath --unix "$GROOVY_HOME"`
+    [ -n "$JAVACMD" ] && JAVACMD=`cygpath --unix "$JAVACMD"`
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+    [ -n "$CP" ] && CP=`cygpath --path --unix "$CP"`
+fi
+
+# Attempt to set GROOVY_HOME if it is not already set.
+if [ -z "$GROOVY_HOME" -o ! -d "$GROOVY_HOME" ] ; then
+    # Resolve links: $0 may be a link to groovy's home.
+    PRG="$0"
+    # Need this for relative symlinks.
+    while [ -h "$PRG" ] ; do
+        ls=`ls -ld "$PRG"`
+        link=`expr "$ls" : '.*-> \(.*\)$'`
+        if expr "$link" : '/.*' > /dev/null; then
+            PRG="$link"
+        else
+            PRG=`dirname "$PRG"`"/$link"
+        fi
+    done
+    SAVED="`pwd`"
+    cd "`dirname \"$PRG\"`/.."
+    GROOVY_HOME="`pwd -P`"
+    cd "$SAVED"
+fi
+
+# Set the default Groovy config if no specific one is mentioned.
+if [ -z "$GROOVY_CONF" ] ; then
+    GROOVY_CONF="$GROOVY_HOME/conf/groovy-starter.conf"
+fi
+STARTER_CLASSPATH="$GROOVY_HOME/lib/groovy-starter.jar"
+
+# Create the final classpath. Setting a classpath using the -cp or -classpath option means not to use the
+# global classpath. Groovy behaves then the same as the java interpreter
+if [ -n "$CP" ] ; then
+    CP="$STARTER_CLASSPATH":"$CP":.
+elif [ -n "$CLASSPATH" ] ; then
+    CP="$STARTER_CLASSPATH":"$CLASSPATH":.
+else
+    CP="$STARTER_CLASSPATH":.
+fi
+
+# Determine the Java command to use to start the JVM.
+if [ -z "$JAVACMD" ] ; then
+    if [ -n "$JAVA_HOME" ] ; then
+        if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+            # IBM's JDK on AIX uses strange locations for the executables
+            JAVACMD="$JAVA_HOME/jre/sh/java"
+        else
+            JAVACMD="$JAVA_HOME/bin/java"
+        fi
+    else
+        JAVACMD="java"
+    fi
+fi
+if [ ! -x "$JAVACMD" ] ; then
+    die "JAVA_HOME is not defined correctly, can not execute: $JAVACMD"
+fi
+if [ -z "$JAVA_HOME" ] ; then
+    warn "JAVA_HOME environment variable is not set"
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query businessSystem maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# Setup Profiler
+useprofiler=false
+if [ "$PROFILER" != "" ] ; then
+    if [ -r "$PROFILER" ] ; then
+        . $PROFILER
+        useprofiler=true
+    else
+        die "Profiler file not found: $PROFILER"
+    fi
+fi
+
+# For Darwin, use classes.jar for TOOLS_JAR
+TOOLS_JAR="$JAVA_HOME/lib/tools.jar"
+#if $darwin; then
+#    TOOLS_JAR="/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Classes/classes.jar"
+#fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    GROOVY_HOME=`cygpath --path --mixed "$GROOVY_HOME"`
+    JAVA_HOME=`cygpath --path --mixed "$JAVA_HOME"`
+    GROOVY_CONF=`cygpath --path --mixed "$GROOVY_CONF"`
+    CP=`cygpath --path --mixed "$CP"`    
+    TOOLS_JAR=`cygpath --path --mixed "$TOOLS_JAR"`
+    STARTER_CLASSPATH=`cygpath --path --mixed "$STARTER_CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GROOVY_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GROOVY_CYGPATTERN)"
+    fi
+    # Now convert the arguments
+    declare -i count
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        if [ $CHECK -ne 0 ] ; then
+            convArg=`cygpath --path --ignore --mixed "$arg"`
+        else
+            convArg=$arg
+        fi
+        ARGUMENTS[$count]=$convArg
+        count+=1
+    done
+
+    #  For some bizarre reason Dash (/bin/sh) on Ubuntu 6.10 Edgy Eft will not parse the array expression
+    #  needed for the Cygwin version of the exec command.  The only solution is for Dash not to see the text
+    #  at all :-(
+
+    . "$DIRNAME/startGroovy_cygwin"
+else
+    startGroovy ( ) {
+        CLASS=$1
+        shift
+    # Start the Profiler or the JVM
+        if $useprofiler ; then
+            runProfiler
+        else
+            exec "$JAVACMD" $JAVA_OPTS \
+                -classpath "$STARTER_CLASSPATH" \
+                -Dprogram.name="$PROGNAME" \
+                -Dgroovy.starter.conf="$GROOVY_CONF" \
+                -Dgroovy.home="$GROOVY_HOME" \
+                -Dtools.jar="$TOOLS_JAR" \
+                $STARTER_MAIN_CLASS \
+                --main $CLASS \
+                --conf "$GROOVY_CONF" \
+                --classpath "$CP" \
+                "$@"
+        fi
+    }    
+fi
+
+STARTER_MAIN_CLASS=org.codehaus.groovy.tools.GroovyStarter
+
+lateInit
diff --git a/groovy-core/src/bin/startGroovy.bat b/groovy-core/src/bin/startGroovy.bat
new file mode 100644
index 0000000..441819a
--- /dev/null
+++ b/groovy-core/src/bin/startGroovy.bat
@@ -0,0 +1,131 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem                                                                         ##
+@rem  Groovy JVM Bootstrap for Windowz                                       ##
+@rem                                                                         ##
+@rem ##########################################################################
+
+@rem 
+@rem $Revision$ $Date$
+@rem 
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~1
+shift
+
+set CLASS=%~1
+shift
+
+if exist "%USERPROFILE%/.groovy/preinit.bat" call "%USERPROFILE%/.groovy/preinit.bat"
+
+@rem Determine the command interpreter to execute the "CD" later
+set COMMAND_COM="cmd.exe"
+if exist "%SystemRoot%\system32\cmd.exe" set COMMAND_COM="%SystemRoot%\system32\cmd.exe"
+if exist "%SystemRoot%\command.com" set COMMAND_COM="%SystemRoot%\command.com"
+
+@rem Use explicit find.exe to prevent cygwin and others find.exe from being used
+set FIND_EXE="find.exe"
+if exist "%SystemRoot%\system32\find.exe" set FIND_EXE="%SystemRoot%\system32\find.exe"
+if exist "%SystemRoot%\command\find.exe" set FIND_EXE="%SystemRoot%\command\find.exe"
+
+:check_JAVA_HOME
+@rem Make sure we have a valid JAVA_HOME
+if not "%JAVA_HOME%" == "" goto have_JAVA_HOME
+
+echo.
+echo ERROR: Environment variable JAVA_HOME has not been set.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+echo.
+goto end
+
+:have_JAVA_HOME
+@rem Validate JAVA_HOME
+%COMMAND_COM% /C DIR "%JAVA_HOME%" 2>&1 | %FIND_EXE% /I /C "%JAVA_HOME%" >nul
+if not errorlevel 1 goto check_GROOVY_HOME
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+echo.
+goto end
+
+:check_GROOVY_HOME
+@rem Define GROOVY_HOME if not set
+if "%GROOVY_HOME%" == "" set GROOVY_HOME=%DIRNAME%..
+
+@rem classpath handling
+set CP=
+if "x%~1" == "x-cp" set CP=%~2
+if "x%~1" == "x-classpath" set CP=%~2
+if "x" == "x%CP%" goto init
+shift 
+shift
+ 
+:init
+@rem Get command-line arguments, handling Windowz variants
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.  
+set CMD_LINE_ARGS=
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
+shift
+goto win9xME_args_slurp
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+set STARTER_CLASSPATH=%GROOVY_HOME%\lib\groovy-starter.jar
+
+if exist "%USERPROFILE%/.groovy/init.bat" call "%USERPROFILE%/.groovy/init.bat"
+
+@rem Setting a classpath using the -cp or -classpath option means not to use
+@rem the global classpath. Groovy behaves then the same as the java 
+@rem interpreter
+if "x" == "x%CP%" goto empty_cp
+:non_empty_cp
+set CP=%STARTER_CLASSPATH%;%CP%;.
+goto after_cp
+:empty_cp
+set CP=%STARTER_CLASSPATH%;.
+if "x" == "x%CLASSPATH%" goto after_cp
+set STARTER_CLASSPATH=%STARTER_CLASSPATH%;%CLASSPATH%
+:after_cp
+
+set STARTER_MAIN_CLASS=org.codehaus.groovy.tools.GroovyStarter
+set STARTER_CONF=%GROOVY_HOME%\conf\groovy-starter.conf
+
+set JAVA_EXE=%JAVA_HOME%\bin\java.exe
+set TOOLS_JAR=%JAVA_HOME%\lib\tools.jar
+
+if "%JAVA_OPTS%" == "" set JAVA_OPTS="-Xmx128m"
+set JAVA_OPTS=%JAVA_OPTS% -Dprogram.name="%PROGNAME%"
+set JAVA_OPTS=%JAVA_OPTS% -Dgroovy.home=%GROOVY_HOME%
+set JAVA_OPTS=%JAVA_OPTS% -Dtools.jar="%TOOLS_JAR%"
+set JAVA_OPTS=%JAVA_OPTS% -Dgroovy.starter.conf="%STARTER_CONF%"
+
+if exist "%USERPROFILE%/.groovy/postinit.bat" call "%USERPROFILE%/.groovy/postinit.bat"
+
+@rem Execute Groovy
+"%JAVA_EXE%" %JAVA_OPTS% -classpath "%STARTER_CLASSPATH%" %STARTER_MAIN_CLASS% --main %CLASS% --conf "%STARTER_CONF%" --classpath "%CP%" %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" endlocal
+
+@rem Optional pause the batch file
+if "%GROOVY_BATCH_PAUSE%" == "on" pause
+
diff --git a/groovy-core/src/bin/startGroovy_cygwin b/groovy-core/src/bin/startGroovy_cygwin
new file mode 100644
index 0000000..8b62bcc
--- /dev/null
+++ b/groovy-core/src/bin/startGroovy_cygwin
@@ -0,0 +1,46 @@
+# -*- mode:sh -*-
+
+##############################################################################
+##                                                                          ##
+##  Groovy JVM Bootstrap for UN*X                                           ##
+##                                                                          ##
+##############################################################################
+
+##
+## $Revision$
+## $Date$
+##
+
+startGroovy ( ) {
+    CLASS=$1
+    shift
+    # Start the Profiler or the JVM
+    if $useprofiler ; then
+        runProfiler
+    else
+        if [ $# -eq 0 ] ; then
+            exec "$JAVACMD" $JAVA_OPTS \
+                -classpath "$STARTER_CLASSPATH" \
+                -Dprogram.name="$PROGNAME" \
+                -Dgroovy.starter.conf="$GROOVY_CONF" \
+                -Dgroovy.home="$GROOVY_HOME" \
+                -Dtools.jar="$TOOLS_JAR" \
+                $STARTER_MAIN_CLASS \
+                --main $CLASS \
+                --conf "$GROOVY_CONF" \
+                --classpath "$CP" 
+        else
+            exec "$JAVACMD" $JAVA_OPTS \
+                -classpath "$STARTER_CLASSPATH" \
+                -Dprogram.name="$PROGNAME" \
+                -Dgroovy.starter.conf="$GROOVY_CONF" \
+                -Dgroovy.home="$GROOVY_HOME" \
+                -Dtools.jar="$TOOLS_JAR" \
+                $STARTER_MAIN_CLASS \
+                --main $CLASS \
+                --conf "$GROOVY_CONF" \
+                --classpath "$CP" \
+                "${ARGUMENTS[@]}"
+        fi
+    fi
+}
diff --git a/groovy-core/src/conf/groovy-starter.conf b/groovy-core/src/conf/groovy-starter.conf
new file mode 100644
index 0000000..56a761f
--- /dev/null
+++ b/groovy-core/src/conf/groovy-starter.conf
@@ -0,0 +1,23 @@
+##############################################################################
+##                                                                          ##
+##  Groovy Classlaoding Configuration                                       ##
+##                                                                          ##
+##############################################################################
+
+##
+## $Revision$ $Date$
+##
+## Note: do not add clases from java.lang here. No rt.jar and no tools.jar
+##
+
+    # Allow access to resources
+    load ${groovy.home}/conf
+    
+    # Load required libraries
+    load ${groovy.home}/lib/*.jar
+
+    # load user specific libraries
+    load ${user.home}/.groovy/lib/*
+    
+    #tools.jar for ant tasks
+    load ${tools.jar}
\ No newline at end of file
diff --git a/groovy-core/src/examples/commandLineTools/AntMap.groovy b/groovy-core/src/examples/commandLineTools/AntMap.groovy
new file mode 100644
index 0000000..f4cc02f
--- /dev/null
+++ b/groovy-core/src/examples/commandLineTools/AntMap.groovy
@@ -0,0 +1,67 @@
+#!/bin/env groovy
+// 
+// convert an ant build file into a format suitable for http://sf.net/projects/freemind
+//
+// by Jeremy Rayner - 2 Dec 2004
+// inspired by Sam Newman ( http://www.magpiebrain.com/archives/2004/12/02/antgui )
+//
+// usage:   groovy AntMap > build.mm
+
+import groovy.util.XmlParser
+
+buildFileName = "build.xml"  // default
+
+// handle command line params
+if (args.length > 0) {
+	buildFileName = args[0]
+}
+
+// header
+println "<map version='0.7.1'>"
+project = new XmlParser().parse(buildFileName)
+name = project['@name']
+println "<node TEXT='${name}'>"
+level = 0
+
+printChildren(project,level)
+
+
+
+def void printChildren(node,level) {
+	level++
+	node.each {
+		name = huntForName(it)
+		if (name != null) {
+			if (level > 1) {
+				println "<node TEXT='${name}' POSITION='right'>"
+			} else if (it.name() == 'property' || it.name() == 'path' ) {
+				if (it.children().size() > 0) {
+					println "<node TEXT='${name}' POSITION='left' FOLDED='true'>"
+				} else {
+					println "<node TEXT='${name}' POSITION='left'>"
+				}
+			} else if (it.children().size() > 0) {
+				println "<node TEXT='${name}' POSITION='right' FOLDED='true'>"
+			} else {
+				println "<node TEXT='${name}' POSITION='right'>"
+			}
+		}
+		if (it.children().size() > 0) printChildren(it,level)
+		if (name!=null)	println "</node>"
+	}
+}
+
+// footer
+println "</node></map>"
+
+
+def String huntForName(node) {
+	preferNodeNames = ["junitreport"]
+	if (node == null) return null
+	if (preferNodeNames.contains(node.name())) return node.name()
+	if (node['@name'] != null) return node['@name']
+	if (node['@todir'] != null) return node['@todir']
+	if (node['@dir'] != null) return node['@dir']
+	if (node['@refid'] != null) return node['@refid']
+	return node.name()
+}
diff --git a/groovy-core/src/examples/commandLineTools/BigTests.groovy b/groovy-core/src/examples/commandLineTools/BigTests.groovy
new file mode 100644
index 0000000..337c943
--- /dev/null
+++ b/groovy-core/src/examples/commandLineTools/BigTests.groovy
@@ -0,0 +1,36 @@
+#!/bin/env groovy
+// 
+// output tests in a junit xml report that took greater than specified time
+//
+// by Jeremy Rayner - 15 Dec 2004
+//
+// usage:   groovy BigTests.groovy <TEST.xml> <time in secs>
+
+import groovy.util.XmlParser
+import java.io.File
+
+fileName = ""  // default
+timeCutOff = new Float("1.0")
+
+if (args.length > 1) {
+	fileName = args[0]
+        timeCutOff = new Float(args[1])
+} else {
+    println "usage: groovy BigTests.groovy <TEST.xml> <time in secs>"
+}
+
+testSuite = new XmlParser().parse(fileName)
+name = testSuite['@name']
+println "TestSuite: ${name}"
+bigTests = [:]
+testSuite.each {
+    if ("testcase" == it.name()) {
+        classname = it['@classname']
+        name = it['@name']
+        time = new Float(it['@time'])
+        if (time > timeCutOff) {
+            println "  ${time} - ${classname}.${name}()"
+        }
+    }
+}
+
diff --git a/groovy-core/src/examples/commandLineTools/ListFiles.groovy b/groovy-core/src/examples/commandLineTools/ListFiles.groovy
new file mode 100644
index 0000000..129a981
--- /dev/null
+++ b/groovy-core/src/examples/commandLineTools/ListFiles.groovy
@@ -0,0 +1,27 @@
+import java.util.Arrays
+
+public class ListFilesManualTest { 
+
+    static void main(args) {
+        println("Called main with ${args}")
+        listFiles(Arrays.asList(args))
+    }
+    
+    static String getPath(file) {
+        return file.absolutePath
+    }
+
+    static void listFiles(dirs) {
+        println("called with ${dirs}")
+        
+        for(dir in dirs) {
+            println("dir: ${dir}")
+            
+	        def files = new java.io.File(dir).listFiles()
+
+    	    for (f in files) {
+        	    println(getPath(f))
+        	} 
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/examples/commandLineTools/Reflections.groovy b/groovy-core/src/examples/commandLineTools/Reflections.groovy
new file mode 100644
index 0000000..fdeeef9
--- /dev/null
+++ b/groovy-core/src/examples/commandLineTools/Reflections.groovy
@@ -0,0 +1,18 @@
+/**
+ * Echoes back whatever is thrown at it (with a <br> at end for browsers) ...
+ * @author <a href="mailto:jeremy.rayner@gmail.com">Jeremy Rayner</a>
+ * 
+ * invoke using
+ *    groovy -l 80 Reflections.groovy
+ * 
+ *       (where 80 is the port to listen for requests upon)
+ */
+
+// echo, echo, echo...
+println "${line} <br>"
+
+//assume no input means we've finished...
+if (line == "") {
+    // clean up gracefully, closing sockets etc
+    return "success"
+}
diff --git a/groovy-core/src/examples/commandLineTools/SimpleWebServer.groovy b/groovy-core/src/examples/commandLineTools/SimpleWebServer.groovy
new file mode 100644
index 0000000..0815108
--- /dev/null
+++ b/groovy-core/src/examples/commandLineTools/SimpleWebServer.groovy
@@ -0,0 +1,74 @@
+/**
+ * Simple web server
+ * @author <a href="mailto:jeremy.rayner@gmail.com">Jeremy Rayner</a>
+ * 
+ * invoke using
+ *    groovy -l 80 SimpleWebServer.groovy
+ * 
+ *       (where 80 is the port to listen for requests upon)
+ */
+import java.io.File
+
+if (init) { 
+    headers = [:] 
+    binaryTypes = ["gif","jpg","png"]          
+    mimeTypes = [
+        "css" : "text/css",         
+        "gif" : "image/gif",
+        "htm" : "text/html",         
+        "html": "text/html",         
+        "jpg" : "image/jpeg",         
+        "png" : "image/png"
+    ]                                 
+}
+
+// parse the request
+if (line.toLowerCase().startsWith("get")) {
+    content = line.tokenize()[1]
+} else {
+    h = line.tokenize(":")
+    headers[h[0]] = h[1]
+}
+
+// all done, now process request
+if (line.size() == 0) {
+    processRequest()
+    return "success"
+}
+
+// ------------------------
+
+def processRequest() {
+    if (content.indexOf("..") < 0) { //simplistic security
+        // simple file browser rooted from current dir
+        f = new File("." + content)
+        if (f.isDirectory()) {
+            printDirectoryListing(f)
+        } else {
+            extension = content.substring(content.lastIndexOf(".") + 1)
+            printHeaders(mimeTypes.get(extension,"text/plain"))          
+                      
+            if (binaryTypes.contains(extension)) {
+                socket.outputStream.write(f.readBytes())
+            } else {
+                println(f.text)
+            }
+        }
+    }
+}
+
+def printDirectoryListing(f) {
+    printHeaders("text/html")          
+    println "<html><head></head><body>"
+    for (i in f.list().toList().sort()) {
+        if ("/" == content) { content = "" } // special case for root document
+        println "<a href='${content}/${i}'>${i}</a><br>"
+    }
+    println "</body></html>"
+}
+
+def printHeaders(mimeType) {
+    println "HTTP/1.0 200 OK"
+    println "Content-Type: ${mimeType}"
+    println ""          
+}
diff --git a/groovy-core/src/examples/console/MortgageCalculator.groovy b/groovy-core/src/examples/console/MortgageCalculator.groovy
new file mode 100644
index 0000000..e0c69c6
--- /dev/null
+++ b/groovy-core/src/examples/console/MortgageCalculator.groovy
@@ -0,0 +1,77 @@
+/** 
+ * Mortgage Calculator
+ * @author: Jeremy Rayner
+ * based on algorithms by Jeff Louie, Dr W Carlini and Newton
+ */
+
+println "__..::~~'''~~::..__"
+println "Mortgage Calculator"
+println "~~~~~~~~~~~~~~~~~~~"
+println "Please input 3 of the 4 values in your mortgage calculation"
+println "This program will then calculate the value you leave blank"
+println ""
+
+def variables = [
+    "Amount of mortgage" : 0.0, 
+    "Annual interest rate (%)" : 0.0, 
+    "Loan duration (months)" : 0.0, 
+    "Monthly payments" : 0.0
+]
+
+for (entry in variables.entrySet()) {
+    print("${entry.key}:")
+    def userInput = System.in.readLine()
+    if ("" == userInput) {
+        valueToCalculate = entry.key
+    } else {
+        entry.value = userInput.toDouble()
+    }
+}
+
+println "$valueToCalculate = ${calculateValueOf(valueToCalculate)}"
+
+
+
+
+
+def calculateValueOf(valueToCalculate) {
+    def result = 0
+    def principal = variables["Amount of mortgage"]
+    def interest = variables["Annual interest rate (%)"] / 1200
+    def months = variables["Loan duration (months)"]
+    def payment = variables["Monthly payments"]
+
+    switch (valueToCalculate) {
+    case "Amount of mortgage":
+        result = 1 + interest
+        result = 1/Math.pow(result,months)
+        result = ((1-result)/interest) * payment
+        break           
+    case "Loan duration (months)":
+        result = (1 - (principal * interest / payment))
+        result = Math.log(result)
+        result = - result / Math.log(1 + interest)  
+        break
+    case "Monthly payments":
+        result = 1 + interest
+        result = 1 / Math.pow(result,months)
+        result = (principal * interest) / (1 - result)
+        break          
+    case "Annual interest rate (%)":
+        result = payment / principal
+        def diff = 100; def accuracy = 0.00001; def maxIterations = 1000
+        def index = 0
+        while ((diff > accuracy) && (index < maxIterations)) {
+            def temp = result
+            def numerator = (principal * temp / payment) + Math.pow((1 + temp), -months) - 1
+            def denominator= (principal / payment) - months * Math.pow((1 + temp), (-months - 1))
+            result = temp - (numerator / denominator)
+            diff = result - temp
+            diff = Math.abs(diff)
+            index++
+        }
+        result *= 1200
+        break           
+    }
+    return result
+}
diff --git a/groovy-core/src/examples/console/knowYourTables.groovy b/groovy-core/src/examples/console/knowYourTables.groovy
new file mode 100644
index 0000000..fbba15b
--- /dev/null
+++ b/groovy-core/src/examples/console/knowYourTables.groovy
@@ -0,0 +1,16 @@
+/** 
+ * Simple mathematics quiz
+ * @author: Jeremy Rayner
+ * based on algorithms from INPUT/Marshall Cavendish/1984
+ */
+while (true) {
+    try {
+        def n = (int)(Math.random() * 12) + 1
+        println "What is $n times 9?"
+        def a = System.in.readLine().toInteger()
+        if (a == n * 9) println "Correct"
+              
+    } catch (Exception e) {
+        println "The computer didn't understand your input"
+    }
+}
diff --git a/groovy-core/src/examples/console/thinkOfANumber.groovy b/groovy-core/src/examples/console/thinkOfANumber.groovy
new file mode 100644
index 0000000..d62c9ec
--- /dev/null
+++ b/groovy-core/src/examples/console/thinkOfANumber.groovy
@@ -0,0 +1,21 @@
+/** 
+ * Simple game
+ * @author: Jeremy Rayner
+ * based on algorithms from INPUT/Marshall Cavendish/1984
+ */
+while (true) {
+    try {
+        int x = Math.random() * 6
+        print "The computer has chosen a number between 0 and 5. Can you guess it?"
+              
+        def line = System.in.readLine()
+        int g = line.toInteger()
+        if (g == x) {
+           println "Well done" 
+        } else {
+           println "Tough luck - you're wrong"
+        }
+     } catch (NumberFormatException e) {
+         println "The computer didn't understand '$line'"
+     }
+}
diff --git a/groovy-core/src/examples/groovy2d/paintingByNumbers.groovy b/groovy-core/src/examples/groovy2d/paintingByNumbers.groovy
new file mode 100644
index 0000000..b050beb
--- /dev/null
+++ b/groovy-core/src/examples/groovy2d/paintingByNumbers.groovy
@@ -0,0 +1,49 @@
+/** 
+ *  simple patchwork graphics demo
+ * @author: Jeremy Rayner, changes by Dierk Koenig
+ */
+
+def width = 500; def height = 400; def blockSize = 10
+def g = createGraphics()
+
+// main loop
+while (true) {
+    drawBlock()
+}
+
+// --------------------------------------------------
+
+// random integer
+def rnd(upperBound){
+    (int)(Math.random() * upperBound)
+}
+
+// draw a random coloured square within bounds
+def drawBlock() {
+    def row    = rnd(height / blockSize)
+    def column = rnd(width  / blockSize)
+    def colour = new java.awt.Color(rnd(255),rnd(255),rnd(255))
+    g.setColor(colour)
+    g.fillRect(column * blockSize, row * blockSize, blockSize, blockSize)
+}
+
+
+// create a new frame and clear screen
+def createGraphics() {
+    def frame = new groovy.swing.SwingBuilder().
+              frame(title:'Painting by numbers', 
+                    location:[20,20], 
+                    size:[width,height],
+                    defaultCloseOperation:javax.swing.WindowConstants.EXIT_ON_CLOSE) {
+    }
+    frame.show()
+              
+    // obtain graphics context
+    def gfx = frame.getGraphics()
+              
+    // clear screen
+    gfx.setColor(java.awt.Color.BLACK)
+    gfx.fillRect(0,0,width,height)
+
+    return gfx
+}
diff --git a/groovy-core/src/examples/searchEngine/Indexer.groovy b/groovy-core/src/examples/searchEngine/Indexer.groovy
new file mode 100644
index 0000000..5212094
--- /dev/null
+++ b/groovy-core/src/examples/searchEngine/Indexer.groovy
@@ -0,0 +1,61 @@
+import org.apache.lucene.analysis.standard.StandardAnalyzer
+import org.apache.lucene.document.Document
+import org.apache.lucene.document.Field
+import org.apache.lucene.index.IndexWriter
+
+/**
+ * Indexer: traverses a file system and indexes .txt files
+ *
+ * @author Jeremy Rayner <groovy@ross-rayner.com>
+ * based on examples in the wonderful 'Lucene in Action' book
+ * by Erik Hatcher and Otis Gospodnetic ( http://www.lucenebook.com )
+ *
+ * requires a lucene-1.x.x.jar from http://lucene.apache.org
+ */
+
+if (args.size() != 2 ) {
+    throw new Exception("Usage: groovy -cp lucene-1.4.3.jar Indexer <index dir> <data dir>")
+}
+def indexDir = new File(args[0]) // Create Lucene index in this directory
+def dataDir = new File(args[1]) // Index files in this directory
+
+def start = new Date().time
+def numIndexed = index(indexDir, dataDir)
+def end = new Date().time
+
+println "Indexing $numIndexed files took ${end - start} milliseconds"
+
+
+
+def index(indexDir, dataDir) {
+    if (!dataDir.exists() || !dataDir.directory) {
+        throw new IOException("$dataDir does not exist or is not a directory")
+    }
+    def writer = new IndexWriter(indexDir, new StandardAnalyzer(), true) // Create Lucene index
+    writer.useCompoundFile = false
+
+    dataDir.eachFileRecurse {
+        if (it.name =~ /.txt$/) { // Index .txt files only
+            indexFile(writer,it)
+        }
+    }
+    def numIndexed = writer.docCount()
+    writer.optimize()
+    writer.close() // Close index
+    return numIndexed
+}
+
+void indexFile(writer, f) {
+    if (f.hidden || !f.exists() || !f.canRead() || f.directory) { return }
+
+    println "Indexing $f.canonicalPath"
+    def doc = new Document()
+
+    // Construct a Field that is tokenized and indexed, but is not stored in the index verbatim.
+    doc.add(Field.Text("contents", new FileReader(f)))
+
+    // Construct a Field that is not tokenized, but is indexed and stored.
+    doc.add(Field.Keyword("filename",f.canonicalPath))
+
+    writer.addDocument(doc) // Add document to Lucene index
+}
\ No newline at end of file
diff --git a/groovy-core/src/examples/searchEngine/Searcher.groovy b/groovy-core/src/examples/searchEngine/Searcher.groovy
new file mode 100644
index 0000000..61f6a82
--- /dev/null
+++ b/groovy-core/src/examples/searchEngine/Searcher.groovy
@@ -0,0 +1,38 @@
+import org.apache.lucene.analysis.standard.StandardAnalyzer
+import org.apache.lucene.queryParser.QueryParser
+import org.apache.lucene.search.IndexSearcher
+import org.apache.lucene.store.FSDirectory
+
+/**
+ * Searcher: searches a Lucene index for a query passed as an argument
+ *
+ * @author Jeremy Rayner <groovy@ross-rayner.com>
+ * based on examples in the wonderful 'Lucene in Action' book
+ * by Erik Hatcher and Otis Gospodnetic ( http://www.lucenebook.com )
+ *
+ * requires a lucene-1.x.x.jar from http://lucene.apache.org
+ */
+
+if (args.size() != 2) {
+    throw new Exception("Usage: groovy -cp lucene-1.4.3.jar Searcher <index dir> <query>")
+}
+def indexDir = new File(args[0]) // Index directory create by Indexer
+def q = args[1] // Query string
+
+if (!indexDir.exists() || !indexDir.directory) {
+    throw new Exception("$indexDir does not exist or is not a directory")
+}
+
+def fsDir = FSDirectory.getDirectory(indexDir, false)
+def is = new IndexSearcher(fsDir) // Open index
+
+def query = QueryParser.parse(q, "contents", new StandardAnalyzer()) // Parse query
+def start = new Date().time
+def hits = is.search(query) // Search index
+def end = new Date().time
+
+println "Found ${hits.length()} document(s) (in ${end - start} milliseconds) that matched query '$q':"
+
+for ( i in 0 ..< hits.length() ) {
+    println(hits.doc(i)["filename"]) // Retrieve matching document and display filename
+}
diff --git a/groovy-core/src/examples/swing/BloglinesClient.groovy b/groovy-core/src/examples/swing/BloglinesClient.groovy
new file mode 100644
index 0000000..c0656a9
--- /dev/null
+++ b/groovy-core/src/examples/swing/BloglinesClient.groovy
@@ -0,0 +1,167 @@
+/*
+ * BloglinesClient.groovy - an example of the Bloglines Web Services
+ *
+ * Written by Marc Hedlund <marc@precipice.org>, September 2004.
+ * 
+ * Mangled by John Wilson September 2004
+ *
+ * Small adaptions to JSR Version by Dierk Koenig, June 2005
+ *
+ * Used in Marc's article at:
+ *    http://www.oreillynet.com/pub/a/network/2004/09/28/bloglines.html
+ *
+ * Requirements:
+ *   - install Groovy as detailed at <http://groovy.codehaus.org/>.
+ *   - put commons-httpclient-3.0-rc3.jar into GROOVY_HOME/lib
+ *       see <http://jakarta.apache.org/commons/httpclient/>.
+ *       note: this is currently designed for HttpClient2.x and not HttpClient3.x
+ *
+ * To Launch:
+ *   groovy BloglinesClient.groovy
+ *
+ * This work is licensed under the Creative Commons Attribution
+ * License. To view a copy of this license, visit
+ * <http://creativecommons.org/licenses/by/2.0/> or send a letter to
+ * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ */
+
+import groovy.swing.SwingBuilder
+import java.awt.BorderLayout
+import java.net.URL
+import javax.swing.BorderFactory
+import javax.swing.JOptionPane
+import javax.swing.JSplitPane
+import javax.swing.JTree
+import javax.swing.ListSelectionModel
+import javax.swing.SwingUtilities
+import javax.swing.WindowConstants
+import javax.swing.tree.DefaultMutableTreeNode
+import javax.swing.tree.TreeSelectionModel
+import org.apache.commons.httpclient.HttpClient
+import org.apache.commons.httpclient.UsernamePasswordCredentials
+import org.apache.commons.httpclient.methods.GetMethod
+
+//Set up global variables and data types
+server = 'rpc.bloglines.com'
+
+class Feed { def name; def id; def unread; String toString() { (unread == "0" ? name : "${name} (${unread})") } }
+
+class Item { def title; def description; String toString() { title } }
+
+//Ask the user for account information (using simple dialogs)
+email = 
+JOptionPane.showInputDialog(null, "Email address:", "Log in to Bloglines", 
+			      JOptionPane.QUESTION_MESSAGE)
+password = 
+JOptionPane.showInputDialog(null, "Password:", "Log in to Bloglines", 
+			      JOptionPane.QUESTION_MESSAGE)
+
+//Use HTTPClient for web requests since the server requires authentication
+client = new HttpClient()
+credentials = new UsernamePasswordCredentials(email, password)
+client.state.setCredentials("Bloglines RPC", server, credentials)
+
+abstractCallBloglines = { method, parameters ->
+  url = "http://${server}/${method}${parameters}"
+  try {
+    get = new GetMethod(url)
+    get.doAuthentication = true
+    client.executeMethod(get)
+    return get.responseBodyAsStream
+  } catch (Exception e) {
+    println "Error retrieving <${url}>: ${e}"
+  }
+}
+
+callBloglinesListsub = abstractCallBloglines.curry('listsubs', '')
+callBloglinesGetItems = abstractCallBloglines.curry('getitems')
+
+//Get the list of subscriptions and parse it into a GPath structure
+opml = new XmlSlurper().parse(callBloglinesListsub())
+
+//Descend into the subscription outline, adding to the feed tree as we go
+treeTop = new DefaultMutableTreeNode("My Feeds")
+parseOutline(opml.body.outline.outline, treeTop)
+
+def parseOutline(parsedXml, treeLevel) {
+  parsedXml.each{ outline ->
+    if (outline['@xmlUrl'] != null) {  // this is an individual feed
+      feed = new Feed(name:outline['@title'], id:outline['@BloglinesSubId'], 
+                      unread:outline['@BloglinesUnread'])
+      treeLevel.add(new DefaultMutableTreeNode(feed))
+    } else {  // this is a folder of feeds
+      folder = new DefaultMutableTreeNode(outline['@title'])
+      parseOutline(outline.outline, folder)
+      treeLevel.add(folder)
+    }
+  }
+}
+
+//Build the base user interface objects and configure them
+swing = new SwingBuilder()
+feedTree = new JTree(treeTop)
+itemList = swing.list()
+itemText = swing.textPane(contentType:'text/html', editable:false)
+model = feedTree.selectionModel
+model.selectionMode = TreeSelectionModel.SINGLE_TREE_SELECTION
+itemList.selectionMode = ListSelectionModel.SINGLE_SELECTION
+
+//Set up the action closures that will react to user selections
+listItems = { feed ->
+  rssStream = callBloglinesGetItems("?s=${feed.id}&n=0")  
+  if (rssStream != null) {
+    try {
+      rss = new XmlSlurper().parse(rssStream)
+      itemList.listData =  rss.channel.item.collect(new Vector()) {
+		new Item(title:it.title, description:it.description)
+       }
+       feed.unread = "0"  // update the unread item count in the feed list
+     } catch (Exception e) {
+       println "Error during <${feed.name}> RSS parse: ${e}"
+    }
+  }
+}
+
+feedTree.valueChanged = { event ->
+  itemText.text = ""  // clear any old item text
+  node = (DefaultMutableTreeNode) feedTree.getLastSelectedPathComponent()
+  if (node != null) {
+    feed = node.userObject
+     if (feed instanceof Feed && feed.unread != "0") {
+       listItems(feed)
+     }
+  }
+}
+
+itemList.valueChanged = { event ->
+  item = event.source.selectedValue
+  if (item instanceof Item && item?.description != null) {
+    itemText.text = "<html><body>${item.description}</body></html>"
+  }
+}
+
+//Put the user interface together and display it
+gui = 
+swing.frame(title:'Bloglines Client', location:[100,100], size:[800,600], 
+	      defaultCloseOperation:WindowConstants.EXIT_ON_CLOSE) {
+
+ panel(layout:new BorderLayout()) {
+   splitPane(orientation:JSplitPane.HORIZONTAL_SPLIT, dividerLocation:200) {
+     scrollPane {
+		  widget(feedTree)
+	 }
+
+      splitPane(orientation:JSplitPane.VERTICAL_SPLIT, dividerLocation:150) {
+        scrollPane(constraints:BorderLayout.CENTER) {
+	        widget(itemList)
+	    }
+
+	    scrollPane(constraints:BorderLayout.CENTER) {
+	      widget(itemText)
+	    }
+      }
+    }
+  }
+}
+
+gui.show()
diff --git a/groovy-core/src/examples/swing/Widgets.groovy b/groovy-core/src/examples/swing/Widgets.groovy
new file mode 100644
index 0000000..7a81676
--- /dev/null
+++ b/groovy-core/src/examples/swing/Widgets.groovy
@@ -0,0 +1,205 @@
+package groovy.swing
+
+import java.awt.BorderLayout
+import java.awt.Color
+import java.awt.GridBagConstraints
+import javax.swing.BorderFactory
+import javax.swing.SwingConstants
+import javax.swing.WindowConstants
+import groovy.model.MvcDemo
+
+class Widgets {
+
+    def swing = new SwingBuilder()
+    def unownedDialog
+    def ownedDialog
+    
+
+    static void main(args) {
+        def demo = new Widgets()
+        demo.run()
+    }
+
+    def showUnownedDialog(event) {
+        unownedDialog.show();
+    }
+    
+    def showOwnedDialog(event) {
+        ownedDialog.show();
+    }
+
+    void run() {
+        unownedDialog = swing.dialog(
+            title:'unrooted dialog',
+            location: [200, 200],
+            size: [100, 100],
+            defaultCloseOperation:WindowConstants.DISPOSE_ON_CLOSE
+            ) {
+                label("I am unowned, but not unwanted");
+            }
+
+        def frame = swing.frame(
+            title:'FrameTitle',
+            location:[100,100],
+            size:[800,400],
+            defaultCloseOperation:WindowConstants.EXIT_ON_CLOSE) {
+
+            menuBar {
+                menu(text:'File') {
+                    menuItem() {
+                        action(name:'New', closure:{ println("clicked on the new menu item!") })
+                    }
+                    menuItem() {
+                        action(name:'Open', closure:{ println("clicked on the open menu item!") })
+                    }
+                    separator()
+                    menuItem() {
+                        action(name:'Save', enabled:false, closure:{ println("clicked on the Save menu item!") })
+                    }
+                }
+                menu(text:'Dialogs') {
+                    menuItem() {
+                        action(name:'Owned Dialog', closure: this.&showOwnedDialog)
+                    }
+                    menuItem() {
+                        action(name:'Unowned Dialog', closure: this.&showUnownedDialog)
+                    }
+                    def deeplyOwnedDialog = swing.dialog(
+                        title:'rooted dialog #2',
+                        location: [200, 200],
+                        size: [100, 100],
+                        defaultCloseOperation:WindowConstants.DISPOSE_ON_CLOSE
+                        ) {
+                        label("ownership is deep");
+                    }
+                    menuItem() {
+                        action(name:'Deeply Owned Dialog', closure: {deeplyOwnedDialog.show()} )
+                    }
+                }
+            }
+
+            tabbedPane() {
+
+                //colorChooser(
+                //    name:"Color Chooser",
+                //    color: 0xfeed42)
+
+                panel(name:"Formatted Text Fields") {
+                    gridLayout(columns: 2, rows: 0)
+                    label("Simple Constructor:")
+                    formattedTextField()
+                    label("Date Value")
+                    formattedTextField(value: new java.util.Date())
+                    label("Integer Value")
+                    formattedTextField(value: new java.lang.Integer(42))
+                    label("Date Format")
+                    formattedTextField(format: java.text.DateFormat.getDateInstance())
+                    label("Currency Format ")
+                    formattedTextField(format: new java.text.DecimalFormat("¤###.00;(¤###.00)"))
+                }
+
+                panel(name:"Sliders") {
+                    flowLayout()
+                    slider(minimum:-100, 
+                        maximum:100, 
+                        majorTickSpacing: 50,
+                        orientation: SwingConstants.VERTICAL, 
+                        paintLabels:true)
+                    slider(minimum:-100, 
+                        maximum:100, 
+                        orientation: SwingConstants.VERTICAL, 
+                        paintLabels:true,
+                        paintTicks:true,
+                        majorTickSpacing: 50,
+                        minorTickSpacing: 10,
+                        snapToTicks:true,
+                        paintTrack:true)
+                }
+
+                panel(name:"Spinners") {
+                    gridBagLayout()
+                    label(
+                        text:"Tempuature in London:",
+                        constraints: gbc(insets:[12, 12, 2, 2], 
+                            anchor: GridBagConstraints.EAST,
+                            gridx: 0))
+                    spinner(
+                        model:spinnerNumberModel(minimum:-10, 
+                            maximum: 40, 
+                            value:20,
+                            stepSize:5),
+                        constraints: gbc(insets:[12, 3, 2, 12], 
+                            anchor: GridBagConstraints.WEST,
+                            gridx: 1,
+                            fill: GridBagConstraints.HORIZONTAL))
+                    label(
+                        text:"Baseball Leagues:",
+                        constraints: gbc(insets:[3, 12, 2, 2], 
+                            anchor: GridBagConstraints.EAST,
+                            gridx: 0))
+                    spinner(
+                        model:spinnerListModel(
+                            list: ["Major League", "AAA", "AA", "A", "Rookie", "Semi-Pro", "Rec A", "Rec B"],
+                            value: "AA"),
+                        constraints: gbc(insets:[3, 3, 2, 12], 
+                            anchor: GridBagConstraints.WEST,
+                            gridx: 1,
+                            fill: GridBagConstraints.HORIZONTAL))
+                    label(
+                        text:"Today's Date:",
+                        constraints: gbc(insets:[3, 12, 2, 2], 
+                            anchor: GridBagConstraints.EAST,
+                            gridx: 0))
+                    spinner(
+                        model:spinnerDateModel(calendarField: Calendar.HOUR_OF_DAY),
+                        constraints: gbc(insets:[3, 3, 2, 12], 
+                            anchor: GridBagConstraints.WEST,
+                            gridx: 1,
+                            fill: GridBagConstraints.HORIZONTAL))
+                }
+
+                panel(name:"Border Layout") {
+                    borderLayout()
+                    label(text:"Border Layout", 
+                          constraints:BorderLayout.NORTH, 
+                          horizontalAlignment:SwingConstants.CENTER)
+                    label(text:"South", 
+                          constraints:BorderLayout.SOUTH, 
+                          background:Color.YELLOW,
+                          opaque:true,
+                          horizontalAlignment:SwingConstants.CENTER,
+                          toolTipText:"Tooltip on south")
+                    label(text:"West", 
+                          constraints:BorderLayout.WEST, 
+                          background:Color.ORANGE,
+                          opaque:true,
+                          horizontalAlignment:SwingConstants.CENTER,
+                          toolTipText:"Tooltip on west")
+                    label(text:"East", 
+                          constraints:BorderLayout.EAST, 
+                          background:Color.GREEN,
+                          opaque:true,
+                          horizontalAlignment:SwingConstants.CENTER,
+                          toolTipText:"Tooltip on east")
+                    label(text:"Center", 
+                          constraints:BorderLayout.CENTER, 
+                          background:Color.WHITE,
+                          opaque:true,
+                          horizontalAlignment:SwingConstants.CENTER,
+                          toolTipText:"<html>This is not the tooltip you are looking for.<br><i>*waves hand*</i>")
+                }
+            }
+
+            ownedDialog = swing.dialog(
+                title:'rooted dialog',
+                location: [200, 200],
+                size: [100, 100],
+                defaultCloseOperation:WindowConstants.DISPOSE_ON_CLOSE
+                ) {
+                label("j00 h4v3 b33n 0wn3xed");
+            }
+        }        
+        frame.show()
+    }
+    
+}
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/groovy/Animal.groovy b/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/groovy/Animal.groovy
new file mode 100644
index 0000000..3cdaa17
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/groovy/Animal.groovy
@@ -0,0 +1,5 @@
+interface Animal {
+
+  String saySomething(String something);
+
+}
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/Fish.groovy b/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/Fish.groovy
new file mode 100644
index 0000000..494d5a8
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/Fish.groovy
@@ -0,0 +1,9 @@
+package zoo
+
+abstract class Fish implements Animal {
+
+  String saySomething(String something) {
+    return "Blubb°: " + something + "..."
+  }
+
+}
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/fish/Shark.groovy b/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/fish/Shark.groovy
new file mode 100644
index 0000000..afdf10c
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/fish/Shark.groovy
@@ -0,0 +1,11 @@
+package zoo.fish
+
+import zoo.Fish
+
+class Shark extends Fish {
+
+  String saySomething(String something) {
+    return "Shark bites " + something + "...ROOOAR°!"
+  }
+
+}
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/fish/Trout.groovy b/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/fish/Trout.groovy
new file mode 100644
index 0000000..faa8f03
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/fish/Trout.groovy
@@ -0,0 +1,9 @@
+package zoo.fish
+
+class Trout extends zoo.Fish {
+
+  String saySomething(String something) {
+    return "Trout says " + something + "...blubb°!"
+  }
+
+}
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/lib/.cvsignore b/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/lib/.cvsignore
new file mode 100644
index 0000000..d392f0e
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/lib/.cvsignore
@@ -0,0 +1 @@
+*.jar
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/web.xml b/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/web.xml
new file mode 100644
index 0000000..118626a
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/WEB-INF/web.xml
@@ -0,0 +1,69 @@
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_3.xsd"
+    version="2.3">
+
+  <servlet>
+    <servlet-name>Groovlet</servlet-name>
+    <servlet-class>groovy.servlet.GroovyServlet</servlet-class>
+    <init-param>
+      <param-name>verbose</param-name>
+      <param-value>true</param-value>
+    </init-param>
+    <init-param>
+      <param-name>resource.name.regex</param-name>
+      <param-value>none</param-value>
+    </init-param>
+    <init-param>
+      <param-name>resource.name.replacement</param-name>
+      <param-value>none</param-value>
+    </init-param>
+  </servlet>
+    
+  <servlet>
+    <servlet-name>Template|GSP</servlet-name>
+    <servlet-class>groovy.servlet.TemplateServlet</servlet-class>
+  </servlet>
+  
+  <servlet>
+    <servlet-name>Template|GString</servlet-name>
+    <servlet-class>groovy.servlet.TemplateServlet</servlet-class>
+    <init-param>
+      <param-name>template.engine</param-name>
+      <param-value>groovy.text.GStringTemplateEngine</param-value>
+    </init-param>
+  </servlet>
+  
+  <servlet>
+    <servlet-name>Template|XML</servlet-name>
+    <servlet-class>groovy.servlet.TemplateServlet</servlet-class>
+    <init-param>
+      <param-name>template.engine</param-name>
+      <param-value>groovy.text.XmlTemplateEngine</param-value>
+    </init-param>
+  </servlet>
+  
+  <servlet-mapping>
+    <servlet-name>Template|GSP</servlet-name>
+    <url-pattern>*.html</url-pattern>
+  </servlet-mapping>
+  
+  <servlet-mapping>
+    <servlet-name>Template|XML</servlet-name>
+    <url-pattern>*.xhtml</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>Groovlet</servlet-name>
+    <url-pattern>*.groovy</url-pattern>
+  </servlet-mapping>
+
+  <welcome-file-list>
+    <welcome-file>index.xhtml</welcome-file>
+    <welcome-file>index.html</welcome-file>
+    <welcome-file>index.jsp</welcome-file>
+    <welcome-file>index.jspx</welcome-file>
+    <welcome-file>index.groovy</welcome-file>
+  </welcome-file-list>
+
+</web-app>
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/codehaus-style.css b/groovy-core/src/examples/webapps/groovlet-examples/codehaus-style.css
new file mode 100644
index 0000000..a5cf0dd
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/codehaus-style.css
@@ -0,0 +1,609 @@
+
+body {
+  font-family: Verdana, Helvetica, Arial, sans-serif;
+  font-size: small;
+  margin: 0;
+}
+
+div {
+  /* line-height: 1.5em; */
+}
+
+a {
+  color: #008800;
+  text-decoration: none;
+  font-weight: bold;
+}
+
+.navLink a {
+  font-weight: normal;
+}
+
+.navLink {
+  margin-left: 5px;
+}
+
+.navLink:first-line {
+  margin-left: -5px;
+}
+
+
+a:link.selfref, a:visited.selfref {
+}
+
+a:link, a:visited {
+}
+
+a:active, a:hover {
+  text-decoration: underline;
+}
+
+a.plain:active, a.plain:hover {
+  text-decoration: none;
+}
+
+.sectionTitle a {
+  text-decoration: underline;
+}
+.subsectionTitle a {
+  text-decoration: underline;
+}
+
+span.highlight {
+  font-weight: bold;
+  color: #990000;
+}
+
+#layout {
+  margin: 0px;
+  padding: 0px;
+}
+
+#banner {
+  padding: 8px;
+}
+
+#breadcrumbs {
+  border-top: 1px solid #009900;
+  border-bottom: 1px solid #009900;
+  padding-left: 12px;
+  padding-right: 12px;
+  padding-top: 2px;
+  padding-bottom: 2px;
+  font-size: x-small;
+  background-color: #dddddd;
+}
+
+#breadcrumbs td {
+  font-size: x-small;
+}
+
+#breadcrumbs a {
+  font-weight: bold;
+}
+
+#layout {
+  /*border-top: 1px solid #009900;*/
+  padding: 0px;
+  margin: 0px;
+
+}
+
+.navSection {
+  background-color: #ffffff;
+  border: 1px solid #999999;
+  border-top: none;
+  padding: 0px;
+  margin-bottom: 8px;
+  font-size: small;
+}
+
+.navSection a {
+  font-weight: normal;
+}
+
+.navSectionHead {
+  border-top: 1px solid #999999;
+  border-bottom: 1px solid #999999;
+  color: #555555;
+  padding: 4px;
+  margin-left: 0px;
+  margin-right: 0px;
+  background-color: #eeeeee;
+  font-weight: bold;
+  font-size: x-small;
+}
+
+.navLink {
+  padding-top: 2px;
+  padding-bottom: 2px;
+  padding-left: 14px;
+  font-size: small;
+}
+
+.section {
+  padding-bottom: 16px;
+}
+
+* + h1 {
+  margin-top: 1.5em;
+}
+
+* + h2 {
+  margin-top: 1.5em;
+}
+
+.sectionTitle, h1 {
+  padding: 4px;
+  border: 1px solid #aaaaaa;
+  color: #007700;
+  font-size: larger;
+  background-color: #eee;
+  color: #007700;
+  font-weight: bold;
+  margin-bottom: .5em;
+  /* margin-top: 1em; */
+}
+
+.subsection {
+  padding-left: 20px;
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+
+body:first-child {
+  padding-top: 0px;
+}
+
+.subsectionTitle, h2 {
+  padding-left: .2em;
+  /* margin-top: 1em; */
+  margin-bottom: .5em;
+  border-bottom: 1px solid #999;
+  border-left: 1px solid #999;
+  background-color: white;
+  font-weight: bold;
+  font-size: larger;
+}
+
+.sectionTitle a {
+  font-weight: normal;
+}
+
+.subsectionTitle a {
+  font-weight: normal;
+}
+
+.subsubsection {
+  padding-left: 30px;
+}
+
+.subsubsectionTitle, h3, .blogheading {
+  font-weight: bold;
+  border-bottom: 1px solid #bbb;
+  padding: .1em;
+  color: #555;
+  margin-bottom: .5em;
+}
+
+h4 {
+  margin-bottom: .5em;
+  padding: .1em;
+  border: 1px solid #ddd;
+
+}
+
+ins.inserted {
+  text-decoration: none;
+  font-weight: bold;
+}
+
+#leftColumn {
+  width: 12em;
+}
+
+#leftColumn h3 {
+  background-color: #ddd;
+  border: 1px solid #ccc;
+  border-bottom: 1px solid #070;
+  margin-bottom: .5em;
+}
+
+#leftColumn a {
+  font-weight: inherit;
+}
+
+#breadcrumbs a {
+  font-weight: inherit;
+}
+
+
+p {
+  margin: 0px;
+  margin-bottom: .5em;
+  line-height: 1.2em;
+  padding-right: 20px;
+  padding-left: 0px;
+}
+
+blockquote p {
+  padding-left: 0px;
+  padding-right: 0px;
+}
+
+ul {
+  margin-top: 1em;
+  margin-bottom: 1em;
+  padding-left: 1.5em;
+}
+
+ul ul {
+  margin: 0px;
+  padding-left: 1em;
+}
+
+li {
+  margin: 0px;
+  margin-right: 15%;
+  line-height: 1.2em;
+}
+
+#leftColumn {
+  border-right: 1px solid #cccccc;
+  background-color: #eeeeee;
+  padding: 12px;
+  font-size: small;
+}
+
+#leftColumn a {
+  font-size: smaller;
+}
+
+#leftColumn tt a {
+  font-size: inherit;
+}
+
+#leftColumn h3 a {
+  font-size: inherit;
+}
+
+tt {
+  font-size: larger;
+}
+
+
+#extraColumn {
+  padding: 12px;
+}
+
+#navBox {
+}
+
+#rightColumn {
+  padding: 12px;
+  border-right: 1px solid #cccccc;
+  font-size: small;
+  padding-left: 16px;
+  padding-right: 16px;
+}
+
+#contentBox {
+
+}
+
+table.bodyTable, table.wikitable {
+  margin: 10px;
+  border-collapse: collapse;
+  border-spacing: 0pt;
+  background-color: #eeeeee;
+}
+
+#Content table.grid {
+  border: 1px solid #bbbbbb;
+}
+
+table.grid {
+  padding: 0px;
+  border-collapse: collapse;
+  border-spacing: 0pt;
+  margin-left: 1em;
+  margin-right: 1em;
+}
+
+table.grid th {
+  background-color: #eeeeee;
+  font-size: smaller;
+  padding: 4px;
+  border: 1px solid #bbbbbb;
+}
+
+table.grid td {
+  font-size: x-small;
+  border: 1px solid #bbbbbb;
+  padding: 3px;
+}
+
+table.bodyTable th, table.bodyTable td, table.wikitable th, table.wikitable td {
+  border: 1px solid #999999;
+  font-size: smaller;
+  padding: 4px;
+}
+
+
+table.bodyTable th, table.wikitable th {
+  text-align: left;
+  background-color: #dddddd;
+  border: 2px solid #999999;
+  padding: 4px;
+}
+
+.nobr
+  white-space: nowrap;
+}
+
+table.bodyTable td {
+  padding: 4px;
+}
+
+/*
+table.bodyTable th, table.wikitable th {
+  border-bottom: 2px solid #999999;
+}
+
+table.bodyTable tr.a {
+  background-color: #dedede;
+}
+
+table.bodyTable tr.b {
+  background-color: #efefef;
+}
+*/
+
+.source, .code {
+  padding: 12px;
+  margin: 1em;
+  border: 1px solid #007700;
+  border-left: 2px solid #007700;
+  border-right: 2px solid #007700;
+  color: #555555;
+}
+
+pre {
+  padding: 12px;
+  font-size: larger;
+}
+
+.java-keyword {
+  color: #009900;
+}
+
+.java-object {
+  color: #000099;
+}
+
+.java-quote {
+  color: #990000;
+}
+
+
+.source, .code pre {
+  margin: 0px;
+  margin-left: 8px;
+  padding: 0px;
+}
+
+#footer {
+  padding-left: 4px;
+  border-top: 1px solid #009900;
+  color: #888888;
+  font-size: x-small;
+}
+
+blockquote {
+  border-top: 1px solid #bbbbbb;
+  border-bottom: 1px solid #bbbbbb;
+  border-left: 3px solid #bbbbbb;
+  border-right: 3px solid #bbbbbb;
+  padding: 12px;
+  margin-left: 3em;
+  margin-right: 3em;
+  color: #666666;
+  background-color: white;
+  line-height: 1.5em;
+}
+
+input[type="text"] {
+  margin: 0px;
+  border: 1px solid #999999;
+  background-color: #dddddd;
+}
+
+input.required {
+  margin: 0px;
+  border: 1px solid #990000;
+}
+
+input {
+  border: 1px solid #999999;
+}
+
+textarea {
+  border: 1px solid #999999;
+}
+
+textarea.required {
+  border: 1px solid #990000;
+}
+
+label {
+  font-size: smaller;
+}
+
+label.required {
+  color: #990000;
+}
+
+.searchResults {
+  color: black;
+}
+
+.searchResults b {
+  color: #007700;
+}
+
+
+.linecomment { color: #bbbbbbb; }
+.blockcomment { color: #bbbbbbb; }
+.prepro { color: #0000BB; }
+.select {}
+.quote { color: #770000; }
+.category1 { color: #007700; }
+.category2 { color: #0000BB; }
+.category3 { color: #0000BB; }
+
+#page_title {
+  border-bottom: 1px solid black;
+  font-weight: bold;
+  font-size: x-large;
+  margin-bottom: .5em;
+}
+
+.greenbar {
+  background-color: green;
+}
+
+.redbar {
+  background-color: red;
+}
+
+tr.testpassed td {
+  padding: 0px;
+  padding-left: 1px;
+  padding-right: 1px;
+  margin: 0px;
+}
+
+tr td.noformatting {
+  border: none;
+  padding: 0px;
+  padding-left: 4px;
+  padding-right: 4px;
+  margin: 0px;
+}
+
+.greybox {
+  font-style: italic;
+  font-weight: bold;
+  margin-top: .5em;
+  margin-bottom: .5em;
+  background-color: #ddd;
+  border: 1px solid #bbb;
+  padding: .3em;
+}
+
+.panelContent {
+  border: 1px solid #999;
+  padding: 1em;
+  margin: 1em;
+}
+
+.header_name {
+	font-size: smaller;
+	padding: 2px;
+	padding-right: 1ex;
+	border-right: 1px solid #555;
+	background-color: #ccc;
+}
+
+.header_value {
+	font-size: smaller;
+	background-color: #ddd;
+	padding: 2px;
+}
+
+.header_fields {
+	width: 100%;
+	border: 1px solid #999;
+	background-color: #fff;
+}
+
+.email_body {
+	margin: 2ex;
+	padding: 1ex;
+	padding-left: 2ex;
+	padding-right: 2ex;
+	border: 1px solid #999;
+	font-size: smaller;
+}
+
+.email_body pre {
+	padding: 0px;
+	margin: 0px;
+}
+
+.email_body blockquote {
+	padding: 0px;
+	margin: 0px;
+	border: 1px solid #ccc;
+}
+
+.msg_navblock {
+	margin-bottom: 2ex;
+	border: 1px solid #999;
+	background-color: #fff;
+}
+
+.msg_navblock th {
+	border: 1px solid #ccc;
+	font-size: smaller;
+}
+
+.msg_navblock td {
+	border: 1px solid #ccc;
+	font-size: smaller;
+}
+
+.single_entry {
+	border: 1px solid #aaa;
+	padding: .5ex;
+	padding-left: 1ex;
+	border-left: 1px solid #090;
+	margin: 2px;
+	background-color: #eee;
+}
+
+.root_entry {
+	border: 1px solid #aaa;
+	padding: .5ex;
+	padding-left: 1ex;
+	border-left: 1px solid #090;
+	margin-top: 8px;
+	margin-bottom: 8px;
+	background-color: #eee;
+}
+
+.root_entry .sub_entry {
+	padding: .5ex;
+	padding-left: 1ex;
+	margin: 2px;
+	margin-left: 1ex;
+	border-left: 1px solid #999;
+}
+
+.list_entry {
+	border: 1px solid #aaa;
+	padding: 1ex;
+	margin-top: 1ex;
+	margin-bottom: 1ex;
+}
+
+.list_entry td {
+	border: 1px solid #999;
+}
+
+.project_entry {
+	border: 1px solid #aaa;
+	padding: 1ex;
+	margin-top: 1ex;
+	margin-bottom: 1ex;
+}
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/hello/hello.groovy b/groovy-core/src/examples/webapps/groovlet-examples/hello/hello.groovy
new file mode 100644
index 0000000..74e97cd
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/hello/hello.groovy
@@ -0,0 +1,33 @@
+println """
+<html>
+    <head>
+        <title>Groovy Servlet Example - hello</title>
+    </head>
+    <body>
+    <a href="../"><img src="../images/return.gif" width="24" height="24" border="0"></a><a href="../">Return</a>
+    <p>
+"""
+
+session = request.getSession(true);
+
+if (session.counter == null) {
+  session.counter = 1
+}
+
+
+println """Hello, ${request.remoteHost}! ${new java.util.Date()}"""
+
+println """
+<dl>
+ <dt><b>requestURI</b></dt><dd>${request.requestURI}</dd>
+ <dt><b>servletPath</b></dt><dd>${request.servletPath}</dd>
+ <dt><b>session.counter</b></dt><dd>${session.counter}</dd>
+</dl>
+"""
+
+println """
+    </body>
+</html>
+"""
+
+session.counter = session.counter + 1
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/images/code.gif b/groovy-core/src/examples/webapps/groovlet-examples/images/code.gif
new file mode 100644
index 0000000..93af2cd
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/images/code.gif
Binary files differ
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/images/execute.gif b/groovy-core/src/examples/webapps/groovlet-examples/images/execute.gif
new file mode 100644
index 0000000..f64d70f
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/images/execute.gif
Binary files differ
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/images/groovy.png b/groovy-core/src/examples/webapps/groovlet-examples/images/groovy.png
new file mode 100644
index 0000000..54af4c1
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/images/groovy.png
Binary files differ
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/images/return.gif b/groovy-core/src/examples/webapps/groovlet-examples/images/return.gif
new file mode 100644
index 0000000..af4f68f
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/images/return.gif
Binary files differ
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/index.groovy b/groovy-core/src/examples/webapps/groovlet-examples/index.groovy
new file mode 100644
index 0000000..534201b
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/index.groovy
@@ -0,0 +1,89 @@
+println """
+
+<!-- Groovy Groovlet Examples. -->
+
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta name="Author" content="Groovy Developers">
+   <title>Groovy - Groovlet Examples</title>
+   <link rel="stylesheet" href="codehaus-style.css" type="text/css">
+</head>
+
+<body bgcolor="#FFFFFF">
+
+<a href="http://groovy.codehaus.org"><img src="images/groovy.png" border="0"></a>
+
+<h1>Groovlet examples showing GroovyServlet in action</h1>
+<p>
+These examples will only work when viewed via an http URL. They will not work
+if you are viewing these pages via a <tt>file://...</tt> URL. You need to
+deploy the <tt>war</tt> archive into a servlet container like Tomcat, Jetty or
+any other will do as well.
+</p>
+
+<p>
+To navigate your way through the examples, the following icons will help:
+
+<table border=0>
+ <tr>
+  <td width="30"><img src="images/execute.gif" ></td>
+  <td>Executes the example</td>
+</tr>
+<tr>
+  <td width="30"><img src="images/code.gif"></td>
+  <td>Look at the source code for the example</td>
+</tr>
+<tr>
+  <td width="30"><img src="images/return.gif"></td>
+  <td>Return to this screen</td>
+</tr>
+</table>
+</p>
+
+<p>Tip: To see the cookie interactions with your browser, try turning on
+the "notify when setting a cookie" option in your browser preferences.
+This will let you see when a session is created and give some feedback
+when looking at the cookie demo.
+</p>
+
+<h2>Table of content</h2>
+
+"""
+
+println """
+
+<table BORDER=0 CELLSPACING=5 WIDTH="85%" >
+
+<!-- Begin Groovlet -->
+<tr VALIGN=TOP>
+<td>Hello World</td>
+
+<td VALIGN=TOP WIDTH="30%"><img SRC="images/execute.gif" HSPACE=4 BORDER=0 align=TOP><a href="hello/hello.groovy">Execute</a></td>
+
+<td WIDTH="30%"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP>Source</td>
+</tr>
+<!-- End Groovlet -->
+
+
+<!-- Begin Groovlet -->
+<tr VALIGN=TOP>
+<td>Zoo</td>
+
+<td VALIGN=TOP WIDTH="30%"><img SRC="images/execute.gif" HSPACE=4 BORDER=0 align=TOP><a href="zoo/zoo.groovy">Execute</a></td>
+
+<td WIDTH="30%"><img SRC="images/code.gif" HSPACE=4 BORDER=0 height=24 width=24 align=TOP>Source</td>
+</tr>
+<!-- End Groovlet -->
+</table>
+
+<h2>Note</h2>
+
+<p>The source code for these examples does not contain all of the
+source code that is actually in the example, only the important sections
+of code. Code not important to understand the example has been removed
+for clarity.
+</body>
+</html>
+"""
\ No newline at end of file
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/readme.txt b/groovy-core/src/examples/webapps/groovlet-examples/readme.txt
new file mode 100644
index 0000000..a041280
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/readme.txt
@@ -0,0 +1,13 @@
+
+GroovyServlet examples
+
+[ / ]
+Only contains the "index.groovy", "codehaus-style.css" and "readme.txt" files.
+
+[ /hello ]
+Contains a single welcome file named "hello.groovy" showing a simple groovlet.
+
+[ /zoo ]
+The zoo demonstrates a groovy setup of scripts, that are partly <i>hidden</i>
+beneath the "WEB-INF/groovy" directory. Note the different package names in the
+script files.
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/xml/index.xhtml b/groovy-core/src/examples/webapps/groovlet-examples/xml/index.xhtml
new file mode 100644
index 0000000..6fc4e89
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/xml/index.xhtml
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!-- DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" -->
+
+<html xmlns:gsp="http://groovy.codehaus.org/2005/gsp">
+
+  <head>
+    <link rel="stylesheet" href="../codehaus-style.css" type="text/css" />
+  </head>
+
+  <body>
+
+  Name = ${request.getParameter("name")} <br/>
+  Name = <gsp:expression>params.get("name")</gsp:expression>
+
+  <hr color="#12334" noshade="noshade" />
+
+  BEGIN
+
+    <br/>
+
+  <gsp:scriptlet>
+   <![CDATA[
+    3.times {
+   ]]>
+  </gsp:scriptlet>
+* Hello World! *
+  <gsp:scriptlet>
+   <![CDATA[  } // 3.times ]]>
+  </gsp:scriptlet>  
+
+    <br/>
+
+    END
+
+  </body>
+
+</html>
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/zoo/HommingbergerGepardenforelle.groovy b/groovy-core/src/examples/webapps/groovlet-examples/zoo/HommingbergerGepardenforelle.groovy
new file mode 100644
index 0000000..760e55f
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/zoo/HommingbergerGepardenforelle.groovy
@@ -0,0 +1,9 @@
+package zoo
+
+class HommingbergerGepardenforelle extends zoo.fish.Trout {
+
+  String saySomething(String something) {
+    return something;
+  }
+  
+}
\ No newline at end of file
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/zoo/visit.groovy b/groovy-core/src/examples/webapps/groovlet-examples/zoo/visit.groovy
new file mode 100644
index 0000000..21abe87
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/zoo/visit.groovy
@@ -0,0 +1,19 @@
+Animal shark = new zoo.fish.Shark()
+Animal trout = new zoo.fish.Trout()
+Animal forelle = new zoo.HommingbergerGepardenforelle()
+
+println """
+<html>
+    <head>
+        <title>Groovy Servlet Example - Visiting the zoo</title>
+    </head>
+    <body>
+     <p>Shark<br> 
+     ${shark.saySomething("\"Where is the trout?\"")}
+     <p>Trout<br> 
+     ${trout.saySomething("Here is the trout!")}
+     <p>Forelle<br> 
+     ${forelle.saySomething("\"<a href=\"http://www.hommingberger-forelle.de\">There is no spoon.</a>\"")}
+    </body>
+</html>
+"""
\ No newline at end of file
diff --git a/groovy-core/src/examples/webapps/groovlet-examples/zoo/zoo.groovy b/groovy-core/src/examples/webapps/groovlet-examples/zoo/zoo.groovy
new file mode 100644
index 0000000..27118db
--- /dev/null
+++ b/groovy-core/src/examples/webapps/groovlet-examples/zoo/zoo.groovy
@@ -0,0 +1,30 @@
+println """
+<html>
+    <head>
+        <title>Groovy Servlet Example - Visiting the zoo</title>
+    </head>
+    <body>
+    <a href="../"><img src="../images/return.gif" width="24" height="24" border="0"></a><a href="../">Return</a>
+    <p>
+"""
+
+Animal shark = new zoo.fish.Shark()
+Animal trout = new zoo.fish.Trout()
+Animal forelle = new zoo.HommingbergerGepardenforelle()
+
+println """
+     <p>Shark<br>
+     ${shark.saySomething("\"Where is the trout?\"")}
+
+     <p>Trout<br>
+     ${trout.saySomething("Here is the trout!")}
+
+     <p>Forelle<br>
+     ${forelle.saySomething("\"<a href=\"http://www.hommingberger-forelle.de\">There is no spoon.</a>\"")}
+     <!-- http://en.wikipedia.org/wiki/Nigritude_ultramarine -->
+"""
+
+println """
+    </body>
+</html>
+"""
diff --git a/groovy-core/src/examples/webapps/gsp-examples/readme.txt b/groovy-core/src/examples/webapps/gsp-examples/readme.txt
new file mode 100644
index 0000000..e00b01e
--- /dev/null
+++ b/groovy-core/src/examples/webapps/gsp-examples/readme.txt
@@ -0,0 +1,2 @@
+TODO First, implement http://jira.codehaus.org/browse/GROOVY-839
+TODO Second, setup WEB-INF and examples gsp files.
\ No newline at end of file
diff --git a/groovy-core/src/examples/webapps/template-examples/3.times.HelloWorld.html b/groovy-core/src/examples/webapps/template-examples/3.times.HelloWorld.html
new file mode 100644
index 0000000..39eec70
--- /dev/null
+++ b/groovy-core/src/examples/webapps/template-examples/3.times.HelloWorld.html
@@ -0,0 +1,13 @@
+<html>
+  <body>
+
+    <% 3.times { %>
+      Hello World!
+    <% } %>
+
+    <br>
+
+    session id = ${session.id}
+
+  </body>
+</html>
diff --git a/groovy-core/src/examples/webapps/template-examples/WEB-INF/lib/.cvsignore b/groovy-core/src/examples/webapps/template-examples/WEB-INF/lib/.cvsignore
new file mode 100644
index 0000000..d392f0e
--- /dev/null
+++ b/groovy-core/src/examples/webapps/template-examples/WEB-INF/lib/.cvsignore
@@ -0,0 +1 @@
+*.jar
diff --git a/groovy-core/src/examples/webapps/template-examples/WEB-INF/lib/groovy-all-xyz.jar.placeholder b/groovy-core/src/examples/webapps/template-examples/WEB-INF/lib/groovy-all-xyz.jar.placeholder
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/groovy-core/src/examples/webapps/template-examples/WEB-INF/lib/groovy-all-xyz.jar.placeholder
diff --git a/groovy-core/src/examples/webapps/template-examples/WEB-INF/web.xml b/groovy-core/src/examples/webapps/template-examples/WEB-INF/web.xml
new file mode 100644
index 0000000..bfa7eab
--- /dev/null
+++ b/groovy-core/src/examples/webapps/template-examples/WEB-INF/web.xml
@@ -0,0 +1,26 @@
+<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
+    version="2.4">
+
+<servlet>
+    <servlet-name>template</servlet-name>
+    <servlet-class>groovy.servlet.TemplateServlet</servlet-class>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>template</servlet-name>
+    <url-pattern>*.htm</url-pattern>
+  </servlet-mapping>
+  
+  <servlet-mapping>
+    <servlet-name>template</servlet-name>
+    <url-pattern>*.html</url-pattern>
+  </servlet-mapping>
+
+  <servlet-mapping>
+    <servlet-name>template</servlet-name>
+    <url-pattern>*.template</url-pattern>
+  </servlet-mapping>
+
+</web-app>
diff --git a/groovy-core/src/examples/webapps/template-examples/javasystemproperties.htm b/groovy-core/src/examples/webapps/template-examples/javasystemproperties.htm
new file mode 100644
index 0000000..e80d84c
--- /dev/null
+++ b/groovy-core/src/examples/webapps/template-examples/javasystemproperties.htm
@@ -0,0 +1,22 @@
+<html>
+<head>
+<title>System properties</title>
+</head>
+<body>
+
+<h1>System properties</h1>
+<% keys = System.getProperties().keySet();
+   if (keys.isEmpty()) {
+     out.println('No keys.');
+   }
+   else {
+  %>
+<dl>
+    <% for (key in keys) { %>
+    <dt> <b> ${key} </b> </dt> 
+    <dd> <tt> ${System.getProperty(key)} </tt> </dd>
+    <% } %>
+</dl>
+<% } %>
+</body>
+</html>
diff --git a/groovy-core/src/examples/webapps/template-examples/readme.txt b/groovy-core/src/examples/webapps/template-examples/readme.txt
new file mode 100644
index 0000000..fb647a0
--- /dev/null
+++ b/groovy-core/src/examples/webapps/template-examples/readme.txt
@@ -0,0 +1,13 @@
+
+TemplateServlet examples
+
+[ /readme.txt ]
+This readme file. For clarity sake, it does not contain a welcome file and
+therefore the servlet container should list all files and subdirectories listed
+below.
+
+[ /3.times.HelloWorld.html ]
+Prints three times "Hello World!" and the session id.
+
+[ /javasystemproperties.htm ]
+Lists Java runtime system properties.
diff --git a/groovy-core/src/latex/ref/README.txt b/groovy-core/src/latex/ref/README.txt
new file mode 100644
index 0000000..a4158b1
--- /dev/null
+++ b/groovy-core/src/latex/ref/README.txt
@@ -0,0 +1,16 @@
+# purpose:
+#  to create a PDF file from latex source
+
+latex groovy-reference-card.tex
+dvips -Ppdf -t landscape groovy-reference-card.dvi
+ps2pdf groovy-reference-card.ps
+
+# or
+
+pdflatex groovy-reference-card.tex
+
+
+# p.s. best for debugging use...
+#   latex $1.tex; xdvi $1.dvi
+# or
+#  http://www.uoregon.edu/~koch/texshop/texshop.html
diff --git a/groovy-core/src/latex/ref/groovy-reference-card.tex b/groovy-core/src/latex/ref/groovy-reference-card.tex
new file mode 100644
index 0000000..a6136f2
--- /dev/null
+++ b/groovy-core/src/latex/ref/groovy-reference-card.tex
@@ -0,0 +1,414 @@
+\documentclass[10pt, landscape]{article}
+\usepackage{multicol}
+\usepackage{graphics}
+
+% turn off header and footer
+\pagestyle{empty}
+
+\setlength{\textheight}{7.5 in}
+\setlength{\textwidth}{11.2 in}
+%\setlength{\hoffset}{-2 in}
+%\setlength{\voffset}{-1 in}
+%\setlength{\footskip}{12 pt}
+\setlength{\oddsidemargin}{-0.74 in}
+\setlength{\evensidemargin}{0.5 in}
+\setlength{\topmargin}{-0.75 in}
+\setlength{\headheight}{0 in}
+\setlength{\headsep}{0 in}
+
+
+\makeatletter
+\renewcommand{\section}{\@startsection{section}{1}{0mm}%
+                                {-1ex plus -.5ex minus -.2ex}%
+                                {0.5ex plus .2ex}%x
+                                {\normalfont\large\bfseries}}
+\renewcommand{\subsection}{\@startsection{subsection}{2}{0mm}%
+                                {-1explus -.5ex minus -.2ex}%
+                                {0.5ex plus .2ex}%
+                                {\normalfont\normalsize\bfseries}}
+\renewcommand\subsubsection{\@startsection{subsubsection}{3}{0mm}%
+                                {-1ex plus -.5ex minus -.2ex}%
+                                {1ex plus .2ex}%
+                                {\normalfont\small\bfseries}}
+\makeatother
+
+% Don't print section numbers
+\setcounter{secnumdepth}{0}
+
+
+\setlength{\columnsep}{0.5 in}
+%\setlength{\columnseprule}{0.4 pt}
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{0pt plus 0.5ex}
+
+
+% -------------------------
+
+\begin{document}
+\raggedright
+\footnotesize
+
+
+
+% -- tabular, good for html output
+\newcommand{\keywordSummaryHeader}[1]{\begin{tabular}{ll} #1 \end{tabular}}
+\newcommand{\keywordSummary}[2]{{\bf #1} & #2 \\}
+%\newcommand{\methodDetailHeader}[1]{\begin{tabular}{rll} #1 \end{tabular}}
+%\newcommand{\methodDetail}[3]{#1 & #2 & #3 \\}
+
+% -- tabbing, good for pdf output
+%\newcommand{\keywordSummaryHeader}[1]{\begin{tabbing} jez \= jez-repeated-for-tab-settings-only \kill #1 \end{tabbing}}
+%\newcommand{\keywordSummary}[2]{#1 \\ \> #2 \\}
+
+\newcommand{\methodDetailHeader}[1]{\begin{tabbing} jezje \= jez-repeated-for-tab-settings-only \kill #1 \end{tabbing}}
+\newcommand{\methodDetail}[4]{#1\>{\bf #2}#3\\{\scriptsize #4}\\}
+
+\newcommand{\methodSummaryHeader}[1]{\begin{tabbing} jezj \= jez-repeated-for-tab-settings-only \kill #1 \end{tabbing}}
+\newcommand{\methodSummary}[4]{#1\>{\bf #2}#3\\}
+
+\newcommand{\toolDetailHeader}[1]{\begin{tabbing} je \= jez-repeated-for-tab-settings-only \kill #1 \end{tabbing}}
+\newcommand{\toolDetail}[4]{#1\>{\bf #2}#3\\{\scriptsize #4}\\}
+
+
+
+
+\newcommand{\head}[1]{{\large\textbf{#1}}\\}
+
+\begin{multicols}{3}
+\setlength{\premulticols}{1pt}
+\setlength{\postmulticols}{1pt}
+\setlength{\multicolsep}{1pt}
+\setlength{\columnsep}{2pt}
+
+
+\begin{tabular}{ll}
+\scalebox{0.35}{\includegraphics{one-groovy-logo.mps}}  &   {\large\textbf{Groovy}}      \\
+                                                        &   {\large\textbf{Reference}}   \\
+                                                        &   {\large\textbf{Summary}}
+\end{tabular}
+
+\vskip 1.8in
+%todo: black line
+
+GROOVY-1.0-BETA-7
+
+\vskip 0.25 in
+
+{\em Second Edition\/} (September 2004)
+
+This card is intended primarily for use by Groovy language programmers. It 
+contains basic language information summarized from the online
+documentation (http://groovy.codehaus.org). The card will be updated from 
+time to time. However the above manual and others cited on the card
+are the authoritative reference sources and will be first to reflect changes.
+
+To distinguish them from instructions carried over from the Java Language,
+the names of instructions essentially new with Groovy are shown
+in italics.
+
+Comments about this publication may be sent to the address below.
+
+\vskip 2 in
+Groovy Technical Publications Systems 
+
+groovy.codehaus.org
+
+
+\section{Keywords}
+\subsection{Grammar}
+\keywordSummaryHeader{
+\keywordSummary{{\em as}        }{   import {\em type\/} as {\em id\/}}
+\keywordSummary{assert          }{   assert {\em expr expr?\/}}
+\keywordSummary{break           }{   break {\em lbl?\/}}
+\keywordSummary{case            }{   switch {\em expr\/} case {\em expr stmt*\/}}
+\keywordSummary{catch           }{   try {\em stmt*\/} catch {\em type id stmt*\/}}
+\keywordSummary{class           }{   {\em mod*\/} class {\em id\/}}
+\keywordSummary{continue        }{   continue {\em lbl?\/}}
+\keywordSummary{{\em def}       }{   def {\em methodDeclaration\/}}
+\keywordSummary{default         }{   switch {\em expr\/} case default{\em stmt*\/} }
+\keywordSummary{do              }{   do {\em stmt*\/} while {\em expr\/}}
+\keywordSummary{else            }{   if {\em expr stmt*\/} else if {\em expr stmt*\/}}
+\keywordSummary{extends         }{   {\em mod*\/} class {\em id\/} extends {\em type\/}}
+\keywordSummary{finally         }{   try {\em stmt*} finally {\em stmt*}}
+\keywordSummary{for             }{   for {\em expr*};{\em expr};{\em expr} {\em stmt*\/}}
+\keywordSummary{{\em for}       }{   for {\em id\/} in {\em id stmt*\/}}
+\keywordSummary{if              }{   if {\em expr stmt*\/} else if {\em expr stmt*\/}}
+\keywordSummary{{\em in}        }{   for {\em id\/} in {\em id stmt*\/}}
+\keywordSummary{implements      }{   {\em mod*\/} class {\em id\/} implements {\em type*}}
+\keywordSummary{import          }{   import {\em type\/}}
+\keywordSummary{instanceof      }{   {\em expr\/} instanceof {\em type}}
+\keywordSummary{interface       }{   {\em mod*\/} interface {\em id\/}}
+%\keywordSummary{{\em mixin}     }{   {\em mod*\/} mixin {\em id\/}}
+\keywordSummary{new             }{   new {\em type\/} }
+\keywordSummary{package         }{   package {\em id\/}}
+\keywordSummary{{\em property}  }{   {\em mod*\/} property {\em type?\/} {\em id\/}}
+\keywordSummary{return          }{   return {\em expr?/} }
+\keywordSummary{switch          }{   switch {\em expr\/} case {\em expr stmt*\/} }
+\keywordSummary{throw           }{   throw {\em expr\/} }
+\keywordSummary{throws          }{   {\em methodDeclaration} throws {\em type\/} }
+\keywordSummary{try             }{   try {\em stmt*\/} catch {\em type id stmt*\/}}
+\keywordSummary{while           }{   do {\em stmt*\/} while {\em expr\/}}
+\keywordSummary{                }{   while {\em expr\/} {\em stmt*\/}}
+}
+
+
+
+% \subsection{Types}
+% \keywordSummaryHeader{
+% \keywordSummary{boolean         }{   true {\em or\/} false}
+% \keywordSummary{byte            }{   -128 to 127}
+% \keywordSummary{char            }{   u0000 to uFFFF }
+% \keywordSummary{double          }{   $\pm 4.9E^{-324}$ to $\pm 1.8E^{+308}$}
+% \keywordSummary{float           }{   $\pm 1.4E^{-45}$ to $\pm 3.4E^{+38}$}
+% \keywordSummary{int             }{   -2,147,483,648 to 2,147,483,647}
+% \keywordSummary{long            }{   -9,223,372,036,854,775,808 }
+% \keywordSummary{                }{   to 9,223,372,036,854,775,807}
+% \keywordSummary{short           }{   -32,768 to 32,767}
+% \keywordSummary{void            }{   }
+% }
+
+\vskip 0.5 in
+
+\section{Groovy JDK}
+% based upon DefaultGroovyMethods r1.114
+\subsection{Collections and properties}
+{\scriptsize {\em Note: cltn in this sense {\em can\/} include lists, sets, matchers, strings, charSeqs and arrays\/}}
+
+\methodDetailHeader{
+% a.getAt(b) and a.putAt(b,c) are equiv to a[b] and a[b] = c respectiv. 
+%\methodDetail{ cltn. }{ getAt}{(index\textbar indices\textbar range) }{ obtains objects at specified {\em indicies\/} or in {\em range\/}}
+%\methodDetail{ cltn. }{ getAt}{(property)                         }{ obtains {\em property\/} from each object in collection}
+%\methodDetail{  obj. }{ putAt}{(idx, value)                       }{ put {\em value\/} at position {\em idx\/} } 
+%\methodDetail{  obj. }{ putAt}{(propertyName, value)              }{ put {\em value\/} in the {\em propertyName\/} }
+\methodDetail{  cltn }{[}{index\textbar indices\textbar range\textbar property {\bf ]}}{ obtains objects at specified location}
+\methodDetail{   obj }{[}{index\textbar property{\bf ] =} value    }{ put {\em value\/} at location } 
+\methodDetail{  cltn }{ \textless\textless}{ obj                  }{ append obj to collection}
+\methodSummary{  cltn }{ $+$}{ obj                                   }{ append obj to collection}
+%\methodDetail{  cltn }{ $+$}{ cltn                                  }{ append collection to collection}
+\methodSummary{  list }{ $-$}{ cltn                                  }{ remove items from list}
+\methodDetail{  cltn }{ $*$}{ num                                   }{ repeat items in collection a number of times}
+\methodDetail{       }{  }{                                       }{ }
+% no count() or getAt(range) for matchers!
+\methodDetail{  obj. }{ getProperties}{()                         }{ obtain Map of properties on {\em obj\/}}
+\methodDetail{  obj. }{ getMetaPropertyValues}{()                 }{ obtain List of meta properties on {\em obj\/}}
+\methodDetail{ cltn. }{ count}{(obj) *                            }{ counts number of occurances of {\em obj\/} in collection}
+\methodSummary{  map. }{ get}{(key, defaultValue) *                }{ try to get {\em key \/} from map, otherwise put {\em defaultValue\/} in map and return }
+\methodSummary{ cltn. }{ size}{() *                                }{ returns size of an array or string }
+\methodDetail{       }{   }{                                      }{ }
+\methodDetail{ cltn. }{ collect}{() \{closure\} *                 }{ new collection of {\em closure \/} transformed items }
+\methodDetail{  obj. }{ each}{() \{closure\} *                    }{ iterate through object applying {\em closure\/} }
+\methodDetail{  obj. }{ eachWithIndex}{() \{closure\}             }{ iterate through object with a counter applying {\em closure\/} }
+\methodDetail{  obj. }{ find}{() \{closure\} *                    }{ find first item picked by {\em closure \/} condition }
+\methodDetail{  obj. }{ findAll}{() \{closure\} *                 }{ returns all items picked by {\em closure\/} condition }
+\methodDetail{  obj. }{ findIndexOf}{() \{closure\}               }{ return first index that matches condition {\em closure\/} }
+\methodSummary{  obj. }{ grep}{(regex\textbar range\textbar etc..) *               }{ returns all matching items }
+\methodDetail{ cltn. }{ inject}{(value) \{closure\}               }{ returns closure( closure( closure(value,item0) ,item1) ,item2) ... }
+\methodDetail{ cltn. }{ max}{([comparator]) \{closure\} *         }{ returns the maximum value found in the collection }
+\methodDetail{ cltn. }{ min}{([comparator]) \{closure\} *         }{ returns the minimum value found in the collection }
+\methodDetail{ list. }{ reverseEach}{() \{closure\}               }{ iterate backwards through list applying {\em closure\/}}
+\methodDetail{ cltn. }{ sort}{([comparator]) *                    }{ sorts collection into a list, optionally using a {\em comparator\/}}
+\methodDetail{ cltn. }{ sort}{() \{closure\} *                    }{ sorts collection into a list using closure as comparator}
+\methodDetail{       }{     }{                                    }{ }
+\methodSummary{ cltn. }{ asImmutable}{()                           }{ create an immutable collection }
+\methodSummary{ cltn. }{ asSynchronized}{()                        }{ create a synchronized collection }
+\methodSummary{ list. }{ flatten}{()                               }{ flattens list }
+\methodDetail{ list. }{ intersect}{(cltn)                         }{ returns intersection of list and collection }
+\methodDetail{ cltn. }{ join}{(separator) *                       }{ concatenate all the elements of {\em cltn\/} into a string }
+\methodDetail{ list. }{ pop}{() *                                   }{ remove and return last item from list }
+%todo: what happened to push() :-)
+\methodSummary{ cltn. }{ reverse}{()                               }{ reverses order of collection or string }
+\methodDetail{  map. }{ subMap}{(keys)                            }{ returns a map of the given keys }
+\methodSummary{ cltn. }{ toList}{()                                }{ turns any collection into a list }
+}
+
+\vskip 0.75 in
+
+\subsection{Strings}
+\methodDetailHeader{
+\methodDetail{  str }{ $++$}{                                      }{ increment the number at end of string}
+\methodDetail{  str }{ $--$}{                                      }{ reduce the number at end of string}
+\methodSummary{  str }{ $+$}{ obj                                  }{ concatenate {\em str\/} and {\em obj\/} together}
+\methodDetail{  str }{ $-$}{ obj                                   }{ remove the first {\em obj\/} from {\em str\/}}
+%\methodDetailHeader{  num }{ + str                                   }{ concatenate str to the end of num }
+\methodSummary{  str }{ \textless\textless}{ value                }{ }
+%\methodDetail{  strBuff }{ \textless\textless}{ value            }{ }
+%center and centre :-) !!!!
+\methodDetail{ str. }{ padRight}{(size,[padding])                }{ left justifies string padded out to {\em size\/}} 
+\methodDetail{ str. }{ center}{(size, [padding])                 }{ centers a string padded out to {\em size\/}}
+% name change for padLeft?
+\methodDetail{ str. }{ padLeft}{(size,[padding])                 }{ right justifies string padded out to {\em size\/}} 
+\methodDetail{ str. }{ contains}{(str2) *                        }{ true if {\em str} contains {\em str2}}
+\methodDetail{ str. }{ eachMatch}{(regex) \{closure\} *          }{ apply {\em closure\/} to each match of the specified {\em regex\/} }
+%leftshift
+\methodSummary{ str. }{ toCharacter}{()                           }{ }
+\methodSummary{ str. }{ toList}{()                                }{ }
+\methodSummary{ str. }{ toLong}{()                                }{ }
+\methodSummary{ str. }{ toURL}{()                                 }{ }
+\methodSummary{ str. }{ tokenize}{([token]) *                     }{ }
+}
+
+
+\subsection{Input/output}
+%todo: unify method names
+{\scriptsize {\em Note: url in this sense {\em can\/} include urls, files, streams and readers\/}}
+\methodDetailHeader{
+\methodDetail{   dir. }{ eachFile}{() \{closure\}                 }{ apply {\em closure\/} to each file in {\em dir\/}}
+\methodDetail{   dir. }{ eachFileRecurse}{() \{closure\}          }{ apply {\em closure\/} to each file in {\em dir\/} recursively}
+\methodDetail{ }{ }{ }{ }
+\methodSummary{   url. }{ eachByte}{() \{closure\}                 }{ apply {\em closure\/} to each byte in {\em file\/}}
+\methodDetail{    url. }{ eachLine}{() \{closure\}                 }{ apply {\em closure\/} to each line of input}
+%\methodDetail{  file. }{ newInputStream}{()                       }{ obtain Stream to read from {\em file\/}}
+%\methodDetail{  file. }{ newReader}{([charset])                   }{ obtain Reader from {\em file}}
+\methodSummary{  file. }{ readBytes}{()                            }{ read bytes from {\em file\/}}
+\methodDetail{    in. }{ readLine}{()                             }{ read a single, whole line from {\em in\/}}
+\methodDetail{  file. }{ readLines}{()                            }{ obtain List of lines from {\em file}}
+\methodDetail{   url. }{ getText}{([charset])                     }{ fetch all available text from resource }
+\methodDetail{  file. }{ splitEachLine}{(regEx) \{closure\}       }{ read in each line of {\em file\/}, apply {\em closure\/} to data delimited by {\em regEx\/}}
+%\methodDetail{  file. }{ withInputStream}{() \{closure\}          }{ apply {\em closure\/} to a new InputStream on {\em file\/}, then close}
+\methodDetail{   url. }{ withReader}{() \{closure\}               }{ apply {\em closure\/} to {\em in\/}, then close {\em in\/}}
+%\methodDetail{    in. }{ withStream}{() \{closure\}               }{ apply {\em closure\/} to {\em in\/}, then close {\em in\/}}
+\methodDetail{ }{ }{ }{ }
+\methodDetail{    out }{ \textless\textless}{ obj                 }{ append {\em obj\/} to stream, process or socket}
+\methodSummary{  file. }{ append}{(text, [charset])                }{ append {\em text\/} at end of {\em file\/} with {\em charset\/} encoding}
+%\methodSummary{  file. }{ asWritable}{([charset]) *                }{ wrap {\em file\/} as Writable }
+\methodSummary{ bytes. }{ encodeBase64}{()                         }{ wraps {\em file\/} in Writable with contents encoded as Base64}
+\methodSummary{   str. }{ decodeBase64}{()                         }{ unwraps bytes from Base64 encoded {\em str\/}}
+\methodDetail{     in. }{ filterLine}{([out]) \{closure\}            }{ read from {\em in\/} and write each line to {\em out\/} only if {\em closure\/}}
+%\methodDetail{  file. }{ newOutputStream}{()                      }{ obtain Stream to write to {\em file\/}}
+%\methodDetail{  file. }{ newPrintWriter}{([charset])              }{ obtain PrintWriter to {\em file\/}}
+%\methodDetail{  file. }{ newWriter}{([charset],[append])          }{ obtain Writer to {\em file\/}}
+% todo: transformChar(out) could be more in line with eachByte?
+\methodSummary{   in. }{ transformChar}{(out) \{closure\}           }{ read {\em in\/} and apply {\em closure\/} to each character being written {\em out\/}}  
+\methodDetail{   in. }{ transformLine}{(out) \{closure\}          }{ read {\em in\/} and apply {\em closure\/} to each line being written {\em out\/}}  
+\methodSummary{  file. }{ withOutputStream}{() \{closure\}         }{ apply {\em closure\/} to a new OutputStream on {\em file\/}, then close}
+\methodSummary{  file. }{ withPrintWriter}{() \{closure\}          }{ apply {\em closure\/} to a new PrintWriter on {\em file\/}, then close}
+\methodSummary{   out. }{ withStream}{() \{closure\}               }{ apply {\em closure\/} to {\em out\/}, then close {\em out\/}}
+\methodSummary{   skt. }{ withStreams}{() \{closure\}              }{ apply {\em closure\/} to [in,out], then close them}
+\methodSummary{   out. }{ withWriter}{([charset]) \{closure\}      }{ apply {\em closure\/} to {\em out\/} using {\em charset\/}, then close {\em out\/}}
+\methodDetail{  file. }{ withWriterAppend}{(charset) \{closure\}  }{ apply {\em closure\/} to a new appending Writer on {\em file\/}, then close}
+\methodSummary{  file. }{ write}{(text, [charset]) *               }{ write {\em text\/} to {\em file\/} using {\em charset\/}}
+\methodSummary{   out. }{ writeLine}{(line)                        }{ write {\em line\/} and append a newline}
+}
+
+\subsection{Misc}
+\methodDetailHeader{
+\methodSummary{   date }{ $++$}{                                       }{ add one day to the date }
+\methodSummary{   date }{ $--$}{                                       }{ subtract one day from the date }
+\methodSummary{   date }{ $+$}{ days                                   }{ add {\em days\/} to the date }
+\methodSummary{   date }{ $-$}{ days                                   }{ subtract {\em days\/} from the date }
+\methodDetail{   obj. }{ dump}{() *                                }{ returns a detailed dump string of {\em obj\/}}
+\methodDetail{   obj. }{ inspect}{() *                             }{ returns the groovy expression used to create this instance of {\em obj}}
+\methodSummary{   obj. }{ invokeMethod}{(method, args) *             }{ invokes {\em method\/} on {\em obj\/} }
+\methodSummary{   obj. }{ print}{(obj) *                             }{ print an object }
+\methodSummary{   obj. }{ print}{(out) *                             }{ print this object to {\em out} }
+\methodSummary{   obj. }{ println}{(object) *                        }{ print an object and then terminate line }
+\methodSummary{   obj. }{ println}{(out) *                           }{ print this object to {\em out} and then terminate line }
+\methodDetail{   num. }{ step}{(endNum, stepNum) \{closure\}        }{ iterates {\em closure\/} starting at this number, stepping up to {\em endNum} }
+\methodDetail{   num. }{ times}{() \{closure\} *                    }{ iterates {\em closure\/} num times }
+%todo: upTo() instead of upto()
+\methodDetail{   num. }{ upto}{(endNum) \{closure\}                 }{ iterates {\em closure\/} starting at this number, up to {\em endNum} }
+\methodDetail{   obj. }{ use}{(categoryClass) \{closure\} *         }{ attach {\em closure\/} to specified class }
+\methodDetail{   obj. }{ use}{(categoryClassList) \{closure\} *     }{ attach {\em closure\/} to specified classes }
+\methodSummary{    ps. }{ waitForOrKill}{(milliSecs)                 }{ wait for process to finish, or stop after specified {\em milliSecs} }
+\methodSummary{    ps. }{ getText}{()                                }{ }
+%Static methods shown with \em
+\methodSummary{    Thd.}{ {\em start}}{() \{closure\}                      }{ }
+\methodSummary{    Thd.}{ {\em startDaemon}}{() \{closure\}                }{ }
+\methodSummary{    Mtr.}{ {\em getLastMatcher}}{()                         }{ }
+}
+
+
+\section{Groovy Developers Kit}
+\subsection{Groovy SQL}
+%START
+% sql = Sql.newInstance(
+%END
+\methodSummaryHeader{
+%\methodSummary{      }{ newInstance}{(url,[props],[driver]) }
+\methodSummary{      }{ Sql}{(datasource\textbar connection\textbar sql)}{ }
+\methodSummary{      }{ newInstance}{(url,[user],[pass],[driver]) }{ }
+\methodSummary{ sql. }{ call}{(str,[params]) }{ }
+\methodSummary{ sql. }{ eachRow}{(str,[params]) \{closure\}}{ }
+\methodSummary{ sql. }{ execute}{(str,[params]) }{ }
+\methodSummary{ sql. }{ executeUpdate}{(str,[params]) }{ }
+\methodSummary{ sql. }{ close}{() }{ }
+}
+
+\section{Snippets}
+\begin{tabbing} jezjezjez \= jez-repeated-for-tab-settings-only \kill 
+{\bf Builder}\>
+{\scriptsize Markup, Node, StreamingMarkup, DOM, }\\
+{\scriptsize Ant, JavaDoc, Swt, JFace, Swing}\\
+\verb+farm = new NodeBuilder().farm(){animal(type:'pig')}+\\
+{\bf GPath}  \>
+{\scriptsize walks the tree}\\
+\verb+farm.animal.collect{it['@type']}.contains('pig')+\\
+\end{tabbing}
+%\section{Sample Groovy Builder}
+%{\scriptsize Builders are provided to construct these tree structures: {\em Markup, Node, StreamingMarkup, DOM, Ant, JavaDoc, Swt, JFace, Swing}}
+%\begin{verbatim}
+%builder = new NodeBuilder()
+%
+%farm = builder.farm(type:'livestock', acres:30) {
+%                 animal(type:'pig')
+%                 animal(type:'sheep')
+%                 tractor(wheelbase:90)
+%}
+%
+%assert farm.animal.collect{it['@type']}.contains('pig')
+%
+%\end{verbatim}
+
+\section{Sample Groovy code}
+\begin{verbatim}
+package com.example
+
+import org.example.Cow
+
+/**
+ * This is a sample of Groovy
+ */
+class HighlandCow extends Cow {
+  
+  void mooAtPeople() {
+    sql = Sql.newInstance("jdbc:foo:bar")
+    sql.eachRow("select * from PERSON") {
+      println("Och-Aye ${it.firstname}")
+    }
+  }
+}        
+\end{verbatim}
+
+\section{Tools}
+\subsection{Ant task}
+\begin{verbatim}
+<taskdef name="groovyc" 
+         classname="org.codehaus.groovy.ant.Groovyc" 
+         classpathref="my.classpath"/>
+<groovyc destdir="${build.classes.dir}" 
+         srcdir="${src.dir}" 
+         listfiles="true">
+  <classpath refid="my.classpath"/>
+</groovyc>
+\end{verbatim}
+\subsection{Command Line Tools}                                      
+\toolDetailHeader{
+\toolDetail{ \textgreater }{ groovy        }{ [options] cheese.groovy [args] }{ interpret and execute specified groovy script }
+\toolDetail{ \textgreater }{ groovyc       }{ [options] cheese.groovy        }{ compiles specified groovy script }
+\toolDetail{ \textgreater }{ groovysh      }{                                }{ begins an interactive groovy session }
+\toolDetail{ \textgreater }{ groovyConsole }{                                }{ begins a GUI based groovy session }
+%\toolDetail{ \textgreater }{ grok   }{                  }{ groovy javadoc }
+}
+
+\rule{0.3\linewidth}{0.25pt}
+\scriptsize
+
+Copyright \copyright\ 2004 Jeremy Rayner
+
+\verb!$Revision$, $Date$.!
+
+http://javanicus.com/
+
+
+\end{multicols}
+\end{document}
diff --git a/groovy-core/src/latex/ref/one-groovy-logo.eps b/groovy-core/src/latex/ref/one-groovy-logo.eps
new file mode 100644
index 0000000..b96a010
--- /dev/null
+++ b/groovy-core/src/latex/ref/one-groovy-logo.eps
Binary files differ
diff --git a/groovy-core/src/latex/ref/one-groovy-logo.mps b/groovy-core/src/latex/ref/one-groovy-logo.mps
new file mode 100644
index 0000000..570bb60
--- /dev/null
+++ b/groovy-core/src/latex/ref/one-groovy-logo.mps
@@ -0,0 +1,1666 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 197 340 415 450 
+%%Creator: MetaPost
+%%CreationDate: 2005.04.17:1127
+%%Pages: 1
+%%EndProlog
+%%Page: 1 1
+newpath 372.793 340.699 moveto
+305.645 366.988 lineto
+238.5 340.707 lineto
+265.012 382.602 lineto
+197 408.258 lineto
+280.531 407.863 lineto
+305.641 450 lineto
+330.754 407.859 lineto
+414.289 408.246 lineto
+346.277 382.598 lineto
+372.793 340.699 lineto
+ closepath fill
+ 0.35832 0.70496 0.749 setrgbcolor
+newpath 363.707 348.195 moveto
+305.703 370.902 lineto
+247.699 348.199 lineto
+270.602 384.391 lineto
+211.848 406.551 lineto
+284.008 406.211 lineto
+305.699 442.609 lineto
+327.395 406.211 lineto
+399.559 406.543 lineto
+340.805 384.387 lineto
+363.707 348.195 lineto
+ closepath fill
+ 0 setgray
+newpath 261.176 428.469 moveto
+266.969 428.469 263.594 413.848 261.531 409.438 curveto
+259.77 405.664 255.797 400.219 251.086 400.219 curveto
+245.441 400.219 245.609 406.605 247.855 411.418 curveto
+249.074 414.02 250.945 416.941 253.52 419.086 curveto
+252.863 416.848 255.094 415.316 254.191 413.387 curveto
+253.574 412.066 252.301 410.629 251.637 409.211 curveto
+250.566 406.918 250.973 402.852 253.562 402.852 curveto
+255.879 402.852 257.938 405.75 258.785 407.555 curveto
+260.512 411.254 264.836 427.043 260.004 427.043 curveto
+254.438 427.043 244.844 413.344 242.836 409.047 curveto
+239.25 401.375 241.852 391.93 250.02 391.93 curveto
+255.539 391.93 260.078 397.289 262.27 401.98 curveto
+263.578 404.773 264.289 407.555 264.57 410.176 curveto
+265.641 410.375 lineto
+265.879 403.156 273.438 391.207 270.219 384.32 curveto
+266.102 375.508 253.785 375.586 246.754 372.461 curveto
+245.273 375.953 243.273 379.199 240.453 381.68 curveto
+246.727 383.809 262.137 387.387 265.492 394.559 curveto
+266.898 397.57 265.941 402.566 264.312 404.258 curveto
+264.035 403.195 263.652 402.109 263.145 401.02 curveto
+260.273 394.883 254.129 390.121 247.793 390.121 curveto
+238.977 390.121 235.238 396.52 239.387 405.398 curveto
+241.879 410.73 254.598 428.469 261.176 428.469 curveto
+ closepath fill
+ 0 9.7534 dtransform truncate idtransform setlinewidth pop [] 0 setdash
+ 1 setlinejoin 10 setmiterlimit
+newpath 261.176 428.469 moveto
+266.969 428.469 263.594 413.848 261.531 409.438 curveto
+259.77 405.664 255.797 400.219 251.086 400.219 curveto
+245.441 400.219 245.609 406.605 247.855 411.418 curveto
+249.074 414.02 250.945 416.941 253.52 419.086 curveto
+252.863 416.848 255.094 415.316 254.191 413.387 curveto
+253.574 412.066 252.301 410.629 251.637 409.211 curveto
+250.566 406.918 250.973 402.852 253.562 402.852 curveto
+255.879 402.852 257.938 405.75 258.785 407.555 curveto
+260.512 411.254 264.836 427.043 260.004 427.043 curveto
+254.438 427.043 244.844 413.344 242.836 409.047 curveto
+239.25 401.375 241.852 391.93 250.02 391.93 curveto
+255.539 391.93 260.078 397.289 262.27 401.98 curveto
+263.578 404.773 264.289 407.555 264.57 410.176 curveto
+265.641 410.375 lineto
+265.879 403.156 273.438 391.207 270.219 384.32 curveto
+266.102 375.508 253.785 375.586 246.754 372.461 curveto
+245.273 375.953 243.273 379.199 240.453 381.68 curveto
+246.727 383.809 262.137 387.387 265.492 394.559 curveto
+266.898 397.57 265.941 402.566 264.312 404.258 curveto
+264.035 403.195 263.652 402.109 263.145 401.02 curveto
+260.273 394.883 254.129 390.121 247.793 390.121 curveto
+238.977 390.121 235.238 396.52 239.387 405.398 curveto
+241.879 410.73 254.598 428.469 261.176 428.469 curveto
+ closepath stroke
+newpath 276.242 407.305 moveto
+276.594 406.434 277.609 401.512 278.379 401.512 curveto
+280.039 401.512 283.039 406.078 283.848 407.262 curveto
+285.324 406.285 284.504 404.234 287.242 404.234 curveto
+288.48 404.234 289.105 406.93 290.395 406.973 curveto
+290.441 405.883 290.508 404.898 289.922 403.641 curveto
+289.012 401.699 286.719 399.066 284.461 399.066 curveto
+282.844 399.066 280.594 401.031 280.152 401.031 curveto
+279.672 401.031 278.789 400.805 278.508 400.203 curveto
+277.332 397.691 280.477 389.297 283.625 389.297 curveto
+285.309 389.297 287.316 390.543 289.078 391.312 curveto
+288.621 388.289 288.559 385.738 289.164 383.133 curveto
+287.559 382.109 285.68 381.676 284.172 381.676 curveto
+276.43 381.676 280.699 399.859 273.559 403.734 curveto
+276.242 407.305 lineto
+ closepath fill
+newpath 276.242 407.305 moveto
+276.594 406.434 277.609 401.512 278.379 401.512 curveto
+280.039 401.512 283.039 406.078 283.848 407.262 curveto
+285.324 406.285 284.504 404.234 287.242 404.234 curveto
+288.48 404.234 289.105 406.93 290.395 406.973 curveto
+290.441 405.883 290.508 404.898 289.922 403.641 curveto
+289.012 401.699 286.719 399.066 284.461 399.066 curveto
+282.844 399.066 280.594 401.031 280.152 401.031 curveto
+279.672 401.031 278.789 400.805 278.508 400.203 curveto
+277.332 397.691 280.477 389.297 283.625 389.297 curveto
+285.309 389.297 287.316 390.543 289.078 391.312 curveto
+288.621 388.289 288.559 385.738 289.164 383.133 curveto
+287.559 382.109 285.68 381.676 284.172 381.676 curveto
+276.43 381.676 280.699 399.859 273.559 403.734 curveto
+276.242 407.305 lineto
+ closepath stroke
+newpath 306 408.762 moveto
+311.852 408.762 314.16 398.133 311.535 392.516 curveto
+309.5 388.16 305.887 385 301.262 385 curveto
+293.09 385 294.113 396.246 297.301 403.066 curveto
+298.18 404.945 301.184 409.039 303.531 409.039 curveto
+304.395 409.039 305.113 408.762 306 408.762 curveto
+ closepath fill
+newpath 305.816 407.77 moveto
+304.898 407.77 304.086 407.309 303.66 406.395 curveto
+302.762 404.477 307.234 402.535 306.594 401.164 curveto
+306.188 400.301 304.652 399.492 303.875 399.492 curveto
+299.996 399.492 300.031 404.586 302.34 407.906 curveto
+300.906 406.98 299.961 405.57 299.352 404.258 curveto
+297.078 399.398 298.883 392.711 304.066 392.711 curveto
+306.934 392.711 310.23 395.312 311.512 398.055 curveto
+313.094 401.43 309.059 407.77 305.816 407.77 curveto
+ closepath fill
+newpath 306 408.762 moveto
+311.852 408.762 314.16 398.133 311.535 392.516 curveto
+309.5 388.16 305.887 385 301.262 385 curveto
+293.09 385 294.113 396.246 297.301 403.066 curveto
+298.18 404.945 301.184 409.039 303.531 409.039 curveto
+304.395 409.039 305.113 408.762 306 408.762 curveto
+ closepath stroke
+newpath 305.816 407.77 moveto
+304.898 407.77 304.086 407.309 303.66 406.395 curveto
+302.762 404.477 307.234 402.535 306.594 401.164 curveto
+306.188 400.301 304.652 399.492 303.875 399.492 curveto
+299.996 399.492 300.031 404.586 302.34 407.906 curveto
+300.906 406.98 299.961 405.57 299.352 404.258 curveto
+297.078 399.398 298.883 392.711 304.066 392.711 curveto
+306.934 392.711 310.23 395.312 311.512 398.055 curveto
+313.094 401.43 309.059 407.77 305.816 407.77 curveto
+ closepath stroke
+newpath 332.59 391.262 moveto
+331.062 387.992 328.211 386.195 325.004 386.195 curveto
+314.824 386.195 312.805 395.57 317.215 405.012 curveto
+318.258 407.238 319.969 409.703 322.578 409.703 curveto
+330.758 409.703 336.453 399.531 332.59 391.262 curveto
+ closepath fill
+newpath 324.469 408.52 moveto
+323.715 408.52 323.059 408.246 322.695 407.477 curveto
+321.906 405.781 326.211 404.27 326.219 402.516 curveto
+325.77 401.98 324.508 401.379 323.961 401.379 curveto
+320.859 401.379 318.516 405.625 321.164 408.781 curveto
+320.09 408.094 319.449 407.062 319 406.09 curveto
+316.312 400.344 320.141 394.535 325.719 394.535 curveto
+328.043 394.535 331.035 395.84 332.242 398.422 curveto
+333.949 402.074 327.867 408.52 324.469 408.52 curveto
+ closepath fill
+newpath 332.59 391.262 moveto
+331.062 387.992 328.211 386.195 325.004 386.195 curveto
+314.824 386.195 312.805 395.57 317.215 405.012 curveto
+318.258 407.238 319.969 409.703 322.578 409.703 curveto
+330.758 409.703 336.453 399.531 332.59 391.262 curveto
+ closepath stroke
+newpath 324.469 408.52 moveto
+323.715 408.52 323.059 408.246 322.695 407.477 curveto
+321.906 405.781 326.211 404.27 326.219 402.516 curveto
+325.77 401.98 324.508 401.379 323.961 401.379 curveto
+320.859 401.379 318.516 405.625 321.164 408.781 curveto
+320.09 408.094 319.449 407.062 319 406.09 curveto
+316.312 400.344 320.141 394.535 325.719 394.535 curveto
+328.043 394.535 331.035 395.84 332.242 398.422 curveto
+333.949 402.074 327.867 408.52 324.469 408.52 curveto
+ closepath stroke
+newpath 343.121 408.574 moveto
+351.891 408.574 356.352 392.316 352.43 383.93 curveto
+351.68 382.324 350.285 380.723 348.441 380.723 curveto
+338.418 380.723 340.977 400.848 335.332 406.562 curveto
+335.852 407.117 336.344 407.695 336.797 408.277 curveto
+340.609 403.758 338.715 391.867 346.859 391.867 curveto
+348.734 391.867 350.156 393.523 350.91 395.145 curveto
+352.934 399.473 349.191 406.984 345.098 406.984 curveto
+345.055 406.984 344.465 406.961 344.48 406.719 curveto
+344.629 403.957 346.781 405.68 344.617 400.98 curveto
+342.402 401.426 340.059 405.016 341.266 407.605 curveto
+341.625 408.363 342.516 408.574 343.121 408.574 curveto
+ closepath fill
+newpath 343.121 408.574 moveto
+351.891 408.574 356.352 392.316 352.43 383.93 curveto
+351.68 382.324 350.285 380.723 348.441 380.723 curveto
+338.418 380.723 340.977 400.848 335.332 406.562 curveto
+335.852 407.117 336.344 407.695 336.797 408.277 curveto
+340.609 403.758 338.715 391.867 346.859 391.867 curveto
+348.734 391.867 350.156 393.523 350.91 395.145 curveto
+352.934 399.473 349.191 406.984 345.098 406.984 curveto
+345.055 406.984 344.465 406.961 344.48 406.719 curveto
+344.629 403.957 346.781 405.68 344.617 400.98 curveto
+342.402 401.426 340.059 405.016 341.266 407.605 curveto
+341.625 408.363 342.516 408.574 343.121 408.574 curveto
+ closepath stroke
+newpath 364.938 408.758 moveto
+365.762 408.68 367.004 408.754 367.711 408.535 curveto
+367.848 408.496 367.746 408.328 367.766 408.195 curveto
+367.984 406.965 368.32 405.801 368.617 404.613 curveto
+369.758 399.988 370.445 395.238 371.758 390.652 curveto
+373.184 385.66 374.672 380.035 372.945 373.77 curveto
+372.777 373.156 372.551 372.535 372.258 371.91 curveto
+370.301 367.719 353.43 362.887 349.023 362.887 curveto
+348.492 362.887 347.914 363.043 347.656 363.391 curveto
+349.516 364.586 350.68 365.812 351.508 367.586 curveto
+352.504 369.719 352.492 371.711 352.359 373.551 curveto
+352.711 373.344 365.672 373.664 366.141 373.664 curveto
+368.047 373.664 369.684 375.523 370.445 377.16 curveto
+371.852 380.164 371.613 383.23 371.367 385.789 curveto
+371.246 387.066 371.074 388.328 370.84 389.559 curveto
+370.48 391.332 lineto
+370.438 391.531 lineto
+370.391 391.723 lineto
+370.605 391.723 370.414 391.348 370.422 391.156 curveto
+370.555 388.059 370.5 383.738 368.852 380.211 curveto
+368.086 378.574 366.832 376.887 364.91 376.887 curveto
+356.488 376.887 360.723 401.016 353.973 406.75 curveto
+354.348 407.375 354.68 408.016 354.961 408.645 curveto
+358.953 403.773 359.164 390.34 365.047 390.34 curveto
+366.473 390.34 367.945 391.691 368.555 392.988 curveto
+371.168 398.578 366.824 405.086 364.938 408.758 curveto
+ closepath fill
+newpath 364.938 408.758 moveto
+365.762 408.68 367.004 408.754 367.711 408.535 curveto
+367.848 408.496 367.746 408.328 367.766 408.195 curveto
+367.984 406.965 368.32 405.801 368.617 404.613 curveto
+369.758 399.988 370.445 395.238 371.758 390.652 curveto
+373.184 385.66 374.672 380.035 372.945 373.77 curveto
+372.777 373.156 372.551 372.535 372.258 371.91 curveto
+370.301 367.719 353.43 362.887 349.023 362.887 curveto
+348.492 362.887 347.914 363.043 347.656 363.391 curveto
+349.516 364.586 350.68 365.812 351.508 367.586 curveto
+352.504 369.719 352.492 371.711 352.359 373.551 curveto
+352.711 373.344 365.672 373.664 366.141 373.664 curveto
+368.047 373.664 369.684 375.523 370.445 377.16 curveto
+371.852 380.164 371.613 383.23 371.367 385.789 curveto
+371.246 387.066 371.074 388.328 370.84 389.559 curveto
+370.48 391.332 lineto
+370.438 391.531 lineto
+370.391 391.723 lineto
+370.605 391.723 370.414 391.348 370.422 391.156 curveto
+370.555 388.059 370.5 383.738 368.852 380.211 curveto
+368.086 378.574 366.832 376.887 364.91 376.887 curveto
+356.488 376.887 360.723 401.016 353.973 406.75 curveto
+354.348 407.375 354.68 408.016 354.961 408.645 curveto
+358.953 403.773 359.164 390.34 365.047 390.34 curveto
+366.473 390.34 367.945 391.691 368.555 392.988 curveto
+371.168 398.578 366.824 405.086 364.938 408.758 curveto
+ closepath stroke
+newpath 261.176 428.469 moveto
+266.969 428.469 263.594 413.848 261.531 409.438 curveto
+259.77 405.664 255.797 400.219 251.086 400.219 curveto
+245.441 400.219 245.609 406.605 247.855 411.418 curveto
+249.074 414.02 250.945 416.941 253.52 419.086 curveto
+252.863 416.848 255.094 415.316 254.191 413.387 curveto
+253.574 412.066 252.301 410.629 251.637 409.211 curveto
+250.566 406.918 250.973 402.852 253.562 402.852 curveto
+255.879 402.852 257.938 405.75 258.785 407.555 curveto
+260.512 411.254 264.836 427.043 260.004 427.043 curveto
+254.438 427.043 244.844 413.344 242.836 409.047 curveto
+239.25 401.375 241.852 391.93 250.02 391.93 curveto
+255.539 391.93 260.078 397.289 262.27 401.98 curveto
+263.578 404.773 264.289 407.555 264.57 410.176 curveto
+265.641 410.375 lineto
+265.879 403.156 273.438 391.207 270.219 384.32 curveto
+266.102 375.508 253.785 375.586 246.754 372.461 curveto
+245.273 375.953 243.273 379.199 240.453 381.68 curveto
+246.727 383.809 262.137 387.387 265.492 394.559 curveto
+266.898 397.57 265.941 402.566 264.312 404.258 curveto
+264.035 403.195 263.652 402.109 263.145 401.02 curveto
+260.273 394.883 254.129 390.121 247.793 390.121 curveto
+238.977 390.121 235.238 396.52 239.387 405.398 curveto
+241.879 410.73 254.598 428.469 261.176 428.469 curveto
+ closepath fill
+ 0 0.8128 dtransform truncate idtransform setlinewidth pop 0 setlinejoin
+newpath 261.176 428.469 moveto
+266.969 428.469 263.594 413.848 261.531 409.438 curveto
+259.77 405.664 255.797 400.219 251.086 400.219 curveto
+245.441 400.219 245.609 406.605 247.855 411.418 curveto
+249.074 414.02 250.945 416.941 253.52 419.086 curveto
+252.863 416.848 255.094 415.316 254.191 413.387 curveto
+253.574 412.066 252.301 410.629 251.637 409.211 curveto
+250.566 406.918 250.973 402.852 253.562 402.852 curveto
+255.879 402.852 257.938 405.75 258.785 407.555 curveto
+260.512 411.254 264.836 427.043 260.004 427.043 curveto
+254.438 427.043 244.844 413.344 242.836 409.047 curveto
+239.25 401.375 241.852 391.93 250.02 391.93 curveto
+255.539 391.93 260.078 397.289 262.27 401.98 curveto
+263.578 404.773 264.289 407.555 264.57 410.176 curveto
+265.641 410.375 lineto
+265.879 403.156 273.438 391.207 270.219 384.32 curveto
+266.102 375.508 253.785 375.586 246.754 372.461 curveto
+245.273 375.953 243.273 379.199 240.453 381.68 curveto
+246.727 383.809 262.137 387.387 265.492 394.559 curveto
+266.898 397.57 265.941 402.566 264.312 404.258 curveto
+264.035 403.195 263.652 402.109 263.145 401.02 curveto
+260.273 394.883 254.129 390.121 247.793 390.121 curveto
+238.977 390.121 235.238 396.52 239.387 405.398 curveto
+241.879 410.73 254.598 428.469 261.176 428.469 curveto
+ closepath stroke
+newpath 276.242 407.305 moveto
+276.594 406.434 277.609 401.512 278.379 401.512 curveto
+280.039 401.512 283.039 406.078 283.848 407.262 curveto
+285.324 406.285 284.504 404.234 287.242 404.234 curveto
+288.48 404.234 289.105 406.93 290.395 406.973 curveto
+290.441 405.883 290.508 404.898 289.922 403.641 curveto
+289.012 401.699 286.719 399.066 284.461 399.066 curveto
+282.844 399.066 280.594 401.031 280.152 401.031 curveto
+279.672 401.031 278.789 400.805 278.508 400.203 curveto
+277.332 397.691 280.477 389.297 283.625 389.297 curveto
+285.309 389.297 287.316 390.543 289.078 391.312 curveto
+288.621 388.289 288.559 385.738 289.164 383.133 curveto
+287.559 382.109 285.68 381.676 284.172 381.676 curveto
+276.43 381.676 280.699 399.859 273.559 403.734 curveto
+276.242 407.305 lineto
+ closepath fill
+newpath 276.242 407.305 moveto
+276.594 406.434 277.609 401.512 278.379 401.512 curveto
+280.039 401.512 283.039 406.078 283.848 407.262 curveto
+285.324 406.285 284.504 404.234 287.242 404.234 curveto
+288.48 404.234 289.105 406.93 290.395 406.973 curveto
+290.441 405.883 290.508 404.898 289.922 403.641 curveto
+289.012 401.699 286.719 399.066 284.461 399.066 curveto
+282.844 399.066 280.594 401.031 280.152 401.031 curveto
+279.672 401.031 278.789 400.805 278.508 400.203 curveto
+277.332 397.691 280.477 389.297 283.625 389.297 curveto
+285.309 389.297 287.316 390.543 289.078 391.312 curveto
+288.621 388.289 288.559 385.738 289.164 383.133 curveto
+287.559 382.109 285.68 381.676 284.172 381.676 curveto
+276.43 381.676 280.699 399.859 273.559 403.734 curveto
+276.242 407.305 lineto
+ closepath stroke
+newpath 306 408.762 moveto
+311.852 408.762 314.16 398.133 311.535 392.516 curveto
+309.5 388.16 305.887 385 301.262 385 curveto
+293.09 385 294.113 396.246 297.301 403.066 curveto
+298.18 404.945 301.184 409.039 303.531 409.039 curveto
+304.395 409.039 305.113 408.762 306 408.762 curveto
+ closepath fill
+newpath 305.816 407.77 moveto
+304.898 407.77 304.086 407.309 303.66 406.395 curveto
+302.762 404.477 307.234 402.535 306.594 401.164 curveto
+306.188 400.301 304.652 399.492 303.875 399.492 curveto
+299.996 399.492 300.031 404.586 302.34 407.906 curveto
+300.906 406.98 299.961 405.57 299.352 404.258 curveto
+297.078 399.398 298.883 392.711 304.066 392.711 curveto
+306.934 392.711 310.23 395.312 311.512 398.055 curveto
+313.094 401.43 309.059 407.77 305.816 407.77 curveto
+ closepath fill
+newpath 306 408.762 moveto
+311.852 408.762 314.16 398.133 311.535 392.516 curveto
+309.5 388.16 305.887 385 301.262 385 curveto
+293.09 385 294.113 396.246 297.301 403.066 curveto
+298.18 404.945 301.184 409.039 303.531 409.039 curveto
+304.395 409.039 305.113 408.762 306 408.762 curveto
+ closepath stroke
+newpath 305.816 407.77 moveto
+304.898 407.77 304.086 407.309 303.66 406.395 curveto
+302.762 404.477 307.234 402.535 306.594 401.164 curveto
+306.188 400.301 304.652 399.492 303.875 399.492 curveto
+299.996 399.492 300.031 404.586 302.34 407.906 curveto
+300.906 406.98 299.961 405.57 299.352 404.258 curveto
+297.078 399.398 298.883 392.711 304.066 392.711 curveto
+306.934 392.711 310.23 395.312 311.512 398.055 curveto
+313.094 401.43 309.059 407.77 305.816 407.77 curveto
+ closepath stroke
+newpath 332.59 391.262 moveto
+331.062 387.992 328.211 386.195 325.004 386.195 curveto
+314.824 386.195 312.805 395.57 317.215 405.012 curveto
+318.258 407.238 319.969 409.703 322.578 409.703 curveto
+330.758 409.703 336.453 399.531 332.59 391.262 curveto
+ closepath fill
+newpath 324.469 408.52 moveto
+323.715 408.52 323.059 408.246 322.695 407.477 curveto
+321.906 405.781 326.211 404.27 326.219 402.516 curveto
+325.77 401.98 324.508 401.379 323.961 401.379 curveto
+320.859 401.379 318.516 405.625 321.164 408.781 curveto
+320.09 408.094 319.449 407.062 319 406.09 curveto
+316.312 400.344 320.141 394.535 325.719 394.535 curveto
+328.043 394.535 331.035 395.84 332.242 398.422 curveto
+333.949 402.074 327.867 408.52 324.469 408.52 curveto
+ closepath fill
+newpath 332.59 391.262 moveto
+331.062 387.992 328.211 386.195 325.004 386.195 curveto
+314.824 386.195 312.805 395.57 317.215 405.012 curveto
+318.258 407.238 319.969 409.703 322.578 409.703 curveto
+330.758 409.703 336.453 399.531 332.59 391.262 curveto
+ closepath stroke
+newpath 324.469 408.52 moveto
+323.715 408.52 323.059 408.246 322.695 407.477 curveto
+321.906 405.781 326.211 404.27 326.219 402.516 curveto
+325.77 401.98 324.508 401.379 323.961 401.379 curveto
+320.859 401.379 318.516 405.625 321.164 408.781 curveto
+320.09 408.094 319.449 407.062 319 406.09 curveto
+316.312 400.344 320.141 394.535 325.719 394.535 curveto
+328.043 394.535 331.035 395.84 332.242 398.422 curveto
+333.949 402.074 327.867 408.52 324.469 408.52 curveto
+ closepath stroke
+newpath 343.121 408.574 moveto
+351.891 408.574 356.352 392.316 352.43 383.93 curveto
+351.68 382.324 350.285 380.723 348.441 380.723 curveto
+338.418 380.723 340.977 400.848 335.332 406.562 curveto
+335.852 407.117 336.344 407.695 336.797 408.277 curveto
+340.609 403.758 338.715 391.867 346.859 391.867 curveto
+348.734 391.867 350.156 393.523 350.91 395.145 curveto
+352.934 399.473 349.191 406.984 345.098 406.984 curveto
+345.055 406.984 344.465 406.961 344.48 406.719 curveto
+344.629 403.957 346.781 405.68 344.617 400.98 curveto
+342.402 401.426 340.059 405.016 341.266 407.605 curveto
+341.625 408.363 342.516 408.574 343.121 408.574 curveto
+ closepath fill
+newpath 343.121 408.574 moveto
+351.891 408.574 356.352 392.316 352.43 383.93 curveto
+351.68 382.324 350.285 380.723 348.441 380.723 curveto
+338.418 380.723 340.977 400.848 335.332 406.562 curveto
+335.852 407.117 336.344 407.695 336.797 408.277 curveto
+340.609 403.758 338.715 391.867 346.859 391.867 curveto
+348.734 391.867 350.156 393.523 350.91 395.145 curveto
+352.934 399.473 349.191 406.984 345.098 406.984 curveto
+345.055 406.984 344.465 406.961 344.48 406.719 curveto
+344.629 403.957 346.781 405.68 344.617 400.98 curveto
+342.402 401.426 340.059 405.016 341.266 407.605 curveto
+341.625 408.363 342.516 408.574 343.121 408.574 curveto
+ closepath stroke
+newpath 364.938 408.758 moveto
+365.762 408.68 367.004 408.754 367.711 408.535 curveto
+367.848 408.496 367.746 408.328 367.766 408.195 curveto
+367.984 406.965 368.32 405.801 368.617 404.613 curveto
+369.758 399.988 370.445 395.238 371.758 390.652 curveto
+373.184 385.66 374.672 380.035 372.945 373.77 curveto
+372.777 373.156 372.551 372.535 372.258 371.91 curveto
+370.301 367.719 365.262 363.73 360.859 363.73 curveto
+360.32 363.73 359.746 363.883 359.488 364.234 curveto
+361.348 365.426 362.512 366.648 363.344 368.426 curveto
+364.336 370.559 364.32 372.551 364.191 374.387 curveto
+364.543 374.184 365.672 373.664 366.141 373.664 curveto
+368.047 373.664 369.684 375.523 370.445 377.16 curveto
+371.852 380.164 371.613 383.23 371.367 385.789 curveto
+371.246 387.066 371.074 388.328 370.84 389.559 curveto
+370.48 391.332 lineto
+370.438 391.531 lineto
+370.391 391.723 lineto
+370.605 391.723 370.414 391.348 370.422 391.156 curveto
+370.555 388.059 370.5 383.738 368.852 380.211 curveto
+368.086 378.574 366.832 376.887 364.91 376.887 curveto
+356.488 376.887 360.723 401.016 353.973 406.75 curveto
+354.348 407.375 354.68 408.016 354.961 408.645 curveto
+358.953 403.773 359.164 390.34 365.047 390.34 curveto
+366.473 390.34 367.945 391.691 368.555 392.988 curveto
+371.168 398.578 366.824 405.086 364.938 408.758 curveto
+ closepath fill
+newpath 364.938 408.758 moveto
+365.762 408.68 367.004 408.754 367.711 408.535 curveto
+367.848 408.496 367.746 408.328 367.766 408.195 curveto
+367.984 406.965 368.32 405.801 368.617 404.613 curveto
+369.758 399.988 370.445 395.238 371.758 390.652 curveto
+373.184 385.66 374.672 380.035 372.945 373.77 curveto
+372.777 373.156 372.551 372.535 372.258 371.91 curveto
+370.301 367.719 365.262 363.73 360.859 363.73 curveto
+360.32 363.73 359.746 363.883 359.488 364.234 curveto
+361.348 365.426 362.512 366.648 363.344 368.426 curveto
+364.336 370.559 364.32 372.551 364.191 374.387 curveto
+364.543 374.184 365.672 373.664 366.141 373.664 curveto
+368.047 373.664 369.684 375.523 370.445 377.16 curveto
+371.852 380.164 371.613 383.23 371.367 385.789 curveto
+371.246 387.066 371.074 388.328 370.84 389.559 curveto
+370.48 391.332 lineto
+370.438 391.531 lineto
+370.391 391.723 lineto
+370.605 391.723 370.414 391.348 370.422 391.156 curveto
+370.555 388.059 370.5 383.738 368.852 380.211 curveto
+368.086 378.574 366.832 376.887 364.91 376.887 curveto
+356.488 376.887 360.723 401.016 353.973 406.75 curveto
+354.348 407.375 354.68 408.016 354.961 408.645 curveto
+358.953 403.773 359.164 390.34 365.047 390.34 curveto
+366.473 390.34 367.945 391.691 368.555 392.988 curveto
+371.168 398.578 366.824 405.086 364.938 408.758 curveto
+ closepath stroke
+newpath 261.176 428.469 moveto
+266.969 428.469 263.594 413.848 261.531 409.438 curveto
+259.77 405.664 255.797 400.219 251.086 400.219 curveto
+245.441 400.219 245.609 406.605 247.855 411.418 curveto
+249.074 414.02 250.945 416.941 253.52 419.086 curveto
+252.863 416.848 255.094 415.316 254.191 413.387 curveto
+253.574 412.066 252.301 410.629 251.637 409.211 curveto
+250.566 406.918 250.973 402.852 253.562 402.852 curveto
+255.879 402.852 257.938 405.75 258.785 407.555 curveto
+260.512 411.254 264.836 427.043 260.004 427.043 curveto
+254.438 427.043 244.844 413.344 242.836 409.047 curveto
+239.25 401.375 241.852 391.93 250.02 391.93 curveto
+255.539 391.93 260.078 397.289 262.27 401.98 curveto
+263.578 404.773 264.289 407.555 264.57 410.176 curveto
+265.641 410.375 lineto
+265.879 403.156 273.438 391.207 270.219 384.32 curveto
+266.102 375.508 253.785 375.586 246.754 372.461 curveto
+245.273 375.953 243.273 379.199 240.453 381.68 curveto
+246.727 383.809 262.137 387.387 265.492 394.559 curveto
+266.898 397.57 265.941 402.566 264.312 404.258 curveto
+264.035 403.195 263.652 402.109 263.145 401.02 curveto
+260.273 394.883 254.129 390.121 247.793 390.121 curveto
+238.977 390.121 235.238 396.52 239.387 405.398 curveto
+241.879 410.73 254.598 428.469 261.176 428.469 curveto
+ closepath fill
+ 0 9.7534 dtransform truncate idtransform setlinewidth pop 1 setlinejoin
+newpath 261.176 428.469 moveto
+266.969 428.469 263.594 413.848 261.531 409.438 curveto
+259.77 405.664 255.797 400.219 251.086 400.219 curveto
+245.441 400.219 245.609 406.605 247.855 411.418 curveto
+249.074 414.02 250.945 416.941 253.52 419.086 curveto
+252.863 416.848 255.094 415.316 254.191 413.387 curveto
+253.574 412.066 252.301 410.629 251.637 409.211 curveto
+250.566 406.918 250.973 402.852 253.562 402.852 curveto
+255.879 402.852 257.938 405.75 258.785 407.555 curveto
+260.512 411.254 264.836 427.043 260.004 427.043 curveto
+254.438 427.043 244.844 413.344 242.836 409.047 curveto
+239.25 401.375 241.852 391.93 250.02 391.93 curveto
+255.539 391.93 260.078 397.289 262.27 401.98 curveto
+263.578 404.773 264.289 407.555 264.57 410.176 curveto
+265.641 410.375 lineto
+265.879 403.156 273.438 391.207 270.219 384.32 curveto
+266.102 375.508 253.785 375.586 246.754 372.461 curveto
+245.273 375.953 243.273 379.199 240.453 381.68 curveto
+246.727 383.809 262.137 387.387 265.492 394.559 curveto
+266.898 397.57 265.941 402.566 264.312 404.258 curveto
+264.035 403.195 263.652 402.109 263.145 401.02 curveto
+260.273 394.883 254.129 390.121 247.793 390.121 curveto
+238.977 390.121 235.238 396.52 239.387 405.398 curveto
+241.879 410.73 254.598 428.469 261.176 428.469 curveto
+ closepath stroke
+newpath 276.242 407.305 moveto
+276.594 406.434 277.609 401.512 278.379 401.512 curveto
+280.039 401.512 283.039 406.078 283.848 407.262 curveto
+285.324 406.285 284.504 404.234 287.242 404.234 curveto
+288.48 404.234 289.105 406.93 290.395 406.973 curveto
+290.441 405.883 290.508 404.898 289.922 403.641 curveto
+289.012 401.699 286.719 399.066 284.461 399.066 curveto
+282.844 399.066 280.594 401.031 280.152 401.031 curveto
+279.672 401.031 278.789 400.805 278.508 400.203 curveto
+277.332 397.691 280.477 389.297 283.625 389.297 curveto
+285.309 389.297 287.316 390.543 289.078 391.312 curveto
+288.621 388.289 288.559 385.738 289.164 383.133 curveto
+287.559 382.109 285.68 381.676 284.172 381.676 curveto
+276.43 381.676 280.699 399.859 273.559 403.734 curveto
+276.242 407.305 lineto
+ closepath fill
+newpath 276.242 407.305 moveto
+276.594 406.434 277.609 401.512 278.379 401.512 curveto
+280.039 401.512 283.039 406.078 283.848 407.262 curveto
+285.324 406.285 284.504 404.234 287.242 404.234 curveto
+288.48 404.234 289.105 406.93 290.395 406.973 curveto
+290.441 405.883 290.508 404.898 289.922 403.641 curveto
+289.012 401.699 286.719 399.066 284.461 399.066 curveto
+282.844 399.066 280.594 401.031 280.152 401.031 curveto
+279.672 401.031 278.789 400.805 278.508 400.203 curveto
+277.332 397.691 280.477 389.297 283.625 389.297 curveto
+285.309 389.297 287.316 390.543 289.078 391.312 curveto
+288.621 388.289 288.559 385.738 289.164 383.133 curveto
+287.559 382.109 285.68 381.676 284.172 381.676 curveto
+276.43 381.676 280.699 399.859 273.559 403.734 curveto
+276.242 407.305 lineto
+ closepath stroke
+newpath 306 408.762 moveto
+311.852 408.762 314.16 398.133 311.535 392.516 curveto
+309.5 388.16 305.887 385 301.262 385 curveto
+293.09 385 294.113 396.246 297.301 403.066 curveto
+298.18 404.945 301.184 409.039 303.531 409.039 curveto
+304.395 409.039 305.113 408.762 306 408.762 curveto
+ closepath fill
+newpath 305.816 407.77 moveto
+304.898 407.77 304.086 407.309 303.66 406.395 curveto
+302.762 404.477 307.234 402.535 306.594 401.164 curveto
+306.188 400.301 304.652 399.492 303.875 399.492 curveto
+299.996 399.492 300.031 404.586 302.34 407.906 curveto
+300.906 406.98 299.961 405.57 299.352 404.258 curveto
+297.078 399.398 298.883 392.711 304.066 392.711 curveto
+306.934 392.711 310.23 395.312 311.512 398.055 curveto
+313.094 401.43 309.059 407.77 305.816 407.77 curveto
+ closepath fill
+newpath 306 408.762 moveto
+311.852 408.762 314.16 398.133 311.535 392.516 curveto
+309.5 388.16 305.887 385 301.262 385 curveto
+293.09 385 294.113 396.246 297.301 403.066 curveto
+298.18 404.945 301.184 409.039 303.531 409.039 curveto
+304.395 409.039 305.113 408.762 306 408.762 curveto
+ closepath stroke
+newpath 305.816 407.77 moveto
+304.898 407.77 304.086 407.309 303.66 406.395 curveto
+302.762 404.477 307.234 402.535 306.594 401.164 curveto
+306.188 400.301 304.652 399.492 303.875 399.492 curveto
+299.996 399.492 300.031 404.586 302.34 407.906 curveto
+300.906 406.98 299.961 405.57 299.352 404.258 curveto
+297.078 399.398 298.883 392.711 304.066 392.711 curveto
+306.934 392.711 310.23 395.312 311.512 398.055 curveto
+313.094 401.43 309.059 407.77 305.816 407.77 curveto
+ closepath stroke
+newpath 332.59 391.262 moveto
+331.062 387.992 328.211 386.195 325.004 386.195 curveto
+314.824 386.195 312.805 395.57 317.215 405.012 curveto
+318.258 407.238 319.969 409.703 322.578 409.703 curveto
+330.758 409.703 336.453 399.531 332.59 391.262 curveto
+ closepath fill
+newpath 324.469 408.52 moveto
+323.715 408.52 323.059 408.246 322.695 407.477 curveto
+321.906 405.781 326.211 404.27 326.219 402.516 curveto
+325.77 401.98 324.508 401.379 323.961 401.379 curveto
+320.859 401.379 318.516 405.625 321.164 408.781 curveto
+320.09 408.094 319.449 407.062 319 406.09 curveto
+316.312 400.344 320.141 394.535 325.719 394.535 curveto
+328.043 394.535 331.035 395.84 332.242 398.422 curveto
+333.949 402.074 327.867 408.52 324.469 408.52 curveto
+ closepath fill
+newpath 332.59 391.262 moveto
+331.062 387.992 328.211 386.195 325.004 386.195 curveto
+314.824 386.195 312.805 395.57 317.215 405.012 curveto
+318.258 407.238 319.969 409.703 322.578 409.703 curveto
+330.758 409.703 336.453 399.531 332.59 391.262 curveto
+ closepath stroke
+newpath 324.469 408.52 moveto
+323.715 408.52 323.059 408.246 322.695 407.477 curveto
+321.906 405.781 326.211 404.27 326.219 402.516 curveto
+325.77 401.98 324.508 401.379 323.961 401.379 curveto
+320.859 401.379 318.516 405.625 321.164 408.781 curveto
+320.09 408.094 319.449 407.062 319 406.09 curveto
+316.312 400.344 320.141 394.535 325.719 394.535 curveto
+328.043 394.535 331.035 395.84 332.242 398.422 curveto
+333.949 402.074 327.867 408.52 324.469 408.52 curveto
+ closepath stroke
+newpath 343.121 408.574 moveto
+351.891 408.574 356.352 392.316 352.43 383.93 curveto
+351.68 382.324 350.285 380.723 348.441 380.723 curveto
+338.418 380.723 340.977 400.848 335.332 406.562 curveto
+335.852 407.117 336.344 407.695 336.797 408.277 curveto
+340.609 403.758 338.715 391.867 346.859 391.867 curveto
+348.734 391.867 350.156 393.523 350.91 395.145 curveto
+352.934 399.473 349.191 406.984 345.098 406.984 curveto
+345.055 406.984 344.465 406.961 344.48 406.719 curveto
+344.629 403.957 346.781 405.68 344.617 400.98 curveto
+342.402 401.426 340.059 405.016 341.266 407.605 curveto
+341.625 408.363 342.516 408.574 343.121 408.574 curveto
+ closepath fill
+newpath 343.121 408.574 moveto
+351.891 408.574 356.352 392.316 352.43 383.93 curveto
+351.68 382.324 350.285 380.723 348.441 380.723 curveto
+338.418 380.723 340.977 400.848 335.332 406.562 curveto
+335.852 407.117 336.344 407.695 336.797 408.277 curveto
+340.609 403.758 338.715 391.867 346.859 391.867 curveto
+348.734 391.867 350.156 393.523 350.91 395.145 curveto
+352.934 399.473 349.191 406.984 345.098 406.984 curveto
+345.055 406.984 344.465 406.961 344.48 406.719 curveto
+344.629 403.957 346.781 405.68 344.617 400.98 curveto
+342.402 401.426 340.059 405.016 341.266 407.605 curveto
+341.625 408.363 342.516 408.574 343.121 408.574 curveto
+ closepath stroke
+newpath 364.938 408.758 moveto
+365.762 408.68 367.004 408.754 367.711 408.535 curveto
+367.848 408.496 367.746 408.328 367.766 408.195 curveto
+367.984 406.965 368.32 405.801 368.617 404.613 curveto
+369.758 399.988 370.445 395.238 371.758 390.652 curveto
+373.184 385.66 374.672 380.035 372.945 373.77 curveto
+372.777 373.156 372.551 372.535 372.258 371.91 curveto
+370.301 367.719 365.262 363.73 360.859 363.73 curveto
+360.32 363.73 359.746 363.883 359.488 364.234 curveto
+361.348 365.426 362.512 366.648 363.344 368.426 curveto
+364.336 370.559 364.32 372.551 364.191 374.387 curveto
+364.543 374.184 365.672 373.664 366.141 373.664 curveto
+368.047 373.664 369.684 375.523 370.445 377.16 curveto
+371.852 380.164 371.613 383.23 371.367 385.789 curveto
+371.246 387.066 371.074 388.328 370.84 389.559 curveto
+370.48 391.332 lineto
+370.438 391.531 lineto
+370.391 391.723 lineto
+370.605 391.723 370.414 391.348 370.422 391.156 curveto
+370.555 388.059 370.5 383.738 368.852 380.211 curveto
+368.086 378.574 366.832 376.887 364.91 376.887 curveto
+356.488 376.887 360.723 401.016 353.973 406.75 curveto
+354.348 407.375 354.68 408.016 354.961 408.645 curveto
+358.953 403.773 359.164 390.34 365.047 390.34 curveto
+366.473 390.34 367.945 391.691 368.555 392.988 curveto
+371.168 398.578 366.824 405.086 364.938 408.758 curveto
+ closepath fill
+newpath 364.938 408.758 moveto
+365.762 408.68 367.004 408.754 367.711 408.535 curveto
+367.848 408.496 367.746 408.328 367.766 408.195 curveto
+367.984 406.965 368.32 405.801 368.617 404.613 curveto
+369.758 399.988 370.445 395.238 371.758 390.652 curveto
+373.184 385.66 374.672 380.035 372.945 373.77 curveto
+372.777 373.156 372.551 372.535 372.258 371.91 curveto
+370.301 367.719 365.262 363.73 360.859 363.73 curveto
+360.32 363.73 359.746 363.883 359.488 364.234 curveto
+361.348 365.426 362.512 366.648 363.344 368.426 curveto
+364.336 370.559 364.32 372.551 364.191 374.387 curveto
+364.543 374.184 365.672 373.664 366.141 373.664 curveto
+368.047 373.664 369.684 375.523 370.445 377.16 curveto
+371.852 380.164 371.613 383.23 371.367 385.789 curveto
+371.246 387.066 371.074 388.328 370.84 389.559 curveto
+370.48 391.332 lineto
+370.438 391.531 lineto
+370.391 391.723 lineto
+370.605 391.723 370.414 391.348 370.422 391.156 curveto
+370.555 388.059 370.5 383.738 368.852 380.211 curveto
+368.086 378.574 366.832 376.887 364.91 376.887 curveto
+356.488 376.887 360.723 401.016 353.973 406.75 curveto
+354.348 407.375 354.68 408.016 354.961 408.645 curveto
+358.953 403.773 359.164 390.34 365.047 390.34 curveto
+366.473 390.34 367.945 391.691 368.555 392.988 curveto
+371.168 398.578 366.824 405.086 364.938 408.758 curveto
+ closepath stroke
+ 1 setgray
+newpath 261.176 428.469 moveto
+266.969 428.469 263.594 413.848 261.531 409.438 curveto
+259.77 405.664 255.797 400.219 251.086 400.219 curveto
+245.441 400.219 245.609 406.605 247.855 411.418 curveto
+249.074 414.02 250.945 416.941 253.52 419.086 curveto
+252.863 416.848 255.094 415.316 254.191 413.387 curveto
+253.574 412.066 252.301 410.629 251.637 409.211 curveto
+250.566 406.918 250.973 402.852 253.562 402.852 curveto
+255.879 402.852 257.938 405.75 258.785 407.555 curveto
+260.512 411.254 264.836 427.043 260.004 427.043 curveto
+254.438 427.043 244.844 413.344 242.836 409.047 curveto
+239.25 401.375 241.852 391.93 250.02 391.93 curveto
+255.539 391.93 260.078 397.289 262.27 401.98 curveto
+263.578 404.773 264.289 407.555 264.57 410.176 curveto
+265.641 410.375 lineto
+265.879 403.156 273.438 391.207 270.219 384.32 curveto
+266.102 375.508 253.785 375.586 246.754 372.461 curveto
+245.273 375.953 243.273 379.199 240.453 381.68 curveto
+246.727 383.809 262.137 387.387 265.492 394.559 curveto
+266.898 397.57 265.941 402.566 264.312 404.258 curveto
+264.035 403.195 263.652 402.109 263.145 401.02 curveto
+260.273 394.883 254.129 390.121 247.793 390.121 curveto
+238.977 390.121 235.238 396.52 239.387 405.398 curveto
+241.879 410.73 254.598 428.469 261.176 428.469 curveto
+ closepath fill
+newpath 276.242 407.305 moveto
+276.594 406.434 277.609 401.512 278.379 401.512 curveto
+280.039 401.512 283.039 406.078 283.848 407.262 curveto
+285.324 406.285 284.504 404.234 287.242 404.234 curveto
+288.48 404.234 289.105 406.93 290.395 406.973 curveto
+290.441 405.883 290.508 404.898 289.922 403.641 curveto
+289.012 401.699 286.719 399.066 284.461 399.066 curveto
+282.844 399.066 280.594 401.031 280.152 401.031 curveto
+279.672 401.031 278.789 400.805 278.508 400.203 curveto
+277.332 397.691 280.477 389.297 283.625 389.297 curveto
+285.309 389.297 287.316 390.543 289.078 391.312 curveto
+288.621 388.289 288.559 385.738 289.164 383.133 curveto
+287.559 382.109 285.68 381.676 284.172 381.676 curveto
+276.43 381.676 280.699 399.859 273.559 403.734 curveto
+276.242 407.305 lineto
+ closepath fill
+newpath 306 408.762 moveto
+311.852 408.762 314.16 398.133 311.535 392.516 curveto
+309.5 388.16 305.887 385 301.262 385 curveto
+293.09 385 294.113 396.246 297.301 403.066 curveto
+298.18 404.945 301.184 409.039 303.531 409.039 curveto
+304.395 409.039 305.113 408.762 306 408.762 curveto
+ closepath fill
+newpath 305.816 407.77 moveto
+304.898 407.77 304.086 407.309 303.66 406.395 curveto
+302.762 404.477 307.234 402.535 306.594 401.164 curveto
+306.188 400.301 304.652 399.492 303.875 399.492 curveto
+299.996 399.492 300.031 404.586 302.34 407.906 curveto
+300.906 406.98 299.961 405.57 299.352 404.258 curveto
+297.078 399.398 298.883 392.711 304.066 392.711 curveto
+306.934 392.711 310.23 395.312 311.512 398.055 curveto
+313.094 401.43 309.059 407.77 305.816 407.77 curveto
+ closepath fill
+newpath 332.59 391.262 moveto
+331.062 387.992 328.211 386.195 325.004 386.195 curveto
+314.824 386.195 312.805 395.57 317.215 405.012 curveto
+318.258 407.238 319.969 409.703 322.578 409.703 curveto
+330.758 409.703 336.453 399.531 332.59 391.262 curveto
+ closepath fill
+newpath 324.469 408.52 moveto
+323.715 408.52 323.059 408.246 322.695 407.477 curveto
+321.906 405.781 326.211 404.27 326.219 402.516 curveto
+325.77 401.98 324.508 401.379 323.961 401.379 curveto
+320.859 401.379 318.516 405.625 321.164 408.781 curveto
+320.09 408.094 319.449 407.062 319 406.09 curveto
+316.312 400.344 320.141 394.535 325.719 394.535 curveto
+328.043 394.535 331.035 395.84 332.242 398.422 curveto
+333.949 402.074 327.867 408.52 324.469 408.52 curveto
+ closepath fill
+newpath 343.121 408.574 moveto
+351.891 408.574 356.352 392.316 352.43 383.93 curveto
+351.68 382.324 350.285 380.723 348.441 380.723 curveto
+338.418 380.723 340.977 400.848 335.332 406.562 curveto
+335.852 407.117 336.344 407.695 336.797 408.277 curveto
+340.609 403.758 338.715 391.867 346.859 391.867 curveto
+348.734 391.867 350.156 393.523 350.91 395.145 curveto
+352.934 399.473 349.191 406.984 345.098 406.984 curveto
+345.055 406.984 344.465 406.961 344.48 406.719 curveto
+344.629 403.957 346.781 405.68 344.617 400.98 curveto
+342.402 401.426 340.059 405.016 341.266 407.605 curveto
+341.625 408.363 342.516 408.574 343.121 408.574 curveto
+ closepath fill
+newpath 364.938 408.758 moveto
+365.762 408.68 367.004 408.754 367.711 408.535 curveto
+367.848 408.496 367.746 408.328 367.766 408.195 curveto
+367.984 406.965 368.32 405.801 368.617 404.613 curveto
+369.758 399.988 370.445 395.238 371.758 390.652 curveto
+373.184 385.66 374.672 380.035 372.945 373.77 curveto
+372.777 373.156 372.551 372.535 372.258 371.91 curveto
+365.691 359.168 351.629 362.602 347.227 362.602 curveto
+346.691 362.602 346.113 362.754 345.859 363.105 curveto
+347.715 364.301 348.879 365.523 349.711 367.301 curveto
+350.703 369.43 350.691 371.426 350.559 373.262 curveto
+350.914 373.055 352.043 372.539 352.508 372.539 curveto
+354.414 372.539 365.035 367.027 370.445 377.16 curveto
+371.852 380.164 371.613 383.23 371.367 385.789 curveto
+371.246 387.066 371.074 388.328 370.84 389.559 curveto
+370.48 391.332 lineto
+370.438 391.531 lineto
+370.391 391.723 lineto
+370.605 391.723 370.414 391.348 370.422 391.156 curveto
+370.555 388.059 370.5 383.738 368.852 380.211 curveto
+368.086 378.574 366.832 376.887 364.91 376.887 curveto
+356.488 376.887 360.723 401.016 353.973 406.75 curveto
+354.348 407.375 354.68 408.016 354.961 408.645 curveto
+358.953 403.773 359.164 390.34 365.047 390.34 curveto
+366.473 390.34 367.945 391.691 368.555 392.988 curveto
+371.168 398.578 366.824 405.086 364.938 408.758 curveto
+ closepath fill
+ 0 setgray
+newpath 372.793 340.699 moveto
+305.645 366.988 lineto
+238.5 340.707 lineto
+265.012 382.602 lineto
+197 408.258 lineto
+280.531 407.863 lineto
+305.641 450 lineto
+330.754 407.859 lineto
+414.289 408.246 lineto
+346.277 382.598 lineto
+372.793 340.699 lineto
+ closepath fill
+ 0.35832 0.70496 0.749 setrgbcolor
+newpath 363.707 348.195 moveto
+305.703 370.902 lineto
+247.699 348.199 lineto
+270.602 384.391 lineto
+211.848 406.551 lineto
+284.008 406.211 lineto
+305.699 442.609 lineto
+327.395 406.211 lineto
+399.559 406.543 lineto
+340.805 384.387 lineto
+363.707 348.195 lineto
+ closepath fill
+ 0 setgray
+newpath 261.176 428.469 moveto
+266.969 428.469 263.594 413.848 261.531 409.438 curveto
+259.77 405.664 255.797 400.219 251.086 400.219 curveto
+245.441 400.219 245.609 406.605 247.855 411.418 curveto
+249.074 414.02 250.945 416.941 253.52 419.086 curveto
+252.863 416.848 255.094 415.316 254.191 413.387 curveto
+253.574 412.066 252.301 410.629 251.637 409.211 curveto
+250.566 406.918 250.973 402.852 253.562 402.852 curveto
+255.879 402.852 257.938 405.75 258.785 407.555 curveto
+260.512 411.254 264.836 427.043 260.004 427.043 curveto
+254.438 427.043 244.844 413.344 242.836 409.047 curveto
+239.25 401.375 241.852 391.93 250.02 391.93 curveto
+255.539 391.93 260.078 397.289 262.27 401.98 curveto
+263.578 404.773 264.289 407.555 264.57 410.176 curveto
+265.641 410.375 lineto
+265.879 403.156 273.438 391.207 270.219 384.32 curveto
+266.102 375.508 253.785 375.586 246.754 372.461 curveto
+245.273 375.953 243.273 379.199 240.453 381.68 curveto
+246.727 383.809 262.137 387.387 265.492 394.559 curveto
+266.898 397.57 265.941 402.566 264.312 404.258 curveto
+264.035 403.195 263.652 402.109 263.145 401.02 curveto
+260.273 394.883 254.129 390.121 247.793 390.121 curveto
+238.977 390.121 235.238 396.52 239.387 405.398 curveto
+241.879 410.73 254.598 428.469 261.176 428.469 curveto
+ closepath fill
+newpath 261.176 428.469 moveto
+266.969 428.469 263.594 413.848 261.531 409.438 curveto
+259.77 405.664 255.797 400.219 251.086 400.219 curveto
+245.441 400.219 245.609 406.605 247.855 411.418 curveto
+249.074 414.02 250.945 416.941 253.52 419.086 curveto
+252.863 416.848 255.094 415.316 254.191 413.387 curveto
+253.574 412.066 252.301 410.629 251.637 409.211 curveto
+250.566 406.918 250.973 402.852 253.562 402.852 curveto
+255.879 402.852 257.938 405.75 258.785 407.555 curveto
+260.512 411.254 264.836 427.043 260.004 427.043 curveto
+254.438 427.043 244.844 413.344 242.836 409.047 curveto
+239.25 401.375 241.852 391.93 250.02 391.93 curveto
+255.539 391.93 260.078 397.289 262.27 401.98 curveto
+263.578 404.773 264.289 407.555 264.57 410.176 curveto
+265.641 410.375 lineto
+265.879 403.156 273.438 391.207 270.219 384.32 curveto
+266.102 375.508 253.785 375.586 246.754 372.461 curveto
+245.273 375.953 243.273 379.199 240.453 381.68 curveto
+246.727 383.809 262.137 387.387 265.492 394.559 curveto
+266.898 397.57 265.941 402.566 264.312 404.258 curveto
+264.035 403.195 263.652 402.109 263.145 401.02 curveto
+260.273 394.883 254.129 390.121 247.793 390.121 curveto
+238.977 390.121 235.238 396.52 239.387 405.398 curveto
+241.879 410.73 254.598 428.469 261.176 428.469 curveto
+ closepath stroke
+newpath 276.242 407.305 moveto
+276.594 406.434 277.609 401.512 278.379 401.512 curveto
+280.039 401.512 283.039 406.078 283.848 407.262 curveto
+285.324 406.285 284.504 404.234 287.242 404.234 curveto
+288.48 404.234 289.105 406.93 290.395 406.973 curveto
+290.441 405.883 290.508 404.898 289.922 403.641 curveto
+289.012 401.699 286.719 399.066 284.461 399.066 curveto
+282.844 399.066 280.594 401.031 280.152 401.031 curveto
+279.672 401.031 278.789 400.805 278.508 400.203 curveto
+277.332 397.691 280.477 389.297 283.625 389.297 curveto
+285.309 389.297 287.316 390.543 289.078 391.312 curveto
+288.621 388.289 288.559 385.738 289.164 383.133 curveto
+287.559 382.109 285.68 381.676 284.172 381.676 curveto
+276.43 381.676 280.699 399.859 273.559 403.734 curveto
+276.242 407.305 lineto
+ closepath fill
+newpath 276.242 407.305 moveto
+276.594 406.434 277.609 401.512 278.379 401.512 curveto
+280.039 401.512 283.039 406.078 283.848 407.262 curveto
+285.324 406.285 284.504 404.234 287.242 404.234 curveto
+288.48 404.234 289.105 406.93 290.395 406.973 curveto
+290.441 405.883 290.508 404.898 289.922 403.641 curveto
+289.012 401.699 286.719 399.066 284.461 399.066 curveto
+282.844 399.066 280.594 401.031 280.152 401.031 curveto
+279.672 401.031 278.789 400.805 278.508 400.203 curveto
+277.332 397.691 280.477 389.297 283.625 389.297 curveto
+285.309 389.297 287.316 390.543 289.078 391.312 curveto
+288.621 388.289 288.559 385.738 289.164 383.133 curveto
+287.559 382.109 285.68 381.676 284.172 381.676 curveto
+276.43 381.676 280.699 399.859 273.559 403.734 curveto
+276.242 407.305 lineto
+ closepath stroke
+newpath 306 408.762 moveto
+311.852 408.762 314.16 398.133 311.535 392.516 curveto
+309.5 388.16 305.887 385 301.262 385 curveto
+293.09 385 294.113 396.246 297.301 403.066 curveto
+298.18 404.945 301.184 409.039 303.531 409.039 curveto
+304.395 409.039 305.113 408.762 306 408.762 curveto
+ closepath fill
+newpath 305.816 407.77 moveto
+304.898 407.77 304.086 407.309 303.66 406.395 curveto
+302.762 404.477 307.234 402.535 306.594 401.164 curveto
+306.188 400.301 304.652 399.492 303.875 399.492 curveto
+299.996 399.492 300.031 404.586 302.34 407.906 curveto
+300.906 406.98 299.961 405.57 299.352 404.258 curveto
+297.078 399.398 298.883 392.711 304.066 392.711 curveto
+306.934 392.711 310.23 395.312 311.512 398.055 curveto
+313.094 401.43 309.059 407.77 305.816 407.77 curveto
+ closepath fill
+newpath 306 408.762 moveto
+311.852 408.762 314.16 398.133 311.535 392.516 curveto
+309.5 388.16 305.887 385 301.262 385 curveto
+293.09 385 294.113 396.246 297.301 403.066 curveto
+298.18 404.945 301.184 409.039 303.531 409.039 curveto
+304.395 409.039 305.113 408.762 306 408.762 curveto
+ closepath stroke
+newpath 305.816 407.77 moveto
+304.898 407.77 304.086 407.309 303.66 406.395 curveto
+302.762 404.477 307.234 402.535 306.594 401.164 curveto
+306.188 400.301 304.652 399.492 303.875 399.492 curveto
+299.996 399.492 300.031 404.586 302.34 407.906 curveto
+300.906 406.98 299.961 405.57 299.352 404.258 curveto
+297.078 399.398 298.883 392.711 304.066 392.711 curveto
+306.934 392.711 310.23 395.312 311.512 398.055 curveto
+313.094 401.43 309.059 407.77 305.816 407.77 curveto
+ closepath stroke
+newpath 332.59 391.262 moveto
+331.062 387.992 328.211 386.195 325.004 386.195 curveto
+314.824 386.195 312.805 395.57 317.215 405.012 curveto
+318.258 407.238 319.969 409.703 322.578 409.703 curveto
+330.758 409.703 336.453 399.531 332.59 391.262 curveto
+ closepath fill
+newpath 324.469 408.52 moveto
+323.715 408.52 323.059 408.246 322.695 407.477 curveto
+321.906 405.781 326.211 404.27 326.219 402.516 curveto
+325.77 401.98 324.508 401.379 323.961 401.379 curveto
+320.859 401.379 318.516 405.625 321.164 408.781 curveto
+320.09 408.094 319.449 407.062 319 406.09 curveto
+316.312 400.344 320.141 394.535 325.719 394.535 curveto
+328.043 394.535 331.035 395.84 332.242 398.422 curveto
+333.949 402.074 327.867 408.52 324.469 408.52 curveto
+ closepath fill
+newpath 332.59 391.262 moveto
+331.062 387.992 328.211 386.195 325.004 386.195 curveto
+314.824 386.195 312.805 395.57 317.215 405.012 curveto
+318.258 407.238 319.969 409.703 322.578 409.703 curveto
+330.758 409.703 336.453 399.531 332.59 391.262 curveto
+ closepath stroke
+newpath 324.469 408.52 moveto
+323.715 408.52 323.059 408.246 322.695 407.477 curveto
+321.906 405.781 326.211 404.27 326.219 402.516 curveto
+325.77 401.98 324.508 401.379 323.961 401.379 curveto
+320.859 401.379 318.516 405.625 321.164 408.781 curveto
+320.09 408.094 319.449 407.062 319 406.09 curveto
+316.312 400.344 320.141 394.535 325.719 394.535 curveto
+328.043 394.535 331.035 395.84 332.242 398.422 curveto
+333.949 402.074 327.867 408.52 324.469 408.52 curveto
+ closepath stroke
+newpath 343.121 408.574 moveto
+351.891 408.574 356.352 392.316 352.43 383.93 curveto
+351.68 382.324 350.285 380.723 348.441 380.723 curveto
+338.418 380.723 340.977 400.848 335.332 406.562 curveto
+335.852 407.117 336.344 407.695 336.797 408.277 curveto
+340.609 403.758 338.715 391.867 346.859 391.867 curveto
+348.734 391.867 350.156 393.523 350.91 395.145 curveto
+352.934 399.473 349.191 406.984 345.098 406.984 curveto
+345.055 406.984 344.465 406.961 344.48 406.719 curveto
+344.629 403.957 346.781 405.68 344.617 400.98 curveto
+342.402 401.426 340.059 405.016 341.266 407.605 curveto
+341.625 408.363 342.516 408.574 343.121 408.574 curveto
+ closepath fill
+newpath 343.121 408.574 moveto
+351.891 408.574 356.352 392.316 352.43 383.93 curveto
+351.68 382.324 350.285 380.723 348.441 380.723 curveto
+338.418 380.723 340.977 400.848 335.332 406.562 curveto
+335.852 407.117 336.344 407.695 336.797 408.277 curveto
+340.609 403.758 338.715 391.867 346.859 391.867 curveto
+348.734 391.867 350.156 393.523 350.91 395.145 curveto
+352.934 399.473 349.191 406.984 345.098 406.984 curveto
+345.055 406.984 344.465 406.961 344.48 406.719 curveto
+344.629 403.957 346.781 405.68 344.617 400.98 curveto
+342.402 401.426 340.059 405.016 341.266 407.605 curveto
+341.625 408.363 342.516 408.574 343.121 408.574 curveto
+ closepath stroke
+newpath 364.938 408.758 moveto
+365.762 408.68 367.004 408.754 367.711 408.535 curveto
+367.848 408.496 367.746 408.328 367.766 408.195 curveto
+367.984 406.965 368.32 405.801 368.617 404.613 curveto
+369.758 399.988 370.445 395.238 371.758 390.652 curveto
+373.184 385.66 374.672 380.035 372.945 373.77 curveto
+372.777 373.156 372.551 372.535 372.258 371.91 curveto
+370.301 367.719 353.43 362.887 349.023 362.887 curveto
+348.492 362.887 347.914 363.043 347.656 363.391 curveto
+349.516 364.586 350.68 365.812 351.508 367.586 curveto
+352.504 369.719 352.492 371.711 352.359 373.551 curveto
+352.711 373.344 365.672 373.664 366.141 373.664 curveto
+368.047 373.664 369.684 375.523 370.445 377.16 curveto
+371.852 380.164 371.613 383.23 371.367 385.789 curveto
+371.246 387.066 371.074 388.328 370.84 389.559 curveto
+370.48 391.332 lineto
+370.438 391.531 lineto
+370.391 391.723 lineto
+370.605 391.723 370.414 391.348 370.422 391.156 curveto
+370.555 388.059 370.5 383.738 368.852 380.211 curveto
+368.086 378.574 366.832 376.887 364.91 376.887 curveto
+356.488 376.887 360.723 401.016 353.973 406.75 curveto
+354.348 407.375 354.68 408.016 354.961 408.645 curveto
+358.953 403.773 359.164 390.34 365.047 390.34 curveto
+366.473 390.34 367.945 391.691 368.555 392.988 curveto
+371.168 398.578 366.824 405.086 364.938 408.758 curveto
+ closepath fill
+newpath 364.938 408.758 moveto
+365.762 408.68 367.004 408.754 367.711 408.535 curveto
+367.848 408.496 367.746 408.328 367.766 408.195 curveto
+367.984 406.965 368.32 405.801 368.617 404.613 curveto
+369.758 399.988 370.445 395.238 371.758 390.652 curveto
+373.184 385.66 374.672 380.035 372.945 373.77 curveto
+372.777 373.156 372.551 372.535 372.258 371.91 curveto
+370.301 367.719 353.43 362.887 349.023 362.887 curveto
+348.492 362.887 347.914 363.043 347.656 363.391 curveto
+349.516 364.586 350.68 365.812 351.508 367.586 curveto
+352.504 369.719 352.492 371.711 352.359 373.551 curveto
+352.711 373.344 365.672 373.664 366.141 373.664 curveto
+368.047 373.664 369.684 375.523 370.445 377.16 curveto
+371.852 380.164 371.613 383.23 371.367 385.789 curveto
+371.246 387.066 371.074 388.328 370.84 389.559 curveto
+370.48 391.332 lineto
+370.438 391.531 lineto
+370.391 391.723 lineto
+370.605 391.723 370.414 391.348 370.422 391.156 curveto
+370.555 388.059 370.5 383.738 368.852 380.211 curveto
+368.086 378.574 366.832 376.887 364.91 376.887 curveto
+356.488 376.887 360.723 401.016 353.973 406.75 curveto
+354.348 407.375 354.68 408.016 354.961 408.645 curveto
+358.953 403.773 359.164 390.34 365.047 390.34 curveto
+366.473 390.34 367.945 391.691 368.555 392.988 curveto
+371.168 398.578 366.824 405.086 364.938 408.758 curveto
+ closepath stroke
+newpath 261.176 428.469 moveto
+266.969 428.469 263.594 413.848 261.531 409.438 curveto
+259.77 405.664 255.797 400.219 251.086 400.219 curveto
+245.441 400.219 245.609 406.605 247.855 411.418 curveto
+249.074 414.02 250.945 416.941 253.52 419.086 curveto
+252.863 416.848 255.094 415.316 254.191 413.387 curveto
+253.574 412.066 252.301 410.629 251.637 409.211 curveto
+250.566 406.918 250.973 402.852 253.562 402.852 curveto
+255.879 402.852 257.938 405.75 258.785 407.555 curveto
+260.512 411.254 264.836 427.043 260.004 427.043 curveto
+254.438 427.043 244.844 413.344 242.836 409.047 curveto
+239.25 401.375 241.852 391.93 250.02 391.93 curveto
+255.539 391.93 260.078 397.289 262.27 401.98 curveto
+263.578 404.773 264.289 407.555 264.57 410.176 curveto
+265.641 410.375 lineto
+265.879 403.156 273.438 391.207 270.219 384.32 curveto
+266.102 375.508 253.785 375.586 246.754 372.461 curveto
+245.273 375.953 243.273 379.199 240.453 381.68 curveto
+246.727 383.809 262.137 387.387 265.492 394.559 curveto
+266.898 397.57 265.941 402.566 264.312 404.258 curveto
+264.035 403.195 263.652 402.109 263.145 401.02 curveto
+260.273 394.883 254.129 390.121 247.793 390.121 curveto
+238.977 390.121 235.238 396.52 239.387 405.398 curveto
+241.879 410.73 254.598 428.469 261.176 428.469 curveto
+ closepath fill
+ 0 0.8128 dtransform truncate idtransform setlinewidth pop 0 setlinejoin
+newpath 261.176 428.469 moveto
+266.969 428.469 263.594 413.848 261.531 409.438 curveto
+259.77 405.664 255.797 400.219 251.086 400.219 curveto
+245.441 400.219 245.609 406.605 247.855 411.418 curveto
+249.074 414.02 250.945 416.941 253.52 419.086 curveto
+252.863 416.848 255.094 415.316 254.191 413.387 curveto
+253.574 412.066 252.301 410.629 251.637 409.211 curveto
+250.566 406.918 250.973 402.852 253.562 402.852 curveto
+255.879 402.852 257.938 405.75 258.785 407.555 curveto
+260.512 411.254 264.836 427.043 260.004 427.043 curveto
+254.438 427.043 244.844 413.344 242.836 409.047 curveto
+239.25 401.375 241.852 391.93 250.02 391.93 curveto
+255.539 391.93 260.078 397.289 262.27 401.98 curveto
+263.578 404.773 264.289 407.555 264.57 410.176 curveto
+265.641 410.375 lineto
+265.879 403.156 273.438 391.207 270.219 384.32 curveto
+266.102 375.508 253.785 375.586 246.754 372.461 curveto
+245.273 375.953 243.273 379.199 240.453 381.68 curveto
+246.727 383.809 262.137 387.387 265.492 394.559 curveto
+266.898 397.57 265.941 402.566 264.312 404.258 curveto
+264.035 403.195 263.652 402.109 263.145 401.02 curveto
+260.273 394.883 254.129 390.121 247.793 390.121 curveto
+238.977 390.121 235.238 396.52 239.387 405.398 curveto
+241.879 410.73 254.598 428.469 261.176 428.469 curveto
+ closepath stroke
+newpath 276.242 407.305 moveto
+276.594 406.434 277.609 401.512 278.379 401.512 curveto
+280.039 401.512 283.039 406.078 283.848 407.262 curveto
+285.324 406.285 284.504 404.234 287.242 404.234 curveto
+288.48 404.234 289.105 406.93 290.395 406.973 curveto
+290.441 405.883 290.508 404.898 289.922 403.641 curveto
+289.012 401.699 286.719 399.066 284.461 399.066 curveto
+282.844 399.066 280.594 401.031 280.152 401.031 curveto
+279.672 401.031 278.789 400.805 278.508 400.203 curveto
+277.332 397.691 280.477 389.297 283.625 389.297 curveto
+285.309 389.297 287.316 390.543 289.078 391.312 curveto
+288.621 388.289 288.559 385.738 289.164 383.133 curveto
+287.559 382.109 285.68 381.676 284.172 381.676 curveto
+276.43 381.676 280.699 399.859 273.559 403.734 curveto
+276.242 407.305 lineto
+ closepath fill
+newpath 276.242 407.305 moveto
+276.594 406.434 277.609 401.512 278.379 401.512 curveto
+280.039 401.512 283.039 406.078 283.848 407.262 curveto
+285.324 406.285 284.504 404.234 287.242 404.234 curveto
+288.48 404.234 289.105 406.93 290.395 406.973 curveto
+290.441 405.883 290.508 404.898 289.922 403.641 curveto
+289.012 401.699 286.719 399.066 284.461 399.066 curveto
+282.844 399.066 280.594 401.031 280.152 401.031 curveto
+279.672 401.031 278.789 400.805 278.508 400.203 curveto
+277.332 397.691 280.477 389.297 283.625 389.297 curveto
+285.309 389.297 287.316 390.543 289.078 391.312 curveto
+288.621 388.289 288.559 385.738 289.164 383.133 curveto
+287.559 382.109 285.68 381.676 284.172 381.676 curveto
+276.43 381.676 280.699 399.859 273.559 403.734 curveto
+276.242 407.305 lineto
+ closepath stroke
+newpath 306 408.762 moveto
+311.852 408.762 314.16 398.133 311.535 392.516 curveto
+309.5 388.16 305.887 385 301.262 385 curveto
+293.09 385 294.113 396.246 297.301 403.066 curveto
+298.18 404.945 301.184 409.039 303.531 409.039 curveto
+304.395 409.039 305.113 408.762 306 408.762 curveto
+ closepath fill
+newpath 305.816 407.77 moveto
+304.898 407.77 304.086 407.309 303.66 406.395 curveto
+302.762 404.477 307.234 402.535 306.594 401.164 curveto
+306.188 400.301 304.652 399.492 303.875 399.492 curveto
+299.996 399.492 300.031 404.586 302.34 407.906 curveto
+300.906 406.98 299.961 405.57 299.352 404.258 curveto
+297.078 399.398 298.883 392.711 304.066 392.711 curveto
+306.934 392.711 310.23 395.312 311.512 398.055 curveto
+313.094 401.43 309.059 407.77 305.816 407.77 curveto
+ closepath fill
+newpath 306 408.762 moveto
+311.852 408.762 314.16 398.133 311.535 392.516 curveto
+309.5 388.16 305.887 385 301.262 385 curveto
+293.09 385 294.113 396.246 297.301 403.066 curveto
+298.18 404.945 301.184 409.039 303.531 409.039 curveto
+304.395 409.039 305.113 408.762 306 408.762 curveto
+ closepath stroke
+newpath 305.816 407.77 moveto
+304.898 407.77 304.086 407.309 303.66 406.395 curveto
+302.762 404.477 307.234 402.535 306.594 401.164 curveto
+306.188 400.301 304.652 399.492 303.875 399.492 curveto
+299.996 399.492 300.031 404.586 302.34 407.906 curveto
+300.906 406.98 299.961 405.57 299.352 404.258 curveto
+297.078 399.398 298.883 392.711 304.066 392.711 curveto
+306.934 392.711 310.23 395.312 311.512 398.055 curveto
+313.094 401.43 309.059 407.77 305.816 407.77 curveto
+ closepath stroke
+newpath 332.59 391.262 moveto
+331.062 387.992 328.211 386.195 325.004 386.195 curveto
+314.824 386.195 312.805 395.57 317.215 405.012 curveto
+318.258 407.238 319.969 409.703 322.578 409.703 curveto
+330.758 409.703 336.453 399.531 332.59 391.262 curveto
+ closepath fill
+newpath 324.469 408.52 moveto
+323.715 408.52 323.059 408.246 322.695 407.477 curveto
+321.906 405.781 326.211 404.27 326.219 402.516 curveto
+325.77 401.98 324.508 401.379 323.961 401.379 curveto
+320.859 401.379 318.516 405.625 321.164 408.781 curveto
+320.09 408.094 319.449 407.062 319 406.09 curveto
+316.312 400.344 320.141 394.535 325.719 394.535 curveto
+328.043 394.535 331.035 395.84 332.242 398.422 curveto
+333.949 402.074 327.867 408.52 324.469 408.52 curveto
+ closepath fill
+newpath 332.59 391.262 moveto
+331.062 387.992 328.211 386.195 325.004 386.195 curveto
+314.824 386.195 312.805 395.57 317.215 405.012 curveto
+318.258 407.238 319.969 409.703 322.578 409.703 curveto
+330.758 409.703 336.453 399.531 332.59 391.262 curveto
+ closepath stroke
+newpath 324.469 408.52 moveto
+323.715 408.52 323.059 408.246 322.695 407.477 curveto
+321.906 405.781 326.211 404.27 326.219 402.516 curveto
+325.77 401.98 324.508 401.379 323.961 401.379 curveto
+320.859 401.379 318.516 405.625 321.164 408.781 curveto
+320.09 408.094 319.449 407.062 319 406.09 curveto
+316.312 400.344 320.141 394.535 325.719 394.535 curveto
+328.043 394.535 331.035 395.84 332.242 398.422 curveto
+333.949 402.074 327.867 408.52 324.469 408.52 curveto
+ closepath stroke
+newpath 343.121 408.574 moveto
+351.891 408.574 356.352 392.316 352.43 383.93 curveto
+351.68 382.324 350.285 380.723 348.441 380.723 curveto
+338.418 380.723 340.977 400.848 335.332 406.562 curveto
+335.852 407.117 336.344 407.695 336.797 408.277 curveto
+340.609 403.758 338.715 391.867 346.859 391.867 curveto
+348.734 391.867 350.156 393.523 350.91 395.145 curveto
+352.934 399.473 349.191 406.984 345.098 406.984 curveto
+345.055 406.984 344.465 406.961 344.48 406.719 curveto
+344.629 403.957 346.781 405.68 344.617 400.98 curveto
+342.402 401.426 340.059 405.016 341.266 407.605 curveto
+341.625 408.363 342.516 408.574 343.121 408.574 curveto
+ closepath fill
+newpath 343.121 408.574 moveto
+351.891 408.574 356.352 392.316 352.43 383.93 curveto
+351.68 382.324 350.285 380.723 348.441 380.723 curveto
+338.418 380.723 340.977 400.848 335.332 406.562 curveto
+335.852 407.117 336.344 407.695 336.797 408.277 curveto
+340.609 403.758 338.715 391.867 346.859 391.867 curveto
+348.734 391.867 350.156 393.523 350.91 395.145 curveto
+352.934 399.473 349.191 406.984 345.098 406.984 curveto
+345.055 406.984 344.465 406.961 344.48 406.719 curveto
+344.629 403.957 346.781 405.68 344.617 400.98 curveto
+342.402 401.426 340.059 405.016 341.266 407.605 curveto
+341.625 408.363 342.516 408.574 343.121 408.574 curveto
+ closepath stroke
+newpath 364.938 408.758 moveto
+365.762 408.68 367.004 408.754 367.711 408.535 curveto
+367.848 408.496 367.746 408.328 367.766 408.195 curveto
+367.984 406.965 368.32 405.801 368.617 404.613 curveto
+369.758 399.988 370.445 395.238 371.758 390.652 curveto
+373.184 385.66 374.672 380.035 372.945 373.77 curveto
+372.777 373.156 372.551 372.535 372.258 371.91 curveto
+370.301 367.719 365.262 363.73 360.859 363.73 curveto
+360.32 363.73 359.746 363.883 359.488 364.234 curveto
+361.348 365.426 362.512 366.648 363.344 368.426 curveto
+364.336 370.559 364.32 372.551 364.191 374.387 curveto
+364.543 374.184 365.672 373.664 366.141 373.664 curveto
+368.047 373.664 369.684 375.523 370.445 377.16 curveto
+371.852 380.164 371.613 383.23 371.367 385.789 curveto
+371.246 387.066 371.074 388.328 370.84 389.559 curveto
+370.48 391.332 lineto
+370.438 391.531 lineto
+370.391 391.723 lineto
+370.605 391.723 370.414 391.348 370.422 391.156 curveto
+370.555 388.059 370.5 383.738 368.852 380.211 curveto
+368.086 378.574 366.832 376.887 364.91 376.887 curveto
+356.488 376.887 360.723 401.016 353.973 406.75 curveto
+354.348 407.375 354.68 408.016 354.961 408.645 curveto
+358.953 403.773 359.164 390.34 365.047 390.34 curveto
+366.473 390.34 367.945 391.691 368.555 392.988 curveto
+371.168 398.578 366.824 405.086 364.938 408.758 curveto
+ closepath fill
+newpath 364.938 408.758 moveto
+365.762 408.68 367.004 408.754 367.711 408.535 curveto
+367.848 408.496 367.746 408.328 367.766 408.195 curveto
+367.984 406.965 368.32 405.801 368.617 404.613 curveto
+369.758 399.988 370.445 395.238 371.758 390.652 curveto
+373.184 385.66 374.672 380.035 372.945 373.77 curveto
+372.777 373.156 372.551 372.535 372.258 371.91 curveto
+370.301 367.719 365.262 363.73 360.859 363.73 curveto
+360.32 363.73 359.746 363.883 359.488 364.234 curveto
+361.348 365.426 362.512 366.648 363.344 368.426 curveto
+364.336 370.559 364.32 372.551 364.191 374.387 curveto
+364.543 374.184 365.672 373.664 366.141 373.664 curveto
+368.047 373.664 369.684 375.523 370.445 377.16 curveto
+371.852 380.164 371.613 383.23 371.367 385.789 curveto
+371.246 387.066 371.074 388.328 370.84 389.559 curveto
+370.48 391.332 lineto
+370.438 391.531 lineto
+370.391 391.723 lineto
+370.605 391.723 370.414 391.348 370.422 391.156 curveto
+370.555 388.059 370.5 383.738 368.852 380.211 curveto
+368.086 378.574 366.832 376.887 364.91 376.887 curveto
+356.488 376.887 360.723 401.016 353.973 406.75 curveto
+354.348 407.375 354.68 408.016 354.961 408.645 curveto
+358.953 403.773 359.164 390.34 365.047 390.34 curveto
+366.473 390.34 367.945 391.691 368.555 392.988 curveto
+371.168 398.578 366.824 405.086 364.938 408.758 curveto
+ closepath stroke
+newpath 261.176 428.469 moveto
+266.969 428.469 263.594 413.848 261.531 409.438 curveto
+259.77 405.664 255.797 400.219 251.086 400.219 curveto
+245.441 400.219 245.609 406.605 247.855 411.418 curveto
+249.074 414.02 250.945 416.941 253.52 419.086 curveto
+252.863 416.848 255.094 415.316 254.191 413.387 curveto
+253.574 412.066 252.301 410.629 251.637 409.211 curveto
+250.566 406.918 250.973 402.852 253.562 402.852 curveto
+255.879 402.852 257.938 405.75 258.785 407.555 curveto
+260.512 411.254 264.836 427.043 260.004 427.043 curveto
+254.438 427.043 244.844 413.344 242.836 409.047 curveto
+239.25 401.375 241.852 391.93 250.02 391.93 curveto
+255.539 391.93 260.078 397.289 262.27 401.98 curveto
+263.578 404.773 264.289 407.555 264.57 410.176 curveto
+265.641 410.375 lineto
+265.879 403.156 273.438 391.207 270.219 384.32 curveto
+266.102 375.508 253.785 375.586 246.754 372.461 curveto
+245.273 375.953 243.273 379.199 240.453 381.68 curveto
+246.727 383.809 262.137 387.387 265.492 394.559 curveto
+266.898 397.57 265.941 402.566 264.312 404.258 curveto
+264.035 403.195 263.652 402.109 263.145 401.02 curveto
+260.273 394.883 254.129 390.121 247.793 390.121 curveto
+238.977 390.121 235.238 396.52 239.387 405.398 curveto
+241.879 410.73 254.598 428.469 261.176 428.469 curveto
+ closepath fill
+ 0 9.7534 dtransform truncate idtransform setlinewidth pop 1 setlinejoin
+newpath 261.176 428.469 moveto
+266.969 428.469 263.594 413.848 261.531 409.438 curveto
+259.77 405.664 255.797 400.219 251.086 400.219 curveto
+245.441 400.219 245.609 406.605 247.855 411.418 curveto
+249.074 414.02 250.945 416.941 253.52 419.086 curveto
+252.863 416.848 255.094 415.316 254.191 413.387 curveto
+253.574 412.066 252.301 410.629 251.637 409.211 curveto
+250.566 406.918 250.973 402.852 253.562 402.852 curveto
+255.879 402.852 257.938 405.75 258.785 407.555 curveto
+260.512 411.254 264.836 427.043 260.004 427.043 curveto
+254.438 427.043 244.844 413.344 242.836 409.047 curveto
+239.25 401.375 241.852 391.93 250.02 391.93 curveto
+255.539 391.93 260.078 397.289 262.27 401.98 curveto
+263.578 404.773 264.289 407.555 264.57 410.176 curveto
+265.641 410.375 lineto
+265.879 403.156 273.438 391.207 270.219 384.32 curveto
+266.102 375.508 253.785 375.586 246.754 372.461 curveto
+245.273 375.953 243.273 379.199 240.453 381.68 curveto
+246.727 383.809 262.137 387.387 265.492 394.559 curveto
+266.898 397.57 265.941 402.566 264.312 404.258 curveto
+264.035 403.195 263.652 402.109 263.145 401.02 curveto
+260.273 394.883 254.129 390.121 247.793 390.121 curveto
+238.977 390.121 235.238 396.52 239.387 405.398 curveto
+241.879 410.73 254.598 428.469 261.176 428.469 curveto
+ closepath stroke
+newpath 276.242 407.305 moveto
+276.594 406.434 277.609 401.512 278.379 401.512 curveto
+280.039 401.512 283.039 406.078 283.848 407.262 curveto
+285.324 406.285 284.504 404.234 287.242 404.234 curveto
+288.48 404.234 289.105 406.93 290.395 406.973 curveto
+290.441 405.883 290.508 404.898 289.922 403.641 curveto
+289.012 401.699 286.719 399.066 284.461 399.066 curveto
+282.844 399.066 280.594 401.031 280.152 401.031 curveto
+279.672 401.031 278.789 400.805 278.508 400.203 curveto
+277.332 397.691 280.477 389.297 283.625 389.297 curveto
+285.309 389.297 287.316 390.543 289.078 391.312 curveto
+288.621 388.289 288.559 385.738 289.164 383.133 curveto
+287.559 382.109 285.68 381.676 284.172 381.676 curveto
+276.43 381.676 280.699 399.859 273.559 403.734 curveto
+276.242 407.305 lineto
+ closepath fill
+newpath 276.242 407.305 moveto
+276.594 406.434 277.609 401.512 278.379 401.512 curveto
+280.039 401.512 283.039 406.078 283.848 407.262 curveto
+285.324 406.285 284.504 404.234 287.242 404.234 curveto
+288.48 404.234 289.105 406.93 290.395 406.973 curveto
+290.441 405.883 290.508 404.898 289.922 403.641 curveto
+289.012 401.699 286.719 399.066 284.461 399.066 curveto
+282.844 399.066 280.594 401.031 280.152 401.031 curveto
+279.672 401.031 278.789 400.805 278.508 400.203 curveto
+277.332 397.691 280.477 389.297 283.625 389.297 curveto
+285.309 389.297 287.316 390.543 289.078 391.312 curveto
+288.621 388.289 288.559 385.738 289.164 383.133 curveto
+287.559 382.109 285.68 381.676 284.172 381.676 curveto
+276.43 381.676 280.699 399.859 273.559 403.734 curveto
+276.242 407.305 lineto
+ closepath stroke
+newpath 306 408.762 moveto
+311.852 408.762 314.16 398.133 311.535 392.516 curveto
+309.5 388.16 305.887 385 301.262 385 curveto
+293.09 385 294.113 396.246 297.301 403.066 curveto
+298.18 404.945 301.184 409.039 303.531 409.039 curveto
+304.395 409.039 305.113 408.762 306 408.762 curveto
+ closepath fill
+newpath 305.816 407.77 moveto
+304.898 407.77 304.086 407.309 303.66 406.395 curveto
+302.762 404.477 307.234 402.535 306.594 401.164 curveto
+306.188 400.301 304.652 399.492 303.875 399.492 curveto
+299.996 399.492 300.031 404.586 302.34 407.906 curveto
+300.906 406.98 299.961 405.57 299.352 404.258 curveto
+297.078 399.398 298.883 392.711 304.066 392.711 curveto
+306.934 392.711 310.23 395.312 311.512 398.055 curveto
+313.094 401.43 309.059 407.77 305.816 407.77 curveto
+ closepath fill
+newpath 306 408.762 moveto
+311.852 408.762 314.16 398.133 311.535 392.516 curveto
+309.5 388.16 305.887 385 301.262 385 curveto
+293.09 385 294.113 396.246 297.301 403.066 curveto
+298.18 404.945 301.184 409.039 303.531 409.039 curveto
+304.395 409.039 305.113 408.762 306 408.762 curveto
+ closepath stroke
+newpath 305.816 407.77 moveto
+304.898 407.77 304.086 407.309 303.66 406.395 curveto
+302.762 404.477 307.234 402.535 306.594 401.164 curveto
+306.188 400.301 304.652 399.492 303.875 399.492 curveto
+299.996 399.492 300.031 404.586 302.34 407.906 curveto
+300.906 406.98 299.961 405.57 299.352 404.258 curveto
+297.078 399.398 298.883 392.711 304.066 392.711 curveto
+306.934 392.711 310.23 395.312 311.512 398.055 curveto
+313.094 401.43 309.059 407.77 305.816 407.77 curveto
+ closepath stroke
+newpath 332.59 391.262 moveto
+331.062 387.992 328.211 386.195 325.004 386.195 curveto
+314.824 386.195 312.805 395.57 317.215 405.012 curveto
+318.258 407.238 319.969 409.703 322.578 409.703 curveto
+330.758 409.703 336.453 399.531 332.59 391.262 curveto
+ closepath fill
+newpath 324.469 408.52 moveto
+323.715 408.52 323.059 408.246 322.695 407.477 curveto
+321.906 405.781 326.211 404.27 326.219 402.516 curveto
+325.77 401.98 324.508 401.379 323.961 401.379 curveto
+320.859 401.379 318.516 405.625 321.164 408.781 curveto
+320.09 408.094 319.449 407.062 319 406.09 curveto
+316.312 400.344 320.141 394.535 325.719 394.535 curveto
+328.043 394.535 331.035 395.84 332.242 398.422 curveto
+333.949 402.074 327.867 408.52 324.469 408.52 curveto
+ closepath fill
+newpath 332.59 391.262 moveto
+331.062 387.992 328.211 386.195 325.004 386.195 curveto
+314.824 386.195 312.805 395.57 317.215 405.012 curveto
+318.258 407.238 319.969 409.703 322.578 409.703 curveto
+330.758 409.703 336.453 399.531 332.59 391.262 curveto
+ closepath stroke
+newpath 324.469 408.52 moveto
+323.715 408.52 323.059 408.246 322.695 407.477 curveto
+321.906 405.781 326.211 404.27 326.219 402.516 curveto
+325.77 401.98 324.508 401.379 323.961 401.379 curveto
+320.859 401.379 318.516 405.625 321.164 408.781 curveto
+320.09 408.094 319.449 407.062 319 406.09 curveto
+316.312 400.344 320.141 394.535 325.719 394.535 curveto
+328.043 394.535 331.035 395.84 332.242 398.422 curveto
+333.949 402.074 327.867 408.52 324.469 408.52 curveto
+ closepath stroke
+newpath 343.121 408.574 moveto
+351.891 408.574 356.352 392.316 352.43 383.93 curveto
+351.68 382.324 350.285 380.723 348.441 380.723 curveto
+338.418 380.723 340.977 400.848 335.332 406.562 curveto
+335.852 407.117 336.344 407.695 336.797 408.277 curveto
+340.609 403.758 338.715 391.867 346.859 391.867 curveto
+348.734 391.867 350.156 393.523 350.91 395.145 curveto
+352.934 399.473 349.191 406.984 345.098 406.984 curveto
+345.055 406.984 344.465 406.961 344.48 406.719 curveto
+344.629 403.957 346.781 405.68 344.617 400.98 curveto
+342.402 401.426 340.059 405.016 341.266 407.605 curveto
+341.625 408.363 342.516 408.574 343.121 408.574 curveto
+ closepath fill
+newpath 343.121 408.574 moveto
+351.891 408.574 356.352 392.316 352.43 383.93 curveto
+351.68 382.324 350.285 380.723 348.441 380.723 curveto
+338.418 380.723 340.977 400.848 335.332 406.562 curveto
+335.852 407.117 336.344 407.695 336.797 408.277 curveto
+340.609 403.758 338.715 391.867 346.859 391.867 curveto
+348.734 391.867 350.156 393.523 350.91 395.145 curveto
+352.934 399.473 349.191 406.984 345.098 406.984 curveto
+345.055 406.984 344.465 406.961 344.48 406.719 curveto
+344.629 403.957 346.781 405.68 344.617 400.98 curveto
+342.402 401.426 340.059 405.016 341.266 407.605 curveto
+341.625 408.363 342.516 408.574 343.121 408.574 curveto
+ closepath stroke
+newpath 364.938 408.758 moveto
+365.762 408.68 367.004 408.754 367.711 408.535 curveto
+367.848 408.496 367.746 408.328 367.766 408.195 curveto
+367.984 406.965 368.32 405.801 368.617 404.613 curveto
+369.758 399.988 370.445 395.238 371.758 390.652 curveto
+373.184 385.66 374.672 380.035 372.945 373.77 curveto
+372.777 373.156 372.551 372.535 372.258 371.91 curveto
+370.301 367.719 365.262 363.73 360.859 363.73 curveto
+360.32 363.73 359.746 363.883 359.488 364.234 curveto
+361.348 365.426 362.512 366.648 363.344 368.426 curveto
+364.336 370.559 364.32 372.551 364.191 374.387 curveto
+364.543 374.184 365.672 373.664 366.141 373.664 curveto
+368.047 373.664 369.684 375.523 370.445 377.16 curveto
+371.852 380.164 371.613 383.23 371.367 385.789 curveto
+371.246 387.066 371.074 388.328 370.84 389.559 curveto
+370.48 391.332 lineto
+370.438 391.531 lineto
+370.391 391.723 lineto
+370.605 391.723 370.414 391.348 370.422 391.156 curveto
+370.555 388.059 370.5 383.738 368.852 380.211 curveto
+368.086 378.574 366.832 376.887 364.91 376.887 curveto
+356.488 376.887 360.723 401.016 353.973 406.75 curveto
+354.348 407.375 354.68 408.016 354.961 408.645 curveto
+358.953 403.773 359.164 390.34 365.047 390.34 curveto
+366.473 390.34 367.945 391.691 368.555 392.988 curveto
+371.168 398.578 366.824 405.086 364.938 408.758 curveto
+ closepath fill
+newpath 364.938 408.758 moveto
+365.762 408.68 367.004 408.754 367.711 408.535 curveto
+367.848 408.496 367.746 408.328 367.766 408.195 curveto
+367.984 406.965 368.32 405.801 368.617 404.613 curveto
+369.758 399.988 370.445 395.238 371.758 390.652 curveto
+373.184 385.66 374.672 380.035 372.945 373.77 curveto
+372.777 373.156 372.551 372.535 372.258 371.91 curveto
+370.301 367.719 365.262 363.73 360.859 363.73 curveto
+360.32 363.73 359.746 363.883 359.488 364.234 curveto
+361.348 365.426 362.512 366.648 363.344 368.426 curveto
+364.336 370.559 364.32 372.551 364.191 374.387 curveto
+364.543 374.184 365.672 373.664 366.141 373.664 curveto
+368.047 373.664 369.684 375.523 370.445 377.16 curveto
+371.852 380.164 371.613 383.23 371.367 385.789 curveto
+371.246 387.066 371.074 388.328 370.84 389.559 curveto
+370.48 391.332 lineto
+370.438 391.531 lineto
+370.391 391.723 lineto
+370.605 391.723 370.414 391.348 370.422 391.156 curveto
+370.555 388.059 370.5 383.738 368.852 380.211 curveto
+368.086 378.574 366.832 376.887 364.91 376.887 curveto
+356.488 376.887 360.723 401.016 353.973 406.75 curveto
+354.348 407.375 354.68 408.016 354.961 408.645 curveto
+358.953 403.773 359.164 390.34 365.047 390.34 curveto
+366.473 390.34 367.945 391.691 368.555 392.988 curveto
+371.168 398.578 366.824 405.086 364.938 408.758 curveto
+ closepath stroke
+ 1 setgray
+newpath 261.176 428.469 moveto
+266.969 428.469 263.594 413.848 261.531 409.438 curveto
+259.77 405.664 255.797 400.219 251.086 400.219 curveto
+245.441 400.219 245.609 406.605 247.855 411.418 curveto
+249.074 414.02 250.945 416.941 253.52 419.086 curveto
+252.863 416.848 255.094 415.316 254.191 413.387 curveto
+253.574 412.066 252.301 410.629 251.637 409.211 curveto
+250.566 406.918 250.973 402.852 253.562 402.852 curveto
+255.879 402.852 257.938 405.75 258.785 407.555 curveto
+260.512 411.254 264.836 427.043 260.004 427.043 curveto
+254.438 427.043 244.844 413.344 242.836 409.047 curveto
+239.25 401.375 241.852 391.93 250.02 391.93 curveto
+255.539 391.93 260.078 397.289 262.27 401.98 curveto
+263.578 404.773 264.289 407.555 264.57 410.176 curveto
+265.641 410.375 lineto
+265.879 403.156 273.438 391.207 270.219 384.32 curveto
+266.102 375.508 253.785 375.586 246.754 372.461 curveto
+245.273 375.953 243.273 379.199 240.453 381.68 curveto
+246.727 383.809 262.137 387.387 265.492 394.559 curveto
+266.898 397.57 265.941 402.566 264.312 404.258 curveto
+264.035 403.195 263.652 402.109 263.145 401.02 curveto
+260.273 394.883 254.129 390.121 247.793 390.121 curveto
+238.977 390.121 235.238 396.52 239.387 405.398 curveto
+241.879 410.73 254.598 428.469 261.176 428.469 curveto
+ closepath fill
+newpath 276.242 407.305 moveto
+276.594 406.434 277.609 401.512 278.379 401.512 curveto
+280.039 401.512 283.039 406.078 283.848 407.262 curveto
+285.324 406.285 284.504 404.234 287.242 404.234 curveto
+288.48 404.234 289.105 406.93 290.395 406.973 curveto
+290.441 405.883 290.508 404.898 289.922 403.641 curveto
+289.012 401.699 286.719 399.066 284.461 399.066 curveto
+282.844 399.066 280.594 401.031 280.152 401.031 curveto
+279.672 401.031 278.789 400.805 278.508 400.203 curveto
+277.332 397.691 280.477 389.297 283.625 389.297 curveto
+285.309 389.297 287.316 390.543 289.078 391.312 curveto
+288.621 388.289 288.559 385.738 289.164 383.133 curveto
+287.559 382.109 285.68 381.676 284.172 381.676 curveto
+276.43 381.676 280.699 399.859 273.559 403.734 curveto
+276.242 407.305 lineto
+ closepath fill
+newpath 306 408.762 moveto
+311.852 408.762 314.16 398.133 311.535 392.516 curveto
+309.5 388.16 305.887 385 301.262 385 curveto
+293.09 385 294.113 396.246 297.301 403.066 curveto
+298.18 404.945 301.184 409.039 303.531 409.039 curveto
+304.395 409.039 305.113 408.762 306 408.762 curveto
+ closepath fill
+newpath 305.816 407.77 moveto
+304.898 407.77 304.086 407.309 303.66 406.395 curveto
+302.762 404.477 307.234 402.535 306.594 401.164 curveto
+306.188 400.301 304.652 399.492 303.875 399.492 curveto
+299.996 399.492 300.031 404.586 302.34 407.906 curveto
+300.906 406.98 299.961 405.57 299.352 404.258 curveto
+297.078 399.398 298.883 392.711 304.066 392.711 curveto
+306.934 392.711 310.23 395.312 311.512 398.055 curveto
+313.094 401.43 309.059 407.77 305.816 407.77 curveto
+ closepath fill
+newpath 332.59 391.262 moveto
+331.062 387.992 328.211 386.195 325.004 386.195 curveto
+314.824 386.195 312.805 395.57 317.215 405.012 curveto
+318.258 407.238 319.969 409.703 322.578 409.703 curveto
+330.758 409.703 336.453 399.531 332.59 391.262 curveto
+ closepath fill
+newpath 324.469 408.52 moveto
+323.715 408.52 323.059 408.246 322.695 407.477 curveto
+321.906 405.781 326.211 404.27 326.219 402.516 curveto
+325.77 401.98 324.508 401.379 323.961 401.379 curveto
+320.859 401.379 318.516 405.625 321.164 408.781 curveto
+320.09 408.094 319.449 407.062 319 406.09 curveto
+316.312 400.344 320.141 394.535 325.719 394.535 curveto
+328.043 394.535 331.035 395.84 332.242 398.422 curveto
+333.949 402.074 327.867 408.52 324.469 408.52 curveto
+ closepath fill
+newpath 343.121 408.574 moveto
+351.891 408.574 356.352 392.316 352.43 383.93 curveto
+351.68 382.324 350.285 380.723 348.441 380.723 curveto
+338.418 380.723 340.977 400.848 335.332 406.562 curveto
+335.852 407.117 336.344 407.695 336.797 408.277 curveto
+340.609 403.758 338.715 391.867 346.859 391.867 curveto
+348.734 391.867 350.156 393.523 350.91 395.145 curveto
+352.934 399.473 349.191 406.984 345.098 406.984 curveto
+345.055 406.984 344.465 406.961 344.48 406.719 curveto
+344.629 403.957 346.781 405.68 344.617 400.98 curveto
+342.402 401.426 340.059 405.016 341.266 407.605 curveto
+341.625 408.363 342.516 408.574 343.121 408.574 curveto
+ closepath fill
+newpath 364.938 408.758 moveto
+365.762 408.68 367.004 408.754 367.711 408.535 curveto
+367.848 408.496 367.746 408.328 367.766 408.195 curveto
+367.984 406.965 368.32 405.801 368.617 404.613 curveto
+369.758 399.988 370.445 395.238 371.758 390.652 curveto
+373.184 385.66 374.672 380.035 372.945 373.77 curveto
+372.777 373.156 372.551 372.535 372.258 371.91 curveto
+365.691 359.168 351.629 362.602 347.227 362.602 curveto
+346.691 362.602 346.113 362.754 345.859 363.105 curveto
+347.715 364.301 348.879 365.523 349.711 367.301 curveto
+350.703 369.43 350.691 371.426 350.559 373.262 curveto
+350.914 373.055 352.043 372.539 352.508 372.539 curveto
+354.414 372.539 365.035 367.027 370.445 377.16 curveto
+371.852 380.164 371.613 383.23 371.367 385.789 curveto
+371.246 387.066 371.074 388.328 370.84 389.559 curveto
+370.48 391.332 lineto
+370.438 391.531 lineto
+370.391 391.723 lineto
+370.605 391.723 370.414 391.348 370.422 391.156 curveto
+370.555 388.059 370.5 383.738 368.852 380.211 curveto
+368.086 378.574 366.832 376.887 364.91 376.887 curveto
+356.488 376.887 360.723 401.016 353.973 406.75 curveto
+354.348 407.375 354.68 408.016 354.961 408.645 curveto
+358.953 403.773 359.164 390.34 365.047 390.34 curveto
+366.473 390.34 367.945 391.691 368.555 392.988 curveto
+371.168 398.578 366.824 405.086 364.938 408.758 curveto
+ closepath fill
+showpage
+%%EOF
diff --git a/groovy-core/src/latex/spec/colophon.tex b/groovy-core/src/latex/spec/colophon.tex
new file mode 100644
index 0000000..4abd051
--- /dev/null
+++ b/groovy-core/src/latex/spec/colophon.tex
@@ -0,0 +1,11 @@
+\chapter{Colophon}
+
+This manual was produced without the aid of Microsoft products.
+It was authored on a Linux laptop using XEmacs\index{XEmacs}, \LaTeX\index{Latex@\LaTeX},
+\texttt{makeindex}, \texttt{xdvi}, \texttt{dia}, and \texttt{epstopdf}.
+
+\rule{0pt}{17em}
+
+\begin{flushright}
+Phish\index{Phish|textbf} rocks.
+\end{flushright}
diff --git a/groovy-core/src/latex/spec/expressions.tex b/groovy-core/src/latex/spec/expressions.tex
new file mode 100644
index 0000000..f212c2e
--- /dev/null
+++ b/groovy-core/src/latex/spec/expressions.tex
@@ -0,0 +1,2 @@
+\chapter{Expressions}
+
diff --git a/groovy-core/src/latex/spec/groovy-lang-spec.tex b/groovy-core/src/latex/spec/groovy-lang-spec.tex
new file mode 100644
index 0000000..d0a4f2f
--- /dev/null
+++ b/groovy-core/src/latex/spec/groovy-lang-spec.tex
@@ -0,0 +1,162 @@
+
+%%
+%%
+%% the groovy language spec
+%%
+%%
+
+\documentclass[10pt,letterpaper]{book}
+
+
+%%
+%% Package Imports
+%%
+
+\usepackage{alltt}
+%\usepackage{cite}
+%\usepackage{plain}
+\usepackage{graphicx}
+\usepackage{hyperref}
+\usepackage{varioref}
+\usepackage{tabularx}
+%\usepackage{array}
+%\usepackage{color}
+\usepackage{makeidx}
+%\usepackage{showidx}
+
+%%
+%% Extra Commands and Evironments
+%%
+
+\newenvironment{codelisting}%
+	{\bigskip\begin{minipage}{250pt}\footnotesize\begin{alltt}}%
+	{\end{alltt}\end{minipage}\bigskip}
+
+\newenvironment{basenote}[1]
+	{
+		\begin{flushright}
+		\vline \hspace{1em}
+		\begin{minipage}{0.7\linewidth}
+		\hspace{-1em}\textsf{\textbf{#1}}\\  
+		\rule{0em}{1.4em}
+		\sl
+	} {
+		\end{minipage}
+		\end{flushright}
+	}
+
+\newenvironment{indnote}[1]
+	{
+		\begin{flushright}
+		\vline \hspace{1em}
+		\begin{minipage}{0.9\linewidth}
+		\hspace{-1em}\textsf{\textbf{#1's note}}\\  
+		\rule{0em}{1.4em}
+		\sl
+	} {
+		\end{minipage}
+		\end{flushright}
+	}
+
+\newenvironment{note}
+	{
+		\begin{basenote}{Note}
+	} {
+		\end{basenote}
+	}
+
+\newenvironment{ednote}
+	{
+		\begin{basenote}{Editor's Note}
+	} {
+		\end{basenote}
+	}
+
+\newenvironment{implnote}
+	{
+		\begin{basenote}{Implementor's Note}
+	} {
+		\end{basenote}
+	}
+
+\newcommand{\diagram}[2]{
+  \bigskip
+  \begin{figure}[h]
+    \begin{center}
+      \includegraphics[scale=0.5]{#1}
+    \end{center}
+    \caption{#2}
+  \end{figure} 
+  \medskip
+}
+
+\newcommand{\indexfile}[1]{\texttt{#1}\index{#1@\texttt{#1} file}}
+\newcommand{\indexclass}[1]{\texttt{#1}\index{#1@\texttt{#1} class}}
+\newcommand{\indexclassex}[1]{\index{#1@\texttt{#1}!example}}
+\newcommand{\indexmethod}[2]{\texttt{#2}\index{#1@\texttt{#1} class!#2@\texttt{#2} method}}
+
+\newcommand{\indexkeyword}[1]{\texttt{#1}\index{#1@\texttt{#1} keyword}}
+\newcommand{\indexoperator}[1]{\texttt{#1}\index{#1@\texttt{#1} operator}}
+
+\newcommand{\file}[1]{\texttt{#1} file}
+\newcommand{\class}[1]{\texttt{#1}}
+\newcommand{\method}[1]{\texttt{#1}}
+
+\raggedbottom
+
+\clubpenalty = 10000
+\widowpenalty = 10000 
+\makeindex
+
+\begin{document}
+
+\let\footnoterule\hrule
+
+\makeatletter
+\renewcommand{\@makefntext}[1]%
+	{\noindent\makebox[1.8em][r]{\@makefnmark}#1}
+\makeatother
+
+\title{
+	Groovy Language Specification
+}
+
+\author{
+	\textsf{The Codehaus}\\
+	\textsf{www.codehaus.org}\\
+}
+
+
+\frontmatter
+
+\maketitle
+
+\tableofcontents
+
+\listoffigures 
+
+\include{preface}
+
+\mainmatter
+
+\include{keywords}
+\include{operators}
+\include{expressions}
+\include{statements}
+
+\index{Betty|see{betty}}
+\index{betty|see{Betty}}
+
+\appendix
+
+\include{faq}
+\include{license}
+
+\backmatter
+
+\include{colophon}
+
+\small
+\printindex
+
+\end{document}
diff --git a/groovy-core/src/latex/spec/keywords.tex b/groovy-core/src/latex/spec/keywords.tex
new file mode 100644
index 0000000..7922452
--- /dev/null
+++ b/groovy-core/src/latex/spec/keywords.tex
@@ -0,0 +1,3 @@
+\chapter{Keywords}
+
+\section{\indexkeyword{class}}
diff --git a/groovy-core/src/latex/spec/operators.tex b/groovy-core/src/latex/spec/operators.tex
new file mode 100644
index 0000000..0eff220
--- /dev/null
+++ b/groovy-core/src/latex/spec/operators.tex
@@ -0,0 +1,7 @@
+\chapter{Operators}
+
+\section{\indexoperator{.} -- property access}
+\section{\indexoperator{[]} -- collection member access}
+\section{\indexoperator{()} -- method invocation}
+\section{\indexoperator{==} -- identity equality testing}
+\section{\indexoperator{!=} -- identity equality testing}
diff --git a/groovy-core/src/latex/spec/preface.tex b/groovy-core/src/latex/spec/preface.tex
new file mode 100644
index 0000000..0f5d1c1
--- /dev/null
+++ b/groovy-core/src/latex/spec/preface.tex
@@ -0,0 +1,3 @@
+\chapter{Preface}
+
+Yadda foo.
diff --git a/groovy-core/src/latex/spec/statements.tex b/groovy-core/src/latex/spec/statements.tex
new file mode 100644
index 0000000..69fac31
--- /dev/null
+++ b/groovy-core/src/latex/spec/statements.tex
@@ -0,0 +1,2 @@
+\chapter{Statements}
+
diff --git a/groovy-core/src/main/groovy/.cvsignore b/groovy-core/src/main/groovy/.cvsignore
new file mode 100644
index 0000000..e43b0f9
--- /dev/null
+++ b/groovy-core/src/main/groovy/.cvsignore
@@ -0,0 +1 @@
+.DS_Store
diff --git a/groovy-core/src/main/groovy/inspect/Inspector.java b/groovy-core/src/main/groovy/inspect/Inspector.java
new file mode 100644
index 0000000..cb90f8c
--- /dev/null
+++ b/groovy-core/src/main/groovy/inspect/Inspector.java
@@ -0,0 +1,310 @@
+package groovy.inspect;
+
+import groovy.lang.GroovyObject;
+import groovy.lang.MetaClass;
+import groovy.lang.MetaMethod;
+import groovy.lang.PropertyValue;
+
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Method;
+import java.lang.reflect.Field;
+import java.lang.reflect.Constructor;
+import java.util.*;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+
+/**
+ * The Inspector provides a unified access to an object's
+ * information that can be determined by introspection.
+ *
+ * @author Dierk Koenig
+ */
+public class Inspector {
+    protected Object objectUnderInspection = null;
+
+    // Indexes to retrieve Class Property information
+    public static final int CLASS_PACKAGE_IDX       = 0;
+    public static final int CLASS_CLASS_IDX         = 1;
+    public static final int CLASS_INTERFACE_IDX     = 2;
+    public static final int CLASS_SUPERCLASS_IDX    = 3;
+    public static final int CLASS_OTHER_IDX         = 4;
+
+    // Indexes to retrieve field and method information
+    public static final int MEMBER_ORIGIN_IDX = 0;
+    public static final int MEMBER_MODIFIER_IDX = 1;
+    public static final int MEMBER_DECLARER_IDX = 2;
+    public static final int MEMBER_TYPE_IDX = 3;
+    public static final int MEMBER_NAME_IDX = 4;
+    public static final int MEMBER_PARAMS_IDX = 5;
+    public static final int MEMBER_VALUE_IDX = 5;
+    public static final int MEMBER_EXCEPTIONS_IDX = 6;
+
+    public static final String NOT_APPLICABLE = "n/a";
+    public static final String GROOVY = "GROOVY";
+    public static final String JAVA = "JAVA";
+
+    /**
+     * @param objectUnderInspection must not be null
+     */
+    public Inspector(Object objectUnderInspection) {
+        if (null == objectUnderInspection){
+            throw new IllegalArgumentException("argument must not be null");
+        }
+        this.objectUnderInspection = objectUnderInspection;
+    }
+
+    /**
+     * Get the Class Properties of the object under inspection.
+     * @return String array to be indexed by the CLASS_xxx_IDX constants
+     */
+    public String[] getClassProps() {
+        String[] result = new String[CLASS_OTHER_IDX+1];
+        Package pack = getClassUnderInspection().getPackage();
+        result[CLASS_PACKAGE_IDX] = "package "+ ((pack == null) ? NOT_APPLICABLE : pack.getName());
+        String modifiers = Modifier.toString(getClassUnderInspection().getModifiers());
+        String classOrInterface = "class";
+        if (getClassUnderInspection().isInterface()){
+            classOrInterface = "interface";
+        }
+        result[CLASS_CLASS_IDX] = modifiers + " "+ classOrInterface+" "+ shortName(getClassUnderInspection());
+        result[CLASS_INTERFACE_IDX] = "implements ";
+        Class[] interfaces = getClassUnderInspection().getInterfaces();
+        for (int i = 0; i < interfaces.length; i++) {
+            result[CLASS_INTERFACE_IDX] += shortName(interfaces[i])+ " ";
+        }
+        result[CLASS_SUPERCLASS_IDX] = "extends " + shortName(getClassUnderInspection().getSuperclass());
+        result[CLASS_OTHER_IDX] = "is Primitive: "+getClassUnderInspection().isPrimitive()
+                  +", is Array: "   +getClassUnderInspection().isArray()
+                  +", is Groovy: "  + isGroovy();
+        return result;
+    }
+
+    public boolean isGroovy() {
+        return getClassUnderInspection().isAssignableFrom(GroovyObject.class);
+    }
+    
+    /**
+     * Gets the object being inspected.
+     */
+    public Object getObject() {
+    	return objectUnderInspection;
+    }
+
+    /**
+     * Get info about usual Java instance and class Methods as well as Constructors.
+     * @return  Array of StringArrays that can be indexed with the MEMBER_xxx_IDX constants
+     */
+    public Object[] getMethods(){
+        Method[] methods = getClassUnderInspection().getMethods();
+        Constructor[] ctors = getClassUnderInspection().getConstructors();
+        Object[] result = new Object[methods.length + ctors.length];
+        int resultIndex = 0;
+        for (; resultIndex < methods.length; resultIndex++) {
+            Method method = methods[resultIndex];
+            result[resultIndex] = methodInfo(method);
+        }
+        for (int i = 0; i < ctors.length; i++, resultIndex++) {
+            Constructor ctor = ctors[i];
+            result[resultIndex] = methodInfo(ctor);
+        }
+        return result;
+    }
+     /**
+     * Get info about instance and class Methods that are dynamically added through Groovy.
+     * @return  Array of StringArrays that can be indexed with the MEMBER_xxx_IDX constants
+     */
+    public Object[] getMetaMethods(){
+        MetaClass metaClass = InvokerHelper.getMetaClass(objectUnderInspection);
+        List metaMethods = metaClass.getMetaMethods();
+        Object[] result = new Object[metaMethods.size()];
+        int i=0;
+        for (Iterator iter = metaMethods.iterator(); iter.hasNext(); i++) {
+            MetaMethod metaMethod = (MetaMethod) iter.next();
+            result[i] = methodInfo(metaMethod);
+        }
+        return result;
+    }
+    
+    /**
+     * Get info about usual Java public fields incl. constants.
+     * @return  Array of StringArrays that can be indexed with the MEMBER_xxx_IDX constants
+     */
+    public Object[] getPublicFields(){
+        Field[] fields = getClassUnderInspection().getFields();
+        Object[] result = new Object[fields.length];
+        for (int i = 0; i < fields.length; i++) {
+            Field field = fields[i];
+            result[i] = fieldInfo(field);
+        }
+        return result;
+    }
+    /**
+     * Get info about Properties (Java and Groovy alike).
+     * @return  Array of StringArrays that can be indexed with the MEMBER_xxx_IDX constants
+     */
+    public Object[] getPropertyInfo(){
+        List props = DefaultGroovyMethods.getMetaPropertyValues(objectUnderInspection);
+        Object[] result = new Object[props.size()];
+        int i=0;
+        for (Iterator iter = props.iterator(); iter.hasNext(); i++) {
+            PropertyValue pv = (PropertyValue) iter.next();
+            result[i] = fieldInfo(pv);
+        }
+        return result;
+    }
+
+    protected String[] fieldInfo(Field field) {
+        String[] result = new String[MEMBER_VALUE_IDX+1];
+        result[MEMBER_ORIGIN_IDX] = JAVA;
+        result[MEMBER_MODIFIER_IDX] = Modifier.toString(field.getModifiers());
+        result[MEMBER_DECLARER_IDX] = shortName(field.getDeclaringClass());
+        result[MEMBER_TYPE_IDX] = shortName(field.getType());
+        result[MEMBER_NAME_IDX] = field.getName();
+        try {
+            result[MEMBER_VALUE_IDX] = InvokerHelper.inspect(field.get(objectUnderInspection));
+        } catch (IllegalAccessException e) {
+            result[MEMBER_VALUE_IDX] = NOT_APPLICABLE;
+        }
+        return withoutNulls(result);
+    }
+    protected String[] fieldInfo(PropertyValue pv) {
+        String[] result = new String[MEMBER_VALUE_IDX+1];
+        result[MEMBER_ORIGIN_IDX] = GROOVY;
+        result[MEMBER_MODIFIER_IDX] = "public";
+        result[MEMBER_DECLARER_IDX] = NOT_APPLICABLE;
+        result[MEMBER_TYPE_IDX] = shortName(pv.getType());
+        result[MEMBER_NAME_IDX] = pv.getName();
+        try {
+            result[MEMBER_VALUE_IDX] = InvokerHelper.inspect(pv.getValue());
+        } catch (Exception e) {
+            result[MEMBER_VALUE_IDX] = NOT_APPLICABLE;
+        }
+        return withoutNulls(result);
+    }
+
+    protected Class getClassUnderInspection() {
+        return objectUnderInspection.getClass();
+    }
+
+    public static String shortName(Class clazz){
+        if (null == clazz) return NOT_APPLICABLE;
+        String className = clazz.getName();
+        if (null == clazz.getPackage()) return className;
+        String packageName = clazz.getPackage().getName();
+        int offset = packageName.length();
+        if (offset > 0) offset++;
+        className = className.substring(offset);
+        return className;
+    }
+
+    protected String[] methodInfo(Method method){
+        String[] result = new String[MEMBER_EXCEPTIONS_IDX+1];
+	    int mod = method.getModifiers();
+        result[MEMBER_ORIGIN_IDX] = JAVA;
+        result[MEMBER_MODIFIER_IDX] = Modifier.toString(mod);
+        result[MEMBER_DECLARER_IDX] = shortName(method.getDeclaringClass());
+        result[MEMBER_TYPE_IDX] = shortName(method.getReturnType());
+        result[MEMBER_NAME_IDX] = method.getName();
+	    Class[] params = method.getParameterTypes();
+        StringBuffer sb = new StringBuffer();
+	    for (int j = 0; j < params.length; j++) {
+		    sb.append(shortName(params[j]));
+		    if (j < (params.length - 1)) sb.append(", ");
+	    }
+        result[MEMBER_PARAMS_IDX] = sb.toString();
+	    sb.setLength(0);
+	    Class[] exceptions = method.getExceptionTypes();
+		for (int k = 0; k < exceptions.length; k++) {
+		    sb.append(shortName(exceptions[k]));
+		    if (k < (exceptions.length - 1)) sb.append(", ");
+	    }
+        result[MEMBER_EXCEPTIONS_IDX] = sb.toString();
+	    return withoutNulls(result);
+    }
+    protected String[] methodInfo(Constructor ctor){
+        String[] result = new String[MEMBER_EXCEPTIONS_IDX+1];
+	    int mod = ctor.getModifiers();
+        result[MEMBER_ORIGIN_IDX] = JAVA;
+        result[MEMBER_MODIFIER_IDX] = Modifier.toString(mod);
+        result[MEMBER_DECLARER_IDX] = shortName(ctor.getDeclaringClass());
+        result[MEMBER_TYPE_IDX] = shortName(ctor.getDeclaringClass());
+        result[MEMBER_NAME_IDX] = ctor.getName();
+	    Class[] params = ctor.getParameterTypes();
+        StringBuffer sb = new StringBuffer();
+	    for (int j = 0; j < params.length; j++) {
+		    sb.append(shortName(params[j]));
+		    if (j < (params.length - 1)) sb.append(", ");
+	    }
+        result[MEMBER_PARAMS_IDX] = sb.toString();
+	    sb.setLength(0);
+	    Class[] exceptions = ctor.getExceptionTypes();
+		for (int k = 0; k < exceptions.length; k++) {
+		    sb.append(shortName(exceptions[k]));
+		    if (k < (exceptions.length - 1)) sb.append(", ");
+	    }
+        result[MEMBER_EXCEPTIONS_IDX] = sb.toString();
+	    return withoutNulls(result);
+    }
+    protected String[] methodInfo(MetaMethod method){
+        String[] result = new String[MEMBER_EXCEPTIONS_IDX+1];
+	    int mod = method.getModifiers();
+        result[MEMBER_ORIGIN_IDX] = GROOVY;
+        result[MEMBER_MODIFIER_IDX] = Modifier.toString(mod);
+        result[MEMBER_DECLARER_IDX] = shortName(method.getDeclaringClass());
+        result[MEMBER_TYPE_IDX] = shortName(method.getReturnType());
+        result[MEMBER_NAME_IDX] = method.getName();
+	    Class[] params = method.getParameterTypes();
+        StringBuffer sb = new StringBuffer();
+	    for (int j = 0; j < params.length; j++) {
+		    sb.append(shortName(params[j]));
+		    if (j < (params.length - 1)) sb.append(", ");
+	    }
+        result[MEMBER_PARAMS_IDX] = sb.toString();
+        result[MEMBER_EXCEPTIONS_IDX] = NOT_APPLICABLE; // no exception info for Groovy MetaMethods
+        return withoutNulls(result);
+    }
+
+    protected String[] withoutNulls(String[] toNormalize){
+        for (int i = 0; i < toNormalize.length; i++) {
+            String s = toNormalize[i];
+            if (null == s) toNormalize[i] = NOT_APPLICABLE;
+        }
+        return toNormalize;
+    }
+
+    public static void print(Object[] memberInfo) {
+        for (int i = 0; i < memberInfo.length; i++) {
+            String[] metaMethod = (String[]) memberInfo[i];
+            System.out.print(i+":\t");
+            for (int j = 0; j < metaMethod.length; j++) {
+                String s = metaMethod[j];
+                System.out.print(s+" ");
+            }
+            System.out.println("");
+        }
+    }
+    public static Collection sort(List memberInfo) {
+        Collections.sort(memberInfo, new MemberComparator());
+        return memberInfo;
+    }
+
+    public static class MemberComparator implements Comparator {
+        public int compare(Object a, Object b) {
+            String[] aStr = (String[]) a;
+            String[] bStr = (String[]) b;
+            int result = aStr[Inspector.MEMBER_NAME_IDX].compareTo(bStr[Inspector.MEMBER_NAME_IDX]);
+            if (0 != result) return result;
+            result = aStr[Inspector.MEMBER_TYPE_IDX].compareTo(bStr[Inspector.MEMBER_TYPE_IDX]);
+            if (0 != result) return result;
+            result = aStr[Inspector.MEMBER_PARAMS_IDX].compareTo(bStr[Inspector.MEMBER_PARAMS_IDX]);
+            if (0 != result) return result;
+            result = aStr[Inspector.MEMBER_DECLARER_IDX].compareTo(bStr[Inspector.MEMBER_DECLARER_IDX]);
+            if (0 != result) return result;
+            result = aStr[Inspector.MEMBER_MODIFIER_IDX].compareTo(bStr[Inspector.MEMBER_MODIFIER_IDX]);
+            if (0 != result) return result;
+            result = aStr[Inspector.MEMBER_ORIGIN_IDX].compareTo(bStr[Inspector.MEMBER_ORIGIN_IDX]);
+            return result;
+        }
+    }
+}
diff --git a/groovy-core/src/main/groovy/inspect/swingui/ObjectBrowser.groovy b/groovy-core/src/main/groovy/inspect/swingui/ObjectBrowser.groovy
new file mode 100644
index 0000000..ba413e5
--- /dev/null
+++ b/groovy-core/src/main/groovy/inspect/swingui/ObjectBrowser.groovy
@@ -0,0 +1,140 @@
+package groovy.inspect.swingui
+
+import java.awt.*
+import javax.swing.*
+import groovy.swing.SwingBuilder
+import groovy.inspect.Inspector
+
+/**
+A little GUI to show some of the Inspector capabilities.
+Starting this script opens the ObjectBrowser on "some String".
+Use it in groovysh or groovyConsole to inspect your object of
+interest with
+<code>
+ObjectBrowser.inspect(myObject)
+</code>.
+
+@author Dierk Koenig
+**/
+class ObjectBrowser {
+    
+    def inspector
+    def swing, frame, fieldTable, methodTable, itemTable, mapTable
+
+    static void main(args) {
+        inspect("some String")
+    }
+    static void inspect(objectUnderInspection){
+        def browser = new ObjectBrowser()
+        browser.inspector = new Inspector(objectUnderInspection)
+        browser.run()
+    }
+    
+    void run() {
+        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
+        swing = new SwingBuilder()
+        
+        frame = swing.frame(title:'Groovy Object Browser', location:[200,200], size:[800,600],
+                defaultCloseOperation:WindowConstants.DISPOSE_ON_CLOSE) {
+                
+            menuBar {
+                menu(text:'Help') {
+                    menuItem() {action(name:'About', closure: this.&showAbout)}
+                }
+            }
+            panel() {
+                borderLayout()
+                panel(  name:"Class Info",
+                        border: BorderFactory.createEmptyBorder(5,10,5,10),
+                        constraints:BorderLayout.NORTH) {
+                    flowLayout(alignment:FlowLayout.LEFT)
+                    def props = inspector.classProps
+                    def classLabel = '<html>' + props.join('<br>')
+                    label(classLabel)
+                }
+                tabbedPane(constraints:BorderLayout.CENTER){
+                    if (inspector.object instanceof Collection) {
+	                    scrollPane(name: ' Collection data ') {
+	                        itemTable = table() {
+	                        	int i = 0
+	                            def data = inspector.object.collect { val -> [i++, val] }
+	                            tableModel(list:data) {
+	                                closureColumn(header:'Index', read:{it[0]})
+	                                closureColumn(header:'Value', read:{it[1]})
+	                            }
+	                        }
+	                    }
+                    }
+                    if (inspector.object instanceof Map) {
+	                    scrollPane(name: ' Map data ') {
+	                        itemTable = table() {
+	                        	int i = 0
+	                            def data = inspector.object.collect { key, val -> [i++, key, val] }
+	                            tableModel(list:data) {
+	                                closureColumn(header:'Index', read:{it[0]})
+	                                closureColumn(header:'Key',   read:{it[1]})
+	                                closureColumn(header:'Value', read:{it[2]})
+	                            }
+	                        }
+	                    }
+                    }
+                    scrollPane(name: ' Public Fields and Properties ') {
+                        fieldTable = table() {
+                            def data = Inspector.sort(inspector.publicFields.toList())
+                            data.addAll(Inspector.sort(inspector.propertyInfo.toList()))
+                            tableModel(list:data) {
+                                closureColumn(header:'Name',        read:{it[Inspector.MEMBER_NAME_IDX]})
+                                closureColumn(header:'Value',       read:{it[Inspector.MEMBER_VALUE_IDX]})
+                                closureColumn(header:'Type',        read:{it[Inspector.MEMBER_TYPE_IDX]})
+                                closureColumn(header:'Origin',      read:{it[Inspector.MEMBER_ORIGIN_IDX]})
+                                closureColumn(header:'Modifier',    read:{it[Inspector.MEMBER_MODIFIER_IDX]})
+                                closureColumn(header:'Declarer',    read:{it[Inspector.MEMBER_DECLARER_IDX]})
+                            }
+                        }
+                    }
+                    scrollPane(name:' (Meta) Methods ' ) {
+                        methodTable = table() {
+                            def data = Inspector.sort(inspector.methods.toList())
+                            data.addAll(Inspector.sort(inspector.metaMethods.toList()))
+
+                            tableModel(list:data) {
+                                closureColumn(header:'Name',        read:{it[Inspector.MEMBER_NAME_IDX]})
+                                closureColumn(header:'Params',      read:{it[Inspector.MEMBER_PARAMS_IDX]})
+                                closureColumn(header:'Type',        read:{it[Inspector.MEMBER_TYPE_IDX]})
+                                closureColumn(header:'Origin',      read:{it[Inspector.MEMBER_ORIGIN_IDX]})
+                                closureColumn(header:'Modifier',    read:{it[Inspector.MEMBER_MODIFIER_IDX]})
+                                closureColumn(header:'Declarer',    read:{it[Inspector.MEMBER_DECLARER_IDX]})
+                                closureColumn(header:'Exceptions',  read:{it[Inspector.MEMBER_EXCEPTIONS_IDX]})
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        
+        // Add a bit of formatting
+        addSorter(itemTable)
+        addSorter(mapTable)
+        addSorter(fieldTable)
+        addSorter(methodTable)
+        
+        frame.show()
+        frame.toFront()
+    }
+    
+    void addSorter(table) {
+    	if (table != null) {
+	    	def sorter = new TableSorter(table.model)
+    		table.model = sorter
+    		sorter.addMouseListenerToHeaderInTable(table)
+    	}
+    }
+    
+    void showAbout(EventObject evt) {
+         def pane = swing.optionPane()
+         // work around GROOVY-1048
+         pane.setMessage('An interactive GUI to explore object capabilities.')
+         def dialog = pane.createDialog(frame, 'About Groovy Object Browser')
+         dialog.show()
+    }
+}
diff --git a/groovy-core/src/main/groovy/inspect/swingui/TableMap.java b/groovy-core/src/main/groovy/inspect/swingui/TableMap.java
new file mode 100644
index 0000000..0f623fa
--- /dev/null
+++ b/groovy-core/src/main/groovy/inspect/swingui/TableMap.java
@@ -0,0 +1,110 @@
+package groovy.inspect.swingui;
+
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All  Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * -Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *
+ * -Redistribution in binary form must reproduct the above copyright
+ *  notice, this list of conditions and the following disclaimer in
+ *  the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
+ * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
+ * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT
+ * BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT
+ * OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
+ * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
+ * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
+ * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN
+ * IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that Software is not designed, licensed or intended for
+ * use in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ */
+
+/*
+ * @(#)TableMap.java	1.11 03/01/23
+ */
+
+/**
+ * In a chain of data manipulators some behaviour is common. TableMap
+ * provides most of this behavour and can be subclassed by filters
+ * that only need to override a handful of specific methods. TableMap
+ * implements TableModel by routing all requests to its model, and
+ * TableModelListener by routing all events to its listeners. Inserting
+ * a TableMap which has not been subclassed into a chain of table filters
+ * should have no effect.
+ *
+ * @version 1.11 01/23/03
+ * @author Philip Milne */
+
+import javax.swing.table.*;
+import javax.swing.event.TableModelListener;
+import javax.swing.event.TableModelEvent;
+
+public class TableMap extends AbstractTableModel implements TableModelListener
+{
+    protected TableModel model;
+
+    public TableModel  getModel() {
+        return model;
+    }
+
+    public void  setModel(TableModel model) {
+        this.model = model;
+        model.addTableModelListener(this);
+    }
+
+    // By default, Implement TableModel by forwarding all messages
+    // to the model.
+
+    public Object getValueAt(int aRow, int aColumn) {
+        return model.getValueAt(aRow, aColumn);
+    }
+
+    public void setValueAt(Object aValue, int aRow, int aColumn) {
+        model.setValueAt(aValue, aRow, aColumn);
+    }
+
+    public int getRowCount() {
+        return (model == null) ? 0 : model.getRowCount();
+    }
+
+    public int getColumnCount() {
+        return (model == null) ? 0 : model.getColumnCount();
+    }
+
+    public String getColumnName(int aColumn) {
+        return model.getColumnName(aColumn);
+    }
+
+    public Class getColumnClass(int aColumn) {
+        return model.getColumnClass(aColumn);
+    }
+
+    public boolean isCellEditable(int row, int column) {
+         return model.isCellEditable(row, column);
+    }
+//
+// Implementation of the TableModelListener interface,
+//
+
+    // By default forward all events to all the listeners.
+    public void tableChanged(TableModelEvent e) {
+        fireTableChanged(e);
+    }
+}
+
diff --git a/groovy-core/src/main/groovy/inspect/swingui/TableSorter.java b/groovy-core/src/main/groovy/inspect/swingui/TableSorter.java
new file mode 100644
index 0000000..a9cdb69
--- /dev/null
+++ b/groovy-core/src/main/groovy/inspect/swingui/TableSorter.java
@@ -0,0 +1,357 @@
+package groovy.inspect.swingui;
+
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All  Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * -Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *
+ * -Redistribution in binary form must reproduct the above copyright
+ *  notice, this list of conditions and the following disclaimer in
+ *  the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
+ * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
+ * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT
+ * BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT
+ * OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS
+ * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
+ * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
+ * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
+ * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN
+ * IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that Software is not designed, licensed or intended for
+ * use in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ */
+
+/*
+ * @(#)TableSorter.java	1.12 03/01/23
+ */
+
+/**
+ * A sorter for TableModels. The sorter has a model (conforming to TableModel)
+ * and itself implements TableModel. TableSorter does not store or copy
+ * the data in the TableModel, instead it maintains an array of
+ * integers which it keeps the same size as the number of rows in its
+ * model. When the model changes it notifies the sorter that something
+ * has changed eg. "rowsAdded" so that its internal array of integers
+ * can be reallocated. As requests are made of the sorter (like
+ * getValueAt(row, col) it redirects them to its model via the mapping
+ * array. That way the TableSorter appears to hold another copy of the table
+ * with the rows in a different order. The sorting algorthm used is stable
+ * which means that it does not move around rows when its comparison
+ * function returns 0 to denote that they are equivalent.
+ *
+ * @version 1.12 01/23/03
+ * @author Philip Milne
+ * @author Minimal adjustments by Dierk Koenig, June 2005
+ */
+
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Date;
+import java.util.Vector;
+
+import javax.swing.JTable;
+import javax.swing.event.TableModelEvent;
+import javax.swing.table.JTableHeader;
+import javax.swing.table.TableColumnModel;
+import javax.swing.table.TableModel;
+
+public class TableSorter extends TableMap
+{
+    int             indexes[];
+    Vector          sortingColumns = new Vector();
+    boolean         ascending = true;
+    int             lastSortedColumn = -1;
+
+    public TableSorter()
+    {
+        indexes = new int[0]; // For consistency.
+    }
+
+    public TableSorter(TableModel model)
+    {
+        setModel(model);
+    }
+
+    public void setModel(TableModel model) {
+        super.setModel(model);
+        reallocateIndexes();
+    }
+
+    public int compareRowsByColumn(int row1, int row2, int column)
+    {
+        Class type = model.getColumnClass(column);
+        TableModel data = model;
+
+        // Check for nulls
+
+        Object o1 = data.getValueAt(row1, column);
+        Object o2 = data.getValueAt(row2, column);
+
+        // If both values are null return 0
+        if (o1 == null && o2 == null) {
+            return 0;
+        }
+        else if (o1 == null) { // Define null less than everything.
+            return -1;
+        }
+        else if (o2 == null) {
+            return 1;
+        }
+
+/* We copy all returned values from the getValue call in case
+an optimised model is reusing one object to return many values.
+The Number subclasses in the JDK are immutable and so will not be used in
+this way but other subclasses of Number might want to do this to save
+space and avoid unnecessary heap allocation.
+*/
+        if (type.getSuperclass() == java.lang.Number.class)
+            {
+                Number n1 = (Number)data.getValueAt(row1, column);
+                double d1 = n1.doubleValue();
+                Number n2 = (Number)data.getValueAt(row2, column);
+                double d2 = n2.doubleValue();
+
+                if (d1 < d2)
+                    return -1;
+                else if (d1 > d2)
+                    return 1;
+                else
+                    return 0;
+            }
+        else if (type == java.util.Date.class)
+            {
+                Date d1 = (Date)data.getValueAt(row1, column);
+                long n1 = d1.getTime();
+                Date d2 = (Date)data.getValueAt(row2, column);
+                long n2 = d2.getTime();
+
+                if (n1 < n2)
+                    return -1;
+                else if (n1 > n2)
+                    return 1;
+                else return 0;
+            }
+        else if (type == String.class)
+            {
+                String s1 = (String)data.getValueAt(row1, column);
+                String s2    = (String)data.getValueAt(row2, column);
+                int result = s1.compareTo(s2);
+
+                if (result < 0)
+                    return -1;
+                else if (result > 0)
+                    return 1;
+                else return 0;
+            }
+        else if (type == Boolean.class)
+            {
+                Boolean bool1 = (Boolean)data.getValueAt(row1, column);
+                boolean b1 = bool1.booleanValue();
+                Boolean bool2 = (Boolean)data.getValueAt(row2, column);
+                boolean b2 = bool2.booleanValue();
+
+                if (b1 == b2)
+                    return 0;
+                else if (b1) // Define false < true
+                    return 1;
+                else
+                    return -1;
+            }
+        else
+            {
+                Object v1 = data.getValueAt(row1, column);
+                String s1 = v1.toString();
+                Object v2 = data.getValueAt(row2, column);
+                String s2 = v2.toString();
+                int result = s1.compareTo(s2);
+
+                if (result < 0)
+                    return -1;
+                else if (result > 0)
+                    return 1;
+                else return 0;
+            }
+    }
+
+    public int compare(int row1, int row2)
+    {
+        for(int level = 0; level < sortingColumns.size(); level++)
+            {
+                Integer column = (Integer)sortingColumns.elementAt(level);
+                int result = compareRowsByColumn(row1, row2, column.intValue());
+                if (result != 0)
+                    return ascending ? result : -result;
+            }
+        return 0;
+    }
+
+    public void  reallocateIndexes()
+    {
+        int rowCount = model.getRowCount();
+
+        // Set up a new array of indexes with the right number of elements
+        // for the new data model.
+        indexes = new int[rowCount];
+
+        // Initialise with the identity mapping.
+        for(int row = 0; row < rowCount; row++)
+            indexes[row] = row;
+    }
+
+    public void tableChanged(TableModelEvent e)
+    {
+	System.out.println("Sorter: tableChanged");
+        reallocateIndexes();
+
+        super.tableChanged(e);
+    }
+
+    public void checkModel()
+    {
+        if (indexes.length != model.getRowCount()) {
+            System.err.println("Sorter not informed of a change in model.");
+        }
+    }
+
+    public void  sort(Object sender)
+    {
+        checkModel();
+        shuttlesort((int[])indexes.clone(), indexes, 0, indexes.length);
+    }
+
+    public void n2sort() {
+        for(int i = 0; i < getRowCount(); i++) {
+            for(int j = i+1; j < getRowCount(); j++) {
+                if (compare(indexes[i], indexes[j]) == -1) {
+                    swap(i, j);
+                }
+            }
+        }
+    }
+
+    // This is a home-grown implementation which we have not had time
+    // to research - it may perform poorly in some circumstances. It
+    // requires twice the space of an in-place algorithm and makes
+    // NlogN assigments shuttling the values between the two
+    // arrays. The number of compares appears to vary between N-1 and
+    // NlogN depending on the initial order but the main reason for
+    // using it here is that, unlike qsort, it is stable.
+    public void shuttlesort(int from[], int to[], int low, int high) {
+        if (high - low < 2) {
+            return;
+        }
+        int middle = (low + high)/2;
+        shuttlesort(to, from, low, middle);
+        shuttlesort(to, from, middle, high);
+
+        int p = low;
+        int q = middle;
+
+        /* This is an optional short-cut; at each recursive call,
+        check to see if the elements in this subset are already
+        ordered.  If so, no further comparisons are needed; the
+        sub-array can just be copied.  The array must be copied rather
+        than assigned otherwise sister calls in the recursion might
+        get out of sinc.  When the number of elements is three they
+        are partitioned so that the first set, [low, mid), has one
+        element and and the second, [mid, high), has two. We skip the
+        optimisation when the number of elements is three or less as
+        the first compare in the normal merge will produce the same
+        sequence of steps. This optimisation seems to be worthwhile
+        for partially ordered lists but some analysis is needed to
+        find out how the performance drops to Nlog(N) as the initial
+        order diminishes - it may drop very quickly.  */
+
+        if (high - low >= 4 && compare(from[middle-1], from[middle]) <= 0) {
+            for (int i = low; i < high; i++) {
+                to[i] = from[i];
+            }
+            return;
+        }
+
+        // A normal merge.
+
+        for(int i = low; i < high; i++) {
+            if (q >= high || (p < middle && compare(from[p], from[q]) <= 0)) {
+                to[i] = from[p++];
+            }
+            else {
+                to[i] = from[q++];
+            }
+        }
+    }
+
+    public void swap(int i, int j) {
+        int tmp = indexes[i];
+        indexes[i] = indexes[j];
+        indexes[j] = tmp;
+    }
+
+    // The mapping only affects the contents of the data rows.
+    // Pass all requests to these rows through the mapping array: "indexes".
+
+    public Object getValueAt(int aRow, int aColumn)
+    {
+        checkModel();
+        return model.getValueAt(indexes[aRow], aColumn);
+    }
+
+    public void setValueAt(Object aValue, int aRow, int aColumn)
+    {
+        checkModel();
+        model.setValueAt(aValue, indexes[aRow], aColumn);
+    }
+
+    public void sortByColumn(int column) {
+        sortByColumn(column, true);
+    }
+
+    public void sortByColumn(int column, boolean ascending) {
+        this.ascending = ascending;
+        sortingColumns.removeAllElements();
+        sortingColumns.addElement(new Integer(column));
+        sort(this);
+        super.tableChanged(new TableModelEvent(this));
+    }
+
+    // There is no-where else to put this.
+    // Add a mouse listener to the Table to trigger a table sort
+    // when a column heading is clicked in the JTable.
+    public void addMouseListenerToHeaderInTable(JTable table) {
+        final TableSorter sorter = this;
+        final JTable tableView = table;
+        tableView.setColumnSelectionAllowed(false);
+        MouseAdapter listMouseListener = new MouseAdapter() {
+            public void mouseClicked(MouseEvent e) {
+                TableColumnModel columnModel = tableView.getColumnModel();
+                int viewColumn = columnModel.getColumnIndexAtX(e.getX());                
+                int column = tableView.convertColumnIndexToModel(viewColumn);
+                if(e.getClickCount() == 1 && column != -1) {
+                    if (lastSortedColumn == column) ascending = !ascending;
+                    sorter.sortByColumn(column, ascending);
+                    lastSortedColumn = column;
+                }
+             }
+         };
+        JTableHeader th = tableView.getTableHeader();
+        th.addMouseListener(listMouseListener);
+    }
+
+
+
+}
+
diff --git a/groovy-core/src/main/groovy/lang/BenchmarkInterceptor.java b/groovy-core/src/main/groovy/lang/BenchmarkInterceptor.java
new file mode 100644
index 0000000..e44c6a4
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/BenchmarkInterceptor.java
@@ -0,0 +1,58 @@
+package groovy.lang;
+
+import java.util.*;
+
+/**
+ * Interceptor that registers the timestamp of each method call
+ * before and after invocation.
+ */
+public class BenchmarkInterceptor implements Interceptor {
+
+    protected Map calls = new HashMap(); // keys to list of invokation times and before and after
+
+
+    public Map getCalls() {
+        return calls;
+    }
+    public void reset() {
+        calls = new HashMap();
+    }
+
+    public Object beforeInvoke(Object object, String methodName, Object[] arguments) {
+        if (!calls.containsKey(methodName)) calls.put(methodName, new LinkedList());
+        ((List) calls.get(methodName)).add(new Long(System.currentTimeMillis()));
+
+        return null;
+    }
+
+    public Object afterInvoke(Object object, String methodName, Object[] arguments, Object result) {
+        ((List) calls.get(methodName)).add(new Long(System.currentTimeMillis()));
+        return result;
+    }
+
+    public boolean doInvoke() {
+        return true;
+    }
+
+    /**
+     * @return a list of lines, each item is [methodname, numberOfCalls, accumulatedTime]
+     */
+    public List statistic() {
+        List result = new LinkedList();
+        for (Iterator iter = calls.keySet().iterator(); iter.hasNext();) {
+            Object[] line = new Object[3];
+            result.add(line);
+            line[0] = (String) iter.next();
+            List times = (List) calls.get(line[0]);
+            line[1] = new Integer(times.size() / 2);
+            int accTime = 0;
+            for (Iterator it = times.iterator(); it.hasNext();) {
+                Long start = (Long) it.next();
+                Long end = (Long) it.next();
+                accTime += end.longValue() - start.longValue();
+            }
+            line[2] = new Long(accTime);
+        }
+        return result;
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/Binding.java b/groovy-core/src/main/groovy/lang/Binding.java
new file mode 100644
index 0000000..1eee99b
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/Binding.java
@@ -0,0 +1,134 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents the variable bindings of a script which can be altered
+ * from outside the script object or created outside of a script and passed
+ * into it.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class Binding extends GroovyObjectSupport {
+    private Map variables;
+    
+    public Binding() {
+        variables = new HashMap();
+    }
+    
+    public Binding(Map variables) {
+        this.variables = variables;
+    }
+    
+    /**
+     * A helper constructor used in main(String[]) method calls
+     * 
+     * @param args are the command line arguments from a main()
+     */
+    public Binding(String[] args) {
+        this();
+        setVariable("args", args);
+    }
+    
+    /**
+     * @param name the name of the variable to lookup
+     * @return the variable value
+     */
+    public Object getVariable(String name) {
+        Object result = variables.get(name);
+        
+        if (result == null && !variables.containsKey(name)) {
+            throw new MissingPropertyException("The property '" + name + "' is missing from the binding.",
+                                               name, Binding.class);
+        }
+        
+        return result;
+    }
+    
+    /**
+     * Sets the value of the given variable
+     * @param name the name of the variable to set
+     * @param value the new value for the given variable
+     */
+    public void setVariable(String name, Object value) {
+        variables.put(name, value);
+    }
+    
+    public Map getVariables() {
+        return variables;
+    }
+
+    /**
+     * Overloaded to make variables appear as bean properties or via the subscript operator
+     */
+    public Object getProperty(String property) {
+        /** @todo we should check if we have the property with the metaClass instead of try/catch  */
+        try {
+            return super.getProperty(property);
+        }
+        catch (MissingPropertyException e) {
+            return getVariable(property);
+        }
+    }
+
+    /**
+     * Overloaded to make variables appear as bean properties or via the subscript operator
+     */
+    public void setProperty(String property, Object newValue) {
+        /** @todo we should check if we have the property with the metaClass instead of try/catch  */
+        try {
+            super.setProperty(property, newValue);
+        }
+        catch (MissingPropertyException e) {
+            setVariable(property, newValue);
+        }
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/lang/BitwiseNegateEvaluatingException.java b/groovy-core/src/main/groovy/lang/BitwiseNegateEvaluatingException.java
new file mode 100644
index 0000000..a32445b
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/BitwiseNegateEvaluatingException.java
@@ -0,0 +1,52 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+public class BitwiseNegateEvaluatingException extends GroovyRuntimeException {
+    public BitwiseNegateEvaluatingException(String message) {
+        super(message);
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/Buildable.java b/groovy-core/src/main/groovy/lang/Buildable.java
new file mode 100644
index 0000000..c2622f3
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/Buildable.java
@@ -0,0 +1,51 @@
+/*
+
+Copyright 2004 (C) John Wilson. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+	
+package groovy.lang;
+
+
+public interface Buildable {
+	void build(GroovyObject builder);
+}
diff --git a/groovy-core/src/main/groovy/lang/Closure.java b/groovy-core/src/main/groovy/lang/Closure.java
new file mode 100644
index 0000000..9047d10
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/Closure.java
@@ -0,0 +1,451 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import org.codehaus.groovy.runtime.CurriedClosure;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Represents any closure object in Groovy.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author <a href="mailto:tug@wilson.co.uk">John Wilson</a>
+ * @version $Revision$
+ */
+public abstract class Closure extends GroovyObjectSupport implements Cloneable, Runnable {
+
+    private static final Object noParameters[] = new Object[]{null};
+    private static final Object emptyArray[] = new Object[0];
+    private static final Object emptyArrayParameter[] = new Object[]{emptyArray};
+
+    private Object delegate;
+    private final Object owner;
+    private Class[] parameterTypes;
+    protected int maximumNumberOfParameters;
+    private final Object thisObject;
+
+
+    private int directive = 0;
+    public final static int DONE = 1, SKIP = 2;
+
+    public Closure(Object owner, Object thisObject) {
+        this.owner = owner;
+        this.delegate = owner;
+        this.thisObject = thisObject;
+
+        Class closureClass = this.getClass();
+        final Class clazz = closureClass;
+        final Method[] methods = (Method[]) AccessController.doPrivileged(new  PrivilegedAction() {
+            public Object run() {
+                return clazz.getDeclaredMethods();
+            }
+        });
+
+        // set it to -1 for starters so parameterTypes will always get a type
+        maximumNumberOfParameters = -1;
+        for (int j = 0; j < methods.length; j++) {
+            if ("doCall".equals(methods[j].getName()) && methods[j].getParameterTypes().length > maximumNumberOfParameters) {
+                parameterTypes = methods[j].getParameterTypes();
+                maximumNumberOfParameters = parameterTypes.length;
+            }
+        }
+        // this line should be useless, but well, just in case
+        maximumNumberOfParameters = Math.max(maximumNumberOfParameters,0);
+    }
+    
+    public Closure(Object owner) {
+        this(owner,null);
+    }
+    
+    protected Object getThisObject(){
+        return thisObject;
+    }
+
+    public Object getProperty(String property) {
+        if ("delegate".equals(property)) {
+            return getDelegate();
+        } else if ("owner".equals(property)) {
+            return getOwner();
+        } else if ("getMaximumNumberOfParameters".equals(property)) {
+            return new Integer(getMaximumNumberOfParameters());
+        } else if ("parameterTypes".equals(property)) {
+            return getParameterTypes();
+        } else if ("metaClass".equals(property)) {
+            return getMetaClass();
+        } else if ("class".equals(property)) {
+            return getClass();
+        } else {
+            try {
+                // lets try getting the property on the owner
+                return InvokerHelper.getProperty(this.owner, property);
+            } catch (MissingPropertyException e1) {
+                if (this.delegate != null && this.delegate != this && this.delegate != this.owner) {
+                    try {
+                        // lets try getting the property on the delegate
+                        return InvokerHelper.getProperty(this.delegate, property);
+                    } catch (GroovyRuntimeException e2) {
+                        // ignore, we'll throw e1
+                    }
+                }
+
+                throw e1;
+            }
+        }
+    }
+
+    public void setProperty(String property, Object newValue) {
+        if ("delegate".equals(property)) {
+            setDelegate(newValue);
+        } else if ("metaClass".equals(property)) {
+            setMetaClass((MetaClass) newValue);
+        } else {
+            try {
+                // lets try setting the property on the owner
+                InvokerHelper.setProperty(this.owner, property, newValue);
+                return;
+            } catch (GroovyRuntimeException e1) {
+                if (this.delegate != null && this.delegate != this && this.delegate != this.owner) {
+                    try {
+                        // lets try setting the property on the delegate
+                        InvokerHelper.setProperty(this.delegate, property, newValue);
+                        return;
+                    } catch (GroovyRuntimeException e2) {
+                        // ignore, we'll throw e1
+                    }
+                }
+
+                throw e1;
+            }
+        }
+    }
+
+    public boolean isCase(Object candidate){
+        return DefaultTypeTransformation.castToBoolean(call(candidate));
+    }
+
+    /**
+     * Invokes the closure without any parameters, returning any value if applicable.
+     *
+     * @return the value if applicable or null if there is no return statement in the closure
+     */
+    public Object call() {
+        return call(new Object[]{});
+    }
+    
+    public Object call(Object[] args) {
+        try {
+            return getMetaClass().invokeMethod(this,"doCall",args);
+        } catch (Exception e) {
+            return throwRuntimeException(e);
+        }
+    }
+    
+    /**
+     * Invokes the closure, returning any value if applicable.
+     *
+     * @param arguments could be a single value or a List of values
+     * @return the value if applicable or null if there is no return statement in the closure
+     */
+    public Object call(final Object arguments) {
+        return call(new Object[]{arguments});
+    }
+    
+    protected static Object throwRuntimeException(Throwable throwable) {
+        if (throwable instanceof RuntimeException) {
+            throw (RuntimeException) throwable;
+        } else {
+            throw new GroovyRuntimeException(throwable.getMessage(), throwable);
+        }
+    }
+
+    /**
+     * @return the owner Object to which method calls will go which is
+     *         typically the outer class when the closure is constructed
+     */
+    public Object getOwner() {
+        return this.owner;
+    }
+
+    /**
+     * @return the delegate Object to which method calls will go which is
+     *         typically the outer class when the closure is constructed
+     */
+    public Object getDelegate() {
+        return this.delegate;
+    }
+
+    /**
+     * Allows the delegate to be changed such as when performing markup building
+     *
+     * @param delegate
+     */
+    public void setDelegate(Object delegate) {
+        this.delegate = delegate;
+    }
+    
+    /**
+     * @return the parameter types of the longest doCall method
+     * of this closure
+     */
+    public Class[] getParameterTypes() {
+        return this.parameterTypes;
+    }
+
+    /**
+     * @return the maximum number of parameters a doCall methos
+     * of this closure can take
+     */
+    public int getMaximumNumberOfParameters() {
+        return this.maximumNumberOfParameters;
+    }
+
+    /**
+     * @return a version of this closure which implements Writable
+     */
+    public Closure asWritable() {
+        return new WritableClosure();
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Runnable#run()
+     */
+    public void run() {
+        call();
+    }
+
+    /**
+     * Support for closure currying
+     *
+     * @param arguments
+     */
+    public Closure curry(final Object arguments[]) {
+        return new CurriedClosure(this,arguments);
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#clone()
+     */
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (final CloneNotSupportedException e) {
+            return null;
+        }
+    }
+    
+    /**
+     * Implementation note: 
+     *   This has to be an inner class!
+     * 
+     * Reason: 
+     *   Closure.this.call will call the outer call method, bur
+     * with the inner class as executing object. This means any
+     * invokeMethod or getProperty call will be called on this 
+     * inner class instead of the outer!
+     */
+    private class WritableClosure extends Closure implements Writable {
+        public WritableClosure() {
+            super(Closure.this);
+        }
+
+        /* (non-Javadoc)
+         * @see groovy.lang.Writable#writeTo(java.io.Writer)
+         */
+        public Writer writeTo(Writer out) throws IOException {
+            Closure.this.call(new Object[]{out});
+
+            return out;
+        }
+
+        /* (non-Javadoc)
+         * @see groovy.lang.GroovyObject#invokeMethod(java.lang.String, java.lang.Object)
+         */
+        public Object invokeMethod(String method, Object arguments) {
+            if ("clone".equals(method)) {
+                return clone();
+            } else if ("curry".equals(method)) {
+                return curry((Object[]) arguments);
+            } else if ("asWritable".equals(method)) {
+                return asWritable();
+            } else {
+                return Closure.this.invokeMethod(method, arguments);
+            }
+        }
+
+        /* (non-Javadoc)
+         * @see groovy.lang.GroovyObject#getProperty(java.lang.String)
+         */
+        public Object getProperty(String property) {
+            return Closure.this.getProperty(property);
+        }
+
+        /* (non-Javadoc)
+         * @see groovy.lang.GroovyObject#setProperty(java.lang.String, java.lang.Object)
+         */
+        public void setProperty(String property, Object newValue) {
+            Closure.this.setProperty(property, newValue);
+        }
+
+        /* (non-Javadoc)
+         * @see groovy.lang.Closure#call()
+         */
+        public Object call() {
+            return Closure.this.call();
+        }
+
+        /* (non-Javadoc)
+         * @see groovy.lang.Closure#call(java.lang.Object)
+         */
+        public Object call(Object arguments) {
+            return Closure.this.call(arguments);
+        }
+
+        /* (non-Javadoc)
+         * @see groovy.lang.Closure#getDelegate()
+         */
+        public Object getDelegate() {
+            return Closure.this.getDelegate();
+        }
+
+        /* (non-Javadoc)
+         * @see groovy.lang.Closure#setDelegate(java.lang.Object)
+         */
+        public void setDelegate(Object delegate) {
+            Closure.this.setDelegate(delegate);
+        }
+
+        /* (non-Javadoc)
+         * @see groovy.lang.Closure#getParameterTypes()
+         */
+        public Class[] getParameterTypes() {
+            return Closure.this.getParameterTypes();
+        }
+        
+        /* (non-Javadoc)
+         * @see groovy.lang.Closure#getParameterTypes()
+         */
+        public int getMaximumNumberOfParameters() {
+            return Closure.this.getMaximumNumberOfParameters();
+        }
+
+        /* (non-Javadoc)
+         * @see groovy.lang.Closure#asWritable()
+         */
+        public Closure asWritable() {
+            return this;
+        }
+
+        /* (non-Javadoc)
+         * @see java.lang.Runnable#run()
+         */
+        public void run() {
+            Closure.this.run();
+        }
+
+        /* (non-Javadoc)
+         * @see java.lang.Object#clone()
+         */
+        public Object clone() {
+            return ((Closure) Closure.this.clone()).asWritable();
+        }
+
+        /* (non-Javadoc)
+         * @see java.lang.Object#hashCode()
+         */
+        public int hashCode() {
+            return Closure.this.hashCode();
+        }
+
+        /* (non-Javadoc)
+         * @see java.lang.Object#equals(java.lang.Object)
+         */
+        public boolean equals(Object arg0) {
+            return Closure.this.equals(arg0);
+        }
+
+        /* (non-Javadoc)
+         * @see java.lang.Object#toString()
+         */
+        public String toString() {
+            final StringWriter writer = new StringWriter();
+
+            try {
+                writeTo(writer);
+            } catch (IOException e) {
+                return null;
+            }
+
+            return writer.toString();
+        }
+        
+        public Closure curry(final Object arguments[]) {
+            return (new CurriedClosure(this,arguments)).asWritable();
+        }
+    }
+
+    /**
+     * @return Returns the directive.
+     */
+    public int getDirective() {
+        return directive;
+    }
+
+    /**
+     * @param directive The directive to set.
+     */
+    public void setDirective(int directive) {
+        this.directive = directive;
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/lang/ClosureException.java b/groovy-core/src/main/groovy/lang/ClosureException.java
new file mode 100644
index 0000000..6503bc9
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/ClosureException.java
@@ -0,0 +1,66 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+/**
+ * An exception thrown by a closure invocation
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ClosureException extends RuntimeException {
+
+    private Closure closure;
+    
+    public ClosureException(Closure closure, Throwable cause) {
+        super("Exception thrown by call to closure: " + closure + " reaason: " + cause, cause);
+        this.closure = closure;
+    }
+
+    public Closure getClosure() {
+        return closure;
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/DelegatingMetaClass.java b/groovy-core/src/main/groovy/lang/DelegatingMetaClass.java
new file mode 100644
index 0000000..6090789
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/DelegatingMetaClass.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.lang.reflect.Method;
+import java.util.List;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class DelegatingMetaClass extends MetaClass {
+    protected final MetaClass delegate;
+    
+    public DelegatingMetaClass(final MetaClass delegate) {
+        super(delegate.theClass);
+        
+        this.delegate = delegate;
+    }
+   
+    public DelegatingMetaClass(final Class theClass) {
+        this(new MetaClassImpl(InvokerHelper.getInstance().getMetaRegistry(), theClass));
+    }
+    
+    /* (non-Javadoc)
+     * @see groovy.lang.MetaClass#addNewInstanceMethod(java.lang.reflect.Method)
+     */
+    public void addNewInstanceMethod(Method method) {
+        delegate.addNewInstanceMethod(method);
+    }
+    /* (non-Javadoc)
+     * @see groovy.lang.MetaClass#addNewStaticMethod(java.lang.reflect.Method)
+     */
+    public void addNewStaticMethod(Method method) {
+        delegate.addNewStaticMethod(method);
+    }
+    /* (non-Javadoc)
+     * @see groovy.lang.MetaClass#initialize()
+     */
+    public void initialize() {
+        delegate.initialize();
+    }
+
+    /* (non-Javadoc)
+     * @see groovy.lang.MetaClass#getAttribute(java.lang.Object, java.lang.String)
+     */
+    public Object getAttribute(Object object, String attribute) {
+        return delegate.getAttribute(object, attribute);
+    }
+    /* (non-Javadoc)
+     * @see groovy.lang.MetaClass#getClassNode()
+     */
+    public ClassNode getClassNode() {
+         return delegate.getClassNode();
+    }
+    /* (non-Javadoc)
+     * @see groovy.lang.MetaClass#getMetaMethods()
+     */
+    public List getMetaMethods() {
+        return delegate.getMetaMethods();
+    }
+    /* (non-Javadoc)
+     * @see groovy.lang.MetaClass#getMethods()
+     */
+    public List getMethods() {
+        return delegate.getMethods();
+    }
+    /* (non-Javadoc)
+     * @see groovy.lang.MetaClass#getProperties()
+     */
+    public List getProperties() {
+        return delegate.getProperties();
+    }
+    /* (non-Javadoc)
+     * @see groovy.lang.MetaClass#getProperty(java.lang.Object, java.lang.String)
+     */
+    public Object getProperty(Object object, String property) {
+        return delegate.getProperty(object, property);
+    }
+    /* (non-Javadoc)
+     * @see groovy.lang.MetaClass#invokeConstructor(java.lang.Object[])
+     */
+    public Object invokeConstructor(Object[] arguments) {
+        return delegate.invokeConstructor(arguments);
+    }
+
+    /* (non-Javadoc)
+     * @see groovy.lang.MetaClass#invokeMethod(java.lang.Object, java.lang.String, java.lang.Object)
+     */
+    public Object invokeMethod(Object object, String methodName, Object arguments) {
+        return delegate.invokeMethod(object, methodName, arguments);
+    }
+    /* (non-Javadoc)
+     * @see groovy.lang.MetaClass#invokeMethod(java.lang.Object, java.lang.String, java.lang.Object[])
+     */
+    public Object invokeMethod(Object object, String methodName, Object[] arguments) {
+        return delegate.invokeMethod(object, methodName, arguments);
+    }
+    /* (non-Javadoc)
+     * @see groovy.lang.MetaClass#invokeStaticMethod(java.lang.Object, java.lang.String, java.lang.Object[])
+     */
+    public Object invokeStaticMethod(Object object, String methodName, Object[] arguments) {
+        return delegate.invokeStaticMethod(object, methodName, arguments);
+    }
+
+    /* (non-Javadoc)
+     * @see groovy.lang.MetaClass#setAttribute(java.lang.Object, java.lang.String, java.lang.Object)
+     */
+    public void setAttribute(Object object, String attribute, Object newValue) {
+        delegate.setAttribute(object, attribute, newValue);
+    }
+    /* (non-Javadoc)
+     * @see groovy.lang.MetaClass#setProperty(java.lang.Object, java.lang.String, java.lang.Object)
+     */
+    public void setProperty(Object object, String property, Object newValue) {
+        delegate.setProperty(object, property, newValue);
+    }
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals(Object obj) {
+        return delegate.equals(obj);
+    }
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        return delegate.hashCode();
+    }
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        return delegate.toString();
+    }
+    /**
+     * @deprecated
+     */
+    public MetaMethod pickMethod(String methodName, Class[] arguments) {
+        return delegate.pickMethod(methodName,arguments);
+    }
+    /**
+     * @deprecated
+     */
+    protected MetaMethod retrieveMethod(String methodName, Class[] arguments) {
+        return delegate.retrieveMethod(methodName,arguments);
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/DeprecationException.java b/groovy-core/src/main/groovy/lang/DeprecationException.java
new file mode 100644
index 0000000..a0e2b05
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/DeprecationException.java
@@ -0,0 +1,24 @@
+package groovy.lang;
+
+/**
+ * Use this exception to mark a method implementation as being deprecated.
+ * Use the message to indicate the recommended way of calling the desired functionality.
+ * Make throwing this exception the only line in the method implementation, i.e. unlike the Java
+ * @-deprecated feature there is no relay to the new implementation but an early and deliberate
+ * halt of execution ("fail early").
+ *
+ * This exception is supposed to be used in the SNAPSHOT releases only. Before release, all
+ * references to this exception should be resolved and the according methods removed.
+ *
+ * @author Dierk Koenig
+ */
+public class DeprecationException extends RuntimeException {
+
+    public DeprecationException(String message) {
+        super(message);
+    }
+
+    public DeprecationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/EmptyRange.java b/groovy-core/src/main/groovy/lang/EmptyRange.java
new file mode 100644
index 0000000..ac1d41e
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/EmptyRange.java
@@ -0,0 +1,152 @@
+package groovy.lang;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.util.*;
+
+/**
+ * Constructing Ranges like 0..<0
+ * @author Dierk Koenig
+ */
+public class EmptyRange implements Range {
+    protected Comparable at = null;
+    protected final List EMPTY_LIST = new ArrayList();
+
+    public EmptyRange(Comparable at) {
+       this.at = at;
+    }
+
+    public Comparable getFrom() {
+        return at;
+    }
+
+    public Comparable getTo() {
+        return at;
+    }
+
+    public boolean isReverse() {
+        return false;
+    }
+
+    public String inspect() {
+        return InvokerHelper.inspect(at)+"..<"+InvokerHelper.inspect(at);
+    }
+
+    public String toString() {
+        if (null == at) return "null..<null";
+        return at.toString()+"..<"+at.toString();
+    }
+
+    public int size() {
+        return 0;
+    }
+
+    public void clear() {
+    }
+
+    public boolean isEmpty() {
+        return true;
+    }
+
+    public Object[] toArray() {
+        return new Object[0];
+    }
+
+    public Object get(int index) {
+        return null;
+    }
+
+    public Object remove(int index) {
+        return null;
+    }
+
+    /**
+     * @throws UnsupportedOperationException
+     */
+    public void add(int index, Object element) {
+        throw new UnsupportedOperationException("cannot add to Empty Ranges");
+    }
+
+    public int indexOf(Object o) {
+        return -1;
+    }
+
+    public int lastIndexOf(Object o) {
+        return -1;
+    }
+
+    /**
+     * @throws UnsupportedOperationException
+     */
+    public boolean add(Object o) {
+        throw new UnsupportedOperationException("cannot add to Empty Ranges");
+    }
+
+    public boolean contains(Object o) {
+        return false;
+    }
+
+    public boolean remove(Object o) {
+        return false;
+    }
+
+    /**
+     * @throws UnsupportedOperationException
+     */
+    public boolean addAll(int index, Collection c) {
+        throw new UnsupportedOperationException("cannot add to Empty Ranges");
+    }
+
+     /**
+     * @throws UnsupportedOperationException
+     */
+    public boolean addAll(Collection c) {
+        throw new UnsupportedOperationException("cannot add to Empty Ranges");
+    }
+
+    public boolean containsAll(Collection c) {
+        return false;
+    }
+
+    public boolean removeAll(Collection c) {
+        return false;
+    }
+
+    public boolean retainAll(Collection c) {
+        return false;
+    }
+
+    public Iterator iterator() {
+        return EMPTY_LIST.iterator();
+    }
+
+    public List subList(int fromIndex, int toIndex) {
+        return EMPTY_LIST.subList(fromIndex, toIndex);
+    }
+
+    public ListIterator listIterator() {
+        return EMPTY_LIST.listIterator();
+    }
+
+    public ListIterator listIterator(int index) {
+        return EMPTY_LIST.listIterator(index);
+    }
+
+     /**
+     * @throws UnsupportedOperationException
+     */
+    public Object set(int index, Object element) {
+        throw new UnsupportedOperationException("cannot set in Empty Ranges");
+    }
+
+    public Object[] toArray(Object a[]) {
+        return new Object[0];
+    }
+
+    public void step(int step, Closure closure) {
+    }
+
+    public List step(int step) {
+        return EMPTY_LIST;
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/GString.java b/groovy-core/src/main/groovy/lang/GString.java
new file mode 100644
index 0000000..d90ddfa
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/GString.java
@@ -0,0 +1,227 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package groovy.lang;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * Represents a String which contains embedded values such as "hello there
+ * ${user} how are you?" which can be evaluated lazily. Advanced users can
+ * iterate over the text and values to perform special processing, such as for
+ * performing SQL operations, the values can be substituted for ? and the
+ * actual value objects can be bound to a JDBC statement. The lovely name of
+ * this class was suggested by Jules Gosnell and was such a good idea, I
+ * couldn't resist :)
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public abstract class GString extends GroovyObjectSupport implements Comparable, CharSequence, Writable, Buildable {
+
+    private Object[] values;
+
+    public GString(Object values) {
+        this.values = (Object[]) values;
+    }
+
+    public GString(Object[] values) {
+        this.values = values;
+    }
+
+    // will be static in an instance
+    public abstract String[] getStrings();
+
+    /**
+     * Overloaded to implement duck typing for Strings 
+     * so that any method that can't be evaluated on this
+     * object will be forwarded to the toString() object instead.
+     */
+    public Object invokeMethod(String name, Object args) {
+        try {
+            return super.invokeMethod(name, args);
+        }
+        catch (MissingMethodException e) {
+            // lets try invoke the method on the real String
+            return InvokerHelper.invokeMethod(toString(), name, args);
+        }
+    }
+
+    public Object[] getValues() {
+        return values;
+    }
+
+    public GString plus(GString that) {
+        List stringList = new ArrayList();
+        List valueList = new ArrayList();
+
+        stringList.addAll(Arrays.asList(getStrings()));
+        valueList.addAll(Arrays.asList(getValues()));
+
+        if (stringList.size() > valueList.size()) {
+            valueList.add("");
+        }
+
+        stringList.addAll(Arrays.asList(that.getStrings()));
+        valueList.addAll(Arrays.asList(that.getValues()));
+
+        final String[] newStrings = new String[stringList.size()];
+        stringList.toArray(newStrings);
+        Object[] newValues = valueList.toArray();
+
+        return new GString(newValues) {
+            public String[] getStrings() {
+                return newStrings;
+            }
+        };
+    }
+
+    public GString plus(String that) {
+        String[] currentStrings = getStrings();
+        String[] newStrings = null;
+        Object[] newValues = null;
+
+        newStrings = new String[currentStrings.length + 1];
+        newValues = new Object[getValues().length + 1];
+        int lastIndex = currentStrings.length;
+        System.arraycopy(currentStrings, 0, newStrings, 0, lastIndex);
+        System.arraycopy(getValues(), 0, newValues, 0, getValues().length);
+        newStrings[lastIndex] = that;
+        newValues[getValues().length] = "";
+
+        final String[] finalStrings = newStrings;
+        return new GString(newValues) {
+
+            public String[] getStrings() {
+                return finalStrings;
+            }
+        };
+    }
+
+    public int getValueCount() {
+        return values.length;
+    }
+
+    public Object getValue(int idx) {
+        return values[idx];
+    }
+
+    public String toString() {
+        StringWriter buffer = new StringWriter();
+        try {
+            writeTo(buffer);
+        }
+        catch (IOException e) {
+            throw new StringWriterIOException(e);
+        }
+        return buffer.toString();
+    }
+
+    public Writer writeTo(Writer out) throws IOException {
+        String[] s = getStrings();
+        int numberOfValues = values.length;
+        for (int i = 0, size = s.length; i < size; i++) {
+            out.write(s[i]);
+            if (i < numberOfValues) {
+                InvokerHelper.write(out, values[i]);
+            }
+        }
+        return out;
+    }
+
+    /* (non-Javadoc)
+     * @see groovy.lang.Buildable#build(groovy.lang.GroovyObject)
+     */
+    public void build(final GroovyObject builder) {
+    final String[] s = getStrings();
+    final int numberOfValues = values.length;
+        
+        for (int i = 0, size = s.length; i < size; i++) {
+            builder.getProperty("mkp");
+            builder.invokeMethod("yield", new Object[]{s[i]});
+            if (i < numberOfValues) {
+                builder.getProperty("mkp");
+                builder.invokeMethod("yield", new Object[]{values[i]});
+            }
+        }
+    }
+
+    public boolean equals(Object that) {
+        if (that instanceof GString) {
+            return equals((GString) that);
+        }
+        return false;
+    }
+
+    public boolean equals(GString that) {
+        return toString().equals(that.toString());
+    }
+
+    public int hashCode() {
+        return 37 + toString().hashCode();
+    }
+
+    public int compareTo(Object that) {
+        return toString().compareTo(that.toString());
+    }
+
+    public char charAt(int index) {
+        return toString().charAt(index);
+    }
+
+    public int length() {
+        return toString().length();
+    }
+
+    public CharSequence subSequence(int start, int end) {
+        return toString().subSequence(start, end);
+    }
+
+    /**
+     * Turns a String into a regular expression pattern
+     *
+     * @return the regular expression pattern
+     */
+    public Pattern negate() {
+        return DefaultGroovyMethods.negate(toString());
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/GroovyClassLoader.java b/groovy-core/src/main/groovy/lang/GroovyClassLoader.java
new file mode 100644
index 0000000..942db36
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/GroovyClassLoader.java
@@ -0,0 +1,853 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+/**
+ * @TODO: multi threaded compiling of the same class but with different roots
+ * for compilation... T1 compiles A, which uses B, T2 compiles B... mark A and B
+ * as parsed and then synchronize compilation. Problems: How to synchronize? 
+ * How to get error messages?   
+ * 
+ */
+package groovy.lang;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.classgen.Verifier;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.Phases;
+import org.codehaus.groovy.control.SourceUnit;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+
+/**
+ * A ClassLoader which can load Groovy classes. The loaded classes are cached, 
+ * classes from other classlaoders should not be cached. To be able to load a 
+ * script that was asked for earlier but was created later it is essential not
+ * to keep anything like a "class not found" information for that class name. 
+ * This includes possible parent loaders. Classes that are not chached are always 
+ * reloaded.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Guillaume Laforge
+ * @author Steve Goetze
+ * @author Bing Ran
+ * @author <a href="mailto:scottstirling@rcn.com">Scott Stirling</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * @version $Revision$
+ */
+public class GroovyClassLoader extends URLClassLoader {
+
+    /**
+     * this cache contains the loaded classes or PARSING, if the class is currently parsed 
+     */
+    protected Map classCache = new HashMap();
+    protected Map sourceCache = new HashMap();
+    private CompilerConfiguration config;
+    private Boolean recompile = null;
+    // use 1000000 as offset to avoid conflicts with names form the GroovyShell 
+    private static int scriptNameCounter = 1000000;
+    
+    private GroovyResourceLoader resourceLoader = new GroovyResourceLoader() {
+        public URL loadGroovySource(final String filename) throws MalformedURLException {
+            URL file = (URL) AccessController.doPrivileged(new PrivilegedAction() {
+                public Object run() {
+                    return  getSourceFile(filename);
+                }
+            });
+            return file;
+        }
+    };
+
+    /**
+     * creates a GroovyClassLoader using the current Thread's context
+     * Class loader as parent.
+     */
+    public GroovyClassLoader() {
+        this(Thread.currentThread().getContextClassLoader());
+    }
+
+    /**
+     * creates a GroovyClassLoader using the given ClassLoader as parent
+     */
+    public GroovyClassLoader(ClassLoader loader) {
+        this(loader, null);
+    }
+
+    /**
+     * creates a GroovyClassLoader using the given GroovyClassLoader as parent.
+     * This loader will get the parent's CompilerConfiguration
+     */
+    public GroovyClassLoader(GroovyClassLoader parent) {
+        this(parent, parent.config, false);
+    }
+
+    /**
+     * creates a GroovyClassLaoder.
+     * @param parent the parten class loader
+     * @param config the compiler configuration
+     * @param useConfigurationClasspath determines if the configurations classpath should be added 
+     */
+    public GroovyClassLoader(ClassLoader parent, CompilerConfiguration config, boolean useConfigurationClasspath) {
+        super(new URL[0],parent);
+        if (config==null) config = CompilerConfiguration.DEFAULT;
+        this.config = config;
+        if (useConfigurationClasspath) {
+            for (Iterator it=config.getClasspath().iterator(); it.hasNext();) {
+                String path = (String) it.next();
+                this.addClasspath(path);
+            }
+        }
+    }
+    
+    /**
+     * creates a GroovyClassLoader using the given ClassLoader as parent.
+     */
+    public GroovyClassLoader(ClassLoader loader, CompilerConfiguration config) {
+        this(loader,config,true);
+    }
+    
+    public void setResourceLoader(GroovyResourceLoader resourceLoader) {
+        if (resourceLoader == null) {
+            throw new IllegalArgumentException("Resource loader must not be null!");
+        }
+        this.resourceLoader = resourceLoader;
+    }
+
+    public GroovyResourceLoader getResourceLoader() {
+        return resourceLoader;
+    }
+
+    /**
+     * Loads the given class node returning the implementation Class
+     *
+     * @param classNode
+     * @return a class
+     */
+    public Class defineClass(ClassNode classNode, String file) {
+        //return defineClass(classNode, file, "/groovy/defineClass");
+        throw new DeprecationException("the method GroovyClassLoader#defineClass(ClassNode, String) is no longer used and removed");
+    }
+
+    /**
+     * Loads the given class node returning the implementation Class. 
+     * 
+     * WARNING: this compilation is not synchronized
+     *
+     * @param classNode
+     * @return a class
+     */
+    public Class defineClass(ClassNode classNode, String file, String newCodeBase) {
+        CodeSource codeSource = null;
+        try {
+            codeSource = new CodeSource(new URL("file", "", newCodeBase), (java.security.cert.Certificate[]) null);
+        } catch (MalformedURLException e) {
+            //swallow
+        }
+
+        CompilationUnit unit = createCompilationUnit(config,codeSource);
+        ClassCollector collector = createCollector(unit,classNode.getModule().getContext());
+        try {
+            unit.addClassNode(classNode);
+            unit.setClassgenCallback(collector);
+            unit.compile(Phases.CLASS_GENERATION);
+
+            return collector.generatedClass;
+        } catch (CompilationFailedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Parses the given file into a Java class capable of being run
+     *
+     * @param file the file name to parse
+     * @return the main class defined in the given script
+     */
+    public Class parseClass(File file) throws CompilationFailedException, IOException {
+        return parseClass(new GroovyCodeSource(file));
+    }
+
+    /**
+     * Parses the given text into a Java class capable of being run
+     *
+     * @param text     the text of the script/class to parse
+     * @param fileName the file name to use as the name of the class
+     * @return the main class defined in the given script
+     */
+    public Class parseClass(String text, String fileName) throws CompilationFailedException {
+        return parseClass(new ByteArrayInputStream(text.getBytes()), fileName);
+    }
+
+    /**
+     * Parses the given text into a Java class capable of being run
+     *
+     * @param text the text of the script/class to parse
+     * @return the main class defined in the given script
+     */
+    public Class parseClass(String text) throws CompilationFailedException {
+        return parseClass(new ByteArrayInputStream(text.getBytes()), "script" + System.currentTimeMillis() + ".groovy");
+    }
+
+    /**
+     * Parses the given character stream into a Java class capable of being run
+     *
+     * @param in an InputStream
+     * @return the main class defined in the given script
+     */
+    public Class parseClass(InputStream in) throws CompilationFailedException {
+        return parseClass(in, generateScriptName());
+    }
+    
+    public synchronized String generateScriptName() {
+        scriptNameCounter++;
+        return "script"+scriptNameCounter+".groovy";
+    }
+
+    public Class parseClass(final InputStream in, final String fileName) throws CompilationFailedException {
+        // For generic input streams, provide a catch-all codebase of
+        // GroovyScript
+        // Security for these classes can be administered via policy grants with
+        // a codebase of file:groovy.script
+        GroovyCodeSource gcs = (GroovyCodeSource) AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                return new GroovyCodeSource(in, fileName, "/groovy/script");
+            }
+        });
+        return parseClass(gcs);
+    }
+
+
+    public Class parseClass(GroovyCodeSource codeSource) throws CompilationFailedException {
+        return parseClass(codeSource, codeSource.isCachable());
+    }
+
+    /**
+     * Parses the given code source into a Java class. If there is a class file
+     * for the given code source, then no parsing is done, instead the cached class is returned.
+     * 
+     * @param shouldCacheSource if true then the generated class will be stored in the source cache 
+     *
+     * @return the main class defined in the given script
+     */
+    public Class parseClass(GroovyCodeSource codeSource, boolean shouldCacheSource) throws CompilationFailedException {
+        synchronized (classCache) {
+            Class answer = (Class) sourceCache.get(codeSource.getName());
+            if (answer!=null) return answer;
+            
+            // Was neither already loaded nor compiling, so compile and add to
+            // cache.
+            try {
+                CompilationUnit unit = createCompilationUnit(config, codeSource.getCodeSource());
+                SourceUnit su = null;
+                if (codeSource.getFile()==null) {
+                    su = unit.addSource(codeSource.getName(), codeSource.getInputStream());
+                } else {
+                    su = unit.addSource(codeSource.getFile());
+                }
+                
+                ClassCollector collector = createCollector(unit,su);
+                unit.setClassgenCallback(collector);
+                int goalPhase = Phases.CLASS_GENERATION;
+                if (config != null && config.getTargetDirectory()!=null) goalPhase = Phases.OUTPUT;
+                unit.compile(goalPhase);
+                
+                answer = collector.generatedClass;
+                for (Iterator iter = collector.getLoadedClasses().iterator(); iter.hasNext();) {
+                    Class clazz = (Class) iter.next();
+                    setClassCacheEntry(clazz);
+                }
+                if (shouldCacheSource) sourceCache.put(codeSource.getName(), answer);
+            } finally {
+                try {
+                    InputStream is = codeSource.getInputStream();
+                    if (is!=null) is.close();
+                } catch (IOException e) {
+                    throw new GroovyRuntimeException("unable to close stream",e);
+                }
+            }
+            return answer;
+        }
+    }
+    
+    /**
+     * gets the currently used classpath. 
+     * @return a String[] containing the file information of the urls 
+     * @see #getURLs()
+     */
+    protected String[] getClassPath() {
+        //workaround for Groovy-835
+        URL[] urls = getURLs();
+        String[] ret = new String[urls.length];
+        for (int i = 0; i < ret.length; i++) {
+            ret[i] =  urls[i].getFile();
+        }
+        return ret;
+    }
+
+    /**
+     * expands the classpath
+     * @param pathList an empty list that will contain the elements of the classpath
+     * @param classpath the classpath specified as a single string
+     * @deprecated
+     */
+    protected void expandClassPath(List pathList, String base, String classpath, boolean isManifestClasspath) {
+        throw new DeprecationException("the method groovy.lang.GroovyClassLoader#expandClassPath(List,String,String,boolean) is no longer used internally and removed");
+    }
+
+    /**
+     * A helper method to allow bytecode to be loaded. spg changed name to
+     * defineClass to make it more consistent with other ClassLoader methods
+     * @deprecated
+     */
+    protected Class defineClass(String name, byte[] bytecode, ProtectionDomain domain) {
+        throw new DeprecationException("the method groovy.lang.GroovyClassLoader#defineClass(String,byte[],ProtectionDomain) is no longer used internally and removed");
+    }
+    
+    public static class InnerLoader extends GroovyClassLoader{
+        private GroovyClassLoader delegate;
+    	public InnerLoader(GroovyClassLoader delegate) {
+    		super(delegate);
+            this.delegate = delegate;
+    	}
+        public void addClasspath(String path) {
+            delegate.addClasspath(path);
+        }
+        public void clearCache() {
+            delegate.clearCache();
+        }
+        public URL findResource(String name) {
+            return delegate.findResource(name);
+        }
+        public Enumeration findResources(String name) throws IOException {
+            return delegate.findResources(name);
+        }
+        public Class[] getLoadedClasses() {
+            return delegate.getLoadedClasses();
+        }
+        public URL getResource(String name) {
+            return delegate.getResource(name);
+        }
+        public InputStream getResourceAsStream(String name) {
+            return delegate.getResourceAsStream(name);
+        }
+        public GroovyResourceLoader getResourceLoader() {
+            return delegate.getResourceLoader();
+        }
+        public URL[] getURLs() {
+            return delegate.getURLs();
+        }
+        public Class loadClass(String name, boolean lookupScriptFiles, boolean preferClassOverScript, boolean resolve) throws ClassNotFoundException, CompilationFailedException {
+            Class c = findLoadedClass(name);
+            if (c!=null) return c;
+            return delegate.loadClass(name, lookupScriptFiles, preferClassOverScript, resolve);
+        }
+        public Class parseClass(GroovyCodeSource codeSource, boolean shouldCache) throws CompilationFailedException {
+            return delegate.parseClass(codeSource, shouldCache);
+        }
+        public void setResourceLoader(GroovyResourceLoader resourceLoader) {
+            delegate.setResourceLoader(resourceLoader);
+        }
+        public void addURL(URL url) {
+            delegate.addURL(url);
+        }        
+    }
+    
+    /**
+     * creates a new CompilationUnit. If you want to add additional
+     * phase operations to the CompilationUnit (for example to inject
+     * additional methods, variables, fields), then you should overwrite
+     * this method.
+     * 
+     * @param config the compiler configuration, usually the same as for this class loader
+     * @param source the source containing the initial file to compile, more files may follow during compilation
+     * 
+     * @return the CompilationUnit
+     */
+    protected CompilationUnit createCompilationUnit(CompilerConfiguration config, CodeSource source) {
+        return new CompilationUnit(config, source, this);
+    }
+
+    /**
+     * creates a ClassCollector for a new compilation.
+     * @param unit the compilationUnit
+     * @param su  the SoruceUnit
+     * @return the ClassCollector
+     */
+    protected ClassCollector createCollector(CompilationUnit unit,SourceUnit su) {
+    	InnerLoader loader = (InnerLoader) AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                return new InnerLoader(GroovyClassLoader.this);
+            }
+        }); 
+        return new ClassCollector(loader, unit, su);
+    }
+
+    public static class ClassCollector extends CompilationUnit.ClassgenCallback {
+        private Class generatedClass;
+        private GroovyClassLoader cl;
+        private SourceUnit su;
+        private CompilationUnit unit;
+        private Collection loadedClasses = null;
+
+        protected ClassCollector(InnerLoader cl, CompilationUnit unit, SourceUnit su) {
+            this.cl = cl;
+            this.unit = unit;
+            this.loadedClasses = new ArrayList();
+            this.su = su;
+        }
+        protected GroovyClassLoader getDefiningClassLoader(){
+            return cl;
+        }
+        protected Class createClass(byte[] code, ClassNode classNode) {
+            GroovyClassLoader cl = getDefiningClassLoader();
+            Class theClass = cl.defineClass(classNode.getName(), code, 0, code.length, unit.getAST().getCodeSource());
+            cl.resolveClass(theClass);
+            this.loadedClasses.add(theClass);
+
+            if (generatedClass == null) {
+                ModuleNode mn = classNode.getModule();
+                SourceUnit msu = null;
+                if (mn!=null) msu = mn.getContext();
+                ClassNode main = null;
+                if (mn!=null) main = (ClassNode) mn.getClasses().get(0);
+                if (msu==su && main==classNode) generatedClass = theClass;
+            }
+
+            return theClass;
+        }
+        
+        protected Class onClassNode(ClassWriter classWriter, ClassNode classNode) {
+            byte[] code = classWriter.toByteArray();
+            return createClass(code,classNode);
+        }
+
+        public void call(ClassVisitor classWriter, ClassNode classNode) {
+            onClassNode((ClassWriter) classWriter, classNode);
+        }
+
+        public Collection getLoadedClasses() {
+            return this.loadedClasses;
+        }
+    }
+
+    /**
+     * open up the super class define that takes raw bytes
+     *
+     */
+    public Class defineClass(String name, byte[] b) {
+        return super.defineClass(name, b, 0, b.length);
+    }
+    
+    /**
+     * loads a class from a file or a parent classloader.
+     * This method does call loadClass(String, boolean, boolean, boolean)
+     * with the last parameter set to false.
+     * @throws CompilationFailedException 
+     */
+    public Class loadClass(final String name, boolean lookupScriptFiles, boolean preferClassOverScript)
+        throws ClassNotFoundException, CompilationFailedException
+    {
+        return loadClass(name,lookupScriptFiles,preferClassOverScript,false);
+    }
+
+    /**
+     * gets a class from the class cache. This cache contains only classes loaded through
+     * this class loader or an InnerLoader instance. If no class is stored for a
+     * specific name, then the method should return null. 
+     *  
+     * @param name of the class
+     * @return the class stored for the given name 
+     * @see #removeClassCacheEntry(String)
+     * @see #setClassCacheEntry(Class)
+     * @see #clearCache()
+     */    
+    protected Class getClassCacheEntry(String name) {
+        if (name==null) return null;
+        synchronized (classCache) {
+            Class cls = (Class) classCache.get(name);
+            return cls;
+        }
+    }
+    
+    /**
+     * sets an entry in the class cache. 
+     * @param cls the class
+     * @see #removeClassCacheEntry(String)
+     * @see #getClassCacheEntry(String)
+     * @see #clearCache()
+     */
+    protected void setClassCacheEntry(Class cls) {
+        synchronized (classCache) {
+            classCache.put(cls.getName(),cls);
+        }
+    }    
+    
+    /**
+     * removes a class from the class cache.
+     * @param name of the class
+     * @see #getClassCacheEntry(String)
+     * @see #setClassCacheEntry(Class)
+     * @see #clearCache()
+     */
+    protected void removeClassCacheEntry(String name) {
+        synchronized (classCache) {
+            classCache.remove(name);
+        }
+    }    
+    
+    /**
+     * adds a URL to the classloader.
+     * @param url the new classpath element 
+     */
+    public void addURL(URL url) {
+        super.addURL(url);
+    }
+    
+    /**
+     * Indicates if a class is recompilable. Recompileable means, that the classloader
+     * will try to locate a groovy source file for this class and then compile it again,
+     * adding the resulting class as entry to the cache. Giving null as class is like a
+     * recompilation, so the method should always return true here. Only classes that are
+     * implementing GroovyObject are compileable and only if the timestamp in the class
+     * is lower than Long.MAX_VALUE.  
+     * 
+     *  NOTE: First the parent loaders will be asked and only if they don't return a
+     *  class the recompilation will happen. Recompilation also only happen if the source
+     *  file is newer.
+     * 
+     * @see #isSourceNewer(URL, Class)
+     * @param cls the class to be tested. If null the method should return true
+     * @return true if the class should be compiled again
+     */
+    protected boolean isRecompilable(Class cls) {
+        if (cls==null) return true;
+        if (recompile==null && !config.getRecompileGroovySource()) return false;
+        if (recompile!=null && !recompile.booleanValue()) return false;
+        if (!GroovyObject.class.isAssignableFrom(cls)) return false;
+        long timestamp = getTimeStamp(cls); 
+        if (timestamp == Long.MAX_VALUE) return false;
+        
+        return true;
+    }
+    
+    /**
+     * sets if the recompilation should be enable. There are 3 possible
+     * values for this. Any value different than null overrides the
+     * value from the compiler configuration. true means to recompile if needed
+     * false means to never recompile.  
+     * @param mode the recompilation mode
+     * @see CompilerConfiguration
+     */
+    public void setShouldRecompile(Boolean mode){
+        recompile = mode;
+    }
+    
+    
+    /**
+     * gets the currently set recompilation mode. null means, the 
+     * compiler configuration is used. False means no recompilation and 
+     * true means that recompilation will be done if needed. 
+     * @return the recompilation mode
+     */
+    public Boolean isShouldRecompile(){
+        return recompile;
+    }
+
+    /**
+     * loads a class from a file or a parent classloader.
+     *
+     * @param name                      of the class to be loaded
+     * @param lookupScriptFiles         if false no lookup at files is done at all
+     * @param preferClassOverScript     if true the file lookup is only done if there is no class
+     * @param resolve                   @see ClassLoader#loadClass(java.lang.String, boolean)
+     * @return                          the class found or the class created from a file lookup
+     * @throws ClassNotFoundException
+     */
+    public Class loadClass(final String name, boolean lookupScriptFiles, boolean preferClassOverScript, boolean resolve)
+        throws ClassNotFoundException, CompilationFailedException
+    {
+        // look into cache
+        Class cls=getClassCacheEntry(name);
+        
+        // enable recompilation?
+        boolean recompile = isRecompilable(cls);
+        if (!recompile) return cls;
+
+        // check security manager
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            String className = name.replace('/', '.');
+            int i = className.lastIndexOf('.');
+            if (i != -1) {
+                sm.checkPackageAccess(className.substring(0, i));
+            }
+        }
+
+        // try parent loader
+        ClassNotFoundException last = null;
+        try {
+            Class parentClassLoaderClass = super.loadClass(name, resolve);
+            // always return if the parent loader was successfull 
+            if (cls!=parentClassLoaderClass) return parentClassLoaderClass;
+        } catch (ClassNotFoundException cnfe) {
+            last = cnfe;
+        } catch (NoClassDefFoundError ncdfe) {
+            if (ncdfe.getMessage().indexOf("wrong name")>0) {
+                last = new ClassNotFoundException(name);
+            } else {
+                throw ncdfe;
+            }
+        }
+
+        if (cls!=null) {
+            // prefer class if no recompilation
+            preferClassOverScript |= !recompile;
+            if (preferClassOverScript) return cls;
+        }
+
+        // at this point the loading from a parent loader failed
+        // and we want to recompile if needed.
+        if (lookupScriptFiles) {
+            // synchronize on cache, as we want only one compilation
+            // at the same time
+            synchronized (classCache) {
+                // try groovy file
+                try {
+                    // check if recompilation already happend.
+                    if (getClassCacheEntry(name)!=cls) return getClassCacheEntry(name);
+                    URL source = resourceLoader.loadGroovySource(name);
+                    cls = recompile(source,name,cls);
+                } catch (IOException ioe) {
+                    last = new ClassNotFoundException("IOException while openening groovy source: " + name, ioe);
+                } finally {
+                    if (cls==null) {
+                        removeClassCacheEntry(name);
+                    } else {
+                        setClassCacheEntry(cls);
+                    }
+                }
+            }
+        }
+
+        if (cls==null) {
+            // no class found, there has to be an exception before then
+            if (last==null) throw new AssertionError(true);
+            throw last;
+        }
+        return cls;
+    }
+
+    /**
+     * (Re)Comipiles the given source. 
+     * This method starts the compilation of a given source, if
+     * the source has changed since the class was created. For
+     * this isSourceNewer is called.
+     * 
+     * @see #isSourceNewer(URL, Class)
+     * @param source the source pointer for the compilation
+     * @param className the name of the class to be generated
+     * @param oldClass a possible former class
+     * @return the old class if the source wasn't new enough, the new class else
+     * @throws CompilationFailedException if the compilation failed
+     * @throws IOException if the source is not readable
+     * 
+     */
+    protected Class recompile(URL source, String className, Class oldClass) throws CompilationFailedException, IOException {
+        if (source != null) {
+            // found a source, compile it if newer
+            if ((oldClass!=null && isSourceNewer(source, oldClass)) || (oldClass==null)) {
+                sourceCache.remove(className);
+                return parseClass(source.openStream(),className);
+            }
+        }
+        return oldClass;
+    }
+
+    /**
+     * Implemented here to check package access prior to returning an
+     * already loaded class.
+     * @throws CompilationFailedException if the compilation failed
+     * @throws ClassNotFoundException if the class was not found
+     * @see java.lang.ClassLoader#loadClass(java.lang.String, boolean)
+     */
+    protected Class loadClass(final String name, boolean resolve) throws ClassNotFoundException {
+        return loadClass(name,true,false,resolve);
+    }
+
+    /**
+     * gets the time stamp of a given class. For groovy
+     * generated classes this usually means to return the value
+     * of the static field __timeStamp. If the parameter doesn't
+     * have such a field, then Long.MAX_VALUE is returned
+     * 
+     * @param cls the class 
+     * @return the time stamp
+     */
+    protected long getTimeStamp(Class cls) {
+        Long o;
+        try {
+            Field field = cls.getField(Verifier.__TIMESTAMP);
+            o = (Long) field.get(null);
+        } catch (Exception e) {
+            return Long.MAX_VALUE;
+        }
+        return o.longValue();
+    }
+
+    private URL getSourceFile(String name) {
+        String filename = name.replace('.', '/') + config.getDefaultScriptExtension();
+        URL ret = getResource(filename);
+        if (ret!=null && ret.getProtocol().equals("file")) {
+            String fileWithoutPackage = filename;
+            if (fileWithoutPackage.indexOf('/')!=-1){
+                int index = fileWithoutPackage.lastIndexOf('/');
+                fileWithoutPackage = fileWithoutPackage.substring(index+1);
+            }
+            File path = new File(ret.getFile()).getParentFile();
+            if (path.exists() && path.isDirectory()) {
+                File file = new File(path, fileWithoutPackage);
+                if (file.exists()) {
+                    // file.exists() might be case insensitive. Let's do
+                    // case sensitive match for the filename
+                    File parent = file.getParentFile();
+                    String[] files = parent.list();
+                    for (int j = 0; j < files.length; j++) {
+                        if (files[j].equals(fileWithoutPackage)) return ret;
+                    }
+                }
+            }
+            //file does not exist!
+            return null;
+        }
+        return ret;
+    }
+
+    /**
+     * Decides if the given source is newer than a class.
+     * 
+     * @see #getTimeStamp(Class)
+     * @param source the source we may want to compile
+     * @param cls the former class
+     * @return true if the source is newer, false else
+     * @throws IOException if it is not possible to open an
+     * connection for the given source
+     */
+    protected boolean isSourceNewer(URL source, Class cls) throws IOException {
+        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 {
+            lastMod = source.openConnection().getLastModified();
+        }
+        long classTime = getTimeStamp(cls);
+        return classTime+config.getMinimumRecompilationInterval() < lastMod;
+    }
+
+    /**
+     * adds a classpath to this classloader.  
+     * @param path is a jar file or a directory.
+     * @see #addURL(URL)
+     */
+    public void addClasspath(final String path) {
+        AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                try {
+                    File f = new File(path);
+                    URL newURL = f.toURI().toURL();
+                    URL[] urls = getURLs();
+                    for (int i=0; i<urls.length; i++) {
+                        if (urls[i].equals(newURL)) return null;
+                    }
+                    addURL(newURL);
+                } catch (MalformedURLException e) {
+                    //TODO: fail through ?
+                }
+                return null;
+            }
+        });
+    }
+
+    /**
+     * <p>Returns all Groovy classes loaded by this class loader.
+     *
+     * @return all classes loaded by this class loader
+     */
+    public Class[] getLoadedClasses() {
+        synchronized (classCache) {
+            return (Class[]) classCache.values().toArray(new Class[0]);
+        }
+    }
+    
+    /**
+     * removes all classes from the class cache.
+     * @see #getClassCacheEntry(String)
+     * @see #setClassCacheEntry(Class)
+     * @see #removeClassCacheEntry(String)
+     */    
+    public void clearCache() {
+        synchronized (classCache) {
+            classCache.clear();
+        }
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/GroovyCodeSource.java b/groovy-core/src/main/groovy/lang/GroovyCodeSource.java
new file mode 100644
index 0000000..6a5c449
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/GroovyCodeSource.java
@@ -0,0 +1,163 @@
+package groovy.lang;
+
+import groovy.security.GroovyCodeSourcePermission;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.cert.Certificate;
+
+/**
+ * CodeSource wrapper class that allows specific security policies to be associated with a class
+ * compiled from groovy source.
+ * 
+ * @author Steve Goetze
+ */
+public class GroovyCodeSource {
+	
+	/** 
+	 * The codeSource to be given the generated class.  This can be used by policy file
+	 * grants to administer security.
+	 */
+	private CodeSource codeSource;
+	/** The name given to the generated class */
+	private String name;
+	/** The groovy source to be compiled and turned into a class */
+	private InputStream inputStream;
+	/** The certificates used to sign the items from the codesource */
+	Certificate[] certs;
+    private boolean cachable = false;
+    
+	private File file;
+	
+	public GroovyCodeSource(String script, String name, String codeBase) {
+		this(new ByteArrayInputStream(script.getBytes()), name, codeBase);
+	}
+	
+	/**
+	 * Construct a GroovyCodeSource for an inputStream of groovyCode that has an
+	 * unknown provenance -- meaning it didn't come from a File or a URL (e.g. a String).
+	 * The supplied codeBase will be used to construct a File URL that should match up
+	 * with a java Policy entry that determines the grants to be associated with the
+	 * class that will be built from the InputStream.
+	 * 
+	 * The permission groovy.security.GroovyCodeSourcePermission will be used to determine if the given codeBase
+	 * may be specified.  That is, the current Policy set must have a GroovyCodeSourcePermission that implies
+	 * the codeBase, or an exception will be thrown.  This is to prevent callers from hijacking
+	 * existing codeBase policy entries unless explicitly authorized by the user.
+	 */
+	public GroovyCodeSource(InputStream inputStream, String name, String codeBase) {
+		this.inputStream = inputStream;
+		this.name = name;
+		SecurityManager sm = System.getSecurityManager();
+		if (sm != null) {
+		    sm.checkPermission(new GroovyCodeSourcePermission(codeBase));
+		}
+		try {
+			this.codeSource = new CodeSource(new URL("file", "", codeBase), (java.security.cert.Certificate[])null);
+		} catch (MalformedURLException murle) {
+			throw new RuntimeException("A CodeSource file URL cannot be constructed from the supplied codeBase: " + codeBase);
+		}
+	}
+
+	/** 
+	 * Package private constructor called by GroovyClassLoader for signed jar entries
+	 */
+	GroovyCodeSource(InputStream inputStream, String name, final File path, final Certificate[] certs) {
+		this.inputStream = inputStream;
+		this.name = name;
+		try {
+			this.codeSource = (CodeSource) AccessController.doPrivileged( new PrivilegedExceptionAction() {
+				public Object run() throws MalformedURLException {
+					//toURI().toURL() will encode, but toURL() will not.
+					return new CodeSource(path.toURI().toURL(), certs);
+				}
+			});
+		} catch (PrivilegedActionException pae) {
+			//shouldn't happen
+			throw new RuntimeException("Could not construct a URL from: " + path);
+		}
+	}
+	
+	public GroovyCodeSource(final File file) throws FileNotFoundException {
+		if (!file.exists())
+		    throw new FileNotFoundException(file.toString() + " (" +  file.getAbsolutePath() +  ")");
+		else {
+		   try {
+		       if (!file.canRead())
+		           throw new RuntimeException(file.toString() + " can not be read. Check the read permisson of the file \"" + file.toString() + "\" (" +  file.getAbsolutePath() +  ").");
+		   }
+		   catch (SecurityException e) {
+		        throw e;
+		    }
+		}
+
+		//this.inputStream = new FileInputStream(file);
+		this.file = file;
+		this.inputStream = null;
+        this.cachable = true;
+		//The calls below require access to user.dir - allow here since getName() and getCodeSource() are
+		//package private and used only by the GroovyClassLoader.
+		try {
+            Object[] info = (Object[]) AccessController.doPrivileged( new PrivilegedExceptionAction() {
+				public Object run() throws MalformedURLException {
+                    Object[] info = new Object[2];
+                    URL url = file.toURI().toURL();
+                    info[0] = url.toExternalForm();
+					//toURI().toURL() will encode, but toURL() will not.
+					info[1] = new CodeSource(url, (Certificate[]) null);
+                    return info;
+				}
+			});
+			this.name = (String) info[0];
+            this.codeSource = (CodeSource) info[1];
+		} catch (PrivilegedActionException pae) {
+			throw new RuntimeException("Could not construct a URL from: " + file);
+		}
+	}
+	
+	public GroovyCodeSource(URL url) throws IOException {
+		if (url == null) {
+			throw new RuntimeException("Could not construct a GroovyCodeSource from a null URL");
+		}
+		this.inputStream = url.openStream();
+		this.name = url.toExternalForm();
+		this.codeSource = new CodeSource(url, (java.security.cert.Certificate[])null);
+	}
+	
+	CodeSource getCodeSource() {
+		return codeSource;
+	}
+
+	public InputStream getInputStream() {
+        try {
+            if (file!=null) return new FileInputStream(file);
+        } catch (FileNotFoundException fnfe) {}
+		return inputStream;
+	}
+
+	public String getName() {
+		return name;
+	}
+    
+    public File getFile() {
+        return file;
+    }
+    
+    public void setCachable(boolean b) {
+        cachable = b;
+    }
+
+    public boolean isCachable() {
+        return cachable;
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/GroovyInterceptable.java b/groovy-core/src/main/groovy/lang/GroovyInterceptable.java
new file mode 100644
index 0000000..cae0bc1
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/GroovyInterceptable.java
@@ -0,0 +1,55 @@
+/*
+ $Id$
+
+ Copyright 2005 (C) Guillaume Laforge. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+/**
+ * Marker interface used to notify that all methods should be intercepted through the <code>invokeMethod</code> mechanism
+ * of <code>GroovyObject</code>.
+ *
+ * @author Guillaume Laforge
+ */
+public interface GroovyInterceptable extends GroovyObject {
+}
diff --git a/groovy-core/src/main/groovy/lang/GroovyLogTestCase.groovy b/groovy-core/src/main/groovy/lang/GroovyLogTestCase.groovy
new file mode 100644
index 0000000..797f962
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/GroovyLogTestCase.groovy
@@ -0,0 +1,66 @@
+package groovy.lang
+
+import java.util.logging.*
+
+/**
+Helper class to spoof log entries as produced by calling arbitrary code.
+This allows non-intrusive testing of dependent objects without
+explicitly using Mock objects as long as those dependent objects
+do some proper logging.
+As a measure of last resort, it can be used on MetaClass to spoof
+it's log entries on 'invokeMethod'.
+
+@author Dierk Koenig
+@see GroovyLogTestCaseTest
+**/
+
+class GroovyLogTestCase extends GroovyTestCase {
+
+    /**
+     Execute the given Closure with the according level for the Logger that
+     is qualified by the qualifier and return the log output as a String.
+     Qualifiers are usually package or class names.
+     Existing log level and handlers are restored after execution.
+    **/
+    static String stringLog (Level level, String qualifier, Closure yield){
+        // store old values
+        Logger logger = Logger.getLogger(qualifier)
+        def usesParentHandlers = logger.useParentHandlers
+        // set new values
+        logger.useParentHandlers = false
+        def out = new ByteArrayOutputStream(1024)
+        Handler stringHandler = new StreamHandler(out, new SimpleFormatter())
+        stringHandler.level = Level.ALL
+        logger.addHandler(stringHandler) // any old handlers remain
+
+        withLevel(level, qualifier, yield)
+
+        // restore old values
+        logger.level = Level.OFF    // temporarily, to avoid logging the 3 stmts below
+        stringHandler.flush()
+        out.close()
+        logger.removeHandler(stringHandler)
+        logger.useParentHandlers = usesParentHandlers
+        return out.toString()
+    }
+
+    /**
+     Execute the given Closure with the according level for the Logger that
+     is qualified by the qualifier. Qualifiers are usually package or class
+     names.
+     The log level is restored after execution.
+    **/
+    static def withLevel(Level level, String qualifier, Closure yield){
+        // store old values
+        Logger logger = Logger.getLogger(qualifier)
+        def loglevel = logger.level
+        // set new values
+        if (!logger.isLoggable(level)) logger.level = level // use min value
+
+        def result = yield()
+
+        // restore old values
+        logger.level = loglevel
+        return result
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/lang/GroovyObject.java b/groovy-core/src/main/groovy/lang/GroovyObject.java
new file mode 100644
index 0000000..762c9f0
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/GroovyObject.java
@@ -0,0 +1,84 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+
+
+/**
+ * The interface implemented by all Groovy objects which is handy for
+ * using Groovy objects when in the Java world
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public interface GroovyObject {
+
+    /** 
+     * Invokes the given method
+     * 
+     */
+    public Object invokeMethod(String name, Object args);
+    
+    /**
+     * @return the given property
+     */
+    public Object getProperty(String property);
+
+    /**
+     * Sets the given property to the new value
+     */
+    public void setProperty(String property, Object newValue);
+        
+    /**
+     * @return the metaClass of this instance
+     */
+    public MetaClass getMetaClass();
+    
+    /**
+     * Allows the MetaClass to be replaced with a derived implementation
+     */
+    public void setMetaClass(MetaClass metaClass);
+}
diff --git a/groovy-core/src/main/groovy/lang/GroovyObjectSupport.java b/groovy-core/src/main/groovy/lang/GroovyObjectSupport.java
new file mode 100644
index 0000000..425c54b
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/GroovyObjectSupport.java
@@ -0,0 +1,83 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * A useful base class for Java objects wishing to be Groovy objects
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public abstract class GroovyObjectSupport implements GroovyObject {
+
+    private MetaClass metaClass;
+
+    public GroovyObjectSupport() {
+        this.metaClass = InvokerHelper.getMetaClass(this);
+    }
+    
+    public Object getProperty(String property) {
+        return metaClass.getProperty(this, property);
+    }
+
+    public void setProperty(String property, Object newValue) {
+         metaClass.setProperty(this, property, newValue);
+    }
+
+    public Object invokeMethod(String name, Object args) {
+        return metaClass.invokeMethod(this, name, args);
+    }
+    
+    public MetaClass getMetaClass() {
+        return metaClass;
+    }
+    
+    public void setMetaClass(MetaClass metaClass) {
+        this.metaClass = metaClass;
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/GroovyResourceLoader.java b/groovy-core/src/main/groovy/lang/GroovyResourceLoader.java
new file mode 100644
index 0000000..abf0b2b
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/GroovyResourceLoader.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2004-2005 the original author or authors.
+ * 
+ * Licensed 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.net.URL;
+import java.net.MalformedURLException;
+
+/**
+ * Allows frameworks that integrate with Groovy to determine how Groovy files are resolved.
+ * 
+ * @author Steven Devijver
+ */
+public interface GroovyResourceLoader {
+
+    /**
+     * Loads a Groovy source file given its name.
+     *
+     * @param filename name of the file
+     * @return a URL
+     */
+    public URL loadGroovySource(String filename) throws MalformedURLException;
+}
diff --git a/groovy-core/src/main/groovy/lang/GroovyRuntimeException.java b/groovy-core/src/main/groovy/lang/GroovyRuntimeException.java
new file mode 100644
index 0000000..ff21195
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/GroovyRuntimeException.java
@@ -0,0 +1,108 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ModuleNode;
+
+/**
+ * An exception thrown by the interpreter
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class GroovyRuntimeException extends RuntimeException {
+
+    private ModuleNode module;
+    private ASTNode node;
+
+    public GroovyRuntimeException(String message) {
+        super(message);
+    }
+
+    public GroovyRuntimeException(String message, ASTNode node) {
+        super(message);
+        this.node = node;
+    }
+
+    public GroovyRuntimeException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public void setModule(ModuleNode module) {
+        this.module = module;
+    }
+
+    public ModuleNode getModule() {
+        return module;
+    }
+
+    public String getMessage() {
+        return super.getMessage() + getLocationText();
+    }
+
+    public ASTNode getNode() {
+        return node;
+    }
+
+    public String getMessageWithoutLocationText() {
+        return super.getMessage();
+    }
+
+    protected String getLocationText() {
+        String answer = ". ";
+        if (node != null) {
+            answer += "At [" + node.getLineNumber() + ":" + node.getColumnNumber() + "] ";
+        }
+        if (module != null) {
+            answer += module.getDescription();
+        }
+        if (answer.equals(". ")) {
+            return "";
+        }
+        return answer;
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/GroovyShell.java b/groovy-core/src/main/groovy/lang/GroovyShell.java
new file mode 100644
index 0000000..fcabd41
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/GroovyShell.java
@@ -0,0 +1,570 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import groovy.ui.GroovyMain;
+
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.io.*;
+import java.lang.reflect.Constructor;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents a groovy shell capable of running arbitrary groovy scripts
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Guillaume Laforge
+ * @version $Revision$
+ */
+public class GroovyShell extends GroovyObjectSupport {
+       
+    public static final String[] EMPTY_ARGS = {};
+
+    
+    private Binding context;
+    private int counter;
+    private CompilerConfiguration config;
+    private GroovyClassLoader loader;
+
+    public static void main(String[] args) {
+        GroovyMain.main(args);
+    }
+
+    public GroovyShell() {
+        this(null, new Binding());
+    }
+
+    public GroovyShell(Binding binding) {
+        this(null, binding);
+    }
+
+    public GroovyShell(CompilerConfiguration config) {
+        this(new Binding(), config);
+    }
+
+    public GroovyShell(Binding binding, CompilerConfiguration config) {
+        this(null, binding, config);
+    }
+
+    public GroovyShell(ClassLoader parent, Binding binding) {
+        this(parent, binding, CompilerConfiguration.DEFAULT);
+    }
+
+    public GroovyShell(ClassLoader parent) {
+        this(parent, new Binding(), CompilerConfiguration.DEFAULT);
+    }
+    
+    public GroovyShell(ClassLoader parent, Binding binding, final CompilerConfiguration config) {
+        if (binding == null) {
+            throw new IllegalArgumentException("Binding must not be null.");
+        }
+        if (config == null) {
+            throw new IllegalArgumentException("Compiler configuration must not be null.");
+        }
+        final ClassLoader parentLoader = (parent!=null)?parent:GroovyShell.class.getClassLoader();
+        this.loader = (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                return new GroovyClassLoader(parentLoader,config);
+            }
+        });
+        this.context = binding;        
+        this.config = config;
+    }
+    
+    public void initializeBinding() {
+        Map map = context.getVariables();
+        if (map.get("shell")==null) map.put("shell",this);
+    }
+    
+    public void resetLoadedClasses() {
+        loader.clearCache();
+    }
+
+    /**
+     * Creates a child shell using a new ClassLoader which uses the parent shell's
+     * class loader as its parent
+     *
+     * @param shell is the parent shell used for the variable bindings and the parent class loader
+     */
+    public GroovyShell(GroovyShell shell) {
+        this(shell.loader, shell.context);
+    }
+
+    public Binding getContext() {
+        return context;
+    }
+
+    public Object getProperty(String property) {
+        Object answer = getVariable(property);
+        if (answer == null) {
+            answer = super.getProperty(property);
+        }
+        return answer;
+    }
+
+    public void setProperty(String property, Object newValue) {
+        setVariable(property, newValue);
+        try {
+            super.setProperty(property, newValue);
+        } catch (GroovyRuntimeException e) {
+            // ignore, was probably a dynamic property
+        }
+    }
+
+    /**
+     * A helper method which runs the given script file with the given command line arguments
+     *
+     * @param scriptFile the file of the script to run
+     * @param list       the command line arguments to pass in
+     */
+    public Object run(File scriptFile, List list) throws CompilationFailedException, IOException {
+        String[] args = new String[list.size()];
+        return run(scriptFile, (String[]) list.toArray(args));
+    }
+
+    /**
+     * A helper method which runs the given cl script with the given command line arguments
+     *
+     * @param scriptText is the text content of the script
+     * @param fileName   is the logical file name of the script (which is used to create the class name of the script)
+     * @param list       the command line arguments to pass in
+     */
+    public Object run(String scriptText, String fileName, List list) throws CompilationFailedException {
+        String[] args = new String[list.size()];
+        list.toArray(args);
+        return run(scriptText, fileName, args);
+    }
+
+    /**
+     * Runs the given script file name with the given command line arguments
+     *
+     * @param scriptFile the file name of the script to run
+     * @param args       the command line arguments to pass in
+     */
+    public Object run(final File scriptFile, String[] args) throws CompilationFailedException, IOException {
+        String scriptName = scriptFile.getName();
+        int p = scriptName.lastIndexOf(".");
+        if (p++ >= 0) {
+            if (scriptName.substring(p).equals("java")) {
+                System.err.println("error: cannot compile file with .java extension: " + scriptName);
+                throw new CompilationFailedException(0, null);
+            }
+        }
+
+        // Get the current context classloader and save it on the stack
+        final Thread thread = Thread.currentThread();
+        //ClassLoader currentClassLoader = thread.getContextClassLoader();
+
+        class DoSetContext implements PrivilegedAction {
+            ClassLoader classLoader;
+
+            public DoSetContext(ClassLoader loader) {
+                classLoader = loader;
+            }
+
+            public Object run() {
+                thread.setContextClassLoader(classLoader);
+                return null;
+            }
+        }
+
+        AccessController.doPrivileged(new DoSetContext(loader));
+
+        // Parse the script, generate the class, and invoke the main method.  This is a little looser than
+        // if you are compiling the script because the JVM isn't executing the main method.
+        Class scriptClass;
+        try {
+            scriptClass = (Class) AccessController.doPrivileged(new PrivilegedExceptionAction() {
+                public Object run() throws CompilationFailedException, IOException {
+                    return loader.parseClass(scriptFile);
+                }
+            });
+        } catch (PrivilegedActionException pae) {
+            Exception e = pae.getException();
+            if (e instanceof CompilationFailedException) {
+                throw (CompilationFailedException) e;
+            } else if (e instanceof IOException) {
+                throw (IOException) e;
+            } else {
+                throw (RuntimeException) pae.getException();
+            }
+        }
+
+        return runMainOrTestOrRunnable(scriptClass, args);
+
+        // Set the context classloader back to what it was.
+        //AccessController.doPrivileged(new DoSetContext(currentClassLoader));
+    }
+
+    /**
+     * if (theClass has a main method) {
+     * run the main method
+     * } else if (theClass instanceof GroovyTestCase) {
+     * use the test runner to run it
+     * } else if (theClass implements Runnable) {
+     * if (theClass has a constructor with String[] params)
+     * instanciate theClass with this constructor and run
+     * else if (theClass has a no-args constructor)
+     * instanciate theClass with the no-args constructor and run
+     * }
+     */
+    private Object runMainOrTestOrRunnable(Class scriptClass, String[] args) {
+        if (scriptClass == null) {
+            return null;
+        }
+        try {
+            // let's find a main method
+            scriptClass.getMethod("main", new Class[]{String[].class});
+        } catch (NoSuchMethodException e) {
+            // As no main() method was found, let's see if it's a unit test
+            // if it's a unit test extending GroovyTestCase, run it with JUnit's TextRunner
+            if (isUnitTestCase(scriptClass)) {
+                return runTest(scriptClass);
+            }
+            // no main() method, not a unit test,
+            // if it implements Runnable, try to instanciate it
+            else if (Runnable.class.isAssignableFrom(scriptClass)) {
+                Constructor constructor = null;
+                Runnable runnable = null;
+                Throwable reason = null;
+                try {
+                    // first, fetch the constructor taking String[] as parameter
+                    constructor = scriptClass.getConstructor(new Class[]{(new String[]{}).getClass()});
+                    try {
+                        // instanciate a runnable and run it
+                        runnable = (Runnable) constructor.newInstance(new Object[]{args});
+                    } catch (Throwable t) {
+                        reason = t;
+                    }
+                } catch (NoSuchMethodException e1) {
+                    try {
+                        // otherwise, find the default constructor
+                        constructor = scriptClass.getConstructor(new Class[]{});
+                        try {
+                            // instanciate a runnable and run it
+                            runnable = (Runnable) constructor.newInstance(new Object[]{});
+                        } catch (Throwable t) {
+                            reason = t;
+                        }
+                    } catch (NoSuchMethodException nsme) {
+                        reason = nsme;
+                    }
+                }
+                if (constructor != null && runnable != null) {
+                    runnable.run();
+                } else {
+                    throw new GroovyRuntimeException("This script or class could not be run. ", reason);
+                }
+            } else {
+                throw new GroovyRuntimeException("This script or class could not be run. \n" +
+                        "It should either: \n" +
+                        "- have a main method, \n" +
+                        "- be a class extending GroovyTestCase, \n" +
+                        "- or implement the Runnable interface.");
+            }
+            return null;
+        }
+        // if that main method exist, invoke it
+        return InvokerHelper.invokeMethod(scriptClass, "main", new Object[]{args});
+    }
+
+    /**
+     * Run the specified class extending GroovyTestCase as a unit test.
+     * This is done through reflection, to avoid adding a dependency to the JUnit framework.
+     * Otherwise, developers embedding Groovy and using GroovyShell to load/parse/compile
+     * groovy scripts and classes would have to add another dependency on their classpath.
+     *
+     * @param scriptClass the class to be run as a unit test
+     */
+    private Object runTest(Class scriptClass) {
+        try {
+            Object testSuite = InvokerHelper.invokeConstructorOf("junit.framework.TestSuite",new Object[]{scriptClass});
+            return InvokerHelper.invokeStaticMethod("junit.textui.TestRunner", "run", new Object[]{testSuite});
+        } catch (ClassNotFoundException e) {
+            throw new GroovyRuntimeException("Failed to run the unit test. JUnit is not on the Classpath.");
+        }
+    }
+
+    /**
+     * Utility method to check through reflection if the parsed class extends GroovyTestCase.
+     *
+     * @param scriptClass the class we want to know if it extends GroovyTestCase
+     * @return true if the class extends groovy.util.GroovyTestCase
+     */
+    private boolean isUnitTestCase(Class scriptClass) {
+        // check if the parsed class is a GroovyTestCase,
+        // so that it is possible to run it as a JUnit test
+        boolean isUnitTestCase = false;
+        try {
+            try {
+                Class testCaseClass = this.loader.loadClass("groovy.util.GroovyTestCase");
+                // if scriptClass extends testCaseClass
+                if (testCaseClass.isAssignableFrom(scriptClass)) {
+                    isUnitTestCase = true;
+                }
+            } catch (ClassNotFoundException e) {
+                // fall through
+            }
+        } catch (Throwable e) {
+            // fall through
+        }
+        return isUnitTestCase;
+    }
+
+    /**
+     * Runs the given script text with command line arguments
+     *
+     * @param scriptText is the text content of the script
+     * @param fileName   is the logical file name of the script (which is used to create the class name of the script)
+     * @param args       the command line arguments to pass in
+     */
+    public Object run(String scriptText, String fileName, String[] args) throws CompilationFailedException {
+        try {
+            return run(new ByteArrayInputStream(scriptText.getBytes(config.getSourceEncoding())), fileName, args);
+        } catch (UnsupportedEncodingException e) {
+            throw new CompilationFailedException(0, null, e);
+        }
+    }
+
+    /**
+     * Runs the given script with command line arguments
+     *
+     * @param in       the stream reading the script
+     * @param fileName is the logical file name of the script (which is used to create the class name of the script)
+     * @param args     the command line arguments to pass in
+     */
+    public Object run(final InputStream in, final String fileName, String[] args) throws CompilationFailedException {
+        GroovyCodeSource gcs = (GroovyCodeSource) AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                return new GroovyCodeSource(in, fileName, "/groovy/shell");
+            }
+        });
+        Class scriptClass = parseClass(gcs);
+        return runMainOrTestOrRunnable(scriptClass, args);
+    }
+
+    public Object getVariable(String name) {
+        return context.getVariables().get(name);
+    }
+
+    public void setVariable(String name, Object value) {
+        context.setVariable(name, value);
+    }
+
+    /**
+     * Evaluates some script against the current Binding and returns the result
+     *
+     * @param codeSource
+     * @throws CompilationFailedException
+     * @throws CompilationFailedException
+     */
+    public Object evaluate(GroovyCodeSource codeSource) throws CompilationFailedException {
+        Script script = parse(codeSource);
+        return script.run();
+    }
+
+    /**
+     * Evaluates some script against the current Binding and returns the result
+     *
+     * @param scriptText the text of the script
+     * @param fileName   is the logical file name of the script (which is used to create the class name of the script)
+     */
+    public Object evaluate(String scriptText, String fileName) throws CompilationFailedException {
+        try {
+            return evaluate(new ByteArrayInputStream(scriptText.getBytes(config.getSourceEncoding())), fileName);
+        } catch (UnsupportedEncodingException e) {
+            throw new CompilationFailedException(0, null, e);
+        }
+    }
+
+    /**
+     * Evaluates some script against the current Binding and returns the result.
+     * The .class file created from the script is given the supplied codeBase
+     */
+    public Object evaluate(String scriptText, String fileName, String codeBase) throws CompilationFailedException {
+        try {
+            return evaluate(new GroovyCodeSource(new ByteArrayInputStream(scriptText.getBytes(config.getSourceEncoding())), fileName, codeBase));
+        } catch (UnsupportedEncodingException e) {
+            throw new CompilationFailedException(0, null, e);
+        }
+    }
+
+    /**
+     * Evaluates some script against the current Binding and returns the result
+     *
+     * @param file is the file of the script (which is used to create the class name of the script)
+     */
+    public Object evaluate(File file) throws CompilationFailedException, IOException {
+        return evaluate(new GroovyCodeSource(file));
+    }
+
+    /**
+     * Evaluates some script against the current Binding and returns the result
+     *
+     * @param scriptText the text of the script
+     */
+    public Object evaluate(String scriptText) throws CompilationFailedException {
+        try {
+            return evaluate(new ByteArrayInputStream(scriptText.getBytes(config.getSourceEncoding())), generateScriptName());
+        } catch (UnsupportedEncodingException e) {
+            throw new CompilationFailedException(0, null, e);
+        }
+    }
+
+    /**
+     * Evaluates some script against the current Binding and returns the result
+     *
+     * @param in the stream reading the script
+     */
+    public Object evaluate(InputStream in) throws CompilationFailedException {
+        return evaluate(in, generateScriptName());
+    }
+
+    /**
+     * Evaluates some script against the current Binding and returns the result
+     *
+     * @param in       the stream reading the script
+     * @param fileName is the logical file name of the script (which is used to create the class name of the script)
+     */
+    public Object evaluate(InputStream in, String fileName) throws CompilationFailedException {
+        Script script = null;
+        try {
+            script = parse(in, fileName);
+            return script.run();
+        } finally {
+            if (script != null) {
+                InvokerHelper.removeClass(script.getClass());
+            }
+        }
+    }
+
+    /**
+     * Parses the given script and returns it ready to be run
+     *
+     * @param in       the stream reading the script
+     * @param fileName is the logical file name of the script (which is used to create the class name of the script)
+     * @return the parsed script which is ready to be run via @link Script.run()
+     */
+    public Script parse(final InputStream in, final String fileName) throws CompilationFailedException {
+        GroovyCodeSource gcs = (GroovyCodeSource) AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                return new GroovyCodeSource(in, fileName, "/groovy/shell");
+            }
+        });
+        return parse(gcs);
+    }
+
+    /**
+     * Parses the groovy code contained in codeSource and returns a java class.
+     */
+    private Class parseClass(final GroovyCodeSource codeSource) throws CompilationFailedException {
+        // Don't cache scripts
+        return loader.parseClass(codeSource, false);
+    }
+
+    /**
+     * Parses the given script and returns it ready to be run.  When running in a secure environment
+     * (-Djava.security.manager) codeSource.getCodeSource() determines what policy grants should be
+     * given to the script.
+     *
+     * @param codeSource
+     * @return ready to run script
+     */
+    public Script parse(final GroovyCodeSource codeSource) throws CompilationFailedException {
+        return InvokerHelper.createScript(parseClass(codeSource), context);
+    }
+
+    /**
+     * Parses the given script and returns it ready to be run
+     *
+     * @param file is the file of the script (which is used to create the class name of the script)
+     */
+    public Script parse(File file) throws CompilationFailedException, IOException {
+        return parse(new GroovyCodeSource(file));
+    }
+
+    /**
+     * Parses the given script and returns it ready to be run
+     *
+     * @param scriptText the text of the script
+     */
+    public Script parse(String scriptText) throws CompilationFailedException {
+        try {
+            return parse(new ByteArrayInputStream(scriptText.getBytes(config.getSourceEncoding())), generateScriptName());
+        } catch (UnsupportedEncodingException e) {
+            throw new CompilationFailedException(0, null, e);
+        }
+    }
+
+    public Script parse(String scriptText, String fileName) throws CompilationFailedException {
+        try {
+            return parse(new ByteArrayInputStream(scriptText.getBytes(config.getSourceEncoding())), fileName);
+        } catch (UnsupportedEncodingException e) {
+            throw new CompilationFailedException(0, null, e);
+        }
+    }
+
+    /**
+     * Parses the given script and returns it ready to be run
+     *
+     * @param in the stream reading the script
+     */
+    public Script parse(InputStream in) throws CompilationFailedException {
+        return parse(in, generateScriptName());
+    }
+
+    protected synchronized String generateScriptName() {
+        return "Script" + (++counter) + ".groovy";
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/IllegalPropertyAccessException.java b/groovy-core/src/main/groovy/lang/IllegalPropertyAccessException.java
new file mode 100644
index 0000000..7481204
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/IllegalPropertyAccessException.java
@@ -0,0 +1,77 @@
+/*
+$Id$
+
+Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+package groovy.lang;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * An exception occurred if a dynamic property dispatch fails with a 
+ * field not accessible.
+ * 
+ * @author <a href="mailto:blackdrag@uni.de">Jochen Theodorou</a>
+ * @version $Revision$
+ */
+public class IllegalPropertyAccessException extends MissingPropertyException {
+    
+    private static String makeMessage(String propertyName, Class clazz, int modifiers, boolean isField) {
+        String access = "private";
+        if (Modifier.isProtected(modifiers)) access = "protected";
+        if (Modifier.isPublic(modifiers)) access = "public";
+        String propertyType = "property";
+        if (isField) propertyType = "field";
+        return  "Can not access the "+access+" "+propertyType+" "+propertyName+" in class "+clazz.getName();
+    }
+    
+    public IllegalPropertyAccessException(String propertyName, Class clazz, int modifiers) {
+        super(makeMessage(propertyName,clazz,modifiers,false),propertyName,clazz);
+    }
+    
+    public IllegalPropertyAccessException(Field field, Class clazz) {
+        super(makeMessage(field.getName(),clazz,field.getModifiers(),true),field.getName(),clazz);
+    }
+    
+}
diff --git a/groovy-core/src/main/groovy/lang/IncorrectClosureArgumentsException.java b/groovy-core/src/main/groovy/lang/IncorrectClosureArgumentsException.java
new file mode 100644
index 0000000..df9e234
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/IncorrectClosureArgumentsException.java
@@ -0,0 +1,77 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package groovy.lang;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * An exception occurred when invoking a Closure with the wrong number and/or
+ * types of arguments
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class IncorrectClosureArgumentsException extends GroovyRuntimeException {
+
+    private Closure closure;
+    private Object arguments;
+    private Class[] expected;
+
+    public IncorrectClosureArgumentsException(Closure closure, Object arguments, Class[] expected) {
+        super(
+            "Incorrect arguments to closure: "
+                + closure
+                + ". Expected: "
+                + InvokerHelper.toString(expected)
+                + ", actual: "
+                + InvokerHelper.toString(arguments));
+        this.closure = closure;
+        this.arguments = arguments;
+        this.expected = expected;
+    }
+
+    public Object getArguments() {
+        return arguments;
+    }
+
+    public Closure getClosure() {
+        return closure;
+    }
+
+    public Class[] getExpected() {
+        return expected;
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/lang/IntRange.java b/groovy-core/src/main/groovy/lang/IntRange.java
new file mode 100644
index 0000000..cc0a888
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/IntRange.java
@@ -0,0 +1,243 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import java.util.AbstractList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.codehaus.groovy.runtime.IteratorClosureAdapter;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+/**
+ * Represents a list of Integer objects from a specified int up to and including
+ * a given and to.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class IntRange extends AbstractList implements Range {
+
+    private int from;
+    private int to;
+    private boolean reverse;
+
+    public IntRange(int from, int to) {
+        if (from > to) {
+            this.from = to;
+            this.to = from;
+            this.reverse = true;
+        }
+        else {
+            this.from = from;
+            this.to = to;
+        }
+    }
+
+    protected IntRange(int from, int to, boolean reverse) {
+        this.from = from;
+        this.to = to;
+        this.reverse = reverse;
+    }
+
+    public boolean equals(Object that) {
+        if (that instanceof IntRange) {
+            return equals((IntRange) that);
+        }
+        else if (that instanceof List) {
+            return equals((List) that);
+        }
+        return false;
+    }
+
+    public boolean equals(List that) {
+        int size = size();
+        if (that.size() == size) {
+            for (int i = 0; i < size; i++) {
+                if (!DefaultTypeTransformation.compareEqual(get(i), that.get(i))) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public boolean equals(IntRange that) {
+        return this.reverse == that.reverse && this.from == that.from && this.to == that.to;
+    }
+
+    public Comparable getFrom() {
+        return new Integer(from);
+    }
+
+    public Comparable getTo() {
+        return new Integer(to);
+    }
+
+    public int getFromInt() {
+        return from;
+    }
+
+    public int getToInt() {
+        return to;
+    }
+
+    public boolean isReverse() {
+        return reverse;
+    }
+
+    public Object get(int index) {
+        if (index < 0) {
+            throw new IndexOutOfBoundsException("Index: " + index + " should not be negative");
+        }
+        if (index >= size()) {
+            throw new IndexOutOfBoundsException("Index: " + index + " too big for range: " + this);
+        }
+        int value = (reverse) ? to - index : index + from;
+        return new Integer(value);
+    }
+
+    public int size() {
+        return to - from + 1;
+    }
+
+    public int hashCode() {
+        return from ^ to + (reverse ? 1 : 0);
+    }
+
+    public Iterator iterator() {
+        return new Iterator() {
+            int index = 0;
+            int size = size();
+            int value = (reverse) ? to : from;
+
+            public boolean hasNext() {
+                return index < size;
+            }
+
+            public Object next() {
+                if (index++ > 0) {
+                    if (index > size) {
+                        return null;
+                    }
+                    else {
+                        if (reverse) {
+                            --value;
+                        }
+                        else {
+                            ++value;
+                        }
+                    }
+                }
+                return new Integer(value);
+            }
+
+            public void remove() {
+                IntRange.this.remove(index);
+            }
+        };
+    }
+
+    public List subList(int fromIndex, int toIndex) {
+        if (fromIndex < 0) {
+            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+        }
+        if (toIndex > size()) {
+            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
+        }
+        if (fromIndex > toIndex) {
+            throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
+        }
+        return new IntRange(fromIndex + this.from, toIndex + this.from - 1, reverse);
+    }
+
+    public String toString() {
+        return (reverse) ? "" + to + ".." + from : "" + from + ".." + to;
+    }
+    
+    public String inspect() {
+        return toString();
+    }
+    
+    public boolean contains(Object value) {
+        if (value instanceof Integer) {
+            Integer integer = (Integer) value;
+            int i = integer.intValue();
+            return i >= from && i <= to;
+        } else if (value instanceof IntRange) {
+            IntRange range = (IntRange) value;
+            return from<=range.from && range.to<=to;
+        } 
+        return false;
+    }
+
+    public void step(int step, Closure closure) {
+        if (reverse) {
+            step = -step;
+        }
+        if (step >= 0) {
+            int value = from;
+            while (value <= to) {
+                closure.call(new Integer(value));
+                value = value + step;
+            }
+        }
+        else {
+            int value = to;
+            while (value >= from) {
+                closure.call(new Integer(value));
+                value = value + step;
+            }
+        }
+    }
+
+    public List step(int step) {
+        IteratorClosureAdapter adapter = new IteratorClosureAdapter(this);
+        step(step, adapter);
+        return adapter.asList();
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/Interceptor.java b/groovy-core/src/main/groovy/lang/Interceptor.java
new file mode 100644
index 0000000..f3a17a6
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/Interceptor.java
@@ -0,0 +1,34 @@
+package groovy.lang;
+
+/**
+ * Implementers of this interface can be registered in the ProxyMetaClass for
+ * notifications about method calls for objects managed by the ProxyMetaClass.
+ * See groovy/lang/InterceptorTest.groovy for details.
+ * @author Dierk Koenig
+ */
+public interface Interceptor {
+    /**
+     * This code is executed before the method is optionally called.
+     * @param object        receiver object for the method call
+     * @param methodName    name of the method to call
+     * @param arguments     arguments to the method call
+     * @return any arbitrary result that replaces the result of the
+     * original method call only if doInvoke() returns false and afterInvoke()
+     * relays this result.
+     */
+    Object beforeInvoke(Object object, String methodName, Object[] arguments);
+    /**
+     * This code is executed after the method is optionally called.
+     * @param object        receiver object for the called method
+     * @param methodName    name of the called method
+     * @param arguments     arguments to the called method
+     * @param result        result of the executed method call or result of beforeInvoke if method was not called
+     * @return any arbitrary result that can replace the result of the
+     * original method call. Typically, the result parameter is returned.
+     */
+    Object afterInvoke(Object object, String methodName, Object[] arguments, Object result);
+    /**
+     * @return whether the target method should be invoked at all.
+     */
+    boolean doInvoke();
+}
diff --git a/groovy-core/src/main/groovy/lang/MetaArrayLengthProperty.java b/groovy-core/src/main/groovy/lang/MetaArrayLengthProperty.java
new file mode 100644
index 0000000..5d59697
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/MetaArrayLengthProperty.java
@@ -0,0 +1,69 @@
+/*
+ * $Id$
+ *
+ * Copyright 2004 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+ 
+package groovy.lang;
+
+
+/**
+ * Represents a property on a bean which may have a getter and/or a setter
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MetaArrayLengthProperty extends MetaProperty {
+
+    public MetaArrayLengthProperty() {
+		super("length", int.class);
+    }
+
+    /**
+     * @return the property of the given object
+     * @throws Exception if the property could not be evaluated
+     */
+    public Object getProperty(Object object) {
+        return new Integer(java.lang.reflect.Array.getLength(object));
+    }
+
+    /**
+     * Sets the property on the given object to the new value
+     * 
+     * @param object on which to set the property
+     * @param newValue the new value of the property
+     * @throws RuntimeException if the property could not be set
+     */
+    public void setProperty(Object object, Object newValue) {
+		throw new ReadOnlyPropertyException("length", object.getClass());
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/MetaBeanProperty.java b/groovy-core/src/main/groovy/lang/MetaBeanProperty.java
new file mode 100644
index 0000000..69c5fec
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/MetaBeanProperty.java
@@ -0,0 +1,140 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package groovy.lang;
+
+import java.lang.reflect.Modifier;
+
+import org.codehaus.groovy.runtime.MetaClassHelper;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+/**
+ * Represents a property on a bean which may have a getter and/or a setter
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+public class MetaBeanProperty extends MetaProperty {
+
+    private MetaMethod getter;
+    private MetaMethod setter;
+    private MetaFieldProperty field;
+    
+    public MetaBeanProperty(String name, Class type, MetaMethod getter, MetaMethod setter) {
+        super(name, type);
+        this.getter = getter;
+        this.setter = setter;
+    }
+
+    /**
+     * Get the property of the given object.
+     *
+     * @param object which to be got
+     * @return the property of the given object
+     * @throws Exception if the property could not be evaluated
+     */
+    public Object getProperty(Object object) {
+        if (getter == null) {
+            //TODO: we probably need a WriteOnlyException class
+            throw new GroovyRuntimeException("Cannot read write-only property: " + name);
+        }
+        return getter.invoke(object, MetaClassHelper.EMPTY_ARRAY);
+    }
+
+    /**
+     * Set the property on the given object to the new value.
+     *
+     * @param object   on which to set the property
+     * @param newValue the new value of the property
+     * @throws RuntimeException if the property could not be set
+     */
+    public void setProperty(Object object, Object newValue) {
+        if (setter == null) {
+            throw new GroovyRuntimeException("Cannot set read-only property: " + name);
+        }
+        newValue = DefaultTypeTransformation.castToType(newValue, getType());
+        setter.invoke(object, new Object[] { newValue });
+    }
+
+    /**
+     * Get the getter method.
+     */
+    public MetaMethod getGetter() {
+        return getter;
+    }
+
+    /**
+     * Get the setter method.
+     */
+    public MetaMethod getSetter() {
+        return setter;
+    }
+
+    /**
+     * This is for MetaClass to patch up the object later when looking for get*() methods.
+     */
+    void setGetter(MetaMethod getter) {
+        this.getter = getter;
+    }
+
+    /**
+     * This is for MetaClass to patch up the object later when looking for set*() methods.
+     */
+    void setSetter(MetaMethod setter) {
+        this.setter = setter;
+    }
+    
+    public int getModifiers() {
+        if (setter!=null && getter==null) return setter.getModifiers();
+        if (getter!=null && setter==null) return getter.getModifiers();
+        int modifiers = getter.getModifiers() | setter.getModifiers();
+        int visibility = 0;
+        if (Modifier.isPublic(modifiers)) visibility = Modifier.PUBLIC;
+        if (Modifier.isProtected(modifiers)) visibility = Modifier.PROTECTED;
+        if (Modifier.isPrivate(modifiers)) visibility = Modifier.PRIVATE;
+        int states = getter.getModifiers() & setter.getModifiers();
+        states &= ~(Modifier.PUBLIC|Modifier.PROTECTED|Modifier.PRIVATE);
+        states |= visibility;
+        return states;       
+    }
+    
+    public void setField(MetaFieldProperty f) {
+        this.field = f;
+    }
+    
+    public MetaFieldProperty getField() {
+        return field;
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/MetaClass.java b/groovy-core/src/main/groovy/lang/MetaClass.java
new file mode 100644
index 0000000..e1f2b19
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/MetaClass.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.lang.reflect.Method;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.runtime.MetaClassHelper;
+
+/**
+ * Base class for meta class implementations. 
+ * The meta class is used to invoke methods or to get 
+ * fields/properties. For proper initialization of this class 
+ * it is not enough to only call the constructor, the
+ * initialize() must be called too. The invoke methods should
+ * check that initialize() was called. Adding methods is
+ * valid unless initilise method was called. Therefore 
+ * addNewStaticMethod and addNewInstanceMethod should check that
+ * that initilise awas not called before.
+ * 
+ * 
+ * @author John Wilson
+ *
+ */
+
+public abstract class MetaClass {
+    protected static final Logger log = Logger.getLogger(MetaClass.class.getName());
+    protected static boolean useReflection = false;
+    public static final Object NO_METHOD_FOUND = new Object();
+    protected final Class theClass;
+    private boolean isGroovyObject;
+    
+    public static boolean isUseReflection() {
+        return MetaClass.useReflection;
+    }
+
+    /**
+     * Allows reflection to be enabled in situations where bytecode generation
+     * of method invocations causes issues.
+     *
+     * @param useReflection
+     */
+    public static void setUseReflection(boolean useReflection) {
+        MetaClass.useReflection = useReflection;
+    }
+    
+    protected MetaClass(final Class theClass) {
+        this.theClass = theClass;
+        isGroovyObject = GroovyObject.class.isAssignableFrom(theClass);
+    }
+    
+    public boolean isGroovyObject(){
+        return isGroovyObject;
+    }
+    
+    public Object invokeMissingMethod(Object instance, String methodName, Object[] arguments) {
+        GroovyObject pogo = (GroovyObject) instance;
+        return pogo.invokeMethod(methodName,arguments);
+    }
+    
+    public Object invokeMethod(Object object, String methodName, Object arguments) {
+        if (arguments == null) {
+            return invokeMethod(object, methodName, MetaClassHelper.EMPTY_ARRAY);
+        }
+        if (arguments instanceof Tuple) {
+            Tuple tuple = (Tuple) arguments;
+            return invokeMethod(object, methodName, tuple.toArray());
+        }
+        if (arguments instanceof Object[]) {
+            return invokeMethod(object, methodName, (Object[])arguments);
+        }
+        else {
+            return invokeMethod(object, methodName, new Object[]{arguments});
+        }
+    }
+    
+    public Object invokeMethod(Class sender, Object receiver, String methodName, Object[] arguments, boolean isCallToSuper, boolean fromInsideClass){
+        return invokeMethod(receiver,methodName,arguments);
+    }
+    
+    public Object getProperty(Class sender, Object receiver, String messageName, boolean useSuper, boolean fromInsideClass) {
+        return getProperty(receiver,messageName);
+    }
+    
+    public void setProperty(Class sender, Object receiver, String messageName, Object messageValue, boolean useSuper, boolean fromInsideClass) {
+        setProperty(receiver,messageName,messageValue);
+    }
+    
+    public Object getAttribute(Class sender, Object receiver, String messageName, boolean useSuper) {
+        return getAttribute(receiver,messageName);
+    }
+    
+    public void setAttribute(Class sender, Object receiver, String messageName, Object messageValue, boolean useSuper, boolean fromInsideClass) {
+        setAttribute(receiver,messageName,messageValue);
+    }
+    
+    public abstract Object invokeConstructor(Object[] arguments);
+    public abstract Object invokeMethod(Object object, String methodName, Object[] arguments);
+    public abstract Object invokeStaticMethod(Object object, String methodName, Object[] arguments);
+    public abstract Object getProperty(Object object, String property);
+    public abstract void setProperty(Object object, String property, Object newValue);
+    public abstract Object getAttribute(Object object, String attribute);
+    public abstract void setAttribute(Object object, String attribute, Object newValue);
+    /**
+     * adds a new instance method to this meta class. Instance
+     * methods are able to overwrite the original methods of the
+     * class. Calling this method should not be done after 
+     * initlise was called.
+     * @param method the method to be added
+     */
+    public abstract void addNewInstanceMethod(Method method);
+    /**
+     * adds a new static method to this meta class. This is only
+     * possible as long as initilise was not called.
+     * @param method the method to be added
+     */
+    public abstract void addNewStaticMethod(Method method);
+    /**
+     * complete the initlialisation process. After this method
+     * is called no methods should be added to the meta class.
+     * Invocation of methods or access to fields/proeprties is
+     * forbidden unless this method is called. This method 
+     * should contain any initialisation code, taking a longer
+     * time to complete. An example is the creation of the 
+     * Reflector. It is suggested to synchronize this 
+     * method.
+     */
+    public abstract void initialize();
+    
+    public abstract List getProperties();
+    public abstract ClassNode getClassNode();
+    public abstract List getMetaMethods();
+    
+    public abstract List getMethods();
+    
+    /**
+     * Warning, this method will be removed
+     * @deprecated use invokeConstructor instead
+     */
+    public Object invokeConstructorAt(Class at, Object[] arguments) {
+        return invokeConstructor(arguments);
+    }
+
+    /**
+     * Selects a method by name and argument classes. This method
+     * does not search for an exact match, it searches for a compatible
+     * method. For this the method selection mechanism is used as provided
+     * bye the implementation of this MetaClass. pickMethod may or may
+     * not used during the method selection process when invoking a method
+     * thereis no warranty for that.
+     * 
+     * @returns a matching MetaMethod or null
+     * @throws GroovyRuntimeException if there is more than one matching method
+     */
+    public abstract MetaMethod pickMethod(String methodName, Class[] arguments);
+    
+    /**
+     * Warning, this method will be removed
+     * @deprecated usw pickMethod instead
+     */
+    protected MetaMethod retrieveMethod(String methodName, Class[] arguments) {
+        return pickMethod(methodName,arguments);
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/lang/MetaClassImpl.java b/groovy-core/src/main/groovy/lang/MetaClassImpl.java
new file mode 100644
index 0000000..16cd5cf
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/MetaClassImpl.java
@@ -0,0 +1,2120 @@
+/*
+$Id$
+
+Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+package groovy.lang;
+
+import java.beans.BeanInfo;
+import java.beans.EventSetDescriptor;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.classgen.BytecodeHelper;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.Phases;
+import org.codehaus.groovy.runtime.CurriedClosure;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.codehaus.groovy.runtime.DefaultMethodKey;
+import org.codehaus.groovy.runtime.GroovyCategorySupport;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.MetaClassHelper;
+import org.codehaus.groovy.runtime.MethodClosure;
+import org.codehaus.groovy.runtime.MethodKey;
+import org.codehaus.groovy.runtime.NewInstanceMetaMethod;
+import org.codehaus.groovy.runtime.NewStaticMetaMethod;
+import org.codehaus.groovy.runtime.ReflectionMetaMethod;
+import org.codehaus.groovy.runtime.Reflector;
+import org.codehaus.groovy.runtime.TransformMetaMethod;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.codehaus.groovy.runtime.wrappers.Wrapper;
+import org.objectweb.asm.ClassVisitor;
+
+/**
+* Allows methods to be dynamically added to existing classes at runtime
+*
+* @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+* @author Guillaume Laforge
+* @author Jochen Theodorou
+* @version $Revision$
+* @see groovy.lang.MetaClass
+*/
+public class MetaClassImpl extends MetaClass {
+
+   protected MetaClassRegistry registry;
+   private ClassNode classNode;
+   private Map classMethodIndex = new HashMap();
+   private Map classMethodIndexForSuper;
+   private Map classStaticMethodIndex = new HashMap();
+   private Map classPropertyIndex = new HashMap();
+   private Map classPropertyIndexForSuper = new HashMap();
+   private Map staticPropertyIndex = new HashMap();
+   private Map listeners = new HashMap();
+   private Map methodCache = Collections.synchronizedMap(new HashMap());
+   private Map staticMethodCache = Collections.synchronizedMap(new HashMap());
+   private MetaMethod genericGetMethod;
+   private MetaMethod genericSetMethod;
+   private List constructors;
+   private List allMethods = new ArrayList();
+   private List interfaceMethods;
+   private Reflector reflector;
+   private boolean initialized;
+   // we only need one of these that can be reused over and over.
+   private MetaProperty arrayLengthProperty = new MetaArrayLengthProperty();
+   private final static MetaMethod AMBIGOUS_LISTENER_METHOD = new MetaMethod(null,null,new Class[]{},null,0);
+   private static final Object[] EMPTY_ARGUMENTS = {};
+   private List newGroovyMethodsList = new LinkedList();
+   
+   public MetaClassImpl(MetaClassRegistry registry, final Class theClass) {
+       super(theClass);
+       this.registry = registry;
+
+       constructors = (List) AccessController.doPrivileged(new  PrivilegedAction() {
+               public Object run() {
+                   return Arrays.asList (theClass.getDeclaredConstructors());
+               }
+           });
+   }
+
+   private void fillMethodIndex() {
+       LinkedList superClasses = getSuperClasses();
+       // let's add all the base class methods
+       for (Iterator iter = superClasses.iterator(); iter.hasNext();) {
+           Class c = (Class) iter.next();
+           addMethods(c);
+       }
+
+       Set interfaces = new HashSet();
+       makeInterfaceSet(theClass,interfaces); 
+
+       inheritMethods(superClasses,classMethodIndex);
+       inheritInterfaceMethods(interfaces);
+       copyClassMethodIndexForSuper();
+       
+       connectMultimethods(superClasses);
+       populateInterfaces(interfaces);
+       removeMultimethodsOverloadedWithPrivateMethods();
+       
+       replaceWithMOPCalls();
+   }
+   
+   private LinkedList getSuperClasses() {
+       LinkedList superClasses = new LinkedList();
+       for (Class c = theClass; c!= null; c = c.getSuperclass()) {
+           superClasses.addFirst(c);
+       }
+       if (theClass.isArray() && theClass!=Object[].class && !theClass.getComponentType().isPrimitive()) {
+           superClasses.addFirst(Object[].class);
+       }
+       return superClasses;
+   }
+
+   private void removeMultimethodsOverloadedWithPrivateMethods() {
+       Map privates = new HashMap();
+       MethodIndexAction mia = new MethodIndexAction() {
+           public List methodNameAction(Class clazz, String methodName, List methods) {
+              boolean hasPrivate=false;
+              for (Iterator iter = methods.iterator(); iter.hasNext();) {
+                  MetaMethod method = (MetaMethod) iter.next();
+                  if (method.isPrivate() && clazz == method.getDeclaringClass()) {
+                      hasPrivate = true;
+                      break;
+                  }
+              }
+              if (!hasPrivate) return null;
+              // We have private methods for that name, so remove the
+              // multimethods. That is the same as in our index for 
+              // super, so just copy the list from there. It is not
+              // possible to use a pointer here, because the methods
+              // in the index for super are replaced later by MOP 
+              // methods like super$5$foo              
+              methods.clear();
+              methods.addAll((Collection) ((Map) classMethodIndexForSuper.get(clazz)).get(methodName));
+              return methods;
+           }
+           public boolean replaceMethodList() {return false;}
+       };
+       mia.iterate(classMethodIndex);
+   }
+   
+   
+   private void replaceWithMOPCalls() {
+       // no MOP methods if not a child of GroovyObject
+       if (!GroovyObject.class.isAssignableFrom(theClass)) return;
+       
+       final Map mainClassMethodIndex = (Map) classMethodIndex.get(theClass);
+       class MOPIter extends MethodIndexAction {
+           boolean useThis;
+           public boolean skipClass(Class clazz) {
+               return !useThis && clazz==theClass;
+           }
+           public void methodListAction(Class clazz, String methodName, MetaMethod method, List oldList, List newList) {
+               String mopName = getMOPMethodName(method.getDeclaringClass(), methodName,useThis);
+               List matches = (List) mainClassMethodIndex.get(mopName);
+               if (matches==null) {
+                   newList.add(method);
+                   return;
+               }
+               matches = new ArrayList(matches);
+               MetaMethod matchingMethod = removeMatchingMethod(matches,method);
+               if (matchingMethod==null) {
+                   newList.add(method);
+                   return;
+               } else {
+                   newList.add(matchingMethod);
+               }
+           }
+       }
+       MOPIter iter = new MOPIter();
+       
+       // replace all calls for super with the correct MOP method
+       iter.useThis = false;
+       iter.iterate(classMethodIndexForSuper);
+       // replace all calls for this with the correct MOP method
+       iter.useThis = true;
+       iter.iterate(classMethodIndex);
+   }
+   
+   private String getMOPMethodName(Class declaringClass, String name, boolean useThis) {
+       int distance = 0;
+       for (;declaringClass!=null; declaringClass=declaringClass.getSuperclass()) {
+           distance++;
+       }
+       return (useThis?"this":"super")+"$"+distance+"$"+name;
+   }
+   
+   private void copyClassMethodIndexForSuper() {
+       classMethodIndexForSuper = new HashMap(classMethodIndex.size());
+       for (Iterator iter = classMethodIndex.entrySet().iterator(); iter.hasNext();) {
+           Map.Entry cmiEntry = (Map.Entry) iter.next();
+           Map methodIndex = (Map) cmiEntry.getValue();
+           Map copy = new HashMap (methodIndex.size());
+           for (Iterator iterator = methodIndex.entrySet().iterator(); iterator.hasNext();) {
+               Map.Entry mEntry = (Map.Entry) iterator.next();
+               copy.put(mEntry.getKey(), new ArrayList((List) mEntry.getValue()));
+           }
+           classMethodIndexForSuper.put(cmiEntry.getKey(),copy);
+       } 
+   }
+   
+   private void inheritInterfaceMethods(Set interfaces) {
+       // add methods declared by DGM for interfaces
+       List methods = registry.getInstanceMethods();
+       for (Iterator iter = methods.iterator(); iter.hasNext();) {
+           Method element = (Method) iter.next();
+           Class dgmClass = element.getParameterTypes()[0]; 
+           if (!interfaces.contains(dgmClass)) continue;
+           NewInstanceMetaMethod method = new NewInstanceMetaMethod(createMetaMethod(element));
+           if (! newGroovyMethodsList.contains(method)){
+               newGroovyMethodsList.add(method);
+           }
+           Map methodIndex = (Map) classMethodIndex.get(theClass);
+           List list = (List) methodIndex.get(method.getName());
+           if (list == null) {
+               list = new ArrayList();
+               methodIndex.put(method.getName(), list);
+               list.add(method);
+           } else {
+               addMethodToList(list,method);
+           }
+       }
+       methods = registry.getStaticMethods();
+       for (Iterator iter = methods.iterator(); iter.hasNext();) {
+           Method element = (Method) iter.next();
+           Class dgmClass = element.getParameterTypes()[0]; 
+           if (!interfaces.contains(dgmClass)) continue;
+           addNewStaticMethod(element);
+       }
+   }
+   
+   private void populateInterfaces(Set interfaces){
+       Map currentIndex = (Map) classMethodIndex.get(theClass);
+       Map index = new HashMap();
+       copyNonPrivateMethods(currentIndex,index);
+       for (Iterator iter = interfaces.iterator(); iter.hasNext();) {
+           Class iClass = (Class) iter.next();
+           Map methodIndex = (Map) classMethodIndex.get(iClass);
+           if (methodIndex==null || methodIndex.size()==0) {
+               classMethodIndex.put(iClass,index);
+               continue;
+           }
+           copyNonPrivateMethods(currentIndex,methodIndex);
+       }
+   }
+   
+   private static void makeInterfaceSet(Class c, Set s) {
+       if (c==null) return;
+       Class[] interfaces = c.getInterfaces();
+       for (int i = 0; i < interfaces.length; i++) {
+           if (!s.contains(interfaces[i])) {
+               s.add(interfaces[i]);
+               makeInterfaceSet(interfaces[i],s);
+           }
+       }
+       makeInterfaceSet(c.getSuperclass(),s);
+   }
+   
+   private void copyNonPrivateMethods(Map from, Map to) {
+       for (Iterator iterator = from.entrySet().iterator(); iterator.hasNext();) {
+           Map.Entry element = (Map.Entry) iterator.next();
+           List oldList = (List) element.getValue();
+           List newList = (List) to.get(element.getKey());
+           if (newList==null) {
+               to.put(element.getKey(),new ArrayList(oldList));
+           } else {
+               addNonPrivateMethods(newList,oldList);
+           }
+       }
+   }
+   
+   private void connectMultimethods(List superClasses){
+       superClasses = DefaultGroovyMethods.reverse(superClasses);
+       Map last = null;
+       for (Iterator iter = superClasses.iterator(); iter.hasNext();) {
+           Class c = (Class) iter.next();
+           Map methodIndex = (Map) classMethodIndex.get(c);
+           if (methodIndex==last) continue;
+           if (last!=null) copyNonPrivateMethods(last,methodIndex);
+           last = methodIndex;
+       }
+   }
+   
+   private void inheritMethods(Collection superClasses, Map classMethodIndex){
+       Map last = null;
+       for (Iterator iter = superClasses.iterator(); iter.hasNext();) {
+           Class c = (Class) iter.next();
+           Map methodIndex = (Map) classMethodIndex.get(c);
+           if (last!=null) {
+               if (methodIndex.size()==0) {
+                   classMethodIndex.put(c,last);
+                   continue;
+               }
+               copyNonPrivateMethods(last,methodIndex);
+           }
+           last = methodIndex;
+       }
+   }
+
+   private void addNonPrivateMethods(List newList, List oldList) {
+       for (Iterator iter = oldList.iterator(); iter.hasNext();) {
+           MetaMethod element = (MetaMethod) iter.next();
+           if (element.isPrivate()) continue;
+           addMethodToList(newList,element);
+       }
+   }
+
+/**
+    * @return all the normal instance methods avaiable on this class for the
+    *         given name
+    */
+   private List getMethods(Class sender, String name, boolean isCallToSuper) {
+       Map methodIndex;
+       if (isCallToSuper) {
+           methodIndex = (Map) classMethodIndexForSuper.get(sender);
+       } else {
+           methodIndex = (Map) classMethodIndex.get(sender);
+       }   
+       List answer;
+       if (methodIndex!=null) {
+           answer = (List) methodIndex.get(name);
+           if (answer == null) answer = Collections.EMPTY_LIST;
+       } else {
+           answer = Collections.EMPTY_LIST;
+       }
+       
+       if (!isCallToSuper && GroovyCategorySupport.hasCategoryInAnyThread()) {
+           List used = GroovyCategorySupport.getCategoryMethods(sender, name);
+           if (used != null) {
+               answer = new ArrayList(answer);
+               for (Iterator iter = used.iterator(); iter.hasNext();) {
+                   MetaMethod element = (MetaMethod) iter.next();
+                   removeMatchingMethod(answer,element);
+               }
+               answer.addAll(used);
+           }
+       }
+       return answer;
+   }
+
+   /**
+    * @return all the normal static methods avaiable on this class for the
+    *         given name
+    */
+   private List getStaticMethods(Class sender, String name) {
+       Map methodIndex = (Map) classStaticMethodIndex.get(sender);
+       if (methodIndex == null) return Collections.EMPTY_LIST;
+       List answer = (List) methodIndex.get(name);
+       if (answer == null) return Collections.EMPTY_LIST;
+       return answer;
+   }
+
+   public void addNewInstanceMethod(Method method) {
+       NewInstanceMetaMethod newMethod = new NewInstanceMetaMethod(createMetaMethod(method));
+       if (! newGroovyMethodsList.contains(newMethod)){
+           newGroovyMethodsList.add(newMethod);
+           addMetaMethod(newMethod);
+       }
+   }
+
+   public void addNewStaticMethod(Method method) {
+       NewStaticMetaMethod newMethod = new NewStaticMetaMethod(createMetaMethod(method));
+       if (! newGroovyMethodsList.contains(newMethod)){
+           newGroovyMethodsList.add(newMethod);
+           addMetaMethod(newMethod);
+       }
+   }
+
+   private void unwrap(Object[] arguments) {
+       //
+       // Temp code to ignore wrapped parameters
+       // The New MOP will deal with these properly
+       //
+       for (int i = 0; i != arguments.length; i++) {
+        if (arguments[i] instanceof Wrapper) {
+          arguments[i] = ((Wrapper)arguments[i]).unwrap();
+        }
+       }       
+   }
+   
+   
+   /**
+    * Invokes the given method on the object.
+    * @deprecated
+    */
+   public Object invokeMethod(Object object, String methodName, Object[] originalArguments) {
+       return invokeMethod(theClass,object,methodName,originalArguments,false,false);
+   }
+   
+   
+   /**
+    * Invokes the given method on the object.
+    *
+    */
+   public Object invokeMethod(Class sender, Object object, String methodName, Object[] originalArguments, boolean isCallToSuper, boolean fromInsideClass) {
+       checkInitalised();
+       if (object == null) {
+           throw new NullPointerException("Cannot invoke method: " + methodName + " on null object");
+       }              
+       if (log.isLoggable(Level.FINER)){
+           MetaClassHelper.logMethodCall(object, methodName, originalArguments);
+       }
+       Object[] arguments = originalArguments;
+       if (arguments==null) arguments = EMPTY_ARGUMENTS;
+       Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
+       unwrap(arguments);
+       
+       MetaMethod method = getMethodWithCaching(sender, methodName, argClasses, isCallToSuper);
+       
+       if (method==null && arguments.length==1 && arguments[0] instanceof List) {
+           Object[] newArguments = ((List) arguments[0]).toArray();
+           Class[] newArgClasses = MetaClassHelper.convertToTypeArray(newArguments);
+           method = getMethodWithCaching(sender, methodName, newArgClasses, isCallToSuper);
+           if (method!=null) {
+               MethodKey methodKey = new DefaultMethodKey(sender, methodName, argClasses, isCallToSuper);
+               method = new TransformMetaMethod(method) {
+                   public Object invoke(Object object, Object[] arguments) {
+                       Object firstArgument = arguments[0];
+                       List list = (List) firstArgument;
+                       arguments = list.toArray();
+                       return super.invoke(object, arguments);
+                   }
+               };
+               cacheInstanceMethod(methodKey, method);
+               return invokeMethod(sender,object,methodName, originalArguments, isCallToSuper, fromInsideClass);
+           }
+       }
+
+       boolean isClosure = object instanceof Closure;
+       if (isClosure) {
+           Closure closure = (Closure) object;
+           Object delegate = closure.getDelegate();
+           Object owner = closure.getOwner();
+           
+           
+           if ("call".equals(methodName) || "doCall".equals(methodName)) {
+               if (object.getClass()==MethodClosure.class) {
+                   MethodClosure mc = (MethodClosure) object;
+                   methodName = mc.getMethod();
+                   Class ownerClass = owner.getClass();
+                   if (owner instanceof Class) ownerClass = (Class) owner;
+                   MetaClass ownerMetaClass = registry.getMetaClass(ownerClass);
+                   return ownerMetaClass.invokeMethod(ownerClass,owner,methodName,arguments,false,false);
+               } else if (object.getClass()==CurriedClosure.class) {
+                   CurriedClosure cc = (CurriedClosure) object;
+                   // change the arguments for an uncurried call
+                   arguments = cc.getUncurriedArguments(arguments);
+                   Class ownerClass = owner.getClass();
+                   if (owner instanceof Class) ownerClass = (Class) owner;
+                   MetaClass ownerMetaClass = registry.getMetaClass(ownerClass);
+                   return ownerMetaClass.invokeMethod(owner,methodName,arguments);
+               }
+           } else if ("curry".equals(methodName)) {
+               return closure.curry(arguments);
+           }
+
+           if (method==null && owner!=closure) {
+               Class ownerClass = owner.getClass();
+               if (owner instanceof Class) ownerClass = (Class) owner;
+               MetaClass ownerMetaClass = registry.getMetaClass(ownerClass);
+               method = ownerMetaClass.pickMethod(methodName,argClasses);
+               if (method!=null) return ownerMetaClass.invokeMethod(owner,methodName,originalArguments);
+           }
+           if (method==null && delegate!=closure && delegate!=null) {
+               Class delegateClass = delegate.getClass();
+               if (delegate instanceof Class) delegateClass = (Class) delegate;
+               MetaClass delegateMetaClass = registry.getMetaClass(delegateClass);
+               method = delegateMetaClass.pickMethod(methodName,argClasses);
+               if (method!=null) return delegateMetaClass.invokeMethod(delegate,methodName,originalArguments);
+           }
+           if (method==null) {
+               // still no methods found, test if delegate or owner are GroovyObjects
+               // and invoke the method on them if so.
+               MissingMethodException last = null;
+               if (owner!=closure && (owner instanceof GroovyObject)) {
+                   try {
+                       GroovyObject go = (GroovyObject) owner;
+                       return go.invokeMethod(methodName,originalArguments);
+                   } catch (MissingMethodException mme) {
+                       if (last==null) last = mme;
+                   }
+               }
+               if (delegate!=closure && (delegate instanceof GroovyObject)) {
+                   try {
+                       GroovyObject go = (GroovyObject) delegate;
+                       return go.invokeMethod(methodName,originalArguments);
+                   } catch (MissingMethodException mme) {
+                       last = mme;
+                   }
+               }
+               if (last!=null) throw last;
+           }
+
+       }
+
+       if (method != null) {
+           return MetaClassHelper.doMethodInvoke(object, method, arguments);
+       } else {
+           // if no method was found, try to find a closure defined as a field of the class and run it
+           try {
+               Object value = this.getProperty(object, methodName);
+               if (value instanceof Closure) {  // This test ensures that value != this If you ever change this ensure that value != this
+                   Closure closure = (Closure) value;
+                   MetaClass delegateMetaClass = closure.getMetaClass();
+                   return delegateMetaClass.invokeMethod(closure.getClass(),closure,"doCall",originalArguments,false,fromInsideClass);
+               }
+           } catch (MissingPropertyException mpe) {}
+
+           throw new MissingMethodException(methodName, theClass, originalArguments, false);
+       }
+   }
+   
+   public MetaMethod getMethodWithCaching(Class sender, String methodName, Class[] arguments, boolean isCallToSuper) {
+       // lets try use the cache to find the method
+       if (GroovyCategorySupport.hasCategoryInAnyThread() && !isCallToSuper) {
+           return getMethodWithoutCaching(sender, methodName, arguments, isCallToSuper);
+       } else {
+           MethodKey methodKey = new DefaultMethodKey(sender, methodName, arguments, isCallToSuper);
+           MetaMethod method = (MetaMethod) methodCache.get(methodKey);
+           if (method == null) {
+               method = getMethodWithoutCaching(sender, methodName, arguments, isCallToSuper);
+               cacheInstanceMethod(methodKey, method);
+           }
+           return method;
+       }
+   }
+   
+   protected void cacheInstanceMethod(MethodKey key, MetaMethod method) {
+       if (method != null && method.isCacheable()) {
+           methodCache.put(key, method);
+       }
+   }
+
+   protected void cacheStaticMethod(MethodKey key, MetaMethod method) {
+       if (method != null && method.isCacheable()) {
+           staticMethodCache.put(key, method);
+       }
+   }
+
+   
+   public Constructor retrieveConstructor(Class[] arguments) {
+       Constructor constructor = (Constructor) chooseMethod("<init>", constructors, arguments, false);
+       if (constructor != null) {
+           return constructor;
+       }
+       constructor = (Constructor) chooseMethod("<init>", constructors, arguments, true);
+       if (constructor != null) {
+           return constructor;
+       }
+       return null;
+   }
+
+   public MetaMethod retrieveStaticMethod(String methodName, Class[] arguments) {
+       MethodKey methodKey = new DefaultMethodKey(theClass, methodName, arguments, false);
+       MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey);
+       if (method == null) {
+           method = pickStaticMethod(theClass,methodName, arguments);
+           cacheStaticMethod(methodKey, method);
+       }
+       return method;
+   }
+
+   public MetaMethod getMethodWithoutCaching(Class sender, String methodName, Class[] arguments, boolean isCallToSuper) {
+       MetaMethod method = null;
+       List methods = getMethods(sender,methodName,isCallToSuper);
+       if (methods!=null && !methods.isEmpty()) {
+           method = (MetaMethod) chooseMethod(methodName, methods, arguments, false);
+       }
+       return method;
+   }
+
+   public Object invokeStaticMethod(Object object, String methodName, Object[] arguments) {
+       checkInitalised();
+       if (log.isLoggable(Level.FINER)){
+           MetaClassHelper.logMethodCall(object, methodName, arguments);
+       }
+       
+       Class sender = object.getClass();
+       if (object instanceof Class) sender = (Class) object;
+       if (sender!=theClass) {
+           MetaClass mc = registry.getMetaClass(sender);
+           return mc.invokeStaticMethod(sender,methodName,arguments);
+       }
+       if (sender==Class.class) {
+           return invokeMethod(object,methodName,arguments);
+       }
+       
+       if (arguments==null) arguments = EMPTY_ARGUMENTS;
+       Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
+       unwrap(arguments);
+       
+       // lets try use the cache to find the method
+       MethodKey methodKey = new DefaultMethodKey(sender, methodName, argClasses, false);
+       MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey);
+       if (method == null) {
+           method = pickStaticMethod(sender, methodName, argClasses);
+           cacheStaticMethod(methodKey.createCopy(), method);
+       }
+
+       if (method != null) {
+           return MetaClassHelper.doMethodInvoke(object, method, arguments);
+       }
+
+       throw new MissingMethodException(methodName, sender, arguments, true);
+   }
+   
+   private MetaMethod pickStaticMethod(Class sender, String methodName, Class[] arguments) {
+       MetaMethod method = null;
+       List methods = getStaticMethods(sender,methodName);
+
+       if (!methods.isEmpty()) {
+           method = (MetaMethod) chooseMethod(methodName, methods, arguments, false);
+       }
+       if (method == null && theClass != Class.class) {
+           MetaClass classMetaClass = registry.getMetaClass(Class.class);
+           method = classMetaClass.pickMethod(methodName, arguments);
+       }
+       if (method == null) {
+           method = (MetaMethod) chooseMethod(methodName, methods, MetaClassHelper.convertToTypeArray(arguments), true);
+       }
+       return method;
+   }
+
+   public Object invokeConstructor(Object[] arguments) {
+       return invokeConstructor(theClass,arguments,false);
+   }
+
+   public int selectConstructorAndTransformArguments(int numberOfCosntructors, Object[] arguments) {
+       //TODO: that is just a quick prototype, not the real thing!
+       if (numberOfCosntructors != constructors.size()) {
+           throw new IncompatibleClassChangeError("the number of constructors during runtime and compile time for "+
+               this.theClass.getName()+" do not match. Expected "+numberOfCosntructors+" but got "+constructors.size());
+       }
+       
+       if (arguments==null) arguments = EMPTY_ARGUMENTS;
+       Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
+       unwrap(arguments);       
+       Constructor constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, false);
+       if (constructor == null) {
+           constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, true);
+       }
+       if (constructor==null) {
+           throw new GroovyRuntimeException(
+                   "Could not find matching constructor for: "
+                       + theClass.getName()
+                       + "("+InvokerHelper.toTypeString(arguments)+")");
+       }
+       List l = new ArrayList(constructors);
+       Comparator comp = new Comparator() {
+           public int compare(Object arg0, Object arg1) {
+               Constructor c0 = (Constructor) arg0;
+               Constructor c1 = (Constructor) arg1;
+               String descriptor0 = BytecodeHelper.getMethodDescriptor(Void.TYPE, c0.getParameterTypes()); 
+               String descriptor1 = BytecodeHelper.getMethodDescriptor(Void.TYPE, c1.getParameterTypes());
+               return descriptor0.compareTo(descriptor1);
+           }            
+       };
+       Collections.sort(l,comp);
+       int found = -1;
+       for (int i=0; i<l.size(); i++) {
+           if (l.get(i)!=constructor) continue;
+           found = i;
+           break;
+       }
+       // NOTE: must be changed to "1 |" if constructor was vargs
+       int ret = 0 | (found << 8);
+       return ret;
+   }
+   
+   /**
+    * checks if the initialisation of the class id complete.
+    * This method should be called as a form of assert, it is no
+    * way to test if there is still initialisation work to be done. 
+    * Such logic must be implemented in a different way.
+    * @throws IllegalStateException if the initialisation is incomplete yet
+    */
+   protected void checkInitalised() {
+       if (!isInitialized())
+           throw new IllegalStateException(
+                   "initialize must be called for meta " +
+                   "class of "+ theClass + 
+                   "("+this.getClass() + ") " +
+                   "to complete initialisation process " +
+                   "before any invocation or field/property " +
+                   "access can be done");
+   }
+   
+   private Object invokeConstructor(Class at, Object[] arguments, boolean setAccessible) {
+       checkInitalised();
+       if (arguments==null) arguments = EMPTY_ARGUMENTS;
+       Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
+       unwrap(arguments);       
+       Constructor constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, false);
+       if (constructor != null) {
+           return doConstructorInvoke(at, constructor, arguments, true);
+       }
+       constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, true);
+       if (constructor != null) {
+           return doConstructorInvoke(at, constructor, arguments, true);
+       }
+
+       if (arguments.length == 1) {
+           Object firstArgument = arguments[0];
+           if (firstArgument instanceof Map) {
+               constructor = (Constructor) chooseMethod("<init>", constructors, MetaClassHelper.EMPTY_TYPE_ARRAY, false);
+               if (constructor != null) {
+                   Object bean = doConstructorInvoke(at, constructor, MetaClassHelper.EMPTY_ARRAY, true);
+                   setProperties(bean, ((Map) firstArgument));
+                   return bean;
+               }
+           }
+       }
+       throw new GroovyRuntimeException(
+                   "Could not find matching constructor for: "
+                       + theClass.getName()
+                       + "("+InvokerHelper.toTypeString(arguments)+")");
+   }
+
+   /**
+    * Sets a number of bean properties from the given Map where the keys are
+    * the String names of properties and the values are the values of the
+    * properties to set
+    */
+   public void setProperties(Object bean, Map map) {
+       checkInitalised();
+       for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
+           Map.Entry entry = (Map.Entry) iter.next();
+           String key = entry.getKey().toString();
+
+           Object value = entry.getValue();
+           setProperty(bean, key, value);
+       }
+   }
+   
+   /**
+    * @return the given property's value on the object
+    */
+   public Object getProperty(Class sender, Object object, String name, boolean useSuper, boolean fromInsideClass) {
+       checkInitalised();
+       
+       //----------------------------------------------------------------------
+       // handling of static
+       //----------------------------------------------------------------------
+       boolean isStatic = theClass != Class.class && object instanceof Class;
+       if (isStatic && object != theClass) {
+           MetaClass mc = registry.getMetaClass((Class) object);
+           return mc.getProperty(sender,object,name,useSuper,false);
+       }
+    
+       MetaMethod method = null;
+       Object[] arguments = EMPTY_ARGUMENTS;
+
+       //----------------------------------------------------------------------
+       // getter
+       //----------------------------------------------------------------------
+       MetaProperty mp = getMetaProperty(sender,name,useSuper, isStatic);
+       if (mp != null) {
+           if (mp instanceof MetaBeanProperty) {
+               MetaBeanProperty mbp = (MetaBeanProperty) mp;
+               method = mbp.getGetter();
+               mp = mbp.getField();
+           } 
+       }
+
+       // check for a category method named like a getter 
+       if (method==null && !useSuper && !isStatic && GroovyCategorySupport.hasCategoryInAnyThread()) {
+           String getterName = "get"+MetaClassHelper.capitalize(name);
+           method = getCategoryMethodGetter(sender,getterName,false);
+       }
+
+       //----------------------------------------------------------------------
+       // field
+       //----------------------------------------------------------------------
+       if (method==null && mp!=null) {
+           return mp.getProperty(object);
+       }
+       
+
+       //----------------------------------------------------------------------
+       // generic get method
+       //----------------------------------------------------------------------       
+       // check for a generic get method provided through a category
+       if (method==null && !useSuper && !isStatic && GroovyCategorySupport.hasCategoryInAnyThread()) {
+           method = getCategoryMethodGetter(sender,"get",true);
+           if (method!=null) arguments = new Object[]{name};
+       }
+
+       // the generic method is valid, if available (!=null), if static or
+       // if it is not static and we do no static access
+       if (method==null && genericGetMethod != null && !(!genericGetMethod.isStatic() && isStatic)) {
+           arguments = new Object[]{ name };
+           method = genericGetMethod;
+       } 
+       
+       //----------------------------------------------------------------------
+       // special cases
+       //----------------------------------------------------------------------
+       if (method==null) {
+           /** todo these special cases should be special MetaClasses maybe */
+           if (theClass != Class.class && object instanceof Class) {
+               MetaClass mc = registry.getMetaClass(Class.class);
+               return mc.getProperty(Class.class,object,name,useSuper,false);
+           } else if (object instanceof Collection) {
+               return DefaultGroovyMethods.getAt((Collection) object, name);
+           } else if (object instanceof Object[]) {
+               return DefaultGroovyMethods.getAt(Arrays.asList((Object[]) object), name);
+           } else {
+               MetaMethod addListenerMethod = (MetaMethod) listeners.get(name);
+               if (addListenerMethod != null) {
+                   //TODO: one day we could try return the previously registered Closure listener for easy removal
+                   return null;
+               }
+           }
+       } else {
+           
+           //----------------------------------------------------------------------
+           // executing the getter method 
+           //----------------------------------------------------------------------
+           return MetaClassHelper.doMethodInvoke(object,method,arguments);
+       }
+       
+       //----------------------------------------------------------------------
+       // error due to missing method/field
+       //----------------------------------------------------------------------
+       throw new MissingPropertyException(name, theClass);   
+   }
+
+   private MetaMethod getCategoryMethodGetter(Class sender, String name, boolean useLongVersion) {
+       List possibleGenericMethods = GroovyCategorySupport.getCategoryMethods(sender, name);
+       if (possibleGenericMethods != null) {
+           for (Iterator iter = possibleGenericMethods.iterator(); iter.hasNext();) {
+               MetaMethod mmethod = (MetaMethod) iter.next();
+               Class[] paramTypes = mmethod.getParameterTypes();
+               if (useLongVersion) {
+                   if (paramTypes.length==1 && paramTypes[0] == String.class) {
+                       return mmethod;
+                   }
+               } else {
+                   if (paramTypes.length==0) return mmethod;
+               }
+           }
+       }
+       return null;
+   }
+   
+   private MetaMethod getCategoryMethodSetter(Class sender, String name, boolean useLongVersion) {
+       List possibleGenericMethods = GroovyCategorySupport.getCategoryMethods(sender, name);
+       if (possibleGenericMethods != null) {
+           for (Iterator iter = possibleGenericMethods.iterator(); iter.hasNext();) {
+               MetaMethod mmethod = (MetaMethod) iter.next();
+               Class[] paramTypes = mmethod.getParameterTypes();
+               if (useLongVersion) {
+                   if (paramTypes.length==2 && paramTypes[0] == String.class) {
+                       return mmethod;
+                   }
+               } else {
+                   if (paramTypes.length==1) return mmethod;
+               }
+           }
+       }
+       return null;
+   }
+
+   /**
+    * Get all the properties defined for this type
+    * @return a list of MetaProperty objects
+    */
+   public List getProperties() {
+       checkInitalised();
+       Map propertyMap = (Map) classPropertyIndex.get(theClass);
+       // simply return the values of the metaproperty map as a List
+       List ret = new ArrayList(propertyMap.size());
+       for (Iterator iter = propertyMap.values().iterator(); iter.hasNext();) {
+           MetaProperty element = (MetaProperty) iter.next();
+           if (element instanceof MetaFieldProperty) continue;
+           // filter out DGM beans
+           if (element instanceof MetaBeanProperty) {
+               MetaBeanProperty mp = (MetaBeanProperty) element;
+               boolean setter = true;
+               boolean getter = true;
+               if (mp.getGetter()==null || mp.getGetter() instanceof NewInstanceMetaMethod) {
+                   getter=false;
+               }
+               if (mp.getSetter()==null || mp.getSetter() instanceof NewInstanceMetaMethod) {
+                   setter=false;
+               }
+               if (!setter && !getter) continue;
+               if (!setter && mp.getSetter()!=null) {
+                   element = new MetaBeanProperty(mp.getName(),mp.getType(),mp.getGetter(),null);
+               }
+               if (!getter && mp.getGetter()!=null) {
+                   element = new MetaBeanProperty(mp.getName(),mp.getType(), null, mp.getSetter());
+               }
+           }
+           ret.add(element);
+       }
+       return ret;
+   }
+   
+   private MetaMethod findPropertyMethod(List methods, boolean isGetter) {
+       LinkedList ret = new LinkedList();
+       for (Iterator iter = methods.iterator(); iter.hasNext();) {
+           MetaMethod element = (MetaMethod) iter.next();
+           if ( !isGetter && 
+                //(element.getReturnType() == Void.class || element.getReturnType() == Void.TYPE) && 
+                element.getParameterTypes().length == 1)
+           {
+               ret.add(element);
+           } 
+           if ( isGetter &&
+                !(element.getReturnType() == Void.class || element.getReturnType() == Void.TYPE) && 
+                element.getParameterTypes().length == 0)
+           {
+               ret.add(element);
+           }
+       }
+       if (ret.size() == 0) return null;
+       if (ret.size() == 1) return (MetaMethod) ret.getFirst();
+       
+       // we found multiple matching methods
+       // this is a problem, because we can use only one
+       // if it is a getter, then use the most general return 
+       // type to decide which method to use. If it is a setter 
+       // we use the type of the first parameter 
+       MetaMethod method = null;
+       int distance = -1;
+       for (Iterator iter = ret.iterator(); iter.hasNext();) {
+           MetaMethod element = (MetaMethod) iter.next();
+           Class c;
+           if (isGetter) {
+               c = element.getReturnType();
+           } else {
+               c = element.getParameterTypes()[0];
+           }
+           int localDistance = distanceToObject(c);
+           //TODO: maybe implement the case localDistance==distance
+           if (distance==-1 || distance>localDistance) {
+               distance = localDistance;
+               method = element;
+           } 
+       }
+       return method;
+   }
+   
+   private static int distanceToObject(Class c) {
+       int count;
+       for (count=0; c!=null; count++) {
+           c=c.getSuperclass();           
+       }
+       return count;
+   }
+   
+   
+   /**
+    * This will build up the property map (Map of MetaProperty objects, keyed on
+    * property name).
+    */
+   private void setupProperties(PropertyDescriptor[] propertyDescriptors) {
+       LinkedList superClasses = getSuperClasses();
+       Set interfaces = new HashSet();
+       makeInterfaceSet(theClass,interfaces);
+       
+       // if this an Array, then add the special read-only "length" property
+       if (theClass.isArray()) {
+           Map map = new HashMap();
+           map.put("length", arrayLengthProperty);
+           classPropertyIndex.put(theClass,map);
+       }
+              
+       inheritStaticInterfaceFields(superClasses, interfaces);       
+       inheritFields(superClasses);
+       applyPropertyDescriptors(propertyDescriptors);
+       
+       applyStrayPropertyMethods(superClasses,classMethodIndex,classPropertyIndex);
+       applyStrayPropertyMethods(superClasses,classMethodIndexForSuper,classPropertyIndexForSuper);
+       
+       copyClassPropertyIndexForSuper();
+       makeStaticPropertyIndex();
+   }
+   
+   private void makeStaticPropertyIndex() {
+       Map propertyMap = (Map) classPropertyIndex.get(theClass);
+       for (Iterator iter = propertyMap.entrySet().iterator(); iter.hasNext();) {
+           Map.Entry entry = (Map.Entry) iter.next();
+           MetaProperty mp = (MetaProperty) entry.getValue();
+           if (mp instanceof MetaFieldProperty) {
+               MetaFieldProperty mfp = (MetaFieldProperty) mp;
+               if (!mfp.isStatic()) continue;
+           } else if (mp instanceof MetaBeanProperty) {
+               MetaBeanProperty mbp = (MetaBeanProperty) mp;
+               boolean getter = mbp.getGetter()==null || mbp.getGetter().isStatic();
+               boolean setter = mbp.getSetter()==null || mbp.getSetter().isStatic();
+               boolean field = mbp.getField()==null || mbp.getField().isStatic();
+               
+               if (!getter && !setter && !field) {
+                   continue;
+               } else if (setter && getter) {
+                   if (field) {
+                       mp = mbp; // nothing to do
+                   } else {
+                       mp = new MetaBeanProperty(mbp.getName(),mbp.getType(),mbp.getGetter(),mbp.getSetter());
+                   }
+               } else if (getter && !setter) {
+                   if (mbp.getGetter()==null) {
+                       mp = mbp.getField();
+                   } else {
+                       MetaBeanProperty newmp = new MetaBeanProperty(mbp.getName(),mbp.getType(),mbp.getGetter(),null);
+                       if (field) newmp.setField(mbp.getField());
+                       mp = newmp;
+                   }
+               } else if (setter && !getter) {
+                   if (mbp.getSetter()==null) {
+                       mp = mbp.getField();
+                   } else {
+                       MetaBeanProperty newmp = new MetaBeanProperty(mbp.getName(),mbp.getType(),null,mbp.getSetter());
+                       if (field) newmp.setField(mbp.getField());
+                       mp = newmp;
+                   }
+               } else if (field) {
+                   mp = mbp.getField();
+               }
+           } else {
+               continue; // ignore all other types
+           }
+           if (mp==null) continue;
+           staticPropertyIndex.put(entry.getKey(),mp);
+       }
+       
+   }
+   
+   private void copyClassPropertyIndexForSuper() {
+       for (Iterator iter = classPropertyIndex.entrySet().iterator(); iter.hasNext();) {
+           Map.Entry entry = (Map.Entry) iter.next();
+           HashMap newVal = new HashMap((Map)entry.getValue());
+           classPropertyIndexForSuper.put(entry.getKey(),newVal);
+       }
+   }
+   
+   private Map getMap2MapNotNull(Map m, Object key) {
+       Map ret = (Map) m.get(key);
+       if (ret==null) {
+           ret = new HashMap();
+           m.put(key,ret);
+       }
+       return ret;
+   }
+   
+   private void inheritStaticInterfaceFields(LinkedList superClasses, Set interfaces) {
+       for (Iterator interfaceIter = interfaces.iterator(); interfaceIter.hasNext();) {
+           Class iclass = (Class) interfaceIter.next();
+           Map iPropertyIndex = getMap2MapNotNull(classPropertyIndex,iclass);
+           addFields(iclass,iPropertyIndex);
+           for (Iterator classIter = superClasses.iterator(); classIter.hasNext();) {
+               Class sclass = (Class) classIter.next();
+               if (! iclass.isAssignableFrom(sclass)) continue;
+               Map sPropertyIndex = getMap2MapNotNull(classPropertyIndex,sclass);
+               copyNonPrivateFields(iPropertyIndex,sPropertyIndex);
+           }
+       }
+   }
+   
+   private void inheritFields(LinkedList superClasses) {
+       Map last = null;
+       for (Iterator iter = superClasses.iterator(); iter.hasNext();) {
+           Class klass = (Class) iter.next();
+           Map propertyIndex = getMap2MapNotNull(classPropertyIndex,klass);
+           if (last != null) {
+               copyNonPrivateFields(last,propertyIndex);
+           }
+           last = propertyIndex;
+           addFields(klass,propertyIndex);
+       }   
+   }
+   
+   private void addFields(final Class klass, Map propertyIndex) {
+       Field[] fields = (Field[]) AccessController.doPrivileged(new  PrivilegedAction() {
+           public Object run() {
+               return klass.getDeclaredFields();
+           }
+       });
+       for(int i = 0; i < fields.length; i++) {
+           MetaFieldProperty mfp = new MetaFieldProperty(fields[i]);
+           propertyIndex.put(fields[i].getName(), mfp);
+       }
+   }
+
+   private void copyNonPrivateFields(Map from, Map to) {
+       for (Iterator iter = from.entrySet().iterator(); iter.hasNext();) {
+           Map.Entry entry = (Map.Entry) iter.next();
+           MetaFieldProperty mfp = (MetaFieldProperty) entry.getValue();
+           if (!Modifier.isPublic(mfp.getModifiers()) && !Modifier.isProtected(mfp.getModifiers())) continue;
+           to.put(entry.getKey(),mfp);
+       }
+   }
+   
+   private void applyStrayPropertyMethods(LinkedList superClasses, Map classMethodIndex, Map classPropertyIndex) {
+       // now look for any stray getters that may be used to define a property
+       for (Iterator iter = superClasses.iterator(); iter.hasNext();) {
+           Class klass = (Class) iter.next();
+           Map methodIndex = (Map) classMethodIndex.get(klass);
+           Map propertyIndex = getMap2MapNotNull(classPropertyIndex,klass);
+           for (Iterator nameMethodIterator = methodIndex.entrySet().iterator(); nameMethodIterator.hasNext();) {
+               Map.Entry entry = (Map.Entry) nameMethodIterator.next();
+               String methodName = (String) entry.getKey();
+               // name too sort?
+               if (methodName.length() < 4) continue;
+               //possible getter/setter
+               boolean isGetter = methodName.startsWith("get");
+               boolean isSetter = methodName.startsWith("set");
+               if (!isGetter && !isSetter) continue;
+               
+               // get the name of the property
+               String propName = methodName.substring(3,4).toLowerCase() + methodName.substring(4);
+               MetaMethod propertyMethod = findPropertyMethod((List) entry.getValue(), isGetter);
+               if (propertyMethod==null) continue;
+               
+               createMetaBeanProperty(propertyIndex, propName, isGetter, propertyMethod);
+           }
+       }
+   }
+   
+   private void createMetaBeanProperty(Map propertyIndex, String propName, boolean isGetter, MetaMethod propertyMethod){
+       // is this property already accounted for?
+       MetaProperty mp = (MetaProperty) propertyIndex.get(propName);
+       if (mp == null) {
+           if (isGetter) {
+               mp = new MetaBeanProperty(propName,
+                       propertyMethod.getReturnType(),
+                       propertyMethod, null);
+           } else {
+               //isSetter
+               mp = new MetaBeanProperty(propName,
+                       propertyMethod.getParameterTypes()[0],
+                       null, propertyMethod);
+           }
+       } else {
+           MetaBeanProperty mbp;
+           MetaFieldProperty mfp;
+           if (mp instanceof MetaBeanProperty) {
+               mbp = (MetaBeanProperty) mp;
+               mfp = mbp.getField();
+           } else if (mp instanceof MetaFieldProperty){
+               mfp = (MetaFieldProperty) mp;
+               mbp = new MetaBeanProperty(propName,
+                       mfp.getType(),
+                       null, null);
+           } else {
+               throw new GroovyBugError("unknown MetaProperty class used. Class is "+mp.getClass());
+           }
+           // we may have already found one for this name
+           if (isGetter && mbp.getGetter()==null) {
+               mbp.setGetter(propertyMethod);
+           } else if (!isGetter && mbp.getSetter()==null) {
+               mbp.setSetter(propertyMethod);
+           }
+           mbp.setField(mfp);
+           mp = mbp;
+       }
+       propertyIndex.put(propName, mp);
+   }
+
+   private void applyPropertyDescriptors(PropertyDescriptor[] propertyDescriptors) {
+       Map propertyMap = (Map) classPropertyIndex.get(theClass);
+       // now iterate over the map of property descriptors and generate
+       // MetaBeanProperty objects
+       for(int i=0; i<propertyDescriptors.length; i++) {
+           PropertyDescriptor pd = propertyDescriptors[i];
+           
+           // skip if the property type is unknown (this seems to be the case if the
+           // property descriptor is based on a setX() method that has two parameters,
+           // which is not a valid property)
+           if(pd.getPropertyType() == null)
+               continue;
+           
+           // get the getter method
+           Method method = pd.getReadMethod();
+           MetaMethod getter;
+           if(method != null)
+               getter = findMethod(method);
+           else
+               getter = null;
+           
+           // get the setter method
+           MetaMethod setter;
+           method = pd.getWriteMethod();
+           if(method != null)
+               setter = findMethod(method);
+           else
+               setter = null;
+           
+           // now create the MetaProperty object
+           MetaBeanProperty mp = new MetaBeanProperty(pd.getName(), pd.getPropertyType(), getter, setter);
+           
+           //keep field
+           MetaFieldProperty field = null;
+           MetaProperty old = (MetaProperty) propertyMap.get(pd.getName());
+           if (old!=null) {
+               if (old instanceof MetaBeanProperty) {
+                   field = ((MetaBeanProperty) old).getField();
+               } else {
+                   field = (MetaFieldProperty) old;
+               }
+               mp.setField(field);
+           }
+           
+           // put it in the list
+           // this will overwrite a possible field property
+           propertyMap.put(pd.getName(), mp);
+       }       
+   }
+   
+   /**
+    * Sets the property value on an object
+    */
+   public void setProperty(Class sender,Object object, String name, Object newValue, boolean useSuper, boolean fromInsideClass) {
+       checkInitalised();
+       
+       //----------------------------------------------------------------------
+       // handling of static
+       //----------------------------------------------------------------------
+       boolean isStatic = theClass != Class.class && object instanceof Class;
+       if (isStatic && object != theClass) {
+           MetaClass mc = registry.getMetaClass((Class) object);
+           mc.getProperty(sender,object,name,useSuper,fromInsideClass);
+           return;
+       }
+       
+       //----------------------------------------------------------------------
+       // Unwrap wrapped values fo now - the new MOP will handle them properly
+       //----------------------------------------------------------------------
+       if (newValue instanceof Wrapper) newValue = ((Wrapper)newValue).unwrap();
+       
+       
+    
+       MetaMethod method = null;
+       Object[] arguments = null;
+
+       //----------------------------------------------------------------------
+       // setter
+       //----------------------------------------------------------------------
+       MetaProperty mp = getMetaProperty(sender,name,useSuper, isStatic);
+       MetaProperty field = null;
+       if (mp != null) {
+           if (mp instanceof MetaBeanProperty) {
+               MetaBeanProperty mbp = (MetaBeanProperty) mp;
+               method = mbp.getSetter();
+               if (method!=null) arguments = new Object[] { newValue };
+               field = mbp.getField();
+           } else {
+               field = mp;
+           }
+       }
+       
+       // check for a category method named like a setter 
+       if (!useSuper && !isStatic && GroovyCategorySupport.hasCategoryInAnyThread()) {
+           String getterName = "set"+MetaClassHelper.capitalize(name);
+           method = getCategoryMethodSetter(sender,getterName,false);
+           if (method!=null) arguments = new Object[] { newValue };
+       }
+
+       //----------------------------------------------------------------------
+       // listener method
+       //----------------------------------------------------------------------
+       boolean ambigousListener = false;
+       boolean usesProxy = false;
+       if (method==null) {
+           method = (MetaMethod) listeners.get(name);
+           ambigousListener = method == AMBIGOUS_LISTENER_METHOD;
+           if ( method != null && 
+                !ambigousListener &&
+                newValue instanceof Closure) 
+           {
+               // lets create a dynamic proxy
+               Object proxy =
+                   MetaClassHelper.createListenerProxy(method.getParameterTypes()[0], name, (Closure) newValue);
+               arguments = new Object[] { proxy };
+               newValue = proxy;
+               usesProxy = true;
+           } else {
+               method = null;
+           }
+       }
+       
+       //----------------------------------------------------------------------
+       // field
+       //----------------------------------------------------------------------
+       if (method==null && field!=null) {
+           field.setProperty(object,newValue);
+           return;
+       }       
+
+       //----------------------------------------------------------------------
+       // generic set method
+       //----------------------------------------------------------------------       
+       // check for a generic get method provided through a category
+       if (method==null && !useSuper && !isStatic && GroovyCategorySupport.hasCategoryInAnyThread()) {
+           method = getCategoryMethodSetter(sender,"set",true);
+           if (method!=null) arguments = new Object[]{name,newValue};
+       }
+
+       // the generic method is valid, if available (!=null), if static or
+       // if it is not static and we do no static access
+       if (method==null && genericSetMethod != null && !(!genericSetMethod.isStatic() && isStatic)) {
+           arguments = new Object[]{ name, newValue };
+           method = genericSetMethod;
+       } 
+       
+       //----------------------------------------------------------------------
+       // executing the getter method 
+       //----------------------------------------------------------------------
+       if (method!=null) {
+           if (arguments.length==1) {
+               newValue = DefaultTypeTransformation.castToType(
+                       newValue,
+                       method.getParameterTypes()[0]);
+               arguments[0] = newValue;
+           } else {
+               newValue = DefaultTypeTransformation.castToType(
+                       newValue,
+                       method.getParameterTypes()[1]);
+               arguments[1] = newValue;
+           }
+           MetaClassHelper.doMethodInvoke(object,method,arguments);
+           return;
+       }
+           
+       //----------------------------------------------------------------------
+       // error due to missing method/field
+       //----------------------------------------------------------------------
+       if (ambigousListener){
+           throw new GroovyRuntimeException("There are multiple listeners for the property "+name+". Please do not use the bean short form to access this listener.");
+       } 
+       throw new MissingPropertyException(name, theClass);   
+   }
+   
+   private MetaProperty getMetaProperty(Class clazz, String name, boolean useSuper, boolean useStatic) {
+       Map propertyMap;
+       if (useStatic) {
+           propertyMap = staticPropertyIndex;
+       } else if (useSuper){
+           propertyMap = (Map) classPropertyIndexForSuper.get(clazz);
+       } else {
+           propertyMap = (Map) classPropertyIndex.get(clazz);
+       }
+       if (propertyMap==null) {
+           if (clazz!=theClass) {
+               return getMetaProperty(theClass,name,useSuper, useStatic);
+           } else {
+               return null;
+           }           
+       }
+       return (MetaProperty) propertyMap.get(name);
+   }
+
+
+   /**
+    * Looks up the given attribute (field) on the given object
+    */
+   public Object getAttribute(Class sender, Object object, String attribute, boolean useSuper, boolean fromInsideClass) {
+       checkInitalised();
+       
+       boolean isStatic = theClass != Class.class && object instanceof Class;
+       if (isStatic && object != theClass) {
+           MetaClass mc = registry.getMetaClass((Class) object);
+           return mc.getAttribute(sender,object,attribute,useSuper);
+       }
+    
+       MetaProperty mp = getMetaProperty(sender,attribute,useSuper, isStatic);
+       
+       if (mp != null) {
+           if (mp instanceof MetaBeanProperty) {
+               MetaBeanProperty mbp = (MetaBeanProperty) mp;
+               mp = mbp.getField();
+           }
+           try {
+               // delegate the get operation to the metaproperty
+               if (mp != null) return mp.getProperty(object);
+           } catch(Exception e) {
+               throw new GroovyRuntimeException("Cannot read field: " + attribute,e);
+           }
+       }
+       
+       throw new MissingFieldException(attribute, theClass);
+   }
+
+   /**
+    * Sets the given attribute (field) on the given object
+    */
+   public void setAttribute(Class sender, Object object, String attribute, Object newValue, boolean useSuper, boolean fromInsideClass) {
+       checkInitalised();
+       
+       boolean isStatic = theClass != Class.class && object instanceof Class;
+       if (isStatic && object != theClass) {
+           MetaClass mc = registry.getMetaClass((Class) object);
+           mc.setAttribute(sender,object,attribute,newValue,useSuper,fromInsideClass);
+           return;
+       }
+    
+       MetaProperty mp = getMetaProperty(sender,attribute,useSuper, isStatic);
+       
+       if (mp != null) {
+           if (mp instanceof MetaBeanProperty) {
+               MetaBeanProperty mbp = (MetaBeanProperty) mp;
+               mp = mbp.getField();
+           }
+           if (mp != null) {
+               mp.setProperty(object,newValue);
+               return;
+           }
+       }
+       
+       throw new MissingFieldException(attribute, theClass);
+   }
+
+   public ClassNode getClassNode() {
+       if (classNode == null && GroovyObject.class.isAssignableFrom(theClass)) {
+           // lets try load it from the classpath
+           String className = theClass.getName();
+           String groovyFile = className;
+           int idx = groovyFile.indexOf('$');
+           if (idx > 0) {
+               groovyFile = groovyFile.substring(0, idx);
+           }
+           groovyFile = groovyFile.replace('.', '/') + ".groovy";
+
+           //System.out.println("Attempting to load: " + groovyFile);
+           URL url = theClass.getClassLoader().getResource(groovyFile);
+           if (url == null) {
+               url = Thread.currentThread().getContextClassLoader().getResource(groovyFile);
+           }
+           if (url != null) {
+               try {
+
+                   /**
+                    * todo there is no CompileUnit in scope so class name
+                    * checking won't work but that mostly affects the bytecode
+                    * generation rather than viewing the AST
+                    */
+                   CompilationUnit.ClassgenCallback search = new CompilationUnit.ClassgenCallback() {
+                       public void call( ClassVisitor writer, ClassNode node ) {
+                           if( node.getName().equals(theClass.getName()) ) {
+                               MetaClassImpl.this.classNode = node;
+                           }
+                       }
+                   };
+
+                   final ClassLoader parent = theClass.getClassLoader();
+                   GroovyClassLoader gcl = (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
+                       public Object run() {
+                           return new GroovyClassLoader(parent);
+                       }
+                   });
+                   CompilationUnit unit = new CompilationUnit( );
+                   unit.setClassgenCallback( search );
+                   unit.addSource( url );
+                   unit.compile( Phases.CLASS_GENERATION );
+               }
+               catch (Exception e) {
+                   throw new GroovyRuntimeException("Exception thrown parsing: " + groovyFile + ". Reason: " + e, e);
+               }
+           }
+
+       }
+       return classNode;
+   }
+
+   public String toString() {
+       return super.toString() + "[" + theClass + "]";
+   }
+
+   // Implementation methods
+   //-------------------------------------------------------------------------
+   
+   /**
+    * Adds all the methods declared in the given class to the metaclass
+    * ignoring any matching methods already defined by a derived class
+    *
+    * @param theClass
+    */
+   private void addMethods(final Class theClass) {
+       Map methodIndex = (Map) classMethodIndex.get(theClass);
+       if (methodIndex==null) {
+           methodIndex = new HashMap();
+           classMethodIndex.put(theClass,methodIndex);
+       }
+       // add methods directly declared in the class
+       Method[] methodArray = (Method[]) AccessController.doPrivileged(new  PrivilegedAction() {
+               public Object run() {
+                   return theClass.getDeclaredMethods();
+               }
+           });
+       for (int i = 0; i < methodArray.length; i++) {
+           Method reflectionMethod = methodArray[i];
+           if ( reflectionMethod.getName().indexOf('+') >= 0 ) {
+               // Skip Synthetic methods inserted by JDK 1.5 compilers and later
+               continue;
+           } else if (Modifier.isAbstract(reflectionMethod.getModifiers())) {
+               continue;
+           }
+           MetaMethod method = createMetaMethod(reflectionMethod);
+           addMetaMethod(method);
+       }
+       // add methods declared by DGM
+       List methods = registry.getInstanceMethods();
+       for (Iterator iter = methods.iterator(); iter.hasNext();) {
+           Method element = (Method) iter.next();
+           if (element.getParameterTypes()[0]!=theClass) continue;
+           addNewInstanceMethod(element);
+       }
+       // add static methods declared by DGM
+       methods = registry.getStaticMethods();
+       for (Iterator iter = methods.iterator(); iter.hasNext();) {
+           Method element = (Method) iter.next();
+           if (element.getParameterTypes()[0]!=theClass) continue;
+           addNewStaticMethod(element);
+       }
+   }
+   
+   private void addToClassMethodIndex(MetaMethod method, Map classMethodIndex) {
+       Map methodIndex = (Map) classMethodIndex.get(method.getDeclaringClass());
+       if (methodIndex==null) {
+           methodIndex = new HashMap();
+           classMethodIndex.put(method.getDeclaringClass(),methodIndex);
+       }
+       String name = method.getName();
+       List list = (List) methodIndex.get(name);
+       if (list == null) {
+           list = new ArrayList();
+           methodIndex.put(name, list);
+           list.add(method);
+       } else {
+           addMethodToList(list,method);
+       }
+   }
+
+   /**
+    * adds a MetaMethod to this class. WARNING: this method will not
+    * do the neccessary steps for multimethod logic and using this
+    * method doesn't mean, that a method added here is replacing another
+    * method from a parent class completely. These steps are usually done
+    * by initalize, which means if you need these steps, you have to add
+    * the method before running initialize the first time.
+    * @see #initialize() 
+    * @param method the MetaMethod
+    */
+   protected void addMetaMethod(MetaMethod method) {
+       if (isInitialized()) {
+           throw new RuntimeException("Already initialized, cannot add new method: " + method);
+       }
+       if (isGenericGetMethod(method) && genericGetMethod == null) {
+           genericGetMethod = method;
+       }
+       else if (MetaClassHelper.isGenericSetMethod(method) && genericSetMethod == null) {
+           genericSetMethod = method;
+       }
+       if (method.isStatic()) {
+           addToClassMethodIndex(method,classStaticMethodIndex);
+       }
+       addToClassMethodIndex(method,classMethodIndex);
+   }
+   
+   protected boolean isInitialized(){
+       return initialized;
+   }
+   
+   private void addMethodToList(List list, MetaMethod method) {
+       MetaMethod match = removeMatchingMethod(list,method);
+       if (match==null) {
+           list.add(method);
+       } else if (match.isPrivate()){
+           // do not overwrite private methods
+           // Note: private methods from parent classes are not shown here,
+           // but when doing the multimethod connection step, we overwrite
+           // methods of the parent class with methods of a subclass and
+           // in that case we want to keep the private methods
+           list.add(match);
+       } else {
+           Class methodC = method.getDeclaringClass();
+           Class matchC = match.getDeclaringClass();
+           if (methodC == matchC){
+               if (method instanceof NewInstanceMetaMethod) {
+                   // let DGM replace existing methods
+                   list.add(method);
+               } else {
+                   list.add(match);
+               }               
+           } else if (MetaClassHelper.isAssignableFrom(methodC,matchC)){
+               list.add(match);
+           } else {
+              list.add(method);
+           }
+       }
+   }
+   
+   /**
+    * remove a method of the same matching prototype was found in the list
+    */
+   private MetaMethod removeMatchingMethod(List list, MetaMethod method) {
+       for (Iterator iter = list.iterator(); iter.hasNext();) {
+           MetaMethod aMethod = (MetaMethod) iter.next();
+           Class[] params1 = aMethod.getParameterTypes();
+           Class[] params2 = method.getParameterTypes();
+           if (params1.length == params2.length) {
+               boolean matches = true;
+               for (int i = 0; i < params1.length; i++) {
+                   if (params1[i] != params2[i]) {
+                       matches = false;
+                       break;
+                   }
+               }
+               if (matches) {
+                   iter.remove();
+                   return (MetaMethod) aMethod;
+               }
+           }
+       }
+       return null;
+   }
+
+   /**
+    * @return the matching method which should be found
+    */
+   private MetaMethod findMethod(Method aMethod) {
+       List methods = getMethods(theClass,aMethod.getName(),false);
+       for (Iterator iter = methods.iterator(); iter.hasNext();) {
+           MetaMethod method = (MetaMethod) iter.next();
+           if (method.isMethod(aMethod)) {
+               return method;
+           }
+       }
+       //log.warning("Creating reflection based dispatcher for: " + aMethod);
+       return new ReflectionMetaMethod(aMethod);
+   }
+
+   /**
+    * @return the getter method for the given object
+    */
+   private MetaMethod findGetter(Object object, String name) {
+       List methods = getMethods(theClass,name,false);
+       for (Iterator iter = methods.iterator(); iter.hasNext();) {
+           MetaMethod method = (MetaMethod) iter.next();
+           if (method.getParameterTypes().length == 0) {
+               return method;
+           }
+       }
+       return null;
+   }
+
+   /**
+    * @return the Method of the given name with no parameters or null
+    */
+   private MetaMethod findStaticGetter(Class type, String name) {
+       List methods = getStaticMethods(type, name);
+       for (Iterator iter = methods.iterator(); iter.hasNext();) {
+           MetaMethod method = (MetaMethod) iter.next();
+           if (method.getParameterTypes().length == 0) {
+               return method;
+           }
+       }
+
+       /** todo dirty hack - don't understand why this code is necessary - all methods should be in the allMethods list! */
+       try {
+           Method method = type.getMethod(name, MetaClassHelper.EMPTY_TYPE_ARRAY);
+           if ((method.getModifiers() & Modifier.STATIC) != 0) {
+               return findMethod(method);
+           }
+           else {
+               return null;
+           }
+       }
+       catch (Exception e) {
+           return null;
+       }
+   }
+   
+   private static Object doConstructorInvoke(final Class at, Constructor constructor, Object[] argumentArray, boolean setAccessible) {
+       if (log.isLoggable(Level.FINER)) {
+           MetaClassHelper.logMethodCall(constructor.getDeclaringClass(), constructor.getName(), argumentArray);
+       }
+
+       if (setAccessible) {
+           // To fix JIRA 435
+           // Every constructor should be opened to the accessible classes.
+           final boolean accessible = MetaClassHelper.accessibleToConstructor(at, constructor);
+           final Constructor ctor = constructor;
+           AccessController.doPrivileged(new PrivilegedAction() {
+               public Object run() {
+                   ctor.setAccessible(accessible);
+                   return null;
+               }
+           });
+       }
+       return MetaClassHelper.doConstructorInvoke(constructor,argumentArray);
+   }
+
+   /**
+    * Chooses the correct method to use from a list of methods which match by
+    * name.
+    *
+    * @param methods
+    *            the possible methods to choose from
+    * @param arguments
+    *            the original argument to the method
+    */
+   private Object chooseMethod(String methodName, List methods, Class[] arguments, boolean coerce) {
+       int methodCount = methods.size();
+       if (methodCount <= 0) {
+           return null;
+       }
+       else if (methodCount == 1) {
+           Object method = methods.get(0);
+           if (MetaClassHelper.isValidMethod(method, arguments, coerce)) {
+               return method;
+           }
+           return null;
+       }
+       Object answer = null;
+       if (arguments == null || arguments.length == 0) {
+           answer = MetaClassHelper.chooseEmptyMethodParams(methods);
+       }
+       else if (arguments.length == 1 && arguments[0] == null) {
+           answer = MetaClassHelper.chooseMostGeneralMethodWith1NullParam(methods);
+       }
+       else {
+           List matchingMethods = new ArrayList();
+
+           for (Iterator iter = methods.iterator(); iter.hasNext();) {
+               Object method = iter.next();
+
+               // making this false helps find matches
+               if (MetaClassHelper.isValidMethod(method, arguments, coerce)) {
+                   matchingMethods.add(method);
+               }
+           }
+           if (matchingMethods.isEmpty()) {
+               return null;
+           }
+           else if (matchingMethods.size() == 1) {
+               return matchingMethods.get(0);
+           }
+           return chooseMostSpecificParams(methodName, matchingMethods, arguments);
+
+       }
+       if (answer != null) {
+           return answer;
+       }
+       throw new GroovyRuntimeException(
+           "Could not find which method to invoke from this list: "
+               + methods
+               + " for arguments: "
+               + InvokerHelper.toString(arguments));
+   }
+
+   private Object chooseMostSpecificParams(String name, List matchingMethods, Class[] arguments) {
+
+       long matchesDistance = -1;
+       LinkedList matches = new LinkedList();
+       for (Iterator iter = matchingMethods.iterator(); iter.hasNext();) {
+           Object method = iter.next();
+           Class[] paramTypes = MetaClassHelper.getParameterTypes(method);
+           if (!MetaClassHelper.parametersAreCompatible(arguments, paramTypes)) continue;
+           long dist = MetaClassHelper.calculateParameterDistance(arguments, paramTypes);
+           if (dist==0) return method;
+           if (matches.size()==0) {
+               matches.add(method);
+               matchesDistance = dist;
+           } else if (dist<matchesDistance) {
+               matchesDistance=dist;
+               matches.clear();
+               matches.add(method);
+           } else if (dist==matchesDistance) {
+               matches.add(method);
+           }
+
+       }
+       if (matches.size()==1) {
+           return matches.getFirst();
+       }
+       if (matches.size()==0) {
+           return null;
+       }
+
+       //more than one matching method found --> ambigous!
+       String msg = "Ambiguous method overloading for method ";
+       msg+= theClass.getName()+"#"+name;
+       msg+= ".\nCannot resolve which method to invoke for ";
+       msg+= InvokerHelper.toString(arguments);
+       msg+= " due to overlapping prototypes between:";
+       for (Iterator iter = matches.iterator(); iter.hasNext();) {
+           Class[] types=MetaClassHelper.getParameterTypes(iter.next());
+           msg+= "\n\t"+InvokerHelper.toString(types);
+       }
+       throw new GroovyRuntimeException(msg);
+   }
+
+   private boolean isGenericGetMethod(MetaMethod method) {
+       if (method.getName().equals("get")) {
+           Class[] parameterTypes = method.getParameterTypes();
+           return parameterTypes.length == 1 && parameterTypes[0] == String.class;
+       }
+       return false;
+   }
+
+   /**
+    * Call this method when any mutation method is called, such as adding a new
+    * method to this MetaClass so that any caching or bytecode generation can be
+    * regenerated.
+    */
+   private synchronized void onMethodChange() {
+       reflector = null;
+   }
+
+   
+   public synchronized void initialize() {
+       if (!isInitialized()) {
+           fillMethodIndex();
+           addProperties();
+           initialized = true;
+       }
+       if (reflector == null) {
+           generateReflector();
+       }
+   }
+
+   private void addProperties()  {
+       BeanInfo info;
+       //     introspect
+       try {
+           info =(BeanInfo) AccessController.doPrivileged(new PrivilegedExceptionAction() {
+               public Object run() throws IntrospectionException {
+                   return Introspector.getBeanInfo(theClass);
+               }
+           });
+       } catch (PrivilegedActionException pae) {
+           throw new GroovyRuntimeException("exception while bean introspection",pae.getException());
+       }
+       PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
+
+       // build up the metaproperties based on the public fields, property descriptors,
+       // and the getters and setters
+       setupProperties(descriptors);
+       
+       EventSetDescriptor[] eventDescriptors = info.getEventSetDescriptors();
+       for (int i = 0; i < eventDescriptors.length; i++) {
+           EventSetDescriptor descriptor = eventDescriptors[i];
+           Method[] listenerMethods = descriptor.getListenerMethods();
+           for (int j = 0; j < listenerMethods.length; j++) {
+               Method listenerMethod = listenerMethods[j];
+               MetaMethod metaMethod = createMetaMethod(descriptor.getAddListenerMethod());
+               String name = listenerMethod.getName();
+               if (listeners.containsKey(name)) {
+                   listeners.put(name, AMBIGOUS_LISTENER_METHOD);
+               } else{
+                   listeners.put(name, metaMethod);
+               }
+           }
+       }    
+   }
+
+   private MetaMethod createMetaMethod(final Method method) {
+       if (registry.useAccessible()) {
+           AccessController.doPrivileged(new PrivilegedAction() {
+               public Object run() {
+                   method.setAccessible(true);
+                   return null;
+               }
+           });
+       }
+
+       MetaMethod answer = new MetaMethod(method);
+       if (isValidReflectorMethod(answer)) {
+           allMethods.add(answer);
+           answer.setMethodIndex(allMethods.size());
+       }
+       else {
+           //log.warning("Creating reflection based dispatcher for: " + method);
+           answer = new ReflectionMetaMethod(method);
+       }
+
+       if (useReflection) {
+           //log.warning("Creating reflection based dispatcher for: " + method);
+           return new ReflectionMetaMethod(method);
+       }
+
+       return answer;
+   }
+
+   private boolean isValidReflectorMethod(MetaMethod method) {
+       // We cannot use a reflector if the method is private, protected, or package accessible only.
+       if (!method.isPublic()) {
+           return false;
+       }
+       // lets see if this method is implemented on an interface
+       List interfaceMethods = getInterfaceMethods();
+       for (Iterator iter = interfaceMethods.iterator(); iter.hasNext();) {
+           MetaMethod aMethod = (MetaMethod) iter.next();
+           if (method.isSame(aMethod)) {
+               method.setInterfaceClass(aMethod.getCallClass());
+               return true;
+           }
+       }
+       // it's no interface method, so try to find the highest class
+       // in hierarchy defining this method
+       Class declaringClass = method.getCallClass();
+       for (Class clazz=declaringClass; clazz!=null; clazz=clazz.getSuperclass()) {
+           try {
+               final Class klazz = clazz;
+               final String mName = method.getName();
+               final Class[] parms = method.getParameterTypes();
+               try {
+                   Method m = (Method) AccessController.doPrivileged(new PrivilegedExceptionAction() {
+                       public Object run() throws NoSuchMethodException {
+                           return klazz.getDeclaredMethod(mName, parms);
+                       }
+                   });
+                   if (!Modifier.isPublic(clazz.getModifiers())) continue;
+                   if (!Modifier.isPublic(m.getModifiers())) continue;
+                   declaringClass = clazz;
+               } catch (PrivilegedActionException pae) {
+                   if (pae.getException() instanceof NoSuchMethodException) {
+                       throw (NoSuchMethodException) pae.getException();
+                   } else {
+                       throw new RuntimeException(pae.getException());
+                   }
+               }
+           } catch (SecurityException e) {
+               continue;
+           } catch (NoSuchMethodException e) {
+               continue;
+           }
+       }
+       if (!Modifier.isPublic(declaringClass.getModifiers())) return false;
+       method.setCallClass(declaringClass);
+
+       return true;
+   }
+
+   private void generateReflector() {
+       reflector = registry.loadReflector(theClass, allMethods);
+       if (reflector == null) {
+           throw new RuntimeException("Should have a reflector for "+theClass.getName());
+       }
+       // lets set the reflector on all the methods
+       for (Iterator iter = allMethods.iterator(); iter.hasNext();) {
+           MetaMethod metaMethod = (MetaMethod) iter.next();
+           metaMethod.setReflector(reflector);
+       }
+   }
+
+   public List getMethods() {
+       return allMethods;
+   }
+
+   public List getMetaMethods() {
+       return new ArrayList(newGroovyMethodsList);
+   }
+
+   private synchronized List getInterfaceMethods() {
+       if (interfaceMethods == null) {
+           interfaceMethods = new ArrayList();
+           Class type = theClass;
+           while (type != null) {
+               Class[] interfaces = type.getInterfaces();
+               for (int i = 0; i < interfaces.length; i++) {
+                   Class iface = interfaces[i];
+                   Method[] methods = iface.getMethods();
+                   addInterfaceMethods(interfaceMethods, methods);
+               }
+               type = type.getSuperclass();
+           }
+       }
+       return interfaceMethods;
+   }
+
+   private void addInterfaceMethods(List list, Method[] methods) {
+       for (int i = 0; i < methods.length; i++) {
+           list.add(createMetaMethod(methods[i]));
+       }
+   }
+   
+   private static class MethodIndexAction {
+       public void iterate(Map classMethodIndex){
+           for (Iterator iter = classMethodIndex.entrySet().iterator(); iter.hasNext();) {
+               Map.Entry classEntry = (Map.Entry) iter.next();
+               Map methodIndex = (Map) classEntry.getValue();
+               Class clazz = (Class) classEntry.getKey();
+               if (skipClass(clazz)) continue;               
+               for (Iterator iterator = methodIndex.entrySet().iterator(); iterator.hasNext();) {
+                   Map.Entry nameEntry = (Map.Entry) iterator.next();
+                   String name = (String) nameEntry.getKey();
+                   List oldList = (List) nameEntry.getValue();
+                   List newList = methodNameAction(clazz, name, oldList);
+                   if (replaceMethodList()) nameEntry.setValue(newList); 
+               }
+           }
+       }
+       public List methodNameAction(Class clazz, String methodName, List methods) {
+           List newList = new ArrayList(methods.size());
+           for (Iterator methodIter = methods.iterator(); methodIter.hasNext();) {
+               MetaMethod method = (MetaMethod) methodIter.next();
+               methodListAction(clazz,methodName,method,methods,newList);
+           }
+           return newList;
+       }
+       public boolean skipClass(Class clazz) {return false;}
+       public void methodListAction(Class clazz, String methodName, MetaMethod method, List oldList, List newList) {}
+       public boolean replaceMethodList(){return true;}
+   }
+
+   /**
+    * @deprecated
+    */
+   public Object getProperty(Object object, String property) {
+       return getProperty(theClass,object,property,false,false);
+   }
+   
+   /**
+    * @deprecated
+    */
+   public void setProperty(Object object, String property, Object newValue) {
+       setProperty(theClass,object,property,newValue,false,false);
+   }
+   
+   /**
+    * @deprecated
+    */
+   public Object getAttribute(Object object, String attribute) {
+       return getAttribute(theClass,object,attribute,false,false);
+   }
+   
+   /**
+    * @deprecated
+    */
+   public void setAttribute(Object object, String attribute, Object newValue) {
+       setAttribute(theClass,object,attribute,newValue,false,false);
+   }
+
+   public MetaMethod pickMethod(String methodName, Class[] arguments) {
+       return getMethodWithoutCaching(theClass,methodName,arguments,false);
+   }
+   
+   /**
+    * @deprecated use pickMethod instead
+    */
+   protected MetaMethod retrieveMethod(String methodName, Class[] arguments) {
+       return pickMethod(methodName,arguments);
+   }
+   
+   /**
+    * remove all method call cache entries. This should be done if a 
+    * method is added during runtime, but not by using a category.
+    */
+   protected void clearInvocationCaches() {
+       staticMethodCache.clear();
+       methodCache.clear();
+   }
+}
diff --git a/groovy-core/src/main/groovy/lang/MetaClassRegistry.java b/groovy-core/src/main/groovy/lang/MetaClassRegistry.java
new file mode 100644
index 0000000..eb34fc6
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/MetaClassRegistry.java
@@ -0,0 +1,293 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.codehaus.groovy.classgen.ReflectorGenerator;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.codehaus.groovy.runtime.DefaultGroovyStaticMethods;
+import org.codehaus.groovy.runtime.MethodHelper;
+import org.codehaus.groovy.runtime.ReferenceMap;
+import org.codehaus.groovy.runtime.Reflector;
+import org.codehaus.groovy.runtime.ReflectorLoader;
+import org.objectweb.asm.ClassWriter;
+
+/**
+ * A registery of MetaClass instances which caches introspection &
+ * reflection information and allows methods to be dynamically added to
+ * existing classes at runtime
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author John Wilson
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * @version $Revision$
+ */
+public class MetaClassRegistry {
+    private ReferenceMap metaClasses = new ReferenceMap();
+    private ReferenceMap loaderMap = new ReferenceMap();
+    private boolean useAccessible;
+    
+    private LinkedList instanceMethods = new LinkedList();
+    private LinkedList staticMethods = new LinkedList();
+
+    public static final int LOAD_DEFAULT = 0;
+    public static final int DONT_LOAD_DEFAULT = 1;
+    private static MetaClassRegistry instanceInclude;
+    private static MetaClassRegistry instanceExclude;
+
+
+    public MetaClassRegistry() {
+        this(LOAD_DEFAULT, true);
+    }
+
+    public MetaClassRegistry(int loadDefault) {
+        this(loadDefault, true);
+    }
+
+    /**
+     * @param useAccessible defines whether or not the {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)}
+     *                      method will be called to enable access to all methods when using reflection
+     */
+    public MetaClassRegistry(boolean useAccessible) {
+        this(LOAD_DEFAULT, useAccessible);
+    }
+    
+    public MetaClassRegistry(final int loadDefault, final boolean useAccessible) {
+        this.useAccessible = useAccessible;
+        
+        if (loadDefault == LOAD_DEFAULT) {
+            // lets register the default methods
+            registerMethods(DefaultGroovyMethods.class, true);
+            registerMethods(DefaultGroovyStaticMethods.class, false);
+        }
+    }
+    
+    private void registerMethods(final Class theClass, final boolean useInstanceMethods) {
+        Method[] methods = theClass.getMethods();
+        for (int i = 0; i < methods.length; i++) {
+            Method method = methods[i];
+            if (MethodHelper.isStatic(method)) {
+                Class[] paramTypes = method.getParameterTypes();
+                if (paramTypes.length > 0) {
+                    if (useInstanceMethods) {
+                        instanceMethods.add(method);
+                    } else {
+                        staticMethods.add(method);
+                    }
+                }
+            }
+        }
+    }
+
+    public MetaClass getMetaClass(Class theClass) {
+        synchronized (theClass) {
+            MetaClass answer = (MetaClass) metaClasses.get(theClass);
+            if (answer == null) {
+                answer = getMetaClassFor(theClass);
+                answer.initialize();
+                metaClasses.put(theClass, answer);
+            }
+            return answer;
+        }
+    }
+
+    public void removeMetaClass(Class theClass) {
+        synchronized (theClass) {
+            metaClasses.remove(theClass);
+        }
+    }
+
+
+    /**
+     * Registers a new MetaClass in the registry to customize the type
+     *
+     * @param theClass
+     * @param theMetaClass
+     */
+    public void setMetaClass(Class theClass, MetaClass theMetaClass) {
+        synchronized(theClass) {
+            metaClasses.putStrong(theClass, theMetaClass);
+        }
+    }
+
+    public boolean useAccessible() {
+        return useAccessible;
+    }
+
+    private ReflectorLoader getReflectorLoader(final ClassLoader loader) {
+        synchronized (loaderMap) {
+            ReflectorLoader reflectorLoader = (ReflectorLoader) loaderMap.get(loader);
+            if (reflectorLoader == null) {
+                reflectorLoader = (ReflectorLoader) AccessController.doPrivileged(new PrivilegedAction() {
+                    public Object run() {
+                        return new ReflectorLoader(loader);
+                    }
+                }); 
+                loaderMap.put(loader, reflectorLoader);
+            }
+            return reflectorLoader;
+        }
+    }
+
+    /**
+     * Used by MetaClass when registering new methods which avoids initializing the MetaClass instances on lookup
+     */
+    MetaClass lookup(Class theClass) {
+        synchronized (theClass) {
+            MetaClass answer = (MetaClass) metaClasses.get(theClass);
+            if (answer == null) {
+                answer = getMetaClassFor(theClass);
+                metaClasses.put(theClass, answer);
+            }
+            return answer;
+        }
+    }
+
+    /**
+     * Find a MetaClass for the class
+     * If there is a custom MetaClass then return an instance of that. Otherwise return an instance of the standard MetaClass
+     * 
+     * @param theClass
+     * @return An instace of the MetaClass which will handle this class
+     */
+    private MetaClass getMetaClassFor(final Class theClass) {
+        try {
+            final Class customMetaClass = Class.forName("groovy.runtime.metaclass." + theClass.getName() + "MetaClass");
+            final Constructor customMetaClassConstructor = customMetaClass.getConstructor(new Class[]{MetaClassRegistry.class, Class.class});
+            
+            return (MetaClass)customMetaClassConstructor.newInstance(new Object[]{this, theClass});
+        } catch (final ClassNotFoundException e) {
+            return new MetaClassImpl(this, theClass);
+        } catch (final Exception e) {
+            throw new GroovyRuntimeException("Could not instantiate custom Metaclass for class: " + theClass.getName() + ". Reason: " + e, e);
+        }
+    }
+
+    /**
+     * Singleton of MetaClassRegistry. Shall we use threadlocal to store the instance?
+     *
+     * @param includeExtension
+     */
+    public static MetaClassRegistry getInstance(int includeExtension) {
+        if (includeExtension != DONT_LOAD_DEFAULT) {
+            if (instanceInclude == null) {
+                instanceInclude = new MetaClassRegistry();
+            }
+            return instanceInclude;
+        }
+        else {
+            if (instanceExclude == null) {
+                instanceExclude = new MetaClassRegistry(DONT_LOAD_DEFAULT);
+            }
+            return instanceExclude;
+        }
+    }
+
+    public synchronized Reflector loadReflector(final Class theClass, List methods) {
+        final String name = getReflectorName(theClass);
+        ClassLoader loader = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                ClassLoader loader = theClass.getClassLoader();
+                if (loader == null) loader = this.getClass().getClassLoader();
+                return loader;
+            }
+        });
+        final ReflectorLoader rloader = getReflectorLoader(loader);
+        Class ref = rloader.getLoadedClass(name);
+        if (ref == null) {
+            /*
+             * Lets generate it && load it.
+             */                        
+            ReflectorGenerator generator = new ReflectorGenerator(methods);
+            ClassWriter cw = new ClassWriter(true);
+            generator.generate(cw, name);
+            final byte[] bytecode = cw.toByteArray();
+            ref = (Class) AccessController.doPrivileged(new PrivilegedAction() {
+                public Object run() {
+                    return rloader.defineClass(name, bytecode, getClass().getProtectionDomain());
+                }
+            }); 
+        }
+        try {
+            return (Reflector) ref.newInstance();
+        } catch (Exception e) {
+            throw new GroovyRuntimeException("Could not generate and load the reflector for class: " + name + ". Reason: " + e, e);
+        }
+    }
+    
+    private String getReflectorName(Class theClass) {
+        String className = theClass.getName();
+        String packagePrefix = "gjdk.";
+        String name = packagePrefix + className + "_GroovyReflector";
+        if (theClass.isArray()) {
+               Class clazz = theClass;
+               name = packagePrefix;
+               int level = 0;
+               while (clazz.isArray()) {
+                  clazz = clazz.getComponentType();
+                  level++;
+               }
+            String componentName = clazz.getName();
+            name = packagePrefix + componentName + "_GroovyReflectorArray";
+            if (level>1) name += level;
+        }
+        return name;
+    }
+
+    List getInstanceMethods() {
+        return instanceMethods;
+    }
+
+    List getStaticMethods() {
+        return staticMethods;
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/MetaExpandoProperty.java b/groovy-core/src/main/groovy/lang/MetaExpandoProperty.java
new file mode 100644
index 0000000..caa75e7
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/MetaExpandoProperty.java
@@ -0,0 +1,73 @@
+/*
+ * $Id$
+ *
+ * Copyright 2004 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+ 
+package groovy.lang;
+
+import java.util.Map.Entry;
+
+/**
+ * Represents a property in an Expando object
+ * 
+ * @author John Stump
+ * @version $Revision$
+ */
+public class MetaExpandoProperty extends MetaProperty {
+
+	Object value = null;
+	
+    public MetaExpandoProperty(Entry entry) {
+		super((String) entry.getKey(), Object.class);
+		
+		value = entry.getValue();
+    }
+
+    /**
+     * @return the property of the given object
+     * @throws Exception if the property could not be evaluated
+     */
+    public Object getProperty(Object object) {
+		return value;
+	}
+
+    /**
+     * Sets the property on the given object to the new value
+     * 
+     * @param object on which to set the property
+     * @param newValue the new value of the property
+     */
+    public void setProperty(Object object, Object newValue) {
+		value = newValue;
+	}
+}
diff --git a/groovy-core/src/main/groovy/lang/MetaFieldProperty.java b/groovy-core/src/main/groovy/lang/MetaFieldProperty.java
new file mode 100644
index 0000000..b0379c1
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/MetaFieldProperty.java
@@ -0,0 +1,116 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+ 
+package groovy.lang;
+
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * Represents a property on a bean which may have a getter and/or a setter
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MetaFieldProperty extends MetaProperty {
+
+    private Field field;
+
+    public MetaFieldProperty(Field field) {
+        super(field.getName(), field.getType());
+        this.field = field;
+    }
+
+    /**
+     * @return the property of the given object
+     * @throws Exception if the property could not be evaluated
+     */
+    public Object getProperty(final Object object) {
+        try {
+            Object value = (Object) AccessController.doPrivileged(new PrivilegedExceptionAction() {
+                public Object run() throws IllegalAccessException {   
+                    field.setAccessible(true);
+                    return field.get(object);
+                }
+            });
+            return value;
+        } catch (PrivilegedActionException pe) {
+            throw new GroovyRuntimeException("Cannot get the property '" + name + "'.", pe.getException());
+        }
+    }
+
+    /**
+     * Sets the property on the given object to the new value
+     * 
+     * @param object on which to set the property
+     * @param newValue the new value of the property
+     * @throws RuntimeException if the property could not be set
+     */
+    public void setProperty(final Object object, Object newValue) {
+        final Object goalValue = DefaultTypeTransformation.castToType(newValue, field.getType());
+        try {
+            AccessController.doPrivileged(new PrivilegedExceptionAction() {
+                public Object run() throws IllegalAccessException, GroovyRuntimeException {
+                    field.setAccessible(true);
+                    field.set(object, goalValue);
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException ex) {
+            throw new GroovyRuntimeException("Cannot set the property '" + name + "'.", ex.getException());
+        }
+    }
+
+    private String toName(Class c) {
+        String s = c.toString();
+        if (s.startsWith("class ") && s.length() > 6)
+            return s.substring(6);
+        else
+            return s;
+    }
+    
+    public int getModifiers() {
+        return field.getModifiers();
+    }
+    
+    public boolean isStatic() {
+        return Modifier.isStatic(field.getModifiers());
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/MetaMethod.java b/groovy-core/src/main/groovy/lang/MetaMethod.java
new file mode 100644
index 0000000..55dc418
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/MetaMethod.java
@@ -0,0 +1,258 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package groovy.lang;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.logging.Logger;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.InvokerInvocationException;
+import org.codehaus.groovy.runtime.MetaClassHelper;
+import org.codehaus.groovy.runtime.Reflector;
+
+/**
+ * Represents a Method on a Java object a little like {@link java.lang.reflect.Method}
+ * except without using reflection to invoke the method
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MetaMethod implements Cloneable {
+
+    private static final Logger log = Logger.getLogger(MetaMethod.class.getName());
+
+    private String name;
+    private Class callClass;
+    private Class declaringClass;
+    private Class interfaceClass;
+    private Class[] parameterTypes;
+    private Class returnType;
+    private int modifiers;
+    private Reflector reflector;
+    private int methodIndex;
+    private Method method;
+
+    public MetaMethod(String name, Class declaringClass, Class[] parameterTypes, Class returnType, int modifiers) {
+        this.name = name;
+        this.callClass = declaringClass;
+        this.declaringClass = declaringClass;
+        this.parameterTypes = parameterTypes;
+        this.returnType = returnType;
+        this.modifiers = modifiers;
+    }
+
+    public MetaMethod(Method method) {
+        this(
+            method.getName(),
+            method.getDeclaringClass(),
+            method.getParameterTypes(),
+            method.getReturnType(),
+            method.getModifiers());
+        this.method = method;
+    }
+
+    public MetaMethod(MetaMethod metaMethod) {
+        this(metaMethod.method);
+    }
+
+    /**
+     * Checks that the given parameters are valid to call this method
+     * 
+     * @param arguments
+     * @throws IllegalArgumentException if the parameters are not valid
+     */
+    public void checkParameters(Class[] arguments) {
+        // lets check that the argument types are valid
+        if (!MetaClassHelper.isValidMethod(getParameterTypes(), arguments, false)) {
+            throw new IllegalArgumentException(
+                    "Parameters to method: "
+                    + getName()
+                    + " do not match types: "
+                    + InvokerHelper.toString(getParameterTypes())
+                    + " for arguments: "
+                    + InvokerHelper.toString(arguments));
+        }
+    }
+    
+    public Object invoke(Object object, Object[] arguments) {
+        try {
+            if (reflector != null) {
+                return reflector.invoke(this, object, arguments);
+            } else {
+                AccessController.doPrivileged(new PrivilegedAction() {
+                    public Object run() {
+                        method.setAccessible(true);
+                        return null;
+                    }
+                });
+                return method.invoke(object, arguments);
+            }
+        } catch (Exception e) {
+            throw new InvokerInvocationException(e);
+        }
+    }
+
+    public Class getCallClass() {
+        return callClass;
+    }
+    
+    public void setCallClass(Class c) {
+        callClass=c;
+    }
+
+    public int getMethodIndex() {
+        return methodIndex;
+    }
+
+    public void setMethodIndex(int methodIndex) {
+        this.methodIndex = methodIndex;
+    }
+
+    public int getModifiers() {
+        return modifiers;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Class[] getParameterTypes() {
+        return parameterTypes;
+    }
+
+    public Class getReturnType() {
+        return returnType;
+    }
+
+    public Reflector getReflector() {
+        return reflector;
+    }
+
+    public void setReflector(Reflector reflector) {
+        this.reflector = reflector;
+    }
+
+    public boolean isMethod(Method method) {
+        return name.equals(method.getName())
+            && modifiers == method.getModifiers()
+            && returnType.equals(method.getReturnType())
+            && equal(parameterTypes, method.getParameterTypes());
+    }
+
+    protected boolean equal(Class[] a, Class[] b) {
+        if (a.length == b.length) {
+            for (int i = 0, size = a.length; i < size; i++) {
+                if (!a[i].equals(b[i])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public String toString() {
+        return super.toString()
+            + "[name: "
+            + name
+            + " params: "
+            + InvokerHelper.toString(parameterTypes)
+            + " returns: "
+            + returnType
+            + " owner: "
+            + callClass
+            + "]";
+    }
+
+    public Object clone() {
+        try {
+            return super.clone();
+        }
+        catch (CloneNotSupportedException e) {
+            throw new GroovyRuntimeException("This should never happen", e);
+        }
+    }
+
+    public boolean isStatic() {
+        return (modifiers & Modifier.STATIC) != 0;
+    }
+
+    public boolean isPrivate() {
+        return (modifiers & Modifier.PRIVATE) != 0;
+    }
+
+    public boolean isProtected() {
+        return (modifiers & Modifier.PROTECTED) != 0;
+    }
+
+    public boolean isPublic() {
+        return (modifiers & Modifier.PUBLIC) != 0;
+    }
+
+    /**
+     * @return true if the given method has the same name, parameters, return type
+     * and modifiers but may be defined on another type
+     */
+    public boolean isSame(MetaMethod method) {
+        return name.equals(method.getName())
+            && compatibleModifiers(modifiers, method.getModifiers())
+            && returnType.equals(method.getReturnType())
+            && equal(parameterTypes, method.getParameterTypes());
+    }
+
+    protected boolean compatibleModifiers(int modifiersA, int modifiersB) {
+        int mask = Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC | Modifier.STATIC;
+        return (modifiersA & mask) == (modifiersB & mask);
+    }
+
+    public Class getInterfaceClass() {
+        return interfaceClass;
+    }
+
+    public void setInterfaceClass(Class interfaceClass) {
+        this.interfaceClass = interfaceClass;
+    }
+
+    public boolean isCacheable() {
+        return true;
+    }
+    
+    public Class getDeclaringClass() {
+        return declaringClass;
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/MetaProperty.java b/groovy-core/src/main/groovy/lang/MetaProperty.java
new file mode 100644
index 0000000..7865ed4
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/MetaProperty.java
@@ -0,0 +1,85 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package groovy.lang;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * Represents a property on a bean which may have a getter and/or a setter
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public abstract class MetaProperty {
+
+    protected String name;
+    protected Class type;
+
+    public MetaProperty(String name, Class type) {
+        this.name = name;
+        this.type = type;
+    }
+
+    /**
+     * @return the property of the given object
+     * @throws Exception if the property could not be evaluated
+     */
+    public abstract Object getProperty(Object object);
+
+    /**
+     * Sets the property on the given object to the new value
+     * 
+     * @param object on which to set the property
+     * @param newValue the new value of the property
+     * @throws RuntimeException if the property could not be set
+     */
+    public abstract void setProperty(Object object, Object newValue);
+
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @return the type of the property
+     */
+    public Class getType() {
+        return type;
+    }
+    
+    public int getModifiers() {
+        return Modifier.PUBLIC;
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/lang/MissingClassException.java b/groovy-core/src/main/groovy/lang/MissingClassException.java
new file mode 100644
index 0000000..e3410da
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/MissingClassException.java
@@ -0,0 +1,81 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassNode;
+
+/**
+ * An exception occurred if a dynamic method dispatch fails with an unknown class.
+ * 
+ * Note that the Missing*Exception classes were named for consistency and
+ * to avoid conflicts with JDK exceptions of the same name.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MissingClassException extends GroovyRuntimeException {
+
+    private String type;
+
+    public MissingClassException(String type, ASTNode node, String message) {
+        super("No such class: " + type + " " + message, node);
+        this.type = type;
+    }
+    
+    public MissingClassException(ClassNode type, String message){
+        super("No such class: " + type.getName() + " " + message);
+        this.type = type.getName();
+    }
+
+    /**
+     * 
+     * @return The type that could not be resolved
+     */
+    public String getType() {
+        return type;
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/MissingFieldException.java b/groovy-core/src/main/groovy/lang/MissingFieldException.java
new file mode 100644
index 0000000..e74dd15
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/MissingFieldException.java
@@ -0,0 +1,95 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+
+/**
+ * An exception occurred if a dynamic field dispatch fails with an unknown field.
+ * 
+ * Note that the Missing*Exception classes were named for consistency and
+ * to avoid conflicts with JDK exceptions of the same name.
+ * 
+ * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
+ * @version $Revision$
+ */
+public class MissingFieldException extends GroovyRuntimeException {
+
+    private String field;
+    private Class type;
+
+    public MissingFieldException(String field, Class type) {
+        super("No such field: " + field + " for class: " + type.getName());
+        this.field = field;
+        this.type = type;
+    }
+
+    public MissingFieldException(String field, Class type, Throwable e) {
+        super("No such field: " + field + " for class: " + type.getName() + ". Reason: " + e, e);
+        this.field = field;
+        this.type = type;
+    }
+
+    public MissingFieldException(String message, String field, Class type) {
+        super(message);
+        this.field = field;
+        this.type = type;
+    }
+
+    /**
+     * @return the name of the field that could not be found
+     */
+    public String getField() {
+        return field;
+    }
+
+    /**
+     * 
+     * @return The type on which the field was attempted to be called
+     */
+    public Class getType() {
+        return type;
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/MissingMethodException.java b/groovy-core/src/main/groovy/lang/MissingMethodException.java
new file mode 100644
index 0000000..190bd43
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/MissingMethodException.java
@@ -0,0 +1,106 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * An exception occurred if a dynamic method dispatch fails with an unknown method.
+ * 
+ * Note that the Missing*Exception classes were named for consistency and
+ * to avoid conflicts with JDK exceptions of the same name.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MissingMethodException extends GroovyRuntimeException {
+
+    private String method;
+    private Class type;
+    private boolean isStatic;
+
+    public MissingMethodException(String method, Class type, Object[] arguments) {
+        this(method,type,arguments,false);
+    }
+    
+    public MissingMethodException(String method, Class type, Object[] arguments, boolean isStatic) {
+	    super(
+	        "No signature of method: "
+	    		+ (isStatic ? "static " : "")
+	    		+ type.getName()
+				+ "."
+	            + method
+				+ "() is applicable for argument types: ("
+				+ InvokerHelper.toTypeString(arguments)
+	            + ") values: "
+				+ InvokerHelper.toString(arguments));
+	    this.method = method;
+	    this.type = type;
+        this.isStatic = isStatic;
+	}
+    
+    /**
+     * @return the name of the method that could not be found
+     */
+    public String getMethod() {
+        return method;
+    }
+
+    /**
+     * @return The type on which the method was attempted to be called
+     */
+    public Class getType() {
+        return type;
+    }
+    
+    /**
+     * @return Whether the method was called in a static way, 
+     * i.e. on a class rather than an object.
+     */
+    public boolean isStatic() {
+        return isStatic;
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/MissingPropertyException.java b/groovy-core/src/main/groovy/lang/MissingPropertyException.java
new file mode 100644
index 0000000..2c4bac8
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/MissingPropertyException.java
@@ -0,0 +1,95 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+
+/**
+ * An exception occurred if a dynamic property dispatch fails with an unknown property.
+ * 
+ * Note that the Missing*Exception classes were named for consistency and
+ * to avoid conflicts with JDK exceptions of the same name.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MissingPropertyException extends GroovyRuntimeException {
+
+    private String property;
+    private Class type;
+
+    public MissingPropertyException(String property, Class type) {
+        super("No such property: " + property + " for class: " + type.getName());
+        this.property = property;
+        this.type = type;
+    }
+
+    public MissingPropertyException(String property, Class type, Throwable e) {
+        super("No such property: " + property + " for class: " + type.getName() + ". Reason: " + e, e);
+        this.property = property;
+        this.type = type;
+    }
+
+    public MissingPropertyException(String message, String property, Class type) {
+        super(message);
+        this.property = property;
+        this.type = type;
+    }
+
+    /**
+     * @return the name of the property that could not be found
+     */
+    public String getProperty() {
+        return property;
+    }
+
+    /**
+     * 
+     * @return The type on which the property was attempted to be called
+     */
+    public Class getType() {
+        return type;
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/NonEmptySequence.java b/groovy-core/src/main/groovy/lang/NonEmptySequence.java
new file mode 100644
index 0000000..f6b6b78
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/NonEmptySequence.java
@@ -0,0 +1,75 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import java.util.List;
+
+/**
+ * Represents a sequence of objects which represents one or many instances of
+ * of objects of a given type. The type can be ommitted in which case any type of
+ * object can be added.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class NonEmptySequence extends Sequence {
+
+    public NonEmptySequence() {
+        super(null);
+    }
+
+    public NonEmptySequence(Class type) {
+        super(type);
+    }
+
+    public NonEmptySequence(Class type, List content) {
+        super(type, content);
+    }
+
+    public int minimumSize() {
+        return 1;
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/lang/ObjectRange.java b/groovy-core/src/main/groovy/lang/ObjectRange.java
new file mode 100644
index 0000000..e8abbec
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/ObjectRange.java
@@ -0,0 +1,343 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+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.util.AbstractList;
+import java.util.Iterator;
+import java.util.List;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/**
+ * Represents an inclusive list of objects from a value to a value using
+ * comparators
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ObjectRange extends AbstractList implements Range {
+
+    private Comparable from;
+    private Comparable to;
+    private int size;
+    private final boolean reverse;
+
+    public ObjectRange(Comparable from, Comparable to) {
+        this.size = -1;
+        this.reverse = ScriptBytecodeAdapter.compareGreaterThan(from, to);
+        if (this.reverse) {
+            constructorHelper(to, from);
+        } else {
+            constructorHelper(from, to);
+        }
+    }
+
+    public ObjectRange(Comparable from, Comparable to, boolean reverse) {
+        this.size = -1;
+        constructorHelper(from, to);
+
+        this.reverse = reverse;
+    }
+
+    private void constructorHelper(Comparable from, Comparable to) {
+        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");
+        }
+        if (from.getClass() == to.getClass()) {
+            this.from = from;
+            this.to = to;
+        } else {
+            this.from = normaliseType(from);
+            this.to = normaliseType(to);
+        }
+        if (from instanceof String || to instanceof String) {
+            // this test depends deeply on the String.next implementation
+            // 009.next is 00:, not 010 
+            String start = from.toString();
+            String end = to.toString();
+            if (start.length() > end.length()) {
+                throw new IllegalArgumentException("Incompatible Strings for Range: starting String is longer than ending string");
+            }
+            int length = Math.min(start.length(), end.length());
+            int i = 0;
+            for (i = 0; i < length; i++) {
+                if (start.charAt(i) != end.charAt(i)) break;
+            }
+            if (i < length - 1) {
+                throw new IllegalArgumentException("Incompatible Strings for Range: String#next() will not reach the expected value");
+            }
+
+        }
+    }
+
+    public int hashCode() {
+        /** @todo should code this the Josh Bloch way */
+        return from.hashCode() ^ to.hashCode() + (reverse ? 1 : 0);
+    }
+
+    public boolean equals(Object that) {
+        if (that instanceof ObjectRange) {
+            return equals((ObjectRange) that);
+        } else if (that instanceof List) {
+            return equals((List) that);
+        }
+        return false;
+    }
+
+    public boolean equals(ObjectRange that) {
+        return this.reverse == that.reverse
+                && DefaultTypeTransformation.compareEqual(this.from, that.from)
+                && DefaultTypeTransformation.compareEqual(this.to, that.to);
+    }
+
+    public boolean equals(List that) {
+        int size = size();
+        if (that.size() == size) {
+            for (int i = 0; i < size; i++) {
+                if (!DefaultTypeTransformation.compareEqual(get(i), that.get(i))) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public Comparable getFrom() {
+        return from;
+    }
+
+    public Comparable getTo() {
+        return to;
+    }
+
+    public boolean isReverse() {
+        return reverse;
+    }
+
+    public Object get(int index) {
+        if (index < 0) {
+            throw new IndexOutOfBoundsException("Index: " + index + " should not be negative");
+        }
+        if (index >= size()) {
+            throw new IndexOutOfBoundsException("Index: " + index + " is too big for range: " + this);
+        }
+        Object value = null;
+        if (reverse) {
+            value = to;
+
+            for (int i = 0; i < index; i++) {
+                value = decrement(value);
+            }
+        } else {
+            value = from;
+            for (int i = 0; i < index; i++) {
+                value = increment(value);
+            }
+        }
+        return value;
+    }
+
+    public Iterator iterator() {
+        return new Iterator() {
+            int index = 0;
+            Object value = (reverse) ? to : from;
+
+            public boolean hasNext() {
+                return index < size();
+            }
+
+            public Object next() {
+                if (index++ > 0) {
+                    if (index > size()) {
+                        value = null;
+                    } else {
+                        if (reverse) {
+                            value = decrement(value);
+                        } else {
+                            value = increment(value);
+                        }
+                    }
+                }
+                return value;
+            }
+
+            public void remove() {
+                ObjectRange.this.remove(index);
+            }
+        };
+    }
+
+    public int size() {
+        if (size == -1) {
+            if (from instanceof Integer && to instanceof Integer) {
+                // lets fast calculate the size
+                size = 0;
+                int fromNum = ((Integer) from).intValue();
+                int toNum = ((Integer) to).intValue();
+                size = toNum - fromNum + 1;
+            } else if (from instanceof BigDecimal || to instanceof BigDecimal) {
+                // lets fast calculate the size
+                size = 0;
+                BigDecimal fromNum = new BigDecimal("" + from);
+                BigDecimal toNum = new BigDecimal("" + to);
+                BigInteger sizeNum = toNum.subtract(fromNum).add(new BigDecimal(1.0)).toBigInteger();
+                size = sizeNum.intValue();
+            } else {
+                // lets lazily calculate the size
+                size = 0;
+                Object value = from;
+                while (to.compareTo(value) >= 0) {
+                    value = increment(value);
+                    size++;
+                }
+            }
+        }
+        return size;
+    }
+
+    public List subList(int fromIndex, int toIndex) {
+        if (fromIndex < 0) {
+            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+        }
+        int size = size();
+        if (toIndex > size) {
+            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
+        }
+        if (fromIndex > toIndex) {
+            throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
+        }
+        if (--toIndex >= size) {
+            return new ObjectRange((Comparable) get(fromIndex), getTo(), reverse);
+        } else {
+            return new ObjectRange((Comparable) get(fromIndex), (Comparable) get(toIndex), reverse);
+        }
+    }
+
+    public String toString() {
+        return (reverse) ? "" + to + ".." + from : "" + from + ".." + to;
+    }
+
+    public String inspect() {
+        String toText = InvokerHelper.inspect(to);
+        String fromText = InvokerHelper.inspect(from);
+        return (reverse) ? "" + toText + ".." + fromText : "" + fromText + ".." + toText;
+    }
+
+    public boolean contains(Object value) {
+        if (value instanceof Comparable) {
+            return contains((Comparable) value);
+        } else {
+            return super.contains(value);
+        }
+    }
+
+    public boolean contains(Comparable value) {
+        int result = from.compareTo(value);
+        return result == 0 || result < 0 && to.compareTo(value) >= 0;
+    }
+
+    public void step(int step, Closure closure) {
+        if (reverse) {
+            step = -step;
+        }
+        if (step >= 0) {
+            Comparable value = from;
+            while (value.compareTo(to) <= 0) {
+                closure.call(value);
+                for (int i = 0; i < step; i++) {
+                    value = (Comparable) increment(value);
+                }
+            }
+        } else {
+            step = -step;
+            Comparable value = to;
+            while (value.compareTo(from) >= 0) {
+                closure.call(value);
+                for (int i = 0; i < step; i++) {
+                    value = (Comparable) decrement(value);
+                }
+            }
+        }
+    }
+
+    public List step(int step) {
+        IteratorClosureAdapter adapter = new IteratorClosureAdapter(this);
+        step(step, adapter);
+        return adapter.asList();
+    }
+
+    protected Object increment(Object value) {
+        return InvokerHelper.invokeMethod(value, "next", null);
+    }
+
+    protected Object decrement(Object value) {
+        return InvokerHelper.invokeMethod(value, "previous", null);
+    }
+
+    private static Comparable normaliseType(final Comparable operand) {
+        if (operand instanceof Character) {
+            return new Integer(((Character) operand).charValue());
+        } else if (operand instanceof String) {
+            final String string = (String) operand;
+
+            if (string.length() == 1)
+                return new Integer(string.charAt(0));
+            else
+                return string;
+        } else {
+            return operand;
+        }
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/ParameterArray.java b/groovy-core/src/main/groovy/lang/ParameterArray.java
new file mode 100644
index 0000000..c1da116
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/ParameterArray.java
@@ -0,0 +1,78 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+/**
+ * Distinguish a parameter array from Object[].
+ *
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+public class ParameterArray {
+
+    private Object parameters;
+
+    public ParameterArray(Object data) {
+        parameters = packArray(data);
+    }
+
+    private 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();
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/PropertyValue.java b/groovy-core/src/main/groovy/lang/PropertyValue.java
new file mode 100644
index 0000000..c9d25fe
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/PropertyValue.java
@@ -0,0 +1,77 @@
+/*
+ $Id$
+
+ Copyright 2004 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+ 
+package groovy.lang;
+
+public class PropertyValue {
+	// the owner of the property
+	private Object bean;
+	
+	// the description of the property
+	private 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);
+	}
+}
+
diff --git a/groovy-core/src/main/groovy/lang/ProxyMetaClass.java b/groovy-core/src/main/groovy/lang/ProxyMetaClass.java
new file mode 100644
index 0000000..2ce73ef
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/ProxyMetaClass.java
@@ -0,0 +1,142 @@
+package groovy.lang;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.beans.IntrospectionException;
+
+/**
+ * As subclass of MetaClass, ProxyMetaClass manages calls from Groovy Objects to POJOs.
+ * It enriches MetaClass with the feature of making method invokations 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.
+ * @author Dierk Koenig
+ */
+public class ProxyMetaClass extends MetaClassImpl {
+
+    protected MetaClass adaptee = null;
+    protected Interceptor interceptor = null;
+
+    /**
+     * convenience factory method for the most usual case.
+     */
+    public static ProxyMetaClass getInstance(Class theClass) throws IntrospectionException {
+        MetaClassRegistry metaRegistry = InvokerHelper.getInstance().getMetaRegistry();
+        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) throws IntrospectionException {
+        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 void use(Closure closure){
+        registry.setMetaClass(theClass, this);
+        
+        try {
+            closure.call();
+        } finally {
+            registry.setMetaClass(theClass, adaptee);
+        }
+    }
+
+     /**
+     * Use the ProxyMetaClass for the given Closure.
+     * Cares for balanced setting/unsetting ProxyMetaClass.
+     * @param closure piece of code to be executed with ProxyMetaClass
+     */
+    public void use(GroovyObject object, Closure closure){
+        object.setMetaClass(this);
+        
+        try {
+            closure.call();
+        } finally {
+            object.setMetaClass(adaptee);
+        }
+    }
+
+    /**
+     * @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 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);
+            }
+        });
+    }
+
+    // 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;
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/Range.java b/groovy-core/src/main/groovy/lang/Range.java
new file mode 100644
index 0000000..86e414d
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/Range.java
@@ -0,0 +1,81 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import java.util.List;
+
+/**
+ * Represents the interface of a Range implementation which includes the
+ * from and to values
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public interface Range extends List {
+
+    
+    /**
+     * @return the lower value in the range
+     */
+    public Comparable getFrom();
+
+    /**
+     * @return the upper value in the range
+     */
+    public Comparable getTo();
+
+    /**
+     * @return true if this is a reverse range, iterating backwards
+     * starting from the to value and ending on the from value
+     */
+    public boolean isReverse();
+
+    /**
+     * @return the verbose String representation of this Range as would be typed into a console
+     * to create the Range instance
+     */
+    public String inspect();
+}
diff --git a/groovy-core/src/main/groovy/lang/ReadOnlyPropertyException.java b/groovy-core/src/main/groovy/lang/ReadOnlyPropertyException.java
new file mode 100644
index 0000000..48b5acf
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/ReadOnlyPropertyException.java
@@ -0,0 +1,60 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+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>
+ * @version $Revision$
+ */
+public class ReadOnlyPropertyException extends MissingPropertyException {
+
+    public ReadOnlyPropertyException(String property, Class type) {
+        super("Cannot set readonly property: " + property + " for class: " + type.getName(), property, type);
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/Reference.java b/groovy-core/src/main/groovy/lang/Reference.java
new file mode 100644
index 0000000..499b5d4
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/Reference.java
@@ -0,0 +1,107 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * Represents a reference to a value
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class Reference extends GroovyObjectSupport {
+
+    private Object value;
+
+    public Reference() {
+    }
+
+    public Reference(Object 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 Object get() {
+        return value;
+    }
+
+    public void set(Object value) {
+        this.value = value;
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/Script.java b/groovy-core/src/main/groovy/lang/Script.java
new file mode 100644
index 0000000..795e551
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/Script.java
@@ -0,0 +1,218 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+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
+ * @version $Revision$
+ */
+public abstract class Script extends GroovyObjectSupport {
+    private Binding binding = new Binding();
+
+    protected Script() {
+    }
+
+    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
+            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 = binding.getVariable(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});
+    }
+
+    /**
+     * 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, IOException {
+        GroovyShell shell = new GroovyShell(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(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(binding);
+        shell.run(file, arguments);
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/Sequence.java b/groovy-core/src/main/groovy/lang/Sequence.java
new file mode 100644
index 0000000..f8ba8e0
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/Sequence.java
@@ -0,0 +1,252 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+/**
+ * Represents a sequence of objects which represents zero or many instances of
+ * of objects of a given type. The type can be ommitted in which case any type of
+ * object can be added.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class Sequence extends ArrayList implements GroovyObject {
+
+    private MetaClass metaClass = InvokerHelper.getMetaClass(this);
+    private 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);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/lang/SpreadListEvaluatingException.java b/groovy-core/src/main/groovy/lang/SpreadListEvaluatingException.java
new file mode 100644
index 0000000..ff8686d
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/SpreadListEvaluatingException.java
@@ -0,0 +1,52 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+public class SpreadListEvaluatingException extends GroovyRuntimeException {
+    public SpreadListEvaluatingException(String message) {
+        super(message);
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/SpreadMap.java b/groovy-core/src/main/groovy/lang/SpreadMap.java
new file mode 100644
index 0000000..b546e45
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/SpreadMap.java
@@ -0,0 +1,157 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Iterator;
+
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+/**
+ * Represents a spreadable map which extends java.util.HashMap.
+ * 
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+public class SpreadMap extends HashMap {
+
+    private Map mapData;
+    private int hashCode;
+
+    public SpreadMap(Object[] values) {
+        mapData = new HashMap(values.length / 2);
+        int i = 0;
+        while (i < values.length) {
+           mapData.put(values[i++], values[i++]);
+        }
+    }
+
+    public SpreadMap(Map map) {
+        this.mapData = map;
+    }
+
+    public Object get(Object obj) {
+        return mapData.get(obj);
+    }
+
+    public Object put(Object key, Object value) {
+        throw new RuntimeException("SpreadMap: " + this + " is an immutable map, and so ("
+                                   + key + ": " + value + ") cannot be added.");
+    }
+
+    public Object remove(Object key) {
+        throw new RuntimeException("SpreadMap: " + this + " is an immutable map, and so the key ("
+                                   + key + ") cannot be deleteded.");
+    }
+
+    public void putAll(Map t) {
+        throw new RuntimeException("SpreadMap: " + this + " is an immutable map, and so the map ("
+                                   + t + ") cannot be put in this spreadMap.");
+    }
+
+    public int size() {
+        return mapData.keySet().size();
+    }
+
+    public boolean equals(Object that) {
+        if (that instanceof SpreadMap) {
+            return equals((SpreadMap) that);
+        }
+        return false;
+    }
+
+    public boolean equals(SpreadMap that) {
+        if (that == null) return false;        
+
+        if (size() == that.size()) {
+            SpreadMap other = (SpreadMap) that;
+            Iterator iter = mapData.keySet().iterator();
+            for (; iter.hasNext(); ) {
+                Object key = iter.next();
+                if (! DefaultTypeTransformation.compareEqual(get(key), other.get(key)) ) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+
+    public int hashCode() {
+        if (hashCode == 0) {
+            Iterator iter = mapData.keySet().iterator();
+            for (; iter.hasNext(); ) {
+                Object key = iter.next();
+                int hash = (key != null) ? key.hashCode() : 0xbabe;
+                hashCode ^= hash;
+            }
+        }
+        return hashCode;
+    }
+
+    /**
+     * Returns the string expression of <code>this</code>.
+     *
+     * @return the string expression of <code>this</code>
+     */
+    public String toString() {
+        if (mapData.isEmpty()) {
+            return "*:[:]";
+        }
+        StringBuffer buff = new StringBuffer("*:[");
+        Iterator iter = mapData.keySet().iterator();
+        for (; iter.hasNext(); ) {
+            Object key = iter.next();
+            buff.append(key + ":" + mapData.get(key));
+            if (iter.hasNext())
+                buff.append(", ");
+        }
+        buff.append("]");
+        return buff.toString();
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/SpreadMapEvaluatingException.java b/groovy-core/src/main/groovy/lang/SpreadMapEvaluatingException.java
new file mode 100644
index 0000000..9effaaa
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/SpreadMapEvaluatingException.java
@@ -0,0 +1,52 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+public class SpreadMapEvaluatingException extends GroovyRuntimeException {
+    public SpreadMapEvaluatingException(String message) {
+        super(message);
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/StringWriterIOException.java b/groovy-core/src/main/groovy/lang/StringWriterIOException.java
new file mode 100644
index 0000000..222336d
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/StringWriterIOException.java
@@ -0,0 +1,65 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import java.io.IOException;
+
+/**
+ * An IO exception occurred trying to append to a StringWriter which should never happen.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class StringWriterIOException extends RuntimeException {
+
+    public StringWriterIOException(IOException e) {
+        super(e);
+    }
+
+    public IOException getIOException() {
+        return (IOException) getCause();
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/TracingInterceptor.java b/groovy-core/src/main/groovy/lang/TracingInterceptor.java
new file mode 100644
index 0000000..30ab9bd
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/TracingInterceptor.java
@@ -0,0 +1,69 @@
+package groovy.lang;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+public class TracingInterceptor implements Interceptor {
+
+    protected Writer writer = new PrintWriter(System.out);
+    private int indent = 0;
+
+    public Writer getWriter() {
+        return writer;
+    }
+
+    public void setWriter(Writer writer) {
+        this.writer = writer;
+    }
+
+    public Object beforeInvoke(Object object, String methodName, Object[] arguments) {
+        write(object, methodName, arguments, "before");
+        indent++ ;
+        return null;
+    }
+
+    public Object afterInvoke(Object object, String methodName, Object[] arguments, Object result) {
+        indent--;
+        write(object, methodName, arguments, "after ");
+        return result;
+    }
+
+    public boolean doInvoke() {
+        return true;
+    }
+    private String indent(){
+        StringBuffer result = new StringBuffer();
+        for (int i=0; i<indent;i++){
+            result.append("  ");
+        }
+        return result.toString();
+    }
+
+    protected void write(Object object, String methodName, Object[] arguments, final String origin) {
+        try {
+            writer.write(indent());
+            writer.write(origin);
+            writer.write(" ");
+            Class theClass = object instanceof Class ? (Class) object: object.getClass();
+            writeInfo(theClass, methodName, arguments);
+            writer.write("\n");
+            writer.flush();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    protected void writeInfo(final Class aClass, String methodName, Object[] arguments) throws IOException {
+        writer.write(aClass.getName());
+        writer.write(".");
+        writer.write(methodName);
+        writer.write("(");
+        for (int i = 0; i < arguments.length; i++) {
+            if (i > 0) writer.write(", ");
+            Object argument = arguments[i];
+            writer.write(argument.getClass().getName());
+        }
+        writer.write(")");
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/Tuple.java b/groovy-core/src/main/groovy/lang/Tuple.java
new file mode 100644
index 0000000..2605f58
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/Tuple.java
@@ -0,0 +1,117 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import java.util.AbstractList;
+import java.util.List;
+
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+/**
+ * Represents a list of Integer objects from a specified int up to but not including
+ * a given and to.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class Tuple extends AbstractList {
+
+    private Object[] contents;
+    private int hashCode;
+
+    public Tuple(Object[] contents) {
+        this.contents = contents;
+    }
+
+    public Object get(int index) {
+        return contents[index];
+    }
+
+    public int size() {
+        return contents.length;
+    }
+
+    public boolean equals(Object that) {
+        if (that instanceof Tuple) {
+            return equals((Tuple) that);
+        }
+        return false;
+    }
+
+    public boolean equals(Tuple that) {
+        if (contents.length == that.contents.length) {
+            for (int i = 0; i < contents.length; i++) {
+                if (! DefaultTypeTransformation.compareEqual(this.contents[i], that.contents[i])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+
+    public int hashCode() {
+        if (hashCode == 0) {
+            for (int i = 0; i < contents.length; i++ ) {
+                Object value = contents[i];
+                int hash = (value != null) ? value.hashCode() : 0xbabe;
+                hashCode ^= hash;
+            }
+            if (hashCode == 0) {
+                hashCode = 0xbabe;
+            }
+        }
+        return hashCode;
+    }
+
+    public List subList(int fromIndex, int toIndex) {
+        int size = toIndex - fromIndex;
+        Object[] newContent = new Object[size];
+        System.arraycopy(contents, fromIndex, newContent, 0, size);
+        return new Tuple(newContent);
+    }
+}
diff --git a/groovy-core/src/main/groovy/lang/Writable.java b/groovy-core/src/main/groovy/lang/Writable.java
new file mode 100644
index 0000000..f75f574
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/Writable.java
@@ -0,0 +1,67 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import java.io.IOException;
+import java.io.Writer;
+
+
+/**
+ * Represents an object which is capable of writing itself to a text stream
+ * in a more efficient format than just creating a toString() representation
+ * of itself. This mechanism is particularly useful for templates and such like.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public interface Writable {
+
+    /**
+     * writes this object to the given stream
+     */
+    public Writer writeTo(Writer out) throws IOException;
+        
+}
diff --git a/groovy-core/src/main/groovy/lang/package.html b/groovy-core/src/main/groovy/lang/package.html
new file mode 100644
index 0000000..688fc33
--- /dev/null
+++ b/groovy-core/src/main/groovy/lang/package.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>package groovy.lang.*</title>
+  </head>
+  <body>
+    <p>Core Groovy language classes for implementing data structures, closures, metadata and so forth.</p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/groovy/mock/ClosureConstraintMatcher.java b/groovy-core/src/main/groovy/mock/ClosureConstraintMatcher.java
new file mode 100644
index 0000000..1185f33
--- /dev/null
+++ b/groovy-core/src/main/groovy/mock/ClosureConstraintMatcher.java
@@ -0,0 +1,35 @@
+package groovy.mock;
+
+import groovy.lang.Closure;
+import com.mockobjects.constraint.Constraint;
+
+/**
+ * 
+ * @author Joe Walnes
+ * @author Chris Stevenson
+ * @version $Revision$
+ */
+public class ClosureConstraintMatcher implements Constraint {
+    private Closure closure;
+    private String message = "closure";
+
+    public ClosureConstraintMatcher(Closure closure) {
+        this.closure = closure;
+    }
+
+    public boolean eval(Object object) {
+        try {
+            closure.call((Object[])object);
+            return true;
+        }
+        catch (AssertionError e) {
+            message = e.getMessage();
+            return false;
+        }
+    }
+
+    public String toString() {
+        return message;
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/mock/GroovyMock.java b/groovy-core/src/main/groovy/mock/GroovyMock.java
new file mode 100644
index 0000000..b3cec43
--- /dev/null
+++ b/groovy-core/src/main/groovy/mock/GroovyMock.java
@@ -0,0 +1,80 @@
+package groovy.mock;
+
+import groovy.lang.GroovyObject;
+import groovy.lang.Closure;
+import groovy.lang.GroovyObjectSupport;
+
+import com.mockobjects.Verifiable;
+import com.mockobjects.dynamic.*;
+
+/**
+ * 
+ * @author Joe Walnes
+ * @author Chris Stevenson
+ * @version $Revision$
+ */
+public class GroovyMock extends GroovyObjectSupport implements Verifiable {
+
+    private CallBag calls = new CallBag();
+    private CallFactory callFactory = new DefaultCallFactory();
+    private Mock mock = new Mock(I.class);
+
+    interface I {
+    }
+
+    private GroovyObject instance = new GroovyObjectSupport() {
+        public Object invokeMethod(String name, Object args) {
+            return callMethod(name, args);
+        }
+    };
+
+    public Object invokeMethod(String name, Object args) {
+        if (name.equals("verify")) {
+            verify();
+        }
+        else {
+            expectMethod(name, args);
+        }
+        return null;
+    }
+
+    public GroovyObject getInstance() {
+        return instance;
+    }
+
+    public static GroovyMock newInstance() {
+        return new GroovyMock();
+    }
+
+    private void expectMethod(String name, Object args) {
+        ConstraintMatcher constraintMatcher = createMatcher(args);
+        calls.addExpect(
+            callFactory.createCallExpectation(
+                callFactory.createCallSignature(name, constraintMatcher, callFactory.createVoidStub())));
+    }
+
+    private ConstraintMatcher createMatcher(Object args) {
+        if(args.getClass().isArray()) {
+            Object argArray[] = (Object[]) args;
+            if (argArray[0] instanceof Closure) {
+                Closure closure = (Closure) argArray[0];
+                return C.args(new ClosureConstraintMatcher(closure));
+            }
+        }
+        return C.args(C.eq(args));
+    }
+
+    private Object callMethod(String name, Object args) {
+        try {
+            return calls.call(mock, name, new Object[] { args });
+        }
+        catch (Throwable throwable) {
+            throw new RuntimeException(throwable);
+        }
+    }
+
+    public void verify() {
+        calls.verify();
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/mock/interceptor/Demand.groovy b/groovy-core/src/main/groovy/mock/interceptor/Demand.groovy
new file mode 100644
index 0000000..d786797
--- /dev/null
+++ b/groovy-core/src/main/groovy/mock/interceptor/Demand.groovy
@@ -0,0 +1,29 @@
+package groovy.mock.interceptor
+
+/**
+    The object that registers method calls on it for the use with Mocks and Stubs.
+    For each call a CallSpec object is added to the recorded list.
+    @author Dierk Koenig
+*/
+
+class Demand {
+
+    def List recorded = []
+
+    Object invokeMethod(String methodName, Object args) {
+        def range = 1..1
+        if (args[0] instanceof IntRange) {
+            range = args[0]
+            if (range.reverse) throw new IllegalArgumentException('Reverse ranges not supported.')
+        }
+        if (args[-1] instanceof Closure) {
+            recorded << new CallSpec(name:methodName, behavior:args[-1], range:range)
+        }
+    }
+}
+
+class CallSpec {
+    String  name
+    Closure behavior
+    Range   range
+}
diff --git a/groovy-core/src/main/groovy/mock/interceptor/LooseExpectation.groovy b/groovy-core/src/main/groovy/mock/interceptor/LooseExpectation.groovy
new file mode 100644
index 0000000..9c5391e
--- /dev/null
+++ b/groovy-core/src/main/groovy/mock/interceptor/LooseExpectation.groovy
@@ -0,0 +1,60 @@
+package groovy.mock.interceptor
+
+import junit.framework.AssertionFailedError
+
+/**
+    Expects demanded call cardinalities to match demanded ranges.
+    The calls are allowed to be out of the recorded sequence.
+    If a method is demanded multiple times, the ranges are filled by order of recording.
+    @See StrictExpectation
+    @author Dierk Koenig
+*/
+
+class LooseExpectation {
+    Demand fDemand  = null
+    List fCalls      = []
+
+    LooseExpectation(Demand demand) {
+        fDemand = demand
+    }
+
+    /**
+        Match the requested method name against eligible demands.
+        Fail early if no match possible.
+        Return the demand's behavior closure on match.
+    */
+    Closure match(String name) {
+        def callIndex = 0
+        // find first eligible callSpec
+        while (! isEligible(name, callIndex) ) callIndex++
+
+        // register the call
+        fCalls[callIndex] += 1
+
+        return fDemand.recorded[callIndex].behavior
+    }
+
+    boolean isEligible(String name, int i) {
+        def calls = fDemand.recorded
+        if (i >= calls.size())  {
+            throw new AssertionFailedError("No more calls to '$name' expected at this point. End of demands.")
+        }
+        if (calls[i].name != name)              return false
+        if (null == fCalls[i])                  fCalls[i] = 0
+        if (fCalls[i] >= calls[i].range.to)     return false
+        return true
+    }
+
+    /** verify all calls are in expected range */ // todo: duplication with StrictExpectation
+    void verify() {
+        for (i in 0 ..< fDemand.recorded.size()) {
+            def call = fDemand.recorded[i]
+            def msg = "verify[$i]: expected ${call.range.toString()} call(s) to '${call.name}' but was "
+            if ( null == fCalls[i] )
+                throw new AssertionFailedError(msg + "never called.")
+            if (! call.range.contains( fCalls[i] ) )
+                throw new AssertionFailedError(msg + "called ${fCalls[i]} time(s).")
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/mock/interceptor/MockFor.groovy b/groovy-core/src/main/groovy/mock/interceptor/MockFor.groovy
new file mode 100644
index 0000000..a24d712
--- /dev/null
+++ b/groovy-core/src/main/groovy/mock/interceptor/MockFor.groovy
@@ -0,0 +1,31 @@
+package groovy.mock.interceptor
+
+/**
+    Facade over the Mocking details.
+    A Mock's expectation is always sequence dependent and it's use always ends with a verify().
+    See also StubFor.
+*/
+
+class MockFor {
+
+    MockProxyMetaClass proxy
+    Demand demand
+    def expect
+
+    MockFor(Class clazz) {
+        proxy = MockProxyMetaClass.make(clazz)
+        demand = new Demand()
+        expect = new StrictExpectation(demand)
+        proxy.interceptor = new MockInterceptor(expectation: expect)
+    }
+
+    void use(Closure closure) {
+        proxy.use closure
+        expect.verify()
+    }
+
+    void use(GroovyObject obj, Closure closure) {
+        proxy.use obj, closure
+        expect.verify()
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/mock/interceptor/MockInterceptor.groovy b/groovy-core/src/main/groovy/mock/interceptor/MockInterceptor.groovy
new file mode 100644
index 0000000..5d2def3
--- /dev/null
+++ b/groovy-core/src/main/groovy/mock/interceptor/MockInterceptor.groovy
@@ -0,0 +1,24 @@
+package groovy.mock.interceptor
+
+/**
+    Intercepting calls to the collaborating object and notify the expectation object.
+    @author Dierk Koenig
+*/
+
+class MockInterceptor implements Interceptor {
+
+    def expectation = null
+
+    Object beforeInvoke(Object object, String methodName, Object[] arguments) {
+        if (!expectation) throw new IllegalStateException("Property 'expectation' must be set before use.")
+        return expectation.match(methodName).call(arguments)
+    }
+
+    Object afterInvoke(Object object, String methodName, Object[] arguments, Object result) {
+        return null // never used
+    }
+
+    boolean doInvoke() {
+        return false // future versions may allow collaborator method calls depending on state
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/mock/interceptor/MockProxyMetaClass.java b/groovy-core/src/main/groovy/mock/interceptor/MockProxyMetaClass.java
new file mode 100644
index 0000000..f89574f
--- /dev/null
+++ b/groovy-core/src/main/groovy/mock/interceptor/MockProxyMetaClass.java
@@ -0,0 +1,57 @@
+package groovy.mock.interceptor;
+
+import groovy.lang.ProxyMetaClass;
+import groovy.lang.MetaClassRegistry;
+import groovy.lang.MetaClass;
+
+import java.beans.IntrospectionException;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * The ProxyMetaClass for the MockInterceptor.
+ * Instance and class methods are intercepted, but constructors are not to allow mocking of aggregated objects.
+ * @author Dierk Koenig
+ */
+
+public class MockProxyMetaClass extends ProxyMetaClass {
+
+    /**
+     * @param adaptee the MetaClass to decorate with interceptability
+     */
+    public MockProxyMetaClass(MetaClassRegistry registry, Class theClass, MetaClass adaptee) throws IntrospectionException {
+        super(registry, theClass, adaptee);
+    }
+
+    /**
+     * convenience factory method for the most usual case.
+     */
+    public static MockProxyMetaClass make(Class theClass) throws IntrospectionException {
+        MetaClassRegistry metaRegistry = InvokerHelper.getInstance().getMetaRegistry();
+        MetaClass meta = metaRegistry.getMetaClass(theClass);
+        return new MockProxyMetaClass(metaRegistry, theClass, meta);
+    }
+
+
+    public Object invokeMethod(final Object object, final String methodName, final Object[] arguments) {
+        if (null == interceptor) {
+            throw new RuntimeException("cannot invoke without interceptor");
+        }
+        return interceptor.beforeInvoke(object, methodName, arguments);
+    }
+
+    public Object invokeStaticMethod(final Object object, final String methodName, final Object[] arguments) {
+        if (null == interceptor) {
+            throw new RuntimeException("cannot invoke without interceptor");
+        }
+        return interceptor.beforeInvoke(object, methodName, arguments);
+    }
+
+    /**
+     * Unlike general impl in superclass, ctors are not intercepted but relayed
+     */
+    public Object invokeConstructor(final Object[] arguments) {
+        return adaptee.invokeConstructor(arguments);
+    }
+    
+}
diff --git a/groovy-core/src/main/groovy/mock/interceptor/StrictExpectation.groovy b/groovy-core/src/main/groovy/mock/interceptor/StrictExpectation.groovy
new file mode 100644
index 0000000..642f9ea
--- /dev/null
+++ b/groovy-core/src/main/groovy/mock/interceptor/StrictExpectation.groovy
@@ -0,0 +1,68 @@
+package groovy.mock.interceptor
+
+import junit.framework.AssertionFailedError
+
+/**
+    Expects demanded call cardinalities to match demanded ranges in the sequence of recording.
+    @See LooseExpectation
+    @author Dierk Koenig
+*/
+
+class StrictExpectation {
+    Demand fDemand  = null
+    int fCallSpecIdx = 0
+    List fCalls      = []
+
+    StrictExpectation(Demand demand) {
+        fDemand = demand
+    }
+
+    /**
+        Match the requested method name against eligible demands.
+        Fail early if no match possible.
+        Return the demand's behavior closure on match.
+    */
+    Closure match(String name) {
+        if (!fCalls[fCallSpecIdx]) fCalls[fCallSpecIdx] = 0
+
+        if (fCallSpecIdx >= fDemand.recorded.size()) {
+            throw new AssertionFailedError("No more calls to '$name' expected at this point. End of demands.")
+        }
+
+        def call = fDemand.recorded[fCallSpecIdx]
+        if (name != call.name) {                             // if name does not match...
+            def open = call.range.from - fCalls[fCallSpecIdx]
+            if ( open > 0) {                                 // ... if we haven't reached the minimum, yet -> Exception
+                throw new AssertionFailedError("No call to '$name' expected at this point. "+
+                "Still $open call(s) to '${call.name}' expected.")
+            } else {                                         // ... proceed finding
+                fCallSpecIdx++
+                return match(name)
+            }
+        }
+
+        // register the call
+        fCalls[fCallSpecIdx] += 1
+
+        // store the behavior for returning
+        def result = call.behavior
+
+        // proceed to next callSpec if we need to
+        if (fCalls[fCallSpecIdx] >= call.range.to ) fCallSpecIdx++
+
+        return result
+    }
+
+    /** verify all calls are in expected range */
+    void verify() {
+        for (i in 0 ..< fDemand.recorded.size()) {
+            def call = fDemand.recorded[i]
+            def msg = "verify[$i]: expected ${call.range.toString()} call(s) to '${call.name}' but was "
+            if ( null == fCalls[i] )
+                throw new AssertionFailedError(msg + "never called.")
+            if (! call.range.contains( fCalls[i] ) )
+                throw new AssertionFailedError(msg + "called ${fCalls[i]} time(s).")
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/mock/interceptor/StubFor.groovy b/groovy-core/src/main/groovy/mock/interceptor/StubFor.groovy
new file mode 100644
index 0000000..567b376
--- /dev/null
+++ b/groovy-core/src/main/groovy/mock/interceptor/StubFor.groovy
@@ -0,0 +1,30 @@
+package groovy.mock.interceptor
+
+/**
+    Facade over the Stubbing details.
+    A Stub's expectation is sequence independent and use of verify() is left to the user.
+    @See MockFor.
+    @author Dierk Koenig
+*/
+
+class StubFor {
+
+    MockProxyMetaClass proxy
+    Demand demand
+    def expect
+
+    StubFor(Class clazz) {
+        proxy = MockProxyMetaClass.make(clazz)
+        demand = new Demand()
+        expect = new LooseExpectation(demand)
+        proxy.interceptor = new MockInterceptor(expectation: expect)
+    }
+
+    void use(Closure closure) {
+        proxy.use closure
+    }
+
+    void use(GroovyObject obj, Closure closure) {
+        proxy.use obj, closure
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/mock/interceptor/package.html b/groovy-core/src/main/groovy/mock/interceptor/package.html
new file mode 100644
index 0000000..9218ed8
--- /dev/null
+++ b/groovy-core/src/main/groovy/mock/interceptor/package.html
@@ -0,0 +1,55 @@
+<html>
+  <head>
+    <title>package groovy.mock.interceptor</title>
+  </head>
+  <body>
+    <p>The groovy.mock.interceptor is an all-groovy mock testing library.</p>
+    <p>Terms:</p>
+    <dl>
+        <dt>Callaborator</dt>
+        <dd>An ordinary Groovy or Java class that's instance or class methods
+        are to be called. Calling them can be time consuming or produce side effects that
+        are unwanted when testing (e.g. database operations). </dd>
+
+        <dt>Caller</dt>
+        <dd>A Groovy Object that calls methods on the Collaborator, i.e.
+        collaborates with it.</dd>
+
+        <dt>Mock</dt>
+        <dd>An object that can be used to augment the Collaborator.
+        Method calls to the Collaborator will be handled by the Mock, showing a <em>demanded</em>
+        <em>behavior</em>. Method calls are <em>expected</em> to occur <em>strictly</em> in the <em>demanded</em>
+        sequence with a given <em>range</em> of cardinality. The <em>use</em> of a Mock implicitely
+        ends with <em>verifying</em> the <em>expectations</em>.
+        </dd>
+
+        <dt>Stub</dt>
+        <dd>Much like a Mock but the <em>expectation</em> about sequences of method calls on the Collaborator is
+        <em>loose</em>, i.e. calls may occur out of the demanded order as long as the <em>ranges</em>
+        of cardinality are met. The <em>use</em> of a Stub does <em>not</em> end with an implict
+        <em>verification</em> since the stubbing effect is typically asserted on the Caller.
+        An explicit call to <em>verify</em> can be issued to assert all demanded method call
+        have been effected with the specified cardinality.</dd>
+    </dl>
+
+    <p>Features:</p>
+    <ul>
+        <li>typical mock style of <em>failing early</em></li>
+        <li>mocks instance and class methods</li>
+        <li>mocks final methods and final Collaborators</li>
+        <li>mocks Groovy and Java Collaborators (but Caller must be groovy)</li>
+        <li>can mock all objects of a given class (or a single Groovy object)</li>
+        <li>mocks even if Collaborator cannot be injected into the Caller</li>
+        <li>mocks even if Collaborator is not accesible on the Caller (no getter)</li>
+        <li>demanded calls specified via recording calls on the Demand object (EasyMock style).</li>
+        <li>cardinality specified as Ranges, default is 1..1; 'optional' can be achieved with 0..1</li>
+        <li>behavior specified via Closures, allowing static or calculated return values, throwing exceptions,
+            asserting argument values, etc. (even tricky sequence constraints
+            by sharing state in the testMethod scope between the behavior Closures)</li>
+        <li>matching parameter list specified via Closure's parameter list, supporting
+            typed or untyped params, default params, and varargs.</li>
+        <li>not dependent on any external mock library</li>
+    </ul>
+   <p>For an extensive list of usages see the unit tests in this package.</p>
+  </body>
+</html>
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/mock/package.html b/groovy-core/src/main/groovy/mock/package.html
new file mode 100644
index 0000000..db2799a
--- /dev/null
+++ b/groovy-core/src/main/groovy/mock/package.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>package groovy.mock.*</title>
+  </head>
+  <body>
+    <p>GroovyMock is a mock testing library for Groovy objects.</p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/groovy/model/ClosureModel.java b/groovy-core/src/main/groovy/model/ClosureModel.java
new file mode 100644
index 0000000..0c51712
--- /dev/null
+++ b/groovy-core/src/main/groovy/model/ClosureModel.java
@@ -0,0 +1,108 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.model;
+
+import groovy.lang.Closure;
+
+/**
+ * Represents a value model using a closure to extract
+ * the value from some source model and an optional write closure
+ * for updating the value.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ClosureModel implements ValueModel, NestedValueModel {
+
+    private ValueModel sourceModel;
+    private Closure readClosure;
+    private Closure writeClosure;
+    private Class type;
+
+    public ClosureModel(ValueModel sourceModel, Closure readClosure) {
+        this(sourceModel, readClosure, null);
+    }
+
+    public ClosureModel(ValueModel sourceModel, Closure readClosure, Closure writeClosure) {
+        this(sourceModel, readClosure, writeClosure, Object.class);
+    }
+
+    public ClosureModel(ValueModel sourceModel, Closure readClosure, Closure writeClosure, Class type) {
+        this.sourceModel = sourceModel;
+        this.readClosure = readClosure;
+        this.writeClosure = writeClosure;
+        this.type = type;
+    }
+
+    public ValueModel getSourceModel() {
+        return sourceModel;
+    }
+
+    public Object getValue() {
+        Object source = sourceModel.getValue();
+        if (source != null) {
+            return readClosure.call(source);
+        }
+        return null;
+    }
+
+    public void setValue(Object value) {
+        if (writeClosure != null) {
+            Object source = sourceModel.getValue();
+            if (source != null) {
+                writeClosure.call(new Object[] { source, value });
+            }
+        }
+    }
+
+    public Class getType() {
+        return type;
+    }
+
+    public boolean isEditable() {
+        return writeClosure != null;
+    }
+}
diff --git a/groovy-core/src/main/groovy/model/DefaultTableColumn.java b/groovy-core/src/main/groovy/model/DefaultTableColumn.java
new file mode 100644
index 0000000..a01a8d3
--- /dev/null
+++ b/groovy-core/src/main/groovy/model/DefaultTableColumn.java
@@ -0,0 +1,107 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.model;
+
+import javax.swing.table.TableColumn;
+
+/** 
+ * Represents a column using a ValueModel to extract
+ * the value.
+ *
+ * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
+ * @version $Revision$
+ */
+public class DefaultTableColumn extends TableColumn {
+
+    private ValueModel valueModel;    
+    
+    public DefaultTableColumn(ValueModel valueModel) {
+        this.valueModel = valueModel;
+    }
+
+    public DefaultTableColumn(Object header, ValueModel valueModel) {
+        this(valueModel);
+        setHeaderValue(header);
+    }
+
+    public String toString() {
+        return super.toString() + "[header:" + getHeaderValue() + " valueModel:" + valueModel + "]";
+    }
+    
+    /**
+     * Evaluates the value of a cell
+     */    
+    public Object getValue(Object row, int rowIndex, int columnIndex) {
+        if (valueModel instanceof NestedValueModel) {
+            NestedValueModel nestedModel = (NestedValueModel) valueModel;
+            nestedModel.getSourceModel().setValue(row);
+        }
+        return valueModel.getValue();
+    }
+
+    public void setValue(Object row, Object value, int rowIndex, int columnIndex) {
+        if (valueModel instanceof NestedValueModel) {
+            NestedValueModel nestedModel = (NestedValueModel) valueModel;
+            nestedModel.getSourceModel().setValue(row);
+        }
+        valueModel.setValue(value);
+    }
+
+    // Properties
+    //-------------------------------------------------------------------------                    
+    
+    /**
+     * @return the column type.
+     */
+    public Class getType() {
+        return valueModel.getType();
+    }
+
+    public ValueModel getValueModel() {
+        return valueModel;
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/model/DefaultTableModel.java b/groovy-core/src/main/groovy/model/DefaultTableModel.java
new file mode 100644
index 0000000..9c81672
--- /dev/null
+++ b/groovy-core/src/main/groovy/model/DefaultTableModel.java
@@ -0,0 +1,215 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.model;
+
+import groovy.lang.Closure;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.DefaultTableColumnModel;
+import javax.swing.table.TableColumnModel;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * A default table model made up of PropertyModels on a Value model.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class DefaultTableModel extends AbstractTableModel {
+
+    private ValueModel rowModel;
+    private ValueModel rowsModel;
+    private MyTableColumnModel columnModel = new MyTableColumnModel();
+
+    public DefaultTableModel(ValueModel rowsModel) {
+        this(rowsModel, new ValueHolder());
+    }
+    
+    public DefaultTableModel(ValueModel rowsModel, ValueModel rowModel) {
+        this.rowModel = rowModel;
+        this.rowsModel = rowsModel;
+    }
+    
+    /**
+     * @return the column definitions.
+     */
+    public List getColumnList() {
+        return columnModel.getColumnList();
+    }
+
+    public TableColumnModel getColumnModel() {
+        return columnModel;
+    }
+    
+    /**
+     * Adds a property model column to the table
+     */
+    public DefaultTableColumn addPropertyColumn(Object headerValue, String property, Class type) {
+        return addColumn(headerValue, new PropertyModel(rowModel, property, type));
+    }
+    
+    /**
+     * Adds a closure based column to the table
+     */
+    public DefaultTableColumn addClosureColumn(Object headerValue, Closure readClosure, Closure writeClosure, Class type) {
+        return addColumn(headerValue, new ClosureModel(rowModel, readClosure, writeClosure, type));
+    }
+    
+    public DefaultTableColumn addColumn(Object headerValue, ValueModel columnValueModel) {
+        DefaultTableColumn answer = new DefaultTableColumn(headerValue, columnValueModel);
+        addColumn(answer);
+        return answer;
+    }
+    
+    /**
+     * Adds a new column definition to the table
+     */
+    public void addColumn(DefaultTableColumn column) {
+        columnModel.addColumn(column);
+    }
+    
+    /**
+     * Removes a column definition from the table
+     */
+    public void removeColumn(DefaultTableColumn column) {
+        columnModel.removeColumn(column);
+    }
+    
+    public int getRowCount() {
+        return getRows().size();
+    }
+
+    public int getColumnCount() {
+        return columnModel.getColumnCount();
+    }
+    
+    public String getColumnName(int columnIndex) {
+        String answer = null;
+        if (columnIndex < 0 || columnIndex >= columnModel.getColumnCount()) {
+            return answer;
+        }
+        Object value = columnModel.getColumn(columnIndex).getHeaderValue();
+        if (value != null) {
+            return value.toString();
+        }
+        return answer;
+    }
+
+    public Class getColumnClass(int columnIndex) {
+        return getColumnModel(columnIndex).getType();
+    }
+
+    public boolean isCellEditable(int rowIndex, int columnIndex) {
+        return getColumnModel(columnIndex).isEditable();
+    }
+
+    public Object getValueAt(int rowIndex, int columnIndex) {
+        List rows = getRows();
+        Object answer = null;
+        if (rowIndex < 0 || rowIndex >= rows.size()) {
+            return answer;
+        }
+        if (columnIndex < 0 || columnIndex >= columnModel.getColumnCount()) {
+            return answer;
+        }
+        Object row = getRows().get(rowIndex);
+        rowModel.setValue(row);
+        DefaultTableColumn column = (DefaultTableColumn) columnModel.getColumn(columnIndex);
+        if (row == null || column == null) {
+            return answer;
+        }
+        return column.getValue(row, rowIndex, columnIndex);
+    }
+
+    public void setValueAt(Object value, int rowIndex, int columnIndex) {
+        List rows = getRows();
+        if (rowIndex < 0 || rowIndex >= rows.size()) {
+            return;
+        }
+        if (columnIndex < 0 || columnIndex >= columnModel.getColumnCount()) {
+            return;
+        }
+        Object row = getRows().get(rowIndex);
+        rowModel.setValue(row);
+        DefaultTableColumn column = (DefaultTableColumn) columnModel.getColumn(columnIndex);
+        if (row == null || column == null) {
+            return;
+        }
+        column.setValue(row, value, rowIndex, columnIndex);
+    }
+
+    protected ValueModel getColumnModel(int columnIndex) {
+        DefaultTableColumn column = (DefaultTableColumn) columnModel.getColumn(columnIndex);
+        return column.getValueModel();
+    }
+
+    protected List getRows() {
+        Object value = rowsModel.getValue();
+        if (value == null) {
+            return Collections.EMPTY_LIST;
+        }
+        return InvokerHelper.asList(value);
+    }
+
+    protected static class MyTableColumnModel extends DefaultTableColumnModel {
+        public List getColumnList() {
+            return tableColumns;
+        }
+    }
+    
+    public ValueModel getRowModel() {
+        return rowModel;
+    }
+
+    public ValueModel getRowsModel() {
+        return rowsModel;
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/model/FormModel.java b/groovy-core/src/main/groovy/model/FormModel.java
new file mode 100644
index 0000000..efcd1b1
--- /dev/null
+++ b/groovy-core/src/main/groovy/model/FormModel.java
@@ -0,0 +1,76 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents a number of field models which can be ValueModel, 
+ * PropertyModel, TableModel, TreeModel or nested FormModel instances
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class FormModel {
+    private Map fieldModels;
+
+    public FormModel() {
+        this(new HashMap());
+    }
+    
+    public FormModel(Map fieldModels) {
+        this.fieldModels = fieldModels;
+    }
+
+    public void addModel(String name, Object model) {
+        fieldModels.put(name, model);
+    }
+    
+    public Object getModel(String name) {
+        return fieldModels.get(name);
+    }
+}
diff --git a/groovy-core/src/main/groovy/model/NestedValueModel.java b/groovy-core/src/main/groovy/model/NestedValueModel.java
new file mode 100644
index 0000000..7d7f279
--- /dev/null
+++ b/groovy-core/src/main/groovy/model/NestedValueModel.java
@@ -0,0 +1,57 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.model;
+
+/**
+ * Represents a nested value model such as a PropertyModel
+ * or a ClosureModel
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public interface NestedValueModel {
+    public ValueModel getSourceModel();
+}
diff --git a/groovy-core/src/main/groovy/model/PropertyModel.java b/groovy-core/src/main/groovy/model/PropertyModel.java
new file mode 100644
index 0000000..cd4737b
--- /dev/null
+++ b/groovy-core/src/main/groovy/model/PropertyModel.java
@@ -0,0 +1,104 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.model;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * Represents a property of a value as a model.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class PropertyModel implements ValueModel, NestedValueModel {
+
+    private ValueModel sourceModel;
+    private String property;
+    private Class type;
+
+    public PropertyModel(ValueModel sourceModel, String property) {
+        this(sourceModel, property, Object.class);
+    }
+
+    public PropertyModel(ValueModel sourceModel, String property, Class type) {
+        this.sourceModel = sourceModel;
+        this.property = property;
+        this.type = type;
+    }
+
+    public String getProperty() {
+        return property;
+    }
+
+    public ValueModel getSourceModel() {
+        return sourceModel;
+    }
+
+    public Object getValue() {
+        Object source = sourceModel.getValue();
+        if (source != null) {
+            return InvokerHelper.getProperty(source, property);
+        }
+        return null;
+    }
+
+    public void setValue(Object value) {
+        Object source = sourceModel.getValue();
+        if (source != null) {
+            InvokerHelper.setProperty(source, property, value);
+        }
+    }
+    
+    public Class getType() {
+        return type;
+    }
+
+    public boolean isEditable() {
+        /** @todo implement this! */
+        return true;
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/model/ValueHolder.java b/groovy-core/src/main/groovy/model/ValueHolder.java
new file mode 100644
index 0000000..c98a531
--- /dev/null
+++ b/groovy-core/src/main/groovy/model/ValueHolder.java
@@ -0,0 +1,123 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.model;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+/**
+ * A simple ValueModle implementation which is a holder of an object value. 
+ * Used to share local variables with closures
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ValueHolder implements ValueModel {
+    private Object value;
+    private Class type;
+    private PropertyChangeSupport propertyChangeSupport;
+    private boolean editable = true;
+
+    public ValueHolder() {
+        this(Object.class);
+    }
+    
+    public ValueHolder(Class type) {
+        this.type = type;
+    }
+    
+    public ValueHolder(Object value) {
+        this.value = value;
+        this.type = (value != null) ? value.getClass() : Object.class;
+    }
+    
+    /** 
+     * Add a PropertyChangeListener to the listener list.
+     * @param listener The listener to add.
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        if ( propertyChangeSupport == null ) {
+            propertyChangeSupport = new PropertyChangeSupport(this);
+        }
+        propertyChangeSupport.addPropertyChangeListener(listener);
+    }
+    
+    /** 
+     * Removes a PropertyChangeListener from the listener list.
+     * @param listener The listener to remove.
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        if ( propertyChangeSupport != null ) {
+            propertyChangeSupport.removePropertyChangeListener(listener);
+        }
+    }
+    
+
+    public Object getValue() {
+        return value;
+    }
+
+    public void setValue(Object value) {
+        Object oldValue = this.value;
+        this.value = value;
+        if ( propertyChangeSupport != null ) {
+            propertyChangeSupport.firePropertyChange("value", oldValue, value);
+        }
+    }
+
+    public Class getType() {
+        return type;
+    }
+
+    public boolean isEditable() {
+        return editable;
+    }
+    
+    public void setEditable(boolean editable) {
+        this.editable = editable;
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/model/ValueModel.java b/groovy-core/src/main/groovy/model/ValueModel.java
new file mode 100644
index 0000000..e2477ad
--- /dev/null
+++ b/groovy-core/src/main/groovy/model/ValueModel.java
@@ -0,0 +1,59 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.model;
+
+/**
+ * Represents a model of a value
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public interface ValueModel {
+    public Object getValue();
+    public void setValue(Object value);
+    public Class getType();
+    public boolean isEditable();
+}
diff --git a/groovy-core/src/main/groovy/model/package.html b/groovy-core/src/main/groovy/model/package.html
new file mode 100644
index 0000000..718cdfb
--- /dev/null
+++ b/groovy-core/src/main/groovy/model/package.html
@@ -0,0 +1,9 @@
+<html>
+  <head>
+    <title>package groovy.model.*</title>
+  </head>
+  <body>
+    <p>An MVC model package for working with user interfaces and data structures and arbitrary Java and Groovy objects
+    </p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/groovy/security/GroovyCodeSourcePermission.java b/groovy-core/src/main/groovy/security/GroovyCodeSourcePermission.java
new file mode 100644
index 0000000..1278531
--- /dev/null
+++ b/groovy-core/src/main/groovy/security/GroovyCodeSourcePermission.java
@@ -0,0 +1,22 @@
+package groovy.security;
+
+import java.security.BasicPermission;
+
+/**
+ * Permission required to explicitly specify a codebase for a groovy script whose
+ * codebase cannot be determined.  Typically this permission is only
+ * required by clients that want to associate a code source with a script which
+ * is a String or an InputStream.
+ *
+ * @author Steve Goetze
+ */
+public class GroovyCodeSourcePermission extends BasicPermission {
+
+	public GroovyCodeSourcePermission(String name) {
+		super(name);
+	}
+
+	public GroovyCodeSourcePermission(String name, String actions) {
+		super(name, actions);
+	}
+}
diff --git a/groovy-core/src/main/groovy/servlet/AbstractHttpServlet.java b/groovy-core/src/main/groovy/servlet/AbstractHttpServlet.java
new file mode 100644
index 0000000..a649935
--- /dev/null
+++ b/groovy-core/src/main/groovy/servlet/AbstractHttpServlet.java
@@ -0,0 +1,390 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ * 
+ * 1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * 3. The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org.
+ * 
+ * 4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ * 
+ * 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *  
+ */
+package groovy.servlet;
+
+import groovy.lang.MetaClass;
+import groovy.util.ResourceConnector;
+import groovy.util.ResourceException;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * A common ground dealing with the HTTP servlet API wrinkles.
+ * 
+ * <h4>Resource name mangling (pattern replacement)</h4>
+ * 
+ * <p> 
+ * Also implements Groovy's {@link groovy.util.ResourceConnector} in dynamic
+ * manner. It allows to modifiy the resource name that is searched for with a
+ * <i>replace all</i> operation. See {@link java.util.regex.Pattern} and
+ * {@link java.util.regex.Matcher} for details.
+ * The servlet init parameter names are:
+ * <pre>
+ * resource.name.regex = empty - defaults to null
+ * resource.name.replacement = empty - defaults to null
+ * resource.name.replace.all = true (default) | false means replaceFirst()
+ * </pre>
+ * Note: If you specify a regex, you have to specify a replacement string too!
+ * Otherwise an exception gets raised.
+ *
+ * <h4>Logging and bug-hunting options</h4>
+ *
+ * <p> 
+ * This implementation provides a verbosity flag switching log statements.
+ * The servlet init parameter name is:
+ * <pre>
+ * verbose = false(default) | true
+ * </pre>
+ * 
+ * <p> 
+ * In order to support class-loading-troubles-debugging with Tomcat 4 or
+ * higher, you can log the class loader responsible for loading some classes.
+ * See <a href="http://jira.codehaus.org/browse/GROOVY-861">GROOVY-861</a> for details.
+ * The servlet init parameter name is:
+ * <pre>
+ * log.GROOVY861 = false(default) | true
+ * </pre>
+ * 
+ * <p> 
+ * If you experience class-loading-troubles with Tomcat 4 (or higher) or any
+ * other servlet container using custom class loader setups, you can fallback
+ * to use (slower) reflection in Groovy's MetaClass implementation. Please
+ * contact the dev team with your problem! Thanks.
+ * The servlet init parameter name is:
+ * <pre>
+ * reflection = false(default) | true
+ * </pre>
+ * 
+ *
+ * @author Christian Stein
+ */
+public abstract class AbstractHttpServlet extends HttpServlet implements ResourceConnector {
+
+    /**
+     * Content type of the HTTP response.
+     */
+    public static final String CONTENT_TYPE_TEXT_HTML = "text/html";
+
+    /**
+     * Servlet API include key name: path_info
+     */
+    public static final String INC_PATH_INFO = "javax.servlet.include.path_info";
+
+    /* *** Not used, yet. See comments in getScriptUri(HttpServletRequest). ***
+     * Servlet API include key name: request_uri
+     */
+    public static final String INC_REQUEST_URI = "javax.servlet.include.request_uri";
+
+    /**
+     * Servlet API include key name: servlet_path
+     */
+    public static final String INC_SERVLET_PATH = "javax.servlet.include.servlet_path";
+
+    /**
+     * Servlet (or the web application) context.
+     */
+    protected ServletContext servletContext;
+
+    /**
+     * <b>Null</b> or compiled pattern matcher read from "resource.name.regex"
+     *  and used in {@link AbstractHttpServlet#getResourceConnection(String)}.
+     */
+    protected Matcher resourceNameMatcher;
+
+    /**
+     * The replacement used by the resource name matcher.
+     */
+    protected String resourceNameReplacement;
+
+    /**
+     * The replace method to use on the matcher.
+     * <pre>
+     * true - replaceAll(resourceNameReplacement); (default)
+     * false - replaceFirst(resourceNameReplacement);
+     * </pre>
+     */
+    protected boolean resourceNameReplaceAll;
+
+    /**
+     * Controls almost all log output.
+     */
+    protected boolean verbose;
+
+    /**
+     * Mirrors the static value of the reflection flag in MetaClass.
+     * See {@link AbstractHttpServlet#logGROOVY861}
+     */
+    protected boolean reflection;
+
+    /**
+     * Debug flag logging the class the class loader of the request.
+     */
+    private boolean logGROOVY861;
+
+    /**
+     * Initializes all fields with default values.
+     */
+    public AbstractHttpServlet() {
+        this.servletContext = null;
+        this.resourceNameMatcher = null;
+        this.resourceNameReplacement = null;
+        this.resourceNameReplaceAll = true;
+        this.verbose = false;
+        this.reflection = false;
+        this.logGROOVY861 = false;
+    }
+
+    /**
+     * Interface method for ResourceContainer. This is used by the GroovyScriptEngine.
+     */
+    public URLConnection getResourceConnection(String name) throws ResourceException {
+        /*
+         * First, mangle resource name with the compiled pattern.
+         */
+        Matcher matcher = resourceNameMatcher;
+        if (matcher != null) {
+            matcher.reset(name);
+            String replaced;
+            if (resourceNameReplaceAll) {
+                replaced = resourceNameMatcher.replaceAll(resourceNameReplacement);
+            } else {
+                replaced = resourceNameMatcher.replaceFirst(resourceNameReplacement);
+            }
+            if (!name.equals(replaced)) {
+                if (verbose) {
+                    log("Replaced resource name \"" + name + "\" with \"" + replaced + "\".");
+                }
+                name = replaced;
+            }
+        }
+
+        /*
+         * Try to locate the resource and return an opened connection to it.
+         */
+        try {
+            URL url = servletContext.getResource("/" + name);
+            if (url == null) {
+                url = servletContext.getResource("/WEB-INF/groovy/" + name);
+            }
+            if (url == null) {
+                throw new ResourceException("Resource \"" + name + "\" not found!");
+            }
+            return url.openConnection();
+        } catch (IOException e) {
+            throw new ResourceException("Problems getting resource named \"" + name + "\"!", e);
+        }
+    }
+
+    /**
+     * Returns the include-aware uri of the script or template file.
+     * 
+     * @param request
+     *  the http request to analyze
+     * @return the include-aware uri either parsed from request attributes or
+     *  hints provided by the servlet container
+     */
+    protected String getScriptUri(HttpServletRequest request) {
+        /*
+         * Log some debug information for http://jira.codehaus.org/browse/GROOVY-861
+         */
+        if (logGROOVY861) {
+            log("Logging request class and its class loader:");
+            log(" c = request.getClass() :\"" + request.getClass() + "\"");
+            log(" l = c.getClassLoader() :\"" + request.getClass().getClassLoader() + "\"");
+            log(" l.getClass()           :\"" + request.getClass().getClassLoader().getClass() + "\"");
+            /*
+             * Keep logging, if we're verbose. Else turn it off.
+             */
+            logGROOVY861 = verbose;
+        }
+
+        //
+        // NOTE: This piece of code is heavily inspired by Apaches Jasper2!
+        // 
+        // http://cvs.apache.org/viewcvs.cgi/jakarta-tomcat-jasper/jasper2/ \
+        //        src/share/org/apache/jasper/servlet/JspServlet.java?view=markup
+        //
+        // Why doesn't it use request.getRequestURI() or INC_REQUEST_URI?
+        //
+
+        String uri = null;
+        String info = null;
+
+        //
+        // Check to see if the requested script/template source file has been the
+        // target of a RequestDispatcher.include().
+        //
+        uri = (String) request.getAttribute(INC_SERVLET_PATH);
+        if (uri != null) {
+            //
+            // Requested script/template file has been target of 
+            // RequestDispatcher.include(). Its path is assembled from the relevant
+            // javax.servlet.include.* request attributes and returned!
+            //
+            info = (String) request.getAttribute(INC_PATH_INFO);
+            if (info != null) {
+                uri += info;
+            }
+            return uri;
+        }
+
+        //
+        // Requested script/template file has not been the target of a 
+        // RequestDispatcher.include(). Reconstruct its path from the request's
+        // getServletPath() and getPathInfo() results.
+        //
+        uri = request.getServletPath();
+        info = request.getPathInfo();
+        if (info != null) {
+            uri += info;
+        }
+
+        /*
+         * TODO : Enable auto ".groovy" extension replacing here!
+         * http://cvs.groovy.codehaus.org/viewrep/groovy/groovy/groovy-core/src/main/groovy/servlet/GroovyServlet.java?r=1.10#l259 
+         */
+
+        return uri;
+    }
+
+    /**
+     * Parses the http request for the real script or template source file.
+     * @param request the http request to analyze
+     * @return a file object using an absolute file path name
+     */
+    protected File getScriptUriAsFile(HttpServletRequest request) {
+        String uri = getScriptUri(request);
+        String real = servletContext.getRealPath(uri);
+        File file = new File(real).getAbsoluteFile();
+        return file;
+    }
+
+    /**
+     * Overrides the generic init method to set some debug flags.
+     * 
+     * @param config
+     *  the servlet coniguration provided by the container
+     * @throws ServletException if init() method defined in super class 
+     *  javax.servlet.GenericServlet throws it
+     */
+    public void init(ServletConfig config) throws ServletException {
+        /*
+         * Never forget super.init()!
+         */
+        super.init(config);
+
+        /*
+         * Grab the servlet context.
+         */
+        this.servletContext = config.getServletContext();
+
+        /*
+         * Get verbosity hint.
+         */
+        String value = config.getInitParameter("verbose");
+        if (value != null) {
+            this.verbose = Boolean.valueOf(value).booleanValue();
+        }
+
+        /*
+         * And now the real init work...
+         */
+        if (verbose) {
+            log("Parsing init parameters...");
+        }
+
+        String regex = config.getInitParameter("resource.name.regex");
+        if (regex != null) {
+            String replacement = config.getInitParameter("resource.name.replacement");
+            if (replacement == null) {
+                Exception npex = new NullPointerException("resource.name.replacement");
+                String message = "Init-param 'resource.name.replacement' not specified!";
+                log(message, npex);
+                throw new ServletException(message, npex);
+            }
+            int flags = 0; // TODO : Parse pattern compile flags.
+            this.resourceNameMatcher = Pattern.compile(regex, flags).matcher("");
+            this.resourceNameReplacement = replacement;
+            String all = config.getInitParameter("resource.name.replace.all");
+            if (all != null) {
+                this.resourceNameReplaceAll = Boolean.valueOf(all).booleanValue();
+            }
+        }
+
+        value = config.getInitParameter("reflection");
+        if (value != null) {
+            this.reflection = Boolean.valueOf(value).booleanValue();
+            MetaClass.setUseReflection(reflection);
+        }
+
+        value = config.getInitParameter("logGROOVY861");
+        if (value != null) {
+            this.logGROOVY861 = Boolean.valueOf(value).booleanValue();
+            // nothing else to do here
+        }
+
+        /*
+         * If verbose, log the parameter values.
+         */
+        if (verbose) {
+            log("(Abstract) init done. Listing some parameter name/value pairs:");
+            log("verbose = " + verbose); // this *is* verbose! ;)
+            log("reflection = " + reflection);
+            log("logGROOVY861 = " + logGROOVY861);
+            if (resourceNameMatcher != null) {
+                log("resource.name.regex = " + resourceNameMatcher.pattern().pattern());
+            }
+            else {
+                log("resource.name.regex = null");
+            }
+            log("resource.name.replacement = " + resourceNameReplacement);
+        }
+    }
+}
diff --git a/groovy-core/src/main/groovy/servlet/GroovyServlet.java b/groovy-core/src/main/groovy/servlet/GroovyServlet.java
new file mode 100644
index 0000000..00a0075
--- /dev/null
+++ b/groovy-core/src/main/groovy/servlet/GroovyServlet.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package groovy.servlet;
+
+import groovy.lang.Binding;
+import groovy.lang.Closure;
+import groovy.util.GroovyScriptEngine;
+import groovy.util.ResourceException;
+import groovy.util.ScriptException;
+
+import java.io.IOException;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.codehaus.groovy.runtime.GroovyCategorySupport;
+
+/**
+ * This servlet will run Groovy scripts as Groovlets.  Groovlets are scripts
+ * with these objects implicit in their scope:
+ *
+ * <ul>
+ * 	<li>request - the HttpServletRequest</li>
+ *  <li>response - the HttpServletResponse</li>
+ *  <li>application - the ServletContext associated with the servlet</li>
+ *  <li>session - the HttpSession associated with the HttpServletRequest</li>
+ *  <li>out - the PrintWriter associated with the ServletRequest</li>
+ * </ul>
+ *
+ * <p>Your script sources can be placed either in your web application's normal
+ * web root (allows for subdirectories) or in /WEB-INF/groovy/* (also allows
+ * subdirectories).
+ *
+ * <p>To make your web application more groovy, you must add the GroovyServlet
+ * to your application's web.xml configuration using any mapping you like, so
+ * long as it follows the pattern *.* (more on this below).  Here is the
+ * web.xml entry:
+ *
+ * <pre>
+ *    <servlet>
+ *      <servlet-name>Groovy</servlet-name>
+ *      <servlet-class>groovy.servlet.GroovyServlet</servlet-class>
+ *    </servlet>
+ *
+ *    <servlet-mapping>
+ *      <servlet-name>Groovy</servlet-name>
+ *      <url-pattern>*.groovy</url-pattern>
+ *      <url-pattern>*.gdo</url-pattern>
+ *    </servlet-mapping>
+ * </pre>
+ *
+ * <p>The URL pattern does not require the "*.groovy" mapping.  You can, for
+ * example, make it more Struts-like but groovy by making your mapping "*.gdo".
+ *
+ * @author Sam Pullara
+ * @author Mark Turansky (markturansky at hotmail.com)
+ * @author Guillaume Laforge
+ * @author Christian Stein
+ * 
+ * @see groovy.servlet.ServletBinding
+ */
+public class GroovyServlet extends AbstractHttpServlet {
+
+    /**
+     * The script engine executing the Groovy scripts for this servlet
+     */
+    private static GroovyScriptEngine gse;
+
+    /**
+     * Initialize the GroovyServlet.
+     *
+     * @throws ServletException
+     *  if this method encountered difficulties
+     */
+    public void init(ServletConfig config) throws ServletException {
+        super.init(config);
+
+        // Set up the scripting engine
+        gse = new GroovyScriptEngine(this);
+
+        servletContext.log("Groovy servlet initialized on " + gse + ".");
+    }
+
+    /**
+     * Handle web requests to the GroovyServlet
+     */
+    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
+
+        // Get the script path from the request - include aware (GROOVY-815)
+        final String scriptUri = getScriptUri(request);
+
+        // Set it to HTML by default
+        response.setContentType("text/html");
+
+        // Set up the script context
+        final Binding binding = new ServletBinding(request, response, servletContext);
+
+        // Run the script
+        try {
+            Closure closure = new Closure(gse) {
+
+                public Object call() {
+                    try {
+                        return ((GroovyScriptEngine) getDelegate()).run(scriptUri, binding);
+                    } catch (ResourceException e) {
+                        throw new RuntimeException(e);
+                    } catch (ScriptException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+
+            };
+            GroovyCategorySupport.use(ServletCategory.class, closure);
+            /*
+             * Set reponse code 200.
+             */
+            response.setStatus(HttpServletResponse.SC_OK);
+        } catch (RuntimeException runtimeException) {
+            StringBuffer error = new StringBuffer("GroovyServlet Error: ");
+            error.append(" script: '");
+            error.append(scriptUri);
+            error.append("': ");
+            Throwable e = runtimeException.getCause();
+            /*
+             * Null cause?!
+             */
+            if (e == null) {
+                error.append(" Script processing failed.");
+                error.append(runtimeException.getMessage());
+                error.append(runtimeException.getStackTrace()[0].toString());
+                servletContext.log(error.toString());
+                System.err.println(error.toString());
+                runtimeException.printStackTrace(System.err);
+                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error.toString());
+                return;
+            }
+            /*
+             * Resource not found.
+             */
+            if (e instanceof ResourceException) {
+                error.append(" Script not found, sending 404.");
+                servletContext.log(error.toString());
+                System.err.println(error.toString());
+                response.sendError(HttpServletResponse.SC_NOT_FOUND);
+                return;
+            }
+            /*
+             * Other internal error. Perhaps syntax?! 
+             */
+            servletContext.log("An error occurred processing the request", runtimeException);
+            error.append(e.getMessage());
+            error.append(e.getStackTrace()[0].toString());
+            servletContext.log(e.toString());
+            System.err.println(e.toString());
+            runtimeException.printStackTrace(System.err);
+            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
+        } finally {
+            /*
+             * Finally, flush the response buffer.
+             */
+            response.flushBuffer();
+            // servletContext.log("Flushed response buffer.");
+        }
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/servlet/ServletBinding.java b/groovy-core/src/main/groovy/servlet/ServletBinding.java
new file mode 100644
index 0000000..99e4c3e
--- /dev/null
+++ b/groovy-core/src/main/groovy/servlet/ServletBinding.java
@@ -0,0 +1,229 @@
+/*
+ $Id$
+
+ Copyright 2005 (C) Guillaume Laforge. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.servlet;
+
+import groovy.lang.Binding;
+import groovy.xml.MarkupBuilder;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Servlet-specific binding extension to lazy load the writer or the output
+ * stream from the response.
+ * 
+ * <p>
+ * <h3>Default variables bound</h3>
+ * <ul>
+ * <li><tt>"request"</tt> : the HttpServletRequest object</li>
+ * <li><tt>"response"</tt> : the HttpServletResponse object</li>
+ * <li><tt>"context"</tt> : the ServletContext object </li>
+ * <li><tt>"application"</tt> : same as context</li>
+ * <li><tt>"session"</tt> : convenient for <code>request.getSession(<b>false</b>)</code> - can be null!</li>
+ * <li><tt>"params"</tt> : map of all form parameters - can be empty</li>
+ * <li><tt>"headers"</tt> : map of all <b>request</b> header fields</li>
+ * </ul>
+ * 
+ * <p>
+ * <h3>Implicite bound variables</h3>
+ * <ul>
+ * <li><tt>"out"</tt> : response.getWriter() </li>
+ * <li><tt>"sout"</tt> : response.getOutputStream() </li>
+ * <li><tt>"html"</tt> : new MarkupBuilder(response.getWriter()) </li>
+ * </ul>
+ * </p>
+ * 
+ * @author Guillaume Laforge
+ * @author Christian Stein
+ */
+public class ServletBinding extends Binding {
+
+    private final Binding binding;
+
+    private final ServletContext context;
+
+    private final HttpServletRequest request;
+
+    private final HttpServletResponse response;
+
+    private MarkupBuilder html;
+
+    /**
+     * Initializes a servlet binding.
+     */
+    public ServletBinding(HttpServletRequest request, HttpServletResponse response, ServletContext context) {
+        this.binding = new Binding();
+        this.request = request;
+        this.response = response;
+        this.context = context;
+
+        /*
+         * Bind the default variables.
+         */
+        binding.setVariable("request", request);
+        binding.setVariable("response", response);
+        binding.setVariable("context", context);
+        binding.setVariable("application", context);
+
+        /*
+         * Bind the HTTP session object - if there is one.
+         * Note: we don't create one here!
+         */
+        binding.setVariable("session", request.getSession(false));
+
+        /*
+         * Bind form parameter key-value hash map.
+         *
+         * If there are multiple, they are passed as an array.
+         */
+        Map params = new HashMap();
+        for (Enumeration names = request.getParameterNames(); names.hasMoreElements();) {
+            String name = (String) names.nextElement();
+            if (!binding.getVariables().containsKey(name)) {
+                String[] values = request.getParameterValues(name);
+                if (values.length == 1) {
+                    params.put(name, values[0]);
+                } else {
+                    params.put(name, values);
+                }
+            }
+        }
+        binding.setVariable("params", params);
+
+        /*
+         * Bind request header key-value hash map.
+         */
+        Map headers = new HashMap();
+        for (Enumeration names = request.getHeaderNames(); names.hasMoreElements();) {
+            String headerName = (String) names.nextElement();
+            String headerValue = request.getHeader(headerName);
+            headers.put(headerName, headerValue);
+        }
+        binding.setVariable("headers", headers);
+    }
+
+    public void setVariable(String name, Object value) {
+        /*
+         * Check sanity.
+         */
+        if (name == null) {
+            throw new IllegalArgumentException("Can't bind variable to null key.");
+        }
+        if (name.length() == 0) {
+            throw new IllegalArgumentException("Can't bind variable to blank key name. [length=0]");
+        }
+        /*
+         * Check implicite key names. See getVariable(String)!
+         */
+        if ("out".equals(name)) {
+            throw new IllegalArgumentException("Can't bind variable to key named '" + name + "'.");
+        }
+        if ("sout".equals(name)) {
+            throw new IllegalArgumentException("Can't bind variable to key named '" + name + "'.");
+        }
+        if ("html".equals(name)) {
+            throw new IllegalArgumentException("Can't bind variable to key named '" + name + "'.");
+        }
+        /*
+         * TODO Check default key names. See constructor(s).
+         */
+        
+        /*
+         * All checks passed, set the variable.
+         */
+        binding.setVariable(name, value);
+    }
+
+    public Map getVariables() {
+        return binding.getVariables();
+    }
+
+    /**
+     * @return a writer, an output stream, a markup builder or another requested object
+     */
+    public Object getVariable(String name) {
+        /*
+         * Check sanity.
+         */
+        if (name == null) {
+            throw new IllegalArgumentException("No variable with null key name.");
+        }
+        if (name.length() == 0) {
+            throw new IllegalArgumentException("No variable with blank key name. [length=0]");
+        }
+        /*
+         * Check implicite key names. See setVariable(String, Object)!
+         */
+        try {
+            if ("out".equals(name)) {
+                return response.getWriter();
+            }
+            if ("sout".equals(name)) {
+                return response.getOutputStream();
+            }
+            if ("html".equals(name)) {
+                if (html == null) {
+                    html = new MarkupBuilder(response.getWriter());
+                }
+                return html;
+            }
+        } catch (IOException e) {
+            String message = "Failed to get writer or output stream from response.";
+            context.log(message, e);
+            throw new RuntimeException(message, e);
+        }
+        /*
+         * Still here? Delegate to the binding object.
+         */
+        return binding.getVariable(name);
+    }
+}
diff --git a/groovy-core/src/main/groovy/servlet/ServletCategory.java b/groovy-core/src/main/groovy/servlet/ServletCategory.java
new file mode 100644
index 0000000..7a5df8b
--- /dev/null
+++ b/groovy-core/src/main/groovy/servlet/ServletCategory.java
@@ -0,0 +1,122 @@
+/*
+$Id$
+
+Copyright 2005 (C) Guillaume Laforge. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+package groovy.servlet;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.servlet.jsp.PageContext;
+
+/**
+ * Servlet support.
+ */
+public class ServletCategory {
+	
+    public static Object get(ServletContext context, String key) {
+        return context.getAttribute(key);
+    }
+    
+    public static Object get(HttpSession session, String key) {
+        return session.getAttribute(key);
+    }
+    
+    public static Object get(ServletRequest request, String key) {
+        return request.getAttribute(key);
+    }
+
+    public static Object get(PageContext context, String key) {
+        return context.getAttribute(key);
+    }
+
+    public static Object getAt(ServletContext context, String key) {
+        return context.getAttribute(key);
+    }
+
+    public static Object getAt(HttpSession session, String key) {
+        return session.getAttribute(key);
+    }
+
+    public static Object getAt(ServletRequest request, String key) {
+        return request.getAttribute(key);
+    }
+
+    public static Object getAt(PageContext context, String key) {
+        return context.getAttribute(key);
+    }
+
+    public static void set(ServletContext context, String key, Object value) {
+        context.setAttribute(key, value);
+    }
+
+    public static void set(HttpSession session, String key, Object value) {
+        session.setAttribute(key, value);
+    }
+
+    public static void set(ServletRequest request, String key, Object value) {
+        request.setAttribute(key, value);
+    }
+
+    public static void set(PageContext context, String key, Object value) {
+        context.setAttribute(key, value);
+    }
+
+    public static void putAt(ServletContext context, String key, Object value) {
+        context.setAttribute(key, value);
+    }
+
+    public static void putAt(HttpSession session, String key, Object value) {
+        session.setAttribute(key, value);
+    }
+
+    public static void putAt(ServletRequest request, String key, Object value) {
+        request.setAttribute(key, value);
+    }
+
+    public static void putAt(PageContext context, String key, Object value) {
+        context.setAttribute(key, value);
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/servlet/TemplateServlet.java b/groovy-core/src/main/groovy/servlet/TemplateServlet.java
new file mode 100644
index 0000000..8549ed9
--- /dev/null
+++ b/groovy-core/src/main/groovy/servlet/TemplateServlet.java
@@ -0,0 +1,511 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ * 
+ * 1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * 3. The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org.
+ * 
+ * 4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ * 
+ * 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *  
+ */
+package groovy.servlet;
+
+import groovy.text.SimpleTemplateEngine;
+import groovy.text.Template;
+import groovy.text.TemplateEngine;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Date;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * A generic servlet for serving (mostly HTML) templates.
+ * 
+ * <p>
+ * It delegates work to a <code>groovy.text.TemplateEngine</code> implementation 
+ * processing HTTP requests.
+ *
+ * <h4>Usage</h4>
+ * 
+ * <code>helloworld.html</code> is a headless HTML-like template
+ * <pre><code>
+ *  &lt;html&gt;
+ *    &lt;body&gt;
+ *      &lt;% 3.times { %&gt;
+ *        Hello World!
+ *      &lt;% } %&gt;
+ *      &lt;br&gt;
+ *    &lt;/body&gt;
+ *  &lt;/html&gt; 
+ * </code></pre>
+ * 
+ * Minimal <code>web.xml</code> example serving HTML-like templates
+ * <pre><code>
+ * &lt;web-app&gt;
+ *   &lt;servlet&gt;
+ *     &lt;servlet-name&gt;template&lt;/servlet-name&gt;
+ *     &lt;servlet-class&gt;groovy.servlet.TemplateServlet&lt;/servlet-class&gt;
+ *   &lt;/servlet&gt;
+ *   &lt;servlet-mapping&gt;
+ *     &lt;servlet-name&gt;template&lt;/servlet-name&gt;
+ *     &lt;url-pattern&gt;*.html&lt;/url-pattern&gt;
+ *   &lt;/servlet-mapping&gt;
+ * &lt;/web-app&gt;
+ * </code></pre>
+ * 
+ * <h4>Template engine configuration</h4>
+ * 
+ * <p>
+ * By default, the TemplateServer uses the {@link groovy.text.SimpleTemplateEngine}
+ * which interprets JSP-like templates. The init parameter <code>template.engine</code>
+ * defines the fully qualified class name of the template to use:
+ * <pre>
+ *   template.engine = [empty] - equals groovy.text.SimpleTemplateEngine
+ *   template.engine = groovy.text.SimpleTemplateEngine
+ *   template.engine = groovy.text.GStringTemplateEngine
+ *   template.engine = groovy.text.XmlTemplateEngine
+ * </pre>
+ * 
+ * <h4>Logging and extra-output options</h4>
+ *
+ * <p>
+ * This implementation provides a verbosity flag switching log statements.
+ * The servlet init parameter name is:
+ * <pre>
+ *   generate.by = true(default) | false
+ * </pre>
+ * 
+ * @see TemplateServlet#setVariables(ServletBinding)
+ * 
+ * @author Christian Stein
+ * @author Guillaume Laforge
+ * @version 2.0
+ */
+public class TemplateServlet extends AbstractHttpServlet {
+
+    /**
+     * Simple cache entry that validates against last modified and length
+     * attributes of the specified file. 
+     *
+     * @author Christian Stein
+     */
+    private static class TemplateCacheEntry {
+
+        Date date;
+        long hit;
+        long lastModified;
+        long length;
+        Template template;
+
+        public TemplateCacheEntry(File file, Template template) {
+            this(file, template, false); // don't get time millis for sake of speed
+        }
+
+        public TemplateCacheEntry(File file, Template template, boolean timestamp) {
+            if (file == null) {
+                throw new NullPointerException("file");
+            }
+            if (template == null) {
+                throw new NullPointerException("template");
+            }
+            if (timestamp) {
+                this.date = new Date(System.currentTimeMillis());
+            } else {
+                this.date = null;
+            }
+            this.hit = 0;
+            this.lastModified = file.lastModified();
+            this.length = file.length();
+            this.template = template;
+        }
+
+        /**
+         * Checks the passed file attributes against those cached ones. 
+         *
+         * @param file
+         *  Other file handle to compare to the cached values.
+         * @return <code>true</code> if all measured values match, else <code>false</code>
+         */
+        public boolean validate(File file) {
+            if (file == null) {
+                throw new NullPointerException("file");
+            }
+            if (file.lastModified() != this.lastModified) {
+                return false;
+            }
+            if (file.length() != this.length) {
+                return false;
+            }
+            hit++;
+            return true;
+        }
+
+        public String toString() {
+            if (date == null) {
+                return "Hit #" + hit;
+            }
+            return "Hit #" + hit + " since " + date;
+        }
+
+    }
+
+    /**
+     * Simple file name to template cache map.
+     */
+    private final Map cache;
+
+    /**
+     * Underlying template engine used to evaluate template source files.
+     */
+    private TemplateEngine engine;
+
+    /**
+     * Flag that controls the appending of the "Generated by ..." comment.
+     */
+    private boolean generateBy;
+
+    /**
+     * Create new TemplateSerlvet.
+     */
+    public TemplateServlet() {
+        this.cache = new WeakHashMap();
+        this.engine = null; // assigned later by init()
+        this.generateBy = true; // may be changed by init()
+    }
+
+    /**
+     * Gets the template created by the underlying engine parsing the request.
+     * 
+     * <p>
+     * This method looks up a simple (weak) hash map for an existing template
+     * object that matches the source file. If the source file didn't change in
+     * length and its last modified stamp hasn't changed compared to a precompiled
+     * template object, this template is used. Otherwise, there is no or an
+     * invalid template object cache entry, a new one is created by the underlying
+     * template engine. This new instance is put to the cache for consecutive
+     * calls.
+     * </p>
+     * 
+     * @return The template that will produce the response text.
+     * @param file
+     *            The HttpServletRequest.
+     * @throws ServletException
+     *            If the request specified an invalid template source file 
+     */
+    protected Template getTemplate(File file) throws ServletException {
+
+        String key = file.getAbsolutePath();
+        Template template = null;
+
+        /*
+         * Test cache for a valid template bound to the key.
+         */
+        if (verbose) {
+            log("Looking for cached template by key \"" + key + "\"");
+        }
+        TemplateCacheEntry entry = (TemplateCacheEntry) cache.get(key);
+        if (entry != null) {
+            if (entry.validate(file)) {
+                if (verbose) {
+                    log("Cache hit! " + entry);
+                }
+                template = entry.template;
+            } else {
+                if (verbose) {
+                    log("Cached template needs recompiliation!");
+                }
+            }
+        } else {
+            if (verbose) {
+                log("Cache miss.");
+            }
+        }
+
+        //
+        // Template not cached or the source file changed - compile new template!
+        //
+        if (template == null) {
+            if (verbose) {
+                log("Creating new template from file " + file + "...");
+            }
+            FileReader reader = null;
+            try {
+                reader = new FileReader(file);
+                template = engine.createTemplate(reader);
+            } catch (Exception e) {
+                throw new ServletException("Creation of template failed: " + e, e);
+            } finally {
+                if (reader != null) {
+                    try {
+                        reader.close();
+                    } catch (IOException ignore) {
+                        // e.printStackTrace();
+                    }
+                }
+            }
+            cache.put(key, new TemplateCacheEntry(file, template, verbose));
+            if (verbose) {
+                log("Created and added template to cache. [key=" + key + "]");
+            }
+        }
+
+        //
+        // Last sanity check.
+        //
+        if (template == null) {
+            throw new ServletException("Template is null? Should not happen here!");
+        }
+
+        return template;
+
+    }
+
+    /**
+     * Initializes the servlet from hints the container passes.
+     * <p>
+     * Delegates to sub-init methods and parses the following parameters:
+     * <ul>
+     * <li> <tt>"generatedBy"</tt> : boolean, appends "Generated by ..." to the
+     *     HTML response text generated by this servlet.
+     *     </li>
+     * </ul>
+     * @param config
+     *  Passed by the servlet container.
+     * @throws ServletException
+     *  if this method encountered difficulties 
+     *  
+     * @see TemplateServlet#initTemplateEngine(ServletConfig)
+     */
+    public void init(ServletConfig config) throws ServletException {
+        super.init(config);
+        this.engine = initTemplateEngine(config);
+        if (engine == null) {
+            throw new ServletException("Template engine not instantiated.");
+        }
+        String value = config.getInitParameter("generated.by");
+        if (value != null) {
+            this.generateBy = Boolean.valueOf(value).booleanValue();
+        }
+        log("Servlet " + getClass().getName() + " initialized on " + engine.getClass());
+    }
+
+    /**
+     * Creates the template engine.
+     * 
+     * Called by {@link TemplateServlet#init(ServletConfig)} and returns just 
+     * <code>new groovy.text.SimpleTemplateEngine()</code> if the init parameter
+     * <code>template.engine</code> is not set by the container configuration.
+     * 
+     * @param config 
+     *  Current serlvet configuration passed by the container.
+     * 
+     * @return The underlying template engine or <code>null</code> on error.
+     */
+    protected TemplateEngine initTemplateEngine(ServletConfig config) {
+        String name = config.getInitParameter("template.engine");
+        if (name == null) {
+            return new SimpleTemplateEngine();
+        }
+        try {
+            return (TemplateEngine) Class.forName(name).newInstance();
+        } catch (InstantiationException e) {
+            log("Could not instantiate template engine: " + name, e);
+        } catch (IllegalAccessException e) {
+            log("Could not access template engine class: " + name, e);
+        } catch (ClassNotFoundException e) {
+            log("Could not find template engine class: " + name, e);
+        }
+        return null;
+    }
+
+    /**
+     * Services the request with a response.
+     * <p>
+     * First the request is parsed for the source file uri. If the specified file
+     * could not be found or can not be read an error message is sent as response.
+     * 
+     * </p>
+     * @param request
+     *            The http request.
+     * @param response
+     *            The http response.
+     * @throws IOException 
+     *            if an input or output error occurs while the servlet is
+     *            handling the HTTP request
+     * @throws ServletException
+     *            if the HTTP request cannot be handled
+     */
+    public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+        if (verbose) {
+            log("Creating/getting cached template...");
+        }
+
+        //
+        // Get the template source file handle.
+        //
+        File file = super.getScriptUriAsFile(request);
+        String name = file.getName();
+        if (!file.exists()) {
+            response.sendError(HttpServletResponse.SC_NOT_FOUND);
+            return; // throw new IOException(file.getAbsolutePath());
+        }
+        if (!file.canRead()) {
+            response.sendError(HttpServletResponse.SC_FORBIDDEN, "Can not read \"" + name + "\"!");
+            return; // throw new IOException(file.getAbsolutePath());
+        }
+
+        //
+        // Get the requested template.
+        //
+        long getMillis = System.currentTimeMillis();
+        Template template = getTemplate(file);
+        getMillis = System.currentTimeMillis() - getMillis;
+
+        //
+        // Create new binding for the current request.
+        //
+        ServletBinding binding = new ServletBinding(request, response, servletContext);
+        setVariables(binding);
+
+        //
+        // Prepare the response buffer content type _before_ getting the writer.
+        // and set status code to ok
+        //
+        response.setContentType(CONTENT_TYPE_TEXT_HTML);
+        response.setStatus(HttpServletResponse.SC_OK);
+
+        //
+        // Get the output stream writer from the binding.
+        //
+        Writer out = (Writer) binding.getVariable("out");
+        if (out == null) {
+            out = response.getWriter();
+        }
+
+        //
+        // Evaluate the template.
+        //
+        if (verbose) {
+            log("Making template \"" + name + "\"...");
+        }
+        // String made = template.make(binding.getVariables()).toString();
+        // log(" = " + made);
+        long makeMillis = System.currentTimeMillis();
+        template.make(binding.getVariables()).writeTo(out);
+        makeMillis = System.currentTimeMillis() - makeMillis;
+
+        if (generateBy) {
+            StringBuffer sb = new StringBuffer(100);
+            sb.append("\n<!-- Generated by Groovy TemplateServlet [create/get=");
+            sb.append(Long.toString(getMillis));
+            sb.append(" ms, make=");
+            sb.append(Long.toString(makeMillis));
+            sb.append(" ms] -->\n");
+            out.write(sb.toString());
+        }
+
+        //
+        // flush the response buffer.
+        //
+        response.flushBuffer();
+
+        if (verbose) {
+            log("Template \"" + name + "\" request responded. [create/get=" + getMillis + " ms, make=" + makeMillis + " ms]");
+        }
+
+    }
+
+    /**
+     * Override this method to set your variables to the Groovy binding.
+     * <p>
+     * All variables bound the binding are passed to the template source text, 
+     * e.g. the HTML file, when the template is merged.
+     * </p>
+     * <p>
+     * The binding provided by TemplateServlet does already include some default
+     * variables. As of this writing, they are (copied from 
+     * {@link groovy.servlet.ServletBinding}):
+     * <ul>
+     * <li><tt>"request"</tt> : HttpServletRequest </li>
+     * <li><tt>"response"</tt> : HttpServletResponse </li>
+     * <li><tt>"context"</tt> : ServletContext </li>
+     * <li><tt>"application"</tt> : ServletContext </li>
+     * <li><tt>"session"</tt> : request.getSession(<b>false</b>) </li>
+     * </ul>
+     * </p>
+     * <p>
+     * And via implicite hard-coded keywords:
+     * <ul>
+     * <li><tt>"out"</tt> : response.getWriter() </li>
+     * <li><tt>"sout"</tt> : response.getOutputStream() </li>
+     * <li><tt>"html"</tt> : new MarkupBuilder(response.getWriter()) </li>
+     * </ul>
+     * </p>
+     *
+     * <p>Example binding all servlet context variables:
+     * <pre><code>
+     * class Mytlet extends TemplateServlet {
+     * 
+     *   protected void setVariables(ServletBinding binding) {
+     *     // Bind a simple variable
+     *     binding.setVariable("answer", new Long(42));
+     *   
+     *     // Bind all servlet context attributes...
+     *     ServletContext context = (ServletContext) binding.getVariable("context");
+     *     Enumeration enumeration = context.getAttributeNames();
+     *     while (enumeration.hasMoreElements()) {
+     *       String name = (String) enumeration.nextElement();
+     *       binding.setVariable(name, context.getAttribute(name));
+     *     }
+     *   }
+     * 
+     * }
+     * <code></pre>
+     * </p>
+     * 
+     * @param binding
+     *  to be modified
+     */
+    protected void setVariables(ServletBinding binding) {
+        // empty
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/servlet/package.html b/groovy-core/src/main/groovy/servlet/package.html
new file mode 100644
index 0000000..134bc7c
--- /dev/null
+++ b/groovy-core/src/main/groovy/servlet/package.html
@@ -0,0 +1,10 @@
+<html>
+  <head>
+    <title>package groovy.servlet.*</title>
+  </head>
+  <body>
+    <p>
+      Support for Groovlets which are Servlets written as a simple Groovy script.
+    </p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/groovy/sql/CallResultSet.java b/groovy-core/src/main/groovy/sql/CallResultSet.java
new file mode 100644
index 0000000..1982e16
--- /dev/null
+++ b/groovy-core/src/main/groovy/sql/CallResultSet.java
@@ -0,0 +1,32 @@
+
+package groovy.sql;
+
+
+import java.sql.CallableStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * @author rfuller
+ *
+ * Represents a ResultSet retrieved as a callable statement out parameter.
+ */
+class CallResultSet extends GroovyResultSet {
+	int indx;
+	CallableStatement call;
+	ResultSet resultSet;
+	boolean firstCall = true;
+	
+	CallResultSet(CallableStatement call, int indx){
+		this.call = call;
+		this.indx = indx;
+	}
+	
+	protected ResultSet getResultSet() throws SQLException{
+		if(firstCall){
+		    resultSet = (ResultSet) call.getObject(indx+1);
+			firstCall = false;
+		}
+		return resultSet;
+	}
+}
diff --git a/groovy-core/src/main/groovy/sql/DataSet.java b/groovy-core/src/main/groovy/sql/DataSet.java
new file mode 100644
index 0000000..1e27636
--- /dev/null
+++ b/groovy-core/src/main/groovy/sql/DataSet.java
@@ -0,0 +1,213 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.sql;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyRuntimeException;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.stmt.Statement;
+
+/**
+ * Represents an extent of objects
+ * 
+ * @author Chris Stevenson
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class DataSet extends Sql {
+
+    private Closure where;
+    private DataSet parent;
+    private String table;
+    private SqlWhereVisitor visitor;
+    private String sql;
+    private List params;
+
+    public DataSet(Sql sql, Class type) {
+        super(sql);
+        String table = type.getName();
+        int idx = table.lastIndexOf('.');
+        if (idx > 0) {
+            table = table.substring(idx + 1);
+        }
+        this.table = table.toLowerCase();
+    }
+
+    public DataSet(Sql sql, String table) {
+        super(sql);
+        this.table = table;
+    }
+
+    public DataSet(DataSet parent, Closure where) {
+        super(parent);
+        this.table = parent.table;
+        this.parent = parent;
+        this.where = where;
+    }
+
+    public void add(Map values) throws SQLException {
+        StringBuffer buffer = new StringBuffer("insert into ");
+        buffer.append(table);
+        buffer.append(" (");
+        StringBuffer paramBuffer = new StringBuffer();
+        boolean first = true;
+        for (Iterator iter = values.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            String column = entry.getKey().toString();
+            if (first) {
+                first = false;
+                paramBuffer.append("?");
+            }
+            else {
+                buffer.append(", ");
+                paramBuffer.append(", ?");
+            }
+            buffer.append(column);
+        }
+        buffer.append(") values (");
+        buffer.append(paramBuffer.toString());
+        buffer.append(")");
+
+        Connection connection = createConnection();
+        PreparedStatement statement = null;
+        try {
+            statement = connection.prepareStatement(buffer.toString());
+            int i = 1;
+            for (Iterator iter = values.entrySet().iterator(); iter.hasNext();) {
+                Map.Entry entry = (Map.Entry) iter.next();
+                setObject(statement, i++, entry.getValue());
+            }
+            int answer = statement.executeUpdate();
+            if (answer != 1) {
+                log.log(Level.WARNING, "Should have updated 1 row not " + answer + " when trying to add: " + values);
+            }
+        }
+        catch (SQLException e) {
+            log.log(Level.WARNING, "Failed to add row for: " + values, e);
+            throw e;
+        }
+        finally {
+            closeResources(connection, statement);
+        }
+    }
+
+    public DataSet findAll(Closure where) {
+        return new DataSet(this, where);
+    }
+
+    public void each(Closure closure) throws SQLException {
+        eachRow(getSql(), getParameters(), closure);
+    }
+
+    public String getSql() {
+        if (sql == null) {
+            sql = "select * from " + table;
+            if (where != null) {
+                String clause = "";
+                if (parent != null && parent.where != null) {
+                    clause += parent.getSqlVisitor().getWhere() + " and ";
+                }
+                clause += getSqlVisitor().getWhere();
+                if (clause.length() > 0) {
+                    sql += " where " + clause;
+                }
+            }
+        }
+        return sql;
+    }
+
+    public List getParameters() {
+        if (params == null) {
+            params = new ArrayList();
+            if (parent != null && parent.where != null) {
+                params.addAll(parent.getParameters());
+            }
+            params.addAll(getSqlVisitor().getParameters());
+        }
+        return params;
+    }
+
+    protected SqlWhereVisitor getSqlVisitor() {
+        if (visitor == null) {
+            visitor = new SqlWhereVisitor();
+            if (where != null) {
+                ClassNode classNode = where.getMetaClass().getClassNode();
+                if (classNode == null) {
+                    throw new GroovyRuntimeException(
+                        "Could not find the ClassNode for MetaClass: " + where.getMetaClass());
+                }
+                List methods = classNode.getDeclaredMethods("doCall");
+                if (!methods.isEmpty()) {
+                    MethodNode method = (MethodNode) methods.get(0);
+                    if (method != null) {
+                        Statement statement = method.getCode();
+                        if (statement != null) {
+                            statement.visit(visitor);
+                        }
+                    }
+                }
+            }
+        }
+        return visitor;
+    }
+    /*
+     * create a subset of the original dataset
+     */
+    public DataSet createView(Closure criteria) {
+    	return new DataSet(this, criteria);
+    }
+}
diff --git a/groovy-core/src/main/groovy/sql/ExpandedVariable.java b/groovy-core/src/main/groovy/sql/ExpandedVariable.java
new file mode 100644
index 0000000..dee5b30
--- /dev/null
+++ b/groovy-core/src/main/groovy/sql/ExpandedVariable.java
@@ -0,0 +1,10 @@
+package groovy.sql;
+/**
+ * Identifies a variable to be expanded into the
+ * sql string rather than representing a placeholder.
+ * @author rfuller
+ *
+ */
+public interface ExpandedVariable {
+    public Object getObject();
+}
diff --git a/groovy-core/src/main/groovy/sql/GroovyResultSet.java b/groovy-core/src/main/groovy/sql/GroovyResultSet.java
new file mode 100644
index 0000000..e959639
--- /dev/null
+++ b/groovy-core/src/main/groovy/sql/GroovyResultSet.java
@@ -0,0 +1,2614 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.sql;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyObjectSupport;
+import groovy.lang.MissingPropertyException;
+
+import java.math.BigDecimal;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Ref;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.Statement;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Represents an extent of objects
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author <a href="mailto:ivan_ganza@yahoo.com">Ivan Ganza</a>
+ * @version $Revision$
+ * @Author Chris Stevenson
+ */
+public class GroovyResultSet extends GroovyObjectSupport implements ResultSet {
+
+    private ResultSet _resultSet;
+    private boolean updated;
+
+
+    public GroovyResultSet(ResultSet resultSet) {
+        this._resultSet = resultSet;
+    }
+
+    protected GroovyResultSet() {
+    }
+
+    protected ResultSet getResultSet() throws SQLException {
+        return _resultSet;
+    }
+
+    public Object getProperty(String property) {
+        try {
+            return getResultSet().getObject(property);
+        }
+        catch (SQLException e) {
+            throw new MissingPropertyException(property, GroovyResultSet.class, e);
+        }
+    }
+
+    public void setProperty(String property, Object newValue) {
+        try {
+            getResultSet().updateObject(property, newValue);
+            updated = true;
+        }
+        catch (SQLException e) {
+            throw new MissingPropertyException(property, GroovyResultSet.class, e);
+        }
+    }
+
+    /**
+     * Supports integer based subscript operators for accessing at numbered columns
+     * starting at zero. Negative indices are supported, they will count from the last column backwards.
+     *
+     * @param index is the number of the column to look at starting at 1
+     */
+    public Object getAt(int index) throws SQLException {
+        index = normalizeIndex(index);
+        return getResultSet().getObject(index);
+    }
+
+    /**
+     * Supports integer based subscript operators for updating the values of numbered columns
+     * starting at zero. Negative indices are supported, they will count from the last column backwards.
+     *
+     * @param index is the number of the column to look at starting at 1
+     */
+    public void putAt(int index, Object newValue) throws SQLException {
+        index = normalizeIndex(index);
+        getResultSet().updateObject(index, newValue);
+    }
+
+    /**
+     * Adds a new row to this result set
+     *
+     * @param values
+     */
+    public void add(Map values) throws SQLException {
+        getResultSet().moveToInsertRow();
+        for (Iterator iter = values.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            getResultSet().updateObject(entry.getKey().toString(), entry.getValue());
+        }
+        getResultSet().insertRow();
+    }
+
+    /**
+     * Takes a zero based index and convert it into an SQL based 1 based index.
+     * A negative index will count backwards from the last column.
+     *
+     * @param index
+     * @return a JDBC index
+     * @throws SQLException if some exception occurs finding out the column count
+     */
+    protected int normalizeIndex(int index) throws SQLException {
+        if (index < 0) {
+            int columnCount = getResultSet().getMetaData().getColumnCount();
+            do {
+                index += columnCount;
+            }
+            while (index < 0);
+        }
+        return index + 1;
+    }
+
+
+    /**
+     * Call the closure once for each row in the result set.
+     *
+     * @param closure
+     * @throws SQLException
+     */
+    public void eachRow(Closure closure) throws SQLException {
+        while (next()) {
+            closure.call(this);
+        }
+    }
+    // Implementation of java.sql.getResultSet()
+    // ------------------------------------------------------------
+
+    /**
+     * Moves the cursor down one row from its current position.
+     * A <code>getResultSet()</code> cursor is initially positioned
+     * before the first row; the first call to the method
+     * <code>next</code> makes the first row the current row; the
+     * second call makes the second row the current row, and so on.
+     * <p/>
+     * <P>If an input stream is open for the current row, a call
+     * to the method <code>next</code> will
+     * implicitly close it. A <code>getResultSet()</code> object's
+     * warning chain is cleared when a new row is read.
+     *
+     * @return <code>true</code> if the new current row is valid;
+     *         <code>false</code> if there are no more rows
+     * @throws SQLException if a database access error occurs
+     */
+    public boolean next() throws SQLException {
+        if (updated) {
+            getResultSet().updateRow();
+            updated = false;
+        }
+        return getResultSet().next();
+    }
+
+
+    /**
+     * Releases this <code>getResultSet()</code> object's database and
+     * JDBC resources immediately instead of waiting for
+     * this to happen when it is automatically closed.
+     * <p/>
+     * <P><B>Note:</B> A <code>getResultSet()</code> object
+     * is automatically closed by the
+     * <code>Statement</code> object that generated it when
+     * that <code>Statement</code> object is closed,
+     * re-executed, or is used to retrieve the next result from a
+     * sequence of multiple results. A <code>getResultSet()</code> object
+     * is also automatically closed when it is garbage collected.
+     *
+     * @throws SQLException if a database access error occurs
+     */
+    public void close() throws SQLException {
+        getResultSet().close();
+    }
+
+    /**
+     * Reports whether
+     * the last column read had a value of SQL <code>NULL</code>.
+     * Note that you must first call one of the getter methods
+     * on a column to try to read its value and then call
+     * the method <code>wasNull</code> to see if the value read was
+     * SQL <code>NULL</code>.
+     *
+     * @return <code>true</code> if the last column value read was SQL
+     *         <code>NULL</code> and <code>false</code> otherwise
+     * @throws SQLException if a database access error occurs
+     */
+    public boolean wasNull() throws SQLException {
+        return getResultSet().wasNull();
+    }
+
+    //======================================================================
+    // Methods for accessing results by column index
+    //======================================================================
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>String</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>null</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public String getString(int columnIndex) throws SQLException {
+        return getResultSet().getString(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>boolean</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>false</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public boolean getBoolean(int columnIndex) throws SQLException {
+        return getResultSet().getBoolean(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>byte</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>0</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public byte getByte(int columnIndex) throws SQLException {
+        return getResultSet().getByte(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>short</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>0</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public short getShort(int columnIndex) throws SQLException {
+        return getResultSet().getShort(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * an <code>int</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>0</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public int getInt(int columnIndex) throws SQLException {
+        return getResultSet().getInt(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>long</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>0</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public long getLong(int columnIndex) throws SQLException {
+        return getResultSet().getLong(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>float</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>0</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public float getFloat(int columnIndex) throws SQLException {
+        return getResultSet().getFloat(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>double</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>0</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public double getDouble(int columnIndex) throws SQLException {
+        return getResultSet().getDouble(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>java.sql.BigDecimal</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param scale       the number of digits to the right of the decimal point
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>null</code>
+     * @throws SQLException if a database access error occurs
+     * @deprecated
+     */
+    public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException {
+        return getResultSet().getBigDecimal(columnIndex, scale);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>byte</code> array in the Java programming language.
+     * The bytes represent the raw values returned by the driver.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>null</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public byte[] getBytes(int columnIndex) throws SQLException {
+        return getResultSet().getBytes(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>java.sql.Date</code> object in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>null</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public java.sql.Date getDate(int columnIndex) throws SQLException {
+        return getResultSet().getDate(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>java.sql.Time</code> object in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>null</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public java.sql.Time getTime(int columnIndex) throws SQLException {
+        return getResultSet().getTime(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>java.sql.Timestamp</code> object in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>null</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public java.sql.Timestamp getTimestamp(int columnIndex) throws SQLException {
+        return getResultSet().getTimestamp(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a stream of ASCII characters. The value can then be read in chunks from the
+     * stream. This method is particularly
+     * suitable for retrieving large <char>LONGVARCHAR</char> values.
+     * The JDBC driver will
+     * do any necessary conversion from the database format into ASCII.
+     * <p/>
+     * <P><B>Note:</B> All the data in the returned stream must be
+     * read prior to getting the value of any other column. The next
+     * call to a getter method implicitly closes the stream.  Also, a
+     * stream may return <code>0</code> when the method
+     * <code>InputStream.available</code>
+     * is called whether there is data available or not.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return a Java input stream that delivers the database column value
+     *         as a stream of one-byte ASCII characters;
+     *         if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>null</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public java.io.InputStream getAsciiStream(int columnIndex) throws SQLException {
+        return getResultSet().getAsciiStream(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * as a stream of two-byte Unicode characters. The first byte is
+     * the high byte; the second byte is the low byte.
+     * <p/>
+     * The value can then be read in chunks from the
+     * stream. This method is particularly
+     * suitable for retrieving large <code>LONGVARCHAR</code>values.  The
+     * JDBC driver will do any necessary conversion from the database
+     * format into Unicode.
+     * <p/>
+     * <P><B>Note:</B> All the data in the returned stream must be
+     * read prior to getting the value of any other column. The next
+     * call to a getter method implicitly closes the stream.
+     * Also, a stream may return <code>0</code> when the method
+     * <code>InputStream.available</code>
+     * is called, whether there is data available or not.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return a Java input stream that delivers the database column value
+     *         as a stream of two-byte Unicode characters;
+     *         if the value is SQL <code>NULL</code>, the value returned is
+     *         <code>null</code>
+     * @throws SQLException if a database access error occurs
+     * @deprecated use <code>getCharacterStream</code> in place of
+     *             <code>getUnicodeStream</code>
+     */
+    public java.io.InputStream getUnicodeStream(int columnIndex) throws SQLException {
+        return getResultSet().getUnicodeStream(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a binary stream of
+     * uninterpreted bytes. The value can then be read in chunks from the
+     * stream. This method is particularly
+     * suitable for retrieving large <code>LONGVARBINARY</code> values.
+     * <p/>
+     * <P><B>Note:</B> All the data in the returned stream must be
+     * read prior to getting the value of any other column. The next
+     * call to a getter method implicitly closes the stream.  Also, a
+     * stream may return <code>0</code> when the method
+     * <code>InputStream.available</code>
+     * is called whether there is data available or not.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return a Java input stream that delivers the database column value
+     *         as a stream of uninterpreted bytes;
+     *         if the value is SQL <code>NULL</code>, the value returned is
+     *         <code>null</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public java.io.InputStream getBinaryStream(int columnIndex)
+            throws SQLException {
+
+        return getResultSet().getBinaryStream(columnIndex);
+    }
+
+    //======================================================================
+    // Methods for accessing results by column name
+    //======================================================================
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>String</code> in the Java programming language.
+     *
+     * @param columnName the SQL name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>null</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public String getString(String columnName) throws SQLException {
+        return getResultSet().getString(columnName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>boolean</code> in the Java programming language.
+     *
+     * @param columnName the SQL name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>false</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public boolean getBoolean(String columnName) throws SQLException {
+        return getResultSet().getBoolean(columnName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>byte</code> in the Java programming language.
+     *
+     * @param columnName the SQL name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>0</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public byte getByte(String columnName) throws SQLException {
+        return getResultSet().getByte(columnName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>short</code> in the Java programming language.
+     *
+     * @param columnName the SQL name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>0</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public short getShort(String columnName) throws SQLException {
+        return getResultSet().getShort(columnName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * an <code>int</code> in the Java programming language.
+     *
+     * @param columnName the SQL name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>0</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public int getInt(String columnName) throws SQLException {
+        return getResultSet().getInt(columnName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>long</code> in the Java programming language.
+     *
+     * @param columnName the SQL name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>0</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public long getLong(String columnName) throws SQLException {
+        return getResultSet().getLong(columnName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>float</code> in the Java programming language.
+     *
+     * @param columnName the SQL name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>0</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public float getFloat(String columnName) throws SQLException {
+        return getResultSet().getFloat(columnName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>double</code> in the Java programming language.
+     *
+     * @param columnName the SQL name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>0</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public double getDouble(String columnName) throws SQLException {
+        return getResultSet().getDouble(columnName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>java.math.BigDecimal</code> in the Java programming language.
+     *
+     * @param columnName the SQL name of the column
+     * @param scale      the number of digits to the right of the decimal point
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>null</code>
+     * @throws SQLException if a database access error occurs
+     * @deprecated
+     */
+    public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException {
+        return getResultSet().getBigDecimal(columnName, scale);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>byte</code> array in the Java programming language.
+     * The bytes represent the raw values returned by the driver.
+     *
+     * @param columnName the SQL name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>null</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public byte[] getBytes(String columnName) throws SQLException {
+        return getResultSet().getBytes(columnName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>java.sql.Date</code> object in the Java programming language.
+     *
+     * @param columnName the SQL name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>null</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public java.sql.Date getDate(String columnName) throws SQLException {
+        return getResultSet().getDate(columnName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>java.sql.Time</code> object in the Java programming language.
+     *
+     * @param columnName the SQL name of the column
+     * @return the column value;
+     *         if the value is SQL <code>NULL</code>,
+     *         the value returned is <code>null</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public java.sql.Time getTime(String columnName) throws SQLException {
+        return getResultSet().getTime(columnName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * a <code>java.sql.Timestamp</code> object.
+     *
+     * @param columnName the SQL name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     *         value returned is <code>null</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public java.sql.Timestamp getTimestamp(String columnName) throws SQLException {
+        return getResultSet().getTimestamp(columnName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a stream of
+     * ASCII characters. The value can then be read in chunks from the
+     * stream. This method is particularly
+     * suitable for retrieving large <code>LONGVARCHAR</code> values.
+     * The JDBC driver will
+     * do any necessary conversion from the database format into ASCII.
+     * <p/>
+     * <P><B>Note:</B> All the data in the returned stream must be
+     * read prior to getting the value of any other column. The next
+     * call to a getter method implicitly closes the stream. Also, a
+     * stream may return <code>0</code> when the method <code>available</code>
+     * is called whether there is data available or not.
+     *
+     * @param columnName the SQL name of the column
+     * @return a Java input stream that delivers the database column value
+     *         as a stream of one-byte ASCII characters.
+     *         If the value is SQL <code>NULL</code>,
+     *         the value returned is <code>null</code>.
+     * @throws SQLException if a database access error occurs
+     */
+    public java.io.InputStream getAsciiStream(String columnName) throws SQLException {
+        return getResultSet().getAsciiStream(columnName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a stream of two-byte
+     * Unicode characters. The first byte is the high byte; the second
+     * byte is the low byte.
+     * <p/>
+     * The value can then be read in chunks from the
+     * stream. This method is particularly
+     * suitable for retrieving large <code>LONGVARCHAR</code> values.
+     * The JDBC technology-enabled driver will
+     * do any necessary conversion from the database format into Unicode.
+     * <p/>
+     * <P><B>Note:</B> All the data in the returned stream must be
+     * read prior to getting the value of any other column. The next
+     * call to a getter method implicitly closes the stream.
+     * Also, a stream may return <code>0</code> when the method
+     * <code>InputStream.available</code> is called, whether there
+     * is data available or not.
+     *
+     * @param columnName the SQL name of the column
+     * @return a Java input stream that delivers the database column value
+     *         as a stream of two-byte Unicode characters.
+     *         If the value is SQL <code>NULL</code>, the value returned
+     *         is <code>null</code>.
+     * @throws SQLException if a database access error occurs
+     * @deprecated use <code>getCharacterStream</code> instead
+     */
+    public java.io.InputStream getUnicodeStream(String columnName) throws SQLException {
+        return getResultSet().getUnicodeStream(columnName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a stream of uninterpreted
+     * <code>byte</code>s.
+     * The value can then be read in chunks from the
+     * stream. This method is particularly
+     * suitable for retrieving large <code>LONGVARBINARY</code>
+     * values.
+     * <p/>
+     * <P><B>Note:</B> All the data in the returned stream must be
+     * read prior to getting the value of any other column. The next
+     * call to a getter method implicitly closes the stream. Also, a
+     * stream may return <code>0</code> when the method <code>available</code>
+     * is called whether there is data available or not.
+     *
+     * @param columnName the SQL name of the column
+     * @return a Java input stream that delivers the database column value
+     *         as a stream of uninterpreted bytes;
+     *         if the value is SQL <code>NULL</code>, the result is <code>null</code>
+     * @throws SQLException if a database access error occurs
+     */
+    public java.io.InputStream getBinaryStream(String columnName)
+            throws SQLException {
+
+        return getResultSet().getBinaryStream(columnName);
+    }
+
+    //=====================================================================
+    // Advanced features:
+    //=====================================================================
+
+    /**
+     * Retrieves the first warning reported by calls on this
+     * <code>getResultSet()</code> object.
+     * Subsequent warnings on this <code>getResultSet()</code> object
+     * will be chained to the <code>SQLWarning</code> object that
+     * this method returns.
+     * <p/>
+     * <P>The warning chain is automatically cleared each time a new
+     * row is read.  This method may not be called on a <code>getResultSet()</code>
+     * object that has been closed; doing so will cause an
+     * <code>SQLException</code> to be thrown.
+     * <p/>
+     * <B>Note:</B> This warning chain only covers warnings caused
+     * by <code>getResultSet()</code> methods.  Any warning caused by
+     * <code>Statement</code> methods
+     * (such as reading OUT parameters) will be chained on the
+     * <code>Statement</code> object.
+     *
+     * @return the first <code>SQLWarning</code> object reported or
+     *         <code>null</code> if there are none
+     * @throws SQLException if a database access error occurs or this method is
+     *                      called on a closed result set
+     */
+    public SQLWarning getWarnings() throws SQLException {
+        return getResultSet().getWarnings();
+    }
+
+    /**
+     * Clears all warnings reported on this <code>getResultSet()</code> object.
+     * After this method is called, the method <code>getWarnings</code>
+     * returns <code>null</code> until a new warning is
+     * reported for this <code>getResultSet()</code> object.
+     *
+     * @throws SQLException if a database access error occurs
+     */
+    public void clearWarnings() throws SQLException {
+        getResultSet().clearWarnings();
+    }
+
+    /**
+     * Retrieves the name of the SQL cursor used by this <code>getResultSet()</code>
+     * object.
+     * <p/>
+     * <P>In SQL, a result table is retrieved through a cursor that is
+     * named. The current row of a result set can be updated or deleted
+     * using a positioned update/delete statement that references the
+     * cursor name. To insure that the cursor has the proper isolation
+     * level to support update, the cursor's <code>SELECT</code> statement
+     * should be of the form <code>SELECT FOR UPDATE</code>. If
+     * <code>FOR UPDATE</code> is omitted, the positioned updates may fail.
+     * <p/>
+     * <P>The JDBC API supports this SQL feature by providing the name of the
+     * SQL cursor used by a <code>getResultSet()</code> object.
+     * The current row of a <code>getResultSet()</code> object
+     * is also the current row of this SQL cursor.
+     * <p/>
+     * <P><B>Note:</B> If positioned update is not supported, a
+     * <code>SQLException</code> is thrown.
+     *
+     * @return the SQL name for this <code>getResultSet()</code> object's cursor
+     * @throws SQLException if a database access error occurs
+     */
+    public String getCursorName() throws SQLException {
+        return getResultSet().getCursorName();
+    }
+
+    /**
+     * Retrieves the  number, types and properties of
+     * this <code>getResultSet()</code> object's columns.
+     *
+     * @return the description of this <code>getResultSet()</code> object's columns
+     * @throws SQLException if a database access error occurs
+     */
+    public ResultSetMetaData getMetaData() throws SQLException {
+        return getResultSet().getMetaData();
+    }
+
+    /**
+     * <p>Gets the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * an <code>Object</code> in the Java programming language.
+     * <p/>
+     * <p>This method will return the value of the given column as a
+     * Java object.  The type of the Java object will be the default
+     * Java object type corresponding to the column's SQL type,
+     * following the mapping for built-in types specified in the JDBC
+     * specification. If the value is an SQL <code>NULL</code>,
+     * the driver returns a Java <code>null</code>.
+     * <p/>
+     * <p>This method may also be used to read database-specific
+     * abstract data types.
+     * <p/>
+     * In the JDBC 2.0 API, the behavior of method
+     * <code>getObject</code> is extended to materialize
+     * data of SQL user-defined types.  When a column contains
+     * a structured or distinct value, the behavior of this method is as
+     * if it were a call to: <code>getObject(columnIndex,
+     * this.getStatement().getConnection().getTypeMap())</code>.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return a <code>java.lang.Object</code> holding the column value
+     * @throws SQLException if a database access error occurs
+     */
+    public Object getObject(int columnIndex) throws SQLException {
+        return getResultSet().getObject(columnIndex);
+    }
+
+    /**
+     * <p>Gets the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as
+     * an <code>Object</code> in the Java programming language.
+     * <p/>
+     * <p>This method will return the value of the given column as a
+     * Java object.  The type of the Java object will be the default
+     * Java object type corresponding to the column's SQL type,
+     * following the mapping for built-in types specified in the JDBC
+     * specification. If the value is an SQL <code>NULL</code>,
+     * the driver returns a Java <code>null</code>.
+     * <p/>
+     * This method may also be used to read database-specific
+     * abstract data types.
+     * <p/>
+     * In the JDBC 2.0 API, the behavior of the method
+     * <code>getObject</code> is extended to materialize
+     * data of SQL user-defined types.  When a column contains
+     * a structured or distinct value, the behavior of this method is as
+     * if it were a call to: <code>getObject(columnIndex,
+     * this.getStatement().getConnection().getTypeMap())</code>.
+     *
+     * @param columnName the SQL name of the column
+     * @return a <code>java.lang.Object</code> holding the column value
+     * @throws SQLException if a database access error occurs
+     */
+    public Object getObject(String columnName) throws SQLException {
+        return getResultSet().getObject(columnName);
+    }
+
+    //----------------------------------------------------------------
+
+    /**
+     * Maps the given <code>getResultSet()</code> column name to its
+     * <code>getResultSet()</code> column index.
+     *
+     * @param columnName the name of the column
+     * @return the column index of the given column name
+     * @throws SQLException if the <code>getResultSet()</code> object
+     *                      does not contain <code>columnName</code> or a database access error occurs
+     */
+    public int findColumn(String columnName) throws SQLException {
+        return getResultSet().findColumn(columnName);
+    }
+
+    //--------------------------JDBC 2.0-----------------------------------
+
+    //---------------------------------------------------------------------
+    // Getters and Setters
+    //---------------------------------------------------------------------
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a
+     * <code>java.io.Reader</code> object.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return a <code>java.io.Reader</code> object that contains the column
+     *         value; if the value is SQL <code>NULL</code>, the value returned is
+     *         <code>null</code> in the Java programming language.
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public java.io.Reader getCharacterStream(int columnIndex) throws SQLException {
+        return getResultSet().getCharacterStream(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a
+     * <code>java.io.Reader</code> object.
+     *
+     * @param columnName the name of the column
+     * @return a <code>java.io.Reader</code> object that contains the column
+     *         value; if the value is SQL <code>NULL</code>, the value returned is
+     *         <code>null</code> in the Java programming language
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public java.io.Reader getCharacterStream(String columnName) throws SQLException {
+        return getResultSet().getCharacterStream(columnName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a
+     * <code>java.math.BigDecimal</code> with full precision.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value (full precision);
+     *         if the value is SQL <code>NULL</code>, the value returned is
+     *         <code>null</code> in the Java programming language.
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
+        return getResultSet().getBigDecimal(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a
+     * <code>java.math.BigDecimal</code> with full precision.
+     *
+     * @param columnName the column name
+     * @return the column value (full precision);
+     *         if the value is SQL <code>NULL</code>, the value returned is
+     *         <code>null</code> in the Java programming language.
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public BigDecimal getBigDecimal(String columnName) throws SQLException {
+        return getResultSet().getBigDecimal(columnName);
+    }
+
+    //---------------------------------------------------------------------
+    // Traversal/Positioning
+    //---------------------------------------------------------------------
+
+    /**
+     * Retrieves whether the cursor is before the first row in
+     * this <code>getResultSet()</code> object.
+     *
+     * @return <code>true</code> if the cursor is before the first row;
+     *         <code>false</code> if the cursor is at any other position or the
+     *         result set contains no rows
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public boolean isBeforeFirst() throws SQLException {
+        return getResultSet().isBeforeFirst();
+    }
+
+    /**
+     * Retrieves whether the cursor is after the last row in
+     * this <code>getResultSet()</code> object.
+     *
+     * @return <code>true</code> if the cursor is after the last row;
+     *         <code>false</code> if the cursor is at any other position or the
+     *         result set contains no rows
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public boolean isAfterLast() throws SQLException {
+        return getResultSet().isAfterLast();
+    }
+
+    /**
+     * Retrieves whether the cursor is on the first row of
+     * this <code>getResultSet()</code> object.
+     *
+     * @return <code>true</code> if the cursor is on the first row;
+     *         <code>false</code> otherwise
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public boolean isFirst() throws SQLException {
+        return getResultSet().isFirst();
+    }
+
+    /**
+     * Retrieves whether the cursor is on the last row of
+     * this <code>getResultSet()</code> object.
+     * Note: Calling the method <code>isLast</code> may be expensive
+     * because the JDBC driver
+     * might need to fetch ahead one row in order to determine
+     * whether the current row is the last row in the result set.
+     *
+     * @return <code>true</code> if the cursor is on the last row;
+     *         <code>false</code> otherwise
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public boolean isLast() throws SQLException {
+        return getResultSet().isLast();
+    }
+
+    /**
+     * Moves the cursor to the front of
+     * this <code>getResultSet()</code> object, just before the
+     * first row. This method has no effect if the result set contains no rows.
+     *
+     * @throws SQLException if a database access error
+     *                      occurs or the result set type is <code>TYPE_FORWARD_ONLY</code>
+     * @since 1.2
+     */
+    public void beforeFirst() throws SQLException {
+        getResultSet().beforeFirst();
+    }
+
+    /**
+     * Moves the cursor to the end of
+     * this <code>getResultSet()</code> object, just after the
+     * last row. This method has no effect if the result set contains no rows.
+     *
+     * @throws SQLException if a database access error
+     *                      occurs or the result set type is <code>TYPE_FORWARD_ONLY</code>
+     * @since 1.2
+     */
+    public void afterLast() throws SQLException {
+        getResultSet().afterLast();
+    }
+
+    /**
+     * Moves the cursor to the first row in
+     * this <code>getResultSet()</code> object.
+     *
+     * @return <code>true</code> if the cursor is on a valid row;
+     *         <code>false</code> if there are no rows in the result set
+     * @throws SQLException if a database access error
+     *                      occurs or the result set type is <code>TYPE_FORWARD_ONLY</code>
+     * @since 1.2
+     */
+    public boolean first() throws SQLException {
+        return getResultSet().first();
+    }
+
+    /**
+     * Moves the cursor to the last row in
+     * this <code>getResultSet()</code> object.
+     *
+     * @return <code>true</code> if the cursor is on a valid row;
+     *         <code>false</code> if there are no rows in the result set
+     * @throws SQLException if a database access error
+     *                      occurs or the result set type is <code>TYPE_FORWARD_ONLY</code>
+     * @since 1.2
+     */
+    public boolean last() throws SQLException {
+        return getResultSet().last();
+    }
+
+    /**
+     * Retrieves the current row number.  The first row is number 1, the
+     * second number 2, and so on.
+     *
+     * @return the current row number; <code>0</code> if there is no current row
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public int getRow() throws SQLException {
+        return getResultSet().getRow();
+    }
+
+    /**
+     * Moves the cursor to the given row number in
+     * this <code>getResultSet()</code> object.
+     * <p/>
+     * <p>If the row number is positive, the cursor moves to
+     * the given row number with respect to the
+     * beginning of the result set.  The first row is row 1, the second
+     * is row 2, and so on.
+     * <p/>
+     * <p>If the given row number is negative, the cursor moves to
+     * an absolute row position with respect to
+     * the end of the result set.  For example, calling the method
+     * <code>absolute(-1)</code> positions the
+     * cursor on the last row; calling the method <code>absolute(-2)</code>
+     * moves the cursor to the next-to-last row, and so on.
+     * <p/>
+     * <p>An attempt to position the cursor beyond the first/last row in
+     * the result set leaves the cursor before the first row or after
+     * the last row.
+     * <p/>
+     * <p><B>Note:</B> Calling <code>absolute(1)</code> is the same
+     * as calling <code>first()</code>. Calling <code>absolute(-1)</code>
+     * is the same as calling <code>last()</code>.
+     *
+     * @param row the number of the row to which the cursor should move.
+     *            A positive number indicates the row number counting from the
+     *            beginning of the result set; a negative number indicates the
+     *            row number counting from the end of the result set
+     * @return <code>true</code> if the cursor is on the result set;
+     *         <code>false</code> otherwise
+     * @throws SQLException if a database access error
+     *                      occurs, or the result set type is <code>TYPE_FORWARD_ONLY</code>
+     * @since 1.2
+     */
+    public boolean absolute(int row) throws SQLException {
+        return getResultSet().absolute(row);
+    }
+
+    /**
+     * Moves the cursor a relative number of rows, either positive or negative.
+     * Attempting to move beyond the first/last row in the
+     * result set positions the cursor before/after the
+     * the first/last row. Calling <code>relative(0)</code> is valid, but does
+     * not change the cursor position.
+     * <p/>
+     * <p>Note: Calling the method <code>relative(1)</code>
+     * is identical to calling the method <code>next()</code> and
+     * calling the method <code>relative(-1)</code> is identical
+     * to calling the method <code>previous()</code>.
+     *
+     * @param rows an <code>int</code> specifying the number of rows to
+     *             move from the current row; a positive number moves the cursor
+     *             forward; a negative number moves the cursor backward
+     * @return <code>true</code> if the cursor is on a row;
+     *         <code>false</code> otherwise
+     * @throws SQLException if a database access error occurs,
+     *                      there is no current row, or the result set type is
+     *                      <code>TYPE_FORWARD_ONLY</code>
+     * @since 1.2
+     */
+    public boolean relative(int rows) throws SQLException {
+        return getResultSet().relative(rows);
+    }
+
+    /**
+     * Moves the cursor to the previous row in this
+     * <code>getResultSet()</code> object.
+     *
+     * @return <code>true</code> if the cursor is on a valid row;
+     *         <code>false</code> if it is off the result set
+     * @throws SQLException if a database access error
+     *                      occurs or the result set type is <code>TYPE_FORWARD_ONLY</code>
+     * @since 1.2
+     */
+    public boolean previous() throws SQLException {
+        if (updated) {
+            getResultSet().updateRow();
+            updated = false;
+        }
+        return getResultSet().previous();
+    }
+
+    /**
+     * Gives a hint as to the direction in which the rows in this
+     * <code>getResultSet()</code> object will be processed.
+     * The initial value is determined by the
+     * <code>Statement</code> object
+     * that produced this <code>getResultSet()</code> object.
+     * The fetch direction may be changed at any time.
+     *
+     * @param direction an <code>int</code> specifying the suggested
+     *                  fetch direction; one of <code>getResultSet().FETCH_FORWARD</code>,
+     *                  <code>getResultSet().FETCH_REVERSE</code>, or
+     *                  <code>getResultSet().FETCH_UNKNOWN</code>
+     * @throws SQLException if a database access error occurs or
+     *                      the result set type is <code>TYPE_FORWARD_ONLY</code> and the fetch
+     *                      direction is not <code>FETCH_FORWARD</code>
+     * @see Statement#setFetchDirection
+     * @see #getFetchDirection
+     * @since 1.2
+     */
+    public void setFetchDirection(int direction) throws SQLException {
+        getResultSet().setFetchDirection(direction);
+    }
+
+    /**
+     * Retrieves the fetch direction for this
+     * <code>getResultSet()</code> object.
+     *
+     * @return the current fetch direction for this <code>getResultSet()</code> object
+     * @throws SQLException if a database access error occurs
+     * @see #setFetchDirection
+     * @since 1.2
+     */
+    public int getFetchDirection() throws SQLException {
+        return getResultSet().getFetchDirection();
+    }
+
+    /**
+     * Gives the JDBC driver a hint as to the number of rows that should
+     * be fetched from the database when more rows are needed for this
+     * <code>getResultSet()</code> object.
+     * If the fetch size specified is zero, the JDBC driver
+     * ignores the value and is free to make its own best guess as to what
+     * the fetch size should be.  The default value is set by the
+     * <code>Statement</code> object
+     * that created the result set.  The fetch size may be changed at any time.
+     *
+     * @param rows the number of rows to fetch
+     * @throws SQLException if a database access error occurs or the
+     *                      condition <code>0 <= rows <= Statement.getMaxRows()</code> is not satisfied
+     * @see #getFetchSize
+     * @since 1.2
+     */
+    public void setFetchSize(int rows) throws SQLException {
+        getResultSet().setFetchSize(rows);
+    }
+
+    /**
+     * Retrieves the fetch size for this
+     * <code>getResultSet()</code> object.
+     *
+     * @return the current fetch size for this <code>getResultSet()</code> object
+     * @throws SQLException if a database access error occurs
+     * @see #setFetchSize
+     * @since 1.2
+     */
+    public int getFetchSize() throws SQLException {
+        return getResultSet().getFetchSize();
+    }
+
+    /**
+     * Retrieves the type of this <code>getResultSet()</code> object.
+     * The type is determined by the <code>Statement</code> object
+     * that created the result set.
+     *
+     * @return <code>getResultSet().TYPE_FORWARD_ONLY</code>,
+     *         <code>getResultSet().TYPE_SCROLL_INSENSITIVE</code>,
+     *         or <code>getResultSet().TYPE_SCROLL_SENSITIVE</code>
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public int getType() throws SQLException {
+        return getResultSet().getType();
+    }
+
+    /**
+     * Retrieves the concurrency mode of this <code>getResultSet()</code> object.
+     * The concurrency used is determined by the
+     * <code>Statement</code> object that created the result set.
+     *
+     * @return the concurrency type, either
+     *         <code>getResultSet().CONCUR_READ_ONLY</code>
+     *         or <code>getResultSet().CONCUR_UPDATABLE</code>
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public int getConcurrency() throws SQLException {
+        return getResultSet().getConcurrency();
+    }
+
+    //---------------------------------------------------------------------
+    // Updates
+    //---------------------------------------------------------------------
+
+    /**
+     * Retrieves whether the current row has been updated.  The value returned
+     * depends on whether or not the result set can detect updates.
+     *
+     * @return <code>true</code> if both (1) the row has been visibly updated
+     *         by the owner or another and (2) updates are detected
+     * @throws SQLException if a database access error occurs
+     * @see java.sql.DatabaseMetaData#updatesAreDetected
+     * @since 1.2
+     */
+    public boolean rowUpdated() throws SQLException {
+        return getResultSet().rowUpdated();
+    }
+
+    /**
+     * Retrieves whether the current row has had an insertion.
+     * The value returned depends on whether or not this
+     * <code>getResultSet()</code> object can detect visible inserts.
+     *
+     * @return <code>true</code> if a row has had an insertion
+     *         and insertions are detected; <code>false</code> otherwise
+     * @throws SQLException if a database access error occurs
+     * @see java.sql.DatabaseMetaData#insertsAreDetected
+     * @since 1.2
+     */
+    public boolean rowInserted() throws SQLException {
+        return getResultSet().rowInserted();
+    }
+
+    /**
+     * Retrieves whether a row has been deleted.  A deleted row may leave
+     * a visible "hole" in a result set.  This method can be used to
+     * detect holes in a result set.  The value returned depends on whether
+     * or not this <code>getResultSet()</code> object can detect deletions.
+     *
+     * @return <code>true</code> if a row was deleted and deletions are detected;
+     *         <code>false</code> otherwise
+     * @throws SQLException if a database access error occurs
+     * @see java.sql.DatabaseMetaData#deletesAreDetected
+     * @since 1.2
+     */
+    public boolean rowDeleted() throws SQLException {
+        return getResultSet().rowDeleted();
+    }
+
+    /**
+     * Gives a nullable column a null value.
+     * <p/>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code>
+     * or <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateNull(int columnIndex) throws SQLException {
+        getResultSet().updateNull(columnIndex);
+    }
+
+    /**
+     * Updates the designated column with a <code>boolean</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateBoolean(int columnIndex, boolean x) throws SQLException {
+        getResultSet().updateBoolean(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>byte</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateByte(int columnIndex, byte x) throws SQLException {
+        getResultSet().updateByte(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>short</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateShort(int columnIndex, short x) throws SQLException {
+        getResultSet().updateShort(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with an <code>int</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateInt(int columnIndex, int x) throws SQLException {
+        getResultSet().updateInt(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>long</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateLong(int columnIndex, long x) throws SQLException {
+        getResultSet().updateLong(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>float</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateFloat(int columnIndex, float x) throws SQLException {
+        getResultSet().updateFloat(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>double</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateDouble(int columnIndex, double x) throws SQLException {
+        getResultSet().updateDouble(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.math.BigDecimal</code>
+     * value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException {
+        getResultSet().updateBigDecimal(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>String</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateString(int columnIndex, String x) throws SQLException {
+        getResultSet().updateString(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>byte</code> array value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateBytes(int columnIndex, byte x[]) throws SQLException {
+        getResultSet().updateBytes(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.sql.Date</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateDate(int columnIndex, java.sql.Date x) throws SQLException {
+        getResultSet().updateDate(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.sql.Time</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateTime(int columnIndex, java.sql.Time x) throws SQLException {
+        getResultSet().updateTime(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.sql.Timestamp</code>
+     * value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateTimestamp(int columnIndex, java.sql.Timestamp x)
+            throws SQLException {
+        getResultSet().updateTimestamp(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with an ascii stream value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @param length      the length of the stream
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateAsciiStream(int columnIndex,
+                                  java.io.InputStream x,
+                                  int length) throws SQLException {
+        getResultSet().updateAsciiStream(columnIndex, x, length);
+    }
+
+    /**
+     * Updates the designated column with a binary stream value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @param length      the length of the stream
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateBinaryStream(int columnIndex,
+                                   java.io.InputStream x,
+                                   int length) throws SQLException {
+        getResultSet().updateBinaryStream(columnIndex, x, length);
+    }
+
+    /**
+     * Updates the designated column with a character stream value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @param length      the length of the stream
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateCharacterStream(int columnIndex,
+                                      java.io.Reader x,
+                                      int length) throws SQLException {
+        getResultSet().updateCharacterStream(columnIndex, x, length);
+    }
+
+    /**
+     * Updates the designated column with an <code>Object</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @param scale       for <code>java.sql.Types.DECIMA</code>
+     *                    or <code>java.sql.Types.NUMERIC</code> types,
+     *                    this is the number of digits after the decimal point.  For all other
+     *                    types this value will be ignored.
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateObject(int columnIndex, Object x, int scale)
+            throws SQLException {
+        getResultSet().updateObject(columnIndex, x, scale);
+    }
+
+    /**
+     * Updates the designated column with an <code>Object</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateObject(int columnIndex, Object x) throws SQLException {
+        getResultSet().updateObject(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>null</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateNull(String columnName) throws SQLException {
+        getResultSet().updateNull(columnName);
+    }
+
+    /**
+     * Updates the designated column with a <code>boolean</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateBoolean(String columnName, boolean x) throws SQLException {
+        getResultSet().updateBoolean(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>byte</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateByte(String columnName, byte x) throws SQLException {
+        getResultSet().updateByte(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>short</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateShort(String columnName, short x) throws SQLException {
+        getResultSet().updateShort(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with an <code>int</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateInt(String columnName, int x) throws SQLException {
+        getResultSet().updateInt(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>long</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateLong(String columnName, long x) throws SQLException {
+        getResultSet().updateLong(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>float    </code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateFloat(String columnName, float x) throws SQLException {
+        getResultSet().updateFloat(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>double</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateDouble(String columnName, double x) throws SQLException {
+        getResultSet().updateDouble(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.sql.BigDecimal</code>
+     * value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateBigDecimal(String columnName, BigDecimal x) throws SQLException {
+        getResultSet().updateBigDecimal(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>String</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateString(String columnName, String x) throws SQLException {
+        getResultSet().updateString(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with a byte array value.
+     * <p/>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code>
+     * or <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateBytes(String columnName, byte x[]) throws SQLException {
+        getResultSet().updateBytes(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.sql.Date</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateDate(String columnName, java.sql.Date x) throws SQLException {
+        getResultSet().updateDate(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.sql.Time</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateTime(String columnName, java.sql.Time x) throws SQLException {
+        getResultSet().updateTime(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.sql.Timestamp</code>
+     * value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateTimestamp(String columnName, java.sql.Timestamp x)
+            throws SQLException {
+        getResultSet().updateTimestamp(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with an ascii stream value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @param length     the length of the stream
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateAsciiStream(String columnName,
+                                  java.io.InputStream x,
+                                  int length) throws SQLException {
+        getResultSet().updateAsciiStream(columnName, x, length);
+    }
+
+    /**
+     * Updates the designated column with a binary stream value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @param length     the length of the stream
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateBinaryStream(String columnName,
+                                   java.io.InputStream x,
+                                   int length) throws SQLException {
+        getResultSet().updateBinaryStream(columnName, x, length);
+    }
+
+    /**
+     * Updates the designated column with a character stream value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param reader     the <code>java.io.Reader</code> object containing
+     *                   the new column value
+     * @param length     the length of the stream
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateCharacterStream(String columnName,
+                                      java.io.Reader reader,
+                                      int length) throws SQLException {
+        getResultSet().updateCharacterStream(columnName, reader, length);
+    }
+
+    /**
+     * Updates the designated column with an <code>Object</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @param scale      for <code>java.sql.Types.DECIMAL</code>
+     *                   or <code>java.sql.Types.NUMERIC</code> types,
+     *                   this is the number of digits after the decimal point.  For all other
+     *                   types this value will be ignored.
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateObject(String columnName, Object x, int scale)
+            throws SQLException {
+        getResultSet().updateObject(columnName, x, scale);
+    }
+
+    /**
+     * Updates the designated column with an <code>Object</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public void updateObject(String columnName, Object x) throws SQLException {
+        getResultSet().updateObject(columnName, x);
+    }
+
+    /**
+     * Inserts the contents of the insert row into this
+     * <code>getResultSet()</code> object and into the database.
+     * The cursor must be on the insert row when this method is called.
+     *
+     * @throws SQLException if a database access error occurs,
+     *                      if this method is called when the cursor is not on the insert row,
+     *                      or if not all of non-nullable columns in
+     *                      the insert row have been given a value
+     * @since 1.2
+     */
+    public void insertRow() throws SQLException {
+        getResultSet().insertRow();
+    }
+
+    /**
+     * Updates the underlying database with the new contents of the
+     * current row of this <code>getResultSet()</code> object.
+     * This method cannot be called when the cursor is on the insert row.
+     *
+     * @throws SQLException if a database access error occurs or
+     *                      if this method is called when the cursor is on the insert row
+     * @since 1.2
+     */
+    public void updateRow() throws SQLException {
+        getResultSet().updateRow();
+    }
+
+    /**
+     * Deletes the current row from this <code>getResultSet()</code> object
+     * and from the underlying database.  This method cannot be called when
+     * the cursor is on the insert row.
+     *
+     * @throws SQLException if a database access error occurs
+     *                      or if this method is called when the cursor is on the insert row
+     * @since 1.2
+     */
+    public void deleteRow() throws SQLException {
+        getResultSet().deleteRow();
+    }
+
+    /**
+     * Refreshes the current row with its most recent value in
+     * the database.  This method cannot be called when
+     * the cursor is on the insert row.
+     * <p/>
+     * <P>The <code>refreshRow</code> method provides a way for an
+     * application to
+     * explicitly tell the JDBC driver to refetch a row(s) from the
+     * database.  An application may want to call <code>refreshRow</code> when
+     * caching or prefetching is being done by the JDBC driver to
+     * fetch the latest value of a row from the database.  The JDBC driver
+     * may actually refresh multiple rows at once if the fetch size is
+     * greater than one.
+     * <p/>
+     * <P> All values are refetched subject to the transaction isolation
+     * level and cursor sensitivity.  If <code>refreshRow</code> is called after
+     * calling an updater method, but before calling
+     * the method <code>updateRow</code>, then the
+     * updates made to the row are lost.  Calling the method
+     * <code>refreshRow</code> frequently will likely slow performance.
+     *
+     * @throws SQLException if a database access error
+     *                      occurs or if this method is called when the cursor is on the insert row
+     * @since 1.2
+     */
+    public void refreshRow() throws SQLException {
+        getResultSet().refreshRow();
+    }
+
+    /**
+     * Cancels the updates made to the current row in this
+     * <code>getResultSet()</code> object.
+     * This method may be called after calling an
+     * updater method(s) and before calling
+     * the method <code>updateRow</code> to roll back
+     * the updates made to a row.  If no updates have been made or
+     * <code>updateRow</code> has already been called, this method has no
+     * effect.
+     *
+     * @throws SQLException if a database access error
+     *                      occurs or if this method is called when the cursor is
+     *                      on the insert row
+     * @since 1.2
+     */
+    public void cancelRowUpdates() throws SQLException {
+        getResultSet().cancelRowUpdates();
+    }
+
+    /**
+     * Moves the cursor to the insert row.  The current cursor position is
+     * remembered while the cursor is positioned on the insert row.
+     * <p/>
+     * The insert row is a special row associated with an updatable
+     * result set.  It is essentially a buffer where a new row may
+     * be constructed by calling the updater methods prior to
+     * inserting the row into the result set.
+     * <p/>
+     * Only the updater, getter,
+     * and <code>insertRow</code> methods may be
+     * called when the cursor is on the insert row.  All of the columns in
+     * a result set must be given a value each time this method is
+     * called before calling <code>insertRow</code>.
+     * An updater method must be called before a
+     * getter method can be called on a column value.
+     *
+     * @throws SQLException if a database access error occurs
+     *                      or the result set is not updatable
+     * @since 1.2
+     */
+    public void moveToInsertRow() throws SQLException {
+        getResultSet().moveToInsertRow();
+    }
+
+    /**
+     * Moves the cursor to the remembered cursor position, usually the
+     * current row.  This method has no effect if the cursor is not on
+     * the insert row.
+     *
+     * @throws SQLException if a database access error occurs
+     *                      or the result set is not updatable
+     * @since 1.2
+     */
+    public void moveToCurrentRow() throws SQLException {
+        getResultSet().moveToCurrentRow();
+    }
+
+    /**
+     * Retrieves the <code>Statement</code> object that produced this
+     * <code>getResultSet()</code> object.
+     * If the result set was generated some other way, such as by a
+     * <code>DatabaseMetaData</code> method, this method returns
+     * <code>null</code>.
+     *
+     * @return the <code>Statment</code> object that produced
+     *         this <code>getResultSet()</code> object or <code>null</code>
+     *         if the result set was produced some other way
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public Statement getStatement() throws SQLException {
+        return getResultSet().getStatement();
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as an <code>Object</code>
+     * in the Java programming language.
+     * If the value is an SQL <code>NULL</code>,
+     * the driver returns a Java <code>null</code>.
+     * This method uses the given <code>Map</code> object
+     * for the custom mapping of the
+     * SQL structured or distinct type that is being retrieved.
+     *
+     * @param i   the first column is 1, the second is 2, ...
+     * @param map a <code>java.util.Map</code> object that contains the mapping
+     *            from SQL type names to classes in the Java programming language
+     * @return an <code>Object</code> in the Java programming language
+     *         representing the SQL value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public Object getObject(int i, java.util.Map map) throws SQLException {
+        return getResultSet().getObject(i, map);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a <code>Ref</code> object
+     * in the Java programming language.
+     *
+     * @param i the first column is 1, the second is 2, ...
+     * @return a <code>Ref</code> object representing an SQL <code>REF</code>
+     *         value
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public Ref getRef(int i) throws SQLException {
+        return getResultSet().getRef(i);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a <code>Blob</code> object
+     * in the Java programming language.
+     *
+     * @param i the first column is 1, the second is 2, ...
+     * @return a <code>Blob</code> object representing the SQL
+     *         <code>BLOB</code> value in the specified column
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public Blob getBlob(int i) throws SQLException {
+        return getResultSet().getBlob(i);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a <code>Clob</code> object
+     * in the Java programming language.
+     *
+     * @param i the first column is 1, the second is 2, ...
+     * @return a <code>Clob</code> object representing the SQL
+     *         <code>CLOB</code> value in the specified column
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public Clob getClob(int i) throws SQLException {
+        return getResultSet().getClob(i);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as an <code>Array</code> object
+     * in the Java programming language.
+     *
+     * @param i the first column is 1, the second is 2, ...
+     * @return an <code>Array</code> object representing the SQL
+     *         <code>ARRAY</code> value in the specified column
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public Array getArray(int i) throws SQLException {
+        return getResultSet().getArray(i);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as an <code>Object</code>
+     * in the Java programming language.
+     * If the value is an SQL <code>NULL</code>,
+     * the driver returns a Java <code>null</code>.
+     * This method uses the specified <code>Map</code> object for
+     * custom mapping if appropriate.
+     *
+     * @param colName the name of the column from which to retrieve the value
+     * @param map     a <code>java.util.Map</code> object that contains the mapping
+     *                from SQL type names to classes in the Java programming language
+     * @return an <code>Object</code> representing the SQL value in the
+     *         specified column
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public Object getObject(String colName, java.util.Map map) throws SQLException {
+        return getResultSet().getObject(colName, map);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a <code>Ref</code> object
+     * in the Java programming language.
+     *
+     * @param colName the column name
+     * @return a <code>Ref</code> object representing the SQL <code>REF</code>
+     *         value in the specified column
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public Ref getRef(String colName) throws SQLException {
+        return getResultSet().getRef(colName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a <code>Blob</code> object
+     * in the Java programming language.
+     *
+     * @param colName the name of the column from which to retrieve the value
+     * @return a <code>Blob</code> object representing the SQL <code>BLOB</code>
+     *         value in the specified column
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public Blob getBlob(String colName) throws SQLException {
+        return getResultSet().getBlob(colName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a <code>Clob</code> object
+     * in the Java programming language.
+     *
+     * @param colName the name of the column from which to retrieve the value
+     * @return a <code>Clob</code> object representing the SQL <code>CLOB</code>
+     *         value in the specified column
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public Clob getClob(String colName) throws SQLException {
+        return getResultSet().getClob(colName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as an <code>Array</code> object
+     * in the Java programming language.
+     *
+     * @param colName the name of the column from which to retrieve the value
+     * @return an <code>Array</code> object representing the SQL <code>ARRAY</code> value in
+     *         the specified column
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public Array getArray(String colName) throws SQLException {
+        return getResultSet().getArray(colName);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a <code>java.sql.Date</code> object
+     * in the Java programming language.
+     * This method uses the given calendar to construct an appropriate millisecond
+     * value for the date if the underlying database does not store
+     * timezone information.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param cal         the <code>java.util.Calendar</code> object
+     *                    to use in constructing the date
+     * @return the column value as a <code>java.sql.Date</code> object;
+     *         if the value is SQL <code>NULL</code>,
+     *         the value returned is <code>null</code> in the Java programming language
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public java.sql.Date getDate(int columnIndex, Calendar cal) throws SQLException {
+        return getResultSet().getDate(columnIndex, cal);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a <code>java.sql.Date</code> object
+     * in the Java programming language.
+     * This method uses the given calendar to construct an appropriate millisecond
+     * value for the date if the underlying database does not store
+     * timezone information.
+     *
+     * @param columnName the SQL name of the column from which to retrieve the value
+     * @param cal        the <code>java.util.Calendar</code> object
+     *                   to use in constructing the date
+     * @return the column value as a <code>java.sql.Date</code> object;
+     *         if the value is SQL <code>NULL</code>,
+     *         the value returned is <code>null</code> in the Java programming language
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public java.sql.Date getDate(String columnName, Calendar cal) throws SQLException {
+        return getResultSet().getDate(columnName, cal);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a <code>java.sql.Time</code> object
+     * in the Java programming language.
+     * This method uses the given calendar to construct an appropriate millisecond
+     * value for the time if the underlying database does not store
+     * timezone information.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param cal         the <code>java.util.Calendar</code> object
+     *                    to use in constructing the time
+     * @return the column value as a <code>java.sql.Time</code> object;
+     *         if the value is SQL <code>NULL</code>,
+     *         the value returned is <code>null</code> in the Java programming language
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public java.sql.Time getTime(int columnIndex, Calendar cal) throws SQLException {
+        return getResultSet().getTime(columnIndex, cal);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a <code>java.sql.Time</code> object
+     * in the Java programming language.
+     * This method uses the given calendar to construct an appropriate millisecond
+     * value for the time if the underlying database does not store
+     * timezone information.
+     *
+     * @param columnName the SQL name of the column
+     * @param cal        the <code>java.util.Calendar</code> object
+     *                   to use in constructing the time
+     * @return the column value as a <code>java.sql.Time</code> object;
+     *         if the value is SQL <code>NULL</code>,
+     *         the value returned is <code>null</code> in the Java programming language
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public java.sql.Time getTime(String columnName, Calendar cal) throws SQLException {
+        return getResultSet().getTime(columnName, cal);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a <code>java.sql.Timestamp</code> object
+     * in the Java programming language.
+     * This method uses the given calendar to construct an appropriate millisecond
+     * value for the timestamp if the underlying database does not store
+     * timezone information.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param cal         the <code>java.util.Calendar</code> object
+     *                    to use in constructing the timestamp
+     * @return the column value as a <code>java.sql.Timestamp</code> object;
+     *         if the value is SQL <code>NULL</code>,
+     *         the value returned is <code>null</code> in the Java programming language
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public java.sql.Timestamp getTimestamp(int columnIndex, Calendar cal)
+            throws SQLException {
+        return getResultSet().getTimestamp(columnIndex, cal);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a <code>java.sql.Timestamp</code> object
+     * in the Java programming language.
+     * This method uses the given calendar to construct an appropriate millisecond
+     * value for the timestamp if the underlying database does not store
+     * timezone information.
+     *
+     * @param columnName the SQL name of the column
+     * @param cal        the <code>java.util.Calendar</code> object
+     *                   to use in constructing the date
+     * @return the column value as a <code>java.sql.Timestamp</code> object;
+     *         if the value is SQL <code>NULL</code>,
+     *         the value returned is <code>null</code> in the Java programming language
+     * @throws SQLException if a database access error occurs
+     * @since 1.2
+     */
+    public java.sql.Timestamp getTimestamp(String columnName, Calendar cal)
+            throws SQLException {
+        return getResultSet().getTimestamp(columnName, cal);
+    }
+
+    //-------------------------- JDBC 3.0 ----------------------------------------
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a <code>java.net.URL</code>
+     * object in the Java programming language.
+     *
+     * @param columnIndex the index of the column 1 is the first, 2 is the second,...
+     * @return the column value as a <code>java.net.URL</code> object;
+     *         if the value is SQL <code>NULL</code>,
+     *         the value returned is <code>null</code> in the Java programming language
+     * @throws SQLException if a database access error occurs,
+     *                      or if a URL is malformed
+     * @since 1.4
+     */
+    public java.net.URL getURL(int columnIndex) throws SQLException {
+        return getResultSet().getURL(columnIndex);
+    }
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>getResultSet()</code> object as a <code>java.net.URL</code>
+     * object in the Java programming language.
+     *
+     * @param columnName the SQL name of the column
+     * @return the column value as a <code>java.net.URL</code> object;
+     *         if the value is SQL <code>NULL</code>,
+     *         the value returned is <code>null</code> in the Java programming language
+     * @throws SQLException if a database access error occurs
+     *                      or if a URL is malformed
+     * @since 1.4
+     */
+    public java.net.URL getURL(String columnName) throws SQLException {
+        return getResultSet().getURL(columnName);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.sql.Ref</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.4
+     */
+    public void updateRef(int columnIndex, java.sql.Ref x) throws SQLException {
+        getResultSet().updateRef(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.sql.Ref</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.4
+     */
+    public void updateRef(String columnName, java.sql.Ref x) throws SQLException {
+        getResultSet().updateRef(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.sql.Blob</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.4
+     */
+    public void updateBlob(int columnIndex, java.sql.Blob x) throws SQLException {
+        getResultSet().updateBlob(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.sql.Blob</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.4
+     */
+    public void updateBlob(String columnName, java.sql.Blob x) throws SQLException {
+        getResultSet().updateBlob(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.sql.Clob</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.4
+     */
+    public void updateClob(int columnIndex, java.sql.Clob x) throws SQLException {
+        getResultSet().updateClob(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.sql.Clob</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.4
+     */
+    public void updateClob(String columnName, java.sql.Clob x) throws SQLException {
+        getResultSet().updateClob(columnName, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.sql.Array</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x           the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.4
+     */
+    public void updateArray(int columnIndex, java.sql.Array x) throws SQLException {
+        getResultSet().updateArray(columnIndex, x);
+    }
+
+    /**
+     * Updates the designated column with a <code>java.sql.Array</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnName the name of the column
+     * @param x          the new column value
+     * @throws SQLException if a database access error occurs
+     * @since 1.4
+     */
+    public void updateArray(String columnName, java.sql.Array x) throws SQLException {
+        getResultSet().updateArray(columnName, x);
+    }
+}
diff --git a/groovy-core/src/main/groovy/sql/GroovyRowResult.java b/groovy-core/src/main/groovy/sql/GroovyRowResult.java
new file mode 100644
index 0000000..090ab14
--- /dev/null
+++ b/groovy-core/src/main/groovy/sql/GroovyRowResult.java
@@ -0,0 +1,194 @@
+/*
+$Id$
+
+Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+package groovy.sql;
+
+import groovy.lang.GroovyObjectSupport;
+import groovy.lang.MissingPropertyException;
+
+import java.util.*;
+
+/**
+ * Represents an extent of objects.
+ * It's used in the oneRow method to be able to access the result
+ * of a SQL query by the name of the column, or by the column number.
+ *
+ * @version $Revision$
+ * @Author Jean-Louis Berliet
+ */
+public class GroovyRowResult extends GroovyObjectSupport implements Map {
+
+    private LinkedHashMap result;
+
+    public GroovyRowResult(LinkedHashMap result) {
+        this.result = result;
+    }
+
+    /**
+     * Retrieve the value of the property by its name    *
+     *
+     * @param property is the name of the property to look at
+     * @return the value of the property
+     */
+    public Object getProperty(String property) {
+        try {
+            Object value = result.get(property);
+            if (value != null)
+                return value;
+            // if property exists and value is null, return null
+            if (result.containsKey(property))
+                return null;
+            // with some databases/drivers, the columns names are stored uppercase.
+            String propertyUpper = property.toUpperCase();
+            value = result.get(propertyUpper);
+            if (value != null)
+                return value;
+            // if property exists and value is null, return null
+            if (result.containsKey(propertyUpper)) 
+                return null;
+            throw new MissingPropertyException(property, GroovyRowResult.class);
+        }
+        catch (Exception e) {
+            throw new MissingPropertyException(property, GroovyRowResult.class, e);
+        }
+    }
+
+    /**
+     * Retrieve the value of the property by its index.
+     * A negative index will count backwards from the last column.
+     *
+     * @param index is the number of the column to look at
+     * @return the value of the property
+     */
+    public Object getAt(int index) {
+        try {
+            // a negative index will count backwards from the last column.
+            if (index < 0)
+                index += result.size();
+            Iterator it = result.values().iterator();
+            int i = 0;
+            Object obj = null;
+            while ((obj == null) && (it.hasNext())) {
+                if (i == index)
+                    obj = it.next();
+                else
+                    it.next();
+                i++;
+            }
+            return (obj);
+        }
+        catch (Exception e) {
+            throw new MissingPropertyException(Integer.toString(index), GroovyRowResult.class, e);
+        }
+    }
+
+    public String toString() {
+        return (result.toString());
+    }
+
+    /*
+     * The following methods are needed for implementing the Map interface.
+     * They are just delegating the request to the internal LinkedHashMap
+     */
+     
+    public void clear() {
+        result.clear();
+    }
+
+    public boolean containsKey(Object key) {
+        return result.containsKey(key);
+    }
+
+    public boolean containsValue(Object value) {
+        return result.containsValue(value);
+    }
+
+    public Set entrySet() {
+        return result.entrySet();
+    }
+
+    public boolean equals(Object o) {
+        return result.equals(o);
+    }
+
+    public Object get(Object property) {
+        if (property instanceof String)
+            return getProperty((String)property);
+        else
+            return null;
+    }
+
+    public int hashCode() {
+        return result.hashCode();
+    }
+
+    public boolean isEmpty() {
+        return result.isEmpty();
+    }
+
+    public Set keySet() {
+        return result.keySet();
+    }
+
+    public Object put(Object key, Object value) {
+        return result.put(key, value);
+    }
+
+    public void putAll(Map t) {
+        result.putAll(t);
+    }
+
+    public Object remove(Object key) {
+        return result.remove(key);
+    }
+
+    public int size() {
+        return result.size();
+    }
+
+    public Collection values() {
+        return result.values();
+    }
+}
diff --git a/groovy-core/src/main/groovy/sql/InOutParameter.java b/groovy-core/src/main/groovy/sql/InOutParameter.java
new file mode 100644
index 0000000..d5e9bb0
--- /dev/null
+++ b/groovy-core/src/main/groovy/sql/InOutParameter.java
@@ -0,0 +1,11 @@
+
+package groovy.sql;
+
+/**
+ * @author rfuller
+ *
+ * A typed parameter passed to, and returned from a CallableStatement.
+ */
+public interface InOutParameter extends InParameter, OutParameter {
+
+}
diff --git a/groovy-core/src/main/groovy/sql/InParameter.java b/groovy-core/src/main/groovy/sql/InParameter.java
new file mode 100644
index 0000000..33c3f23
--- /dev/null
+++ b/groovy-core/src/main/groovy/sql/InParameter.java
@@ -0,0 +1,20 @@
+
+package groovy.sql;
+
+/**
+ * @author rfuller
+ *
+ * A typed parameter to pass to a query
+ */
+public interface InParameter {
+
+	/**
+	 * The JDBC data type.
+	 */
+	public int getType();
+
+	/**
+	 * The object holding the data value.
+	 */
+	public Object getValue();
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/sql/OutParameter.java b/groovy-core/src/main/groovy/sql/OutParameter.java
new file mode 100644
index 0000000..020d031
--- /dev/null
+++ b/groovy-core/src/main/groovy/sql/OutParameter.java
@@ -0,0 +1,14 @@
+
+package groovy.sql;
+
+/**
+ * @author rfuller
+ *
+ * A parameter to be returned from a CallableStatement.
+ */
+public interface OutParameter {
+	/**
+	 * Get the JDBC datatype for this parameter.
+	 */
+     public int getType();
+}
diff --git a/groovy-core/src/main/groovy/sql/ResultSetOutParameter.java b/groovy-core/src/main/groovy/sql/ResultSetOutParameter.java
new file mode 100644
index 0000000..653eaf4
--- /dev/null
+++ b/groovy-core/src/main/groovy/sql/ResultSetOutParameter.java
@@ -0,0 +1,10 @@
+package groovy.sql;
+
+/**
+ * A ResultSet out parameter.
+ * @author rfuller
+ *
+ */
+public interface ResultSetOutParameter extends OutParameter{
+
+}
diff --git a/groovy-core/src/main/groovy/sql/Sql.java b/groovy-core/src/main/groovy/sql/Sql.java
new file mode 100644
index 0000000..c8dc200
--- /dev/null
+++ b/groovy-core/src/main/groovy/sql/Sql.java
@@ -0,0 +1,1262 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package groovy.sql;
+
+import groovy.lang.Closure;
+import groovy.lang.GString;
+
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.LinkedHashMap;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.sql.DataSource;
+
+/**
+ * Represents an extent of objects
+ *
+ * @author Chris Stevenson
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan </a>
+ * @version $Revision$
+ */
+public class Sql {
+
+    protected Logger log = Logger.getLogger(getClass().getName());
+
+    private DataSource dataSource;
+
+    private Connection useConnection;
+
+    /** lets only warn of using deprecated methods once */
+    private boolean warned;
+
+    // store the last row count for executeUpdate
+    int updateCount = 0;
+
+    /** allows a closure to be used to configure the statement before its use */
+    private Closure configureStatement;
+
+    /**
+     * A helper method which creates a new Sql instance from a JDBC connection
+     * URL
+     *
+     * @param url
+     * @return a new Sql instance with a connection
+     */
+    public static Sql newInstance(String url) throws SQLException {
+        Connection connection = DriverManager.getConnection(url);
+        return new Sql(connection);
+    }
+
+    /**
+     * A helper method which creates a new Sql instance from a JDBC connection
+     * URL
+     *
+     * @param url
+     * @return a new Sql instance with a connection
+     */
+    public static Sql newInstance(String url, Properties properties) throws SQLException {
+        Connection connection = DriverManager.getConnection(url, properties);
+        return new Sql(connection);
+    }
+
+    /**
+     * A helper method which creates a new Sql instance from a JDBC connection
+     * URL and driver class name
+     *
+     * @param url
+     * @return a new Sql instance with a connection
+     */
+    public static Sql newInstance(String url, Properties properties, String driverClassName) throws SQLException, ClassNotFoundException {
+        loadDriver(driverClassName);
+        return newInstance(url, properties);
+    }
+
+    /**
+     * A helper method which creates a new Sql instance from a JDBC connection
+     * URL, username and password
+     *
+     * @param url
+     * @return a new Sql instance with a connection
+     */
+    public static Sql newInstance(String url, String user, String password) throws SQLException {
+        Connection connection = DriverManager.getConnection(url, user, password);
+        return new Sql(connection);
+    }
+
+    /**
+     * A helper method which creates a new Sql instance from a JDBC connection
+     * URL, username, password and driver class name
+     *
+     * @param url
+     * @return a new Sql instance with a connection
+     */
+    public static Sql newInstance(String url, String user, String password, String driverClassName) throws SQLException,
+            ClassNotFoundException {
+        loadDriver(driverClassName);
+        return newInstance(url, user, password);
+    }
+
+    /**
+     * A helper method which creates a new Sql instance from a JDBC connection
+     * URL and driver class name
+     *
+     * @param url
+     * @param driverClassName
+     *            the class name of the driver
+     * @return a new Sql instance with a connection
+     */
+    public static Sql newInstance(String url, String driverClassName) throws SQLException, ClassNotFoundException {
+        loadDriver(driverClassName);
+        return newInstance(url);
+    }
+
+    /**
+     * Attempts to load the JDBC driver on the thread, current or system class
+     * loaders
+     *
+     * @param driverClassName
+     * @throws ClassNotFoundException
+     */
+    public static void loadDriver(String driverClassName) throws ClassNotFoundException {
+        // lets try the thread context class loader first
+        // lets try to use the system class loader
+        try {
+            Class.forName(driverClassName);
+        }
+        catch (ClassNotFoundException e) {
+            try {
+                Thread.currentThread().getContextClassLoader().loadClass(driverClassName);
+            }
+            catch (ClassNotFoundException e2) {
+                // now lets try the classloader which loaded us
+                try {
+                    Sql.class.getClassLoader().loadClass(driverClassName);
+                }
+                catch (ClassNotFoundException e3) {
+                    throw e;
+                }
+            }
+        }
+    }
+
+    public static final OutParameter ARRAY         = new OutParameter(){ public int getType() { return Types.ARRAY; }};
+    public static final OutParameter BIGINT        = new OutParameter(){ public int getType() { return Types.BIGINT; }};
+    public static final OutParameter BINARY        = new OutParameter(){ public int getType() { return Types.BINARY; }};
+    public static final OutParameter BIT           = new OutParameter(){ public int getType() { return Types.BIT; }};
+    public static final OutParameter BLOB          = new OutParameter(){ public int getType() { return Types.BLOB; }};
+    public static final OutParameter BOOLEAN       = new OutParameter(){ public int getType() { return Types.BOOLEAN; }};
+    public static final OutParameter CHAR          = new OutParameter(){ public int getType() { return Types.CHAR; }};
+    public static final OutParameter CLOB          = new OutParameter(){ public int getType() { return Types.CLOB; }};
+    public static final OutParameter DATALINK      = new OutParameter(){ public int getType() { return Types.DATALINK; }};
+    public static final OutParameter DATE          = new OutParameter(){ public int getType() { return Types.DATE; }};
+    public static final OutParameter DECIMAL       = new OutParameter(){ public int getType() { return Types.DECIMAL; }};
+    public static final OutParameter DISTINCT      = new OutParameter(){ public int getType() { return Types.DISTINCT; }};
+    public static final OutParameter DOUBLE        = new OutParameter(){ public int getType() { return Types.DOUBLE; }};
+    public static final OutParameter FLOAT         = new OutParameter(){ public int getType() { return Types.FLOAT; }};
+    public static final OutParameter INTEGER       = new OutParameter(){ public int getType() { return Types.INTEGER; }};
+    public static final OutParameter JAVA_OBJECT   = new OutParameter(){ public int getType() { return Types.JAVA_OBJECT; }};
+    public static final OutParameter LONGVARBINARY = new OutParameter(){ public int getType() { return Types.LONGVARBINARY; }};
+    public static final OutParameter LONGVARCHAR   = new OutParameter(){ public int getType() { return Types.LONGVARCHAR; }};
+    public static final OutParameter NULL          = new OutParameter(){ public int getType() { return Types.NULL; }};
+    public static final OutParameter NUMERIC       = new OutParameter(){ public int getType() { return Types.NUMERIC; }};
+    public static final OutParameter OTHER         = new OutParameter(){ public int getType() { return Types.OTHER; }};
+    public static final OutParameter REAL          = new OutParameter(){ public int getType() { return Types.REAL; }};
+    public static final OutParameter REF           = new OutParameter(){ public int getType() { return Types.REF; }};
+    public static final OutParameter SMALLINT      = new OutParameter(){ public int getType() { return Types.SMALLINT; }};
+    public static final OutParameter STRUCT        = new OutParameter(){ public int getType() { return Types.STRUCT; }};
+    public static final OutParameter TIME          = new OutParameter(){ public int getType() { return Types.TIME; }};
+    public static final OutParameter TIMESTAMP     = new OutParameter(){ public int getType() { return Types.TIMESTAMP; }};
+    public static final OutParameter TINYINT       = new OutParameter(){ public int getType() { return Types.TINYINT; }};
+    public static final OutParameter VARBINARY     = new OutParameter(){ public int getType() { return Types.VARBINARY; }};
+    public static final OutParameter VARCHAR       = new OutParameter(){ public int getType() { return Types.VARCHAR; }};
+
+    public static InParameter ARRAY(Object value) { return in(Types.ARRAY, value); }
+    public static InParameter BIGINT(Object value) { return in(Types.BIGINT, value); }
+    public static InParameter BINARY(Object value) { return in(Types.BINARY, value); }
+    public static InParameter BIT(Object value) { return in(Types.BIT, value); }
+    public static InParameter BLOB(Object value) { return in(Types.BLOB, value); }
+    public static InParameter BOOLEAN(Object value) { return in(Types.BOOLEAN, value); }
+    public static InParameter CHAR(Object value) { return in(Types.CHAR, value); }
+    public static InParameter CLOB(Object value) { return in(Types.CLOB, value); }
+    public static InParameter DATALINK(Object value) { return in(Types.DATALINK, value); }
+    public static InParameter DATE(Object value) { return in(Types.DATE, value); }
+    public static InParameter DECIMAL(Object value) { return in(Types.DECIMAL, value); }
+    public static InParameter DISTINCT(Object value) { return in(Types.DISTINCT, value); }
+    public static InParameter DOUBLE(Object value) { return in(Types.DOUBLE, value); }
+    public static InParameter FLOAT(Object value) { return in(Types.FLOAT, value); }
+    public static InParameter INTEGER(Object value) { return in(Types.INTEGER, value); }
+    public static InParameter JAVA_OBJECT(Object value) { return in(Types.JAVA_OBJECT, value); }
+    public static InParameter LONGVARBINARY(Object value) { return in(Types.LONGVARBINARY, value); }
+    public static InParameter LONGVARCHAR(Object value) { return in(Types.LONGVARCHAR, value); }
+    public static InParameter NULL(Object value) { return in(Types.NULL, value); }
+    public static InParameter NUMERIC(Object value) { return in(Types.NUMERIC, value); }
+    public static InParameter OTHER(Object value) { return in(Types.OTHER, value); }
+    public static InParameter REAL(Object value) { return in(Types.REAL, value); }
+    public static InParameter REF(Object value) { return in(Types.REF, value); }
+    public static InParameter SMALLINT(Object value) { return in(Types.SMALLINT, value); }
+    public static InParameter STRUCT(Object value) { return in(Types.STRUCT, value); }
+    public static InParameter TIME(Object value) { return in(Types.TIME, value); }
+    public static InParameter TIMESTAMP(Object value) { return in(Types.TIMESTAMP, value); }
+    public static InParameter TINYINT(Object value) { return in(Types.TINYINT, value); }
+    public static InParameter VARBINARY(Object value) { return in(Types.VARBINARY, value); }
+    public static InParameter VARCHAR(Object value) { return in(Types.VARCHAR, value); }
+
+    /**
+     * Create a new InParameter
+     * @param type the JDBC data type
+     * @param value the object value
+     * @return an InParameter
+     */
+    public static InParameter in(final int type, final Object value) {
+        return new InParameter() {
+            public int getType() {
+                return type;
+            }
+            public Object getValue() {
+                return value;
+            }
+        };
+    }
+    
+    /**
+     * Create a new OutParameter
+     * @param type the JDBC data type.
+     * @return an OutParameter
+     */
+    public static OutParameter out(final int type){
+        return new OutParameter(){
+            public int getType() {
+                return type;
+            }
+        };
+    }
+    
+    /**
+     * Create an inout parameter using this in parameter.
+     * @param in
+     */
+    public static InOutParameter inout(final InParameter in){
+        return new InOutParameter(){
+            public int getType() {
+                return in.getType();
+            }
+            public Object getValue() {
+                return in.getValue();
+            }            
+        };
+    }
+    
+    /**
+     * Create a new ResultSetOutParameter
+     * @param type the JDBC data type.
+     * @return a ResultSetOutParameter
+     */
+    public static ResultSetOutParameter resultSet(final int type){
+        return new ResultSetOutParameter(){
+            public int getType() {
+                return type;
+            }
+        };
+    }
+        
+    /**
+     * Creates a variable to be expanded in the Sql string rather
+     * than representing an sql parameter.
+     * @param object
+     */
+    public static ExpandedVariable expand(final Object object){
+        return new ExpandedVariable(){
+            public Object getObject() {
+                return object;
+            }};
+    }
+    
+    /**
+     * Constructs an SQL instance using the given DataSource. Each operation
+     * will use a Connection from the DataSource pool and close it when the
+     * operation is completed putting it back into the pool.
+     *
+     * @param dataSource
+     */
+    public Sql(DataSource dataSource) {
+        this.dataSource = dataSource;
+    }
+
+    /**
+     * Construts an SQL instance using the given Connection. It is the callers
+     * responsibility to close the Connection after the Sql instance has been
+     * used. You can do this on the connection object directly or by calling the
+     * {@link java.sql.Connection#close()}  method.
+     *
+     * @param connection
+     */
+    public Sql(Connection connection) {
+        if (connection == null) {
+            throw new NullPointerException("Must specify a non-null Connection");
+        }
+        this.useConnection = connection;
+    }
+
+    public Sql(Sql parent) {
+        this.dataSource = parent.dataSource;
+        this.useConnection = parent.useConnection;
+    }
+
+    public DataSet dataSet(String table) {
+        return new DataSet(this, table);
+    }
+
+    public DataSet dataSet(Class type) {
+        return new DataSet(this, type);
+    }
+
+    /**
+     * Performs the given SQL query calling the closure with the result set
+     */
+    public void query(String sql, Closure closure) throws SQLException {
+        Connection connection = createConnection();
+        Statement statement = connection.createStatement();
+        configure(statement);
+        ResultSet results = null;
+        try {
+            log.fine(sql);
+            results = statement.executeQuery(sql);
+            closure.call(results);
+        }
+        catch (SQLException e) {
+            log.log(Level.FINE, "Failed to execute: " + sql, e);
+            throw e;
+        }
+        finally {
+            closeResources(connection, statement, results);
+        }
+    }
+
+    /**
+     * Performs the given SQL query with parameters calling the closure with the
+     * result set
+     */
+    public void query(String sql, List params, Closure closure) throws SQLException {
+        Connection connection = createConnection();
+        PreparedStatement statement = null;
+        ResultSet results = null;
+        try {
+            log.fine(sql);
+            statement = connection.prepareStatement(sql);
+            setParameters(params, statement);
+            configure(statement);
+            results = statement.executeQuery();
+            closure.call(results);
+        }
+        catch (SQLException e) {
+            log.log(Level.FINE, "Failed to execute: " + sql, e);
+            throw e;
+        }
+        finally {
+            closeResources(connection, statement, results);
+        }
+    }
+
+    /**
+     * Performs the given SQL query calling the closure with the result set
+     */
+    public void query(GString gstring, Closure closure) throws SQLException {
+        List params = getParameters(gstring);
+        String sql = asSql(gstring, params);
+        query(sql, params, closure);
+    }
+
+    /**
+     * @deprecated please use eachRow instead
+     */
+    public void queryEach(String sql, Closure closure) throws SQLException {
+        warnDeprecated();
+        eachRow(sql, closure);
+    }
+
+    /**
+     * Performs the given SQL query calling the closure with each row of the
+     * result set
+     */
+    public void eachRow(String sql, Closure closure) throws SQLException {
+        Connection connection = createConnection();
+        Statement statement = connection.createStatement();
+        configure(statement);
+        ResultSet results = null;
+        try {
+            log.fine(sql);
+            results = statement.executeQuery(sql);
+
+            GroovyResultSet groovyRS = new GroovyResultSet(results);
+            while (groovyRS.next()) {
+                closure.call(groovyRS);
+            }
+        }
+        catch (SQLException e) {
+            log.log(Level.FINE, "Failed to execute: " + sql, e);
+            throw e;
+        }
+        finally {
+            closeResources(connection, statement, results);
+        }
+    }
+
+    /**
+     * @deprecated please use eachRow instead
+     */
+    public void queryEach(String sql, List params, Closure closure) throws SQLException {
+        warnDeprecated();
+        eachRow(sql, params, closure);
+    }
+
+    /**
+     * Performs the given SQL query calling the closure with the result set
+     */
+    public void eachRow(String sql, List params, Closure closure) throws SQLException {
+        Connection connection = createConnection();
+        PreparedStatement statement = null;
+        ResultSet results = null;
+        try {
+            log.fine(sql);
+            statement = connection.prepareStatement(sql);
+            setParameters(params, statement);
+            configure(statement);
+            results = statement.executeQuery();
+
+            GroovyResultSet groovyRS = new GroovyResultSet(results);
+            while (groovyRS.next()) {
+                closure.call(groovyRS);
+            }
+        }
+        catch (SQLException e) {
+            log.log(Level.FINE, "Failed to execute: " + sql, e);
+            throw e;
+        }
+        finally {
+            closeResources(connection, statement, results);
+        }
+    }
+
+    /**
+     * Performs the given SQL query calling the closure with the result set
+     */
+    public void eachRow(GString gstring, Closure closure) throws SQLException {
+        List params = getParameters(gstring);
+        String sql = asSql(gstring, params);
+        eachRow(sql, params, closure);
+    }
+
+    /**
+     * @deprecated please use eachRow instead
+     */
+    public void queryEach(GString gstring, Closure closure) throws SQLException {
+        warnDeprecated();
+        eachRow(gstring, closure);
+    }
+
+    /**
+     * Performs the given SQL query and return the rows of the result set
+     */
+     public List rows(String sql) throws SQLException {
+        List results = new ArrayList();
+        Connection connection = createConnection();
+        Statement statement = connection.createStatement();
+        configure(statement);
+        ResultSet rs = null;
+        try {
+            log.fine(sql);
+            rs = statement.executeQuery(sql);
+            while (rs.next()) {
+                ResultSetMetaData metadata = rs.getMetaData();
+                LinkedHashMap lhm = new LinkedHashMap(metadata.getColumnCount(),1,true);
+                for(int i=1 ; i<=metadata.getColumnCount() ; i++) {
+                      lhm.put(metadata.getColumnName(i),rs.getObject(i));
+                }
+                GroovyRowResult row = new GroovyRowResult(lhm);
+                results.add(row);
+            }
+            return(results);
+        }
+        catch (SQLException e) {
+            log.log(Level.FINE, "Failed to execute: " + sql, e);
+            throw e;
+        }
+        finally {
+            closeResources(connection, statement, rs);
+        }
+    }
+
+    /**
+     * Performs the given SQL query and return the first row of the result set
+     */
+    public Object firstRow(String sql) throws SQLException {
+        List rows = rows(sql);
+        if (rows.isEmpty()) return null;
+        return(rows.get(0));
+    }
+
+    /**
+     * Performs the given SQL query with the list of params and return
+     * the rows of the result set
+     */
+    public List rows(String sql, List params) throws SQLException {
+        List results = new ArrayList();
+        Connection connection = createConnection();
+        PreparedStatement statement = null;
+        ResultSet rs = null;
+        try {
+            log.fine(sql);
+            statement = connection.prepareStatement(sql);
+            setParameters(params, statement);
+            configure(statement);
+            rs = statement.executeQuery();
+            while (rs.next()) {
+                ResultSetMetaData metadata = rs.getMetaData();
+                LinkedHashMap lhm = new LinkedHashMap(metadata.getColumnCount(),1,true);
+                for(int i=1 ; i<=metadata.getColumnCount() ; i++) {
+                    lhm.put(metadata.getColumnName(i),rs.getObject(i));
+                }
+                GroovyRowResult row = new GroovyRowResult(lhm);
+                results.add(row);
+            }
+            return(results);
+        }
+        catch (SQLException e) {
+            log.log(Level.FINE, "Failed to execute: " + sql, e);
+            throw e;
+        }
+        finally {
+            closeResources(connection, statement, rs);
+        }
+    }
+
+     /**
+      * Performs the given SQL query with the list of params and return
+      * the first row of the result set
+      */
+    public Object firstRow(String sql, List params) throws SQLException {
+         List rows = rows(sql, params);
+         if (rows.isEmpty()) return null;
+         return rows.get(0);
+     }
+
+    /**
+     * Executes the given piece of SQL
+     */
+    public boolean execute(String sql) throws SQLException {
+        Connection connection = createConnection();
+        Statement statement = null;
+        try {
+            log.fine(sql);
+            statement = connection.createStatement();
+            configure(statement);
+            boolean isResultSet = statement.execute(sql);
+            this.updateCount = statement.getUpdateCount();
+            return isResultSet;
+        }
+        catch (SQLException e) {
+            log.log(Level.FINE, "Failed to execute: " + sql, e);
+            throw e;
+        }
+        finally {
+            closeResources(connection, statement);
+        }
+    }
+
+    /**
+     * Executes the given SQL update
+     * 
+     * @return the number of rows updated
+     */
+    public int executeUpdate(String sql) throws SQLException {
+        Connection connection = createConnection();
+        Statement statement = null;
+        try {
+            log.fine(sql);
+            statement = connection.createStatement();
+            configure(statement);
+            this.updateCount = statement.executeUpdate(sql);
+            return this.updateCount;
+        }
+        catch (SQLException e) {
+            log.log(Level.FINE, "Failed to execute: " + sql, e);
+            throw e;
+        }
+        finally {
+            closeResources(connection, statement);
+        }
+    }
+
+    /**
+     * Executes the given SQL statement. See {@link #executeInsert(GString)}
+     * for more details. 
+     * @param sql The SQL statement to execute.
+     * @return A list of the auto-generated column values for each
+     * inserted row.
+     */
+    public List executeInsert(String sql) throws SQLException {
+        Connection connection = createConnection();
+        Statement statement = null;
+        try {
+            log.fine(sql);
+            statement = connection.createStatement();
+            configure(statement);
+            boolean hasResultSet = statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
+
+            // Prepare a list to contain the auto-generated column
+            // values, and then fetch them from the statement.
+            List autoKeys = new ArrayList();
+        	ResultSet keys = statement.getGeneratedKeys();
+        	int count = keys.getMetaData().getColumnCount();
+
+        	// Copy the column values into a list of a list.
+        	while (keys.next()) {
+        		List rowKeys = new ArrayList(count);
+        		for (int i = 1; i <= count; i++) {
+        			rowKeys.add(keys.getObject(i));
+        		}
+
+        		autoKeys.add(rowKeys);
+        	}
+
+        	// Store the update count so that it can be retrieved by
+        	// clients, and then return the list of auto-generated
+        	// values.
+        	this.updateCount = statement.getUpdateCount();
+        	return autoKeys;
+        }
+        catch (SQLException e) {
+            log.log(Level.FINE, "Failed to execute: " + sql, e);
+            throw e;
+        }
+        finally {
+            closeResources(connection, statement);
+        }
+    }
+
+    /**
+     * Executes the given piece of SQL with parameters
+     */
+    public boolean execute(String sql, List params) throws SQLException {
+        Connection connection = createConnection();
+        PreparedStatement statement = null;
+        try {
+            log.fine(sql);
+            statement = connection.prepareStatement(sql);
+            setParameters(params, statement);
+            configure(statement);
+            boolean isResultSet = statement.execute();
+            this.updateCount = statement.getUpdateCount();
+            return isResultSet;
+        }
+        catch (SQLException e) {
+            log.log(Level.FINE, "Failed to execute: " + sql, e);
+            throw e;
+        }
+        finally {
+            closeResources(connection, statement);
+        }
+    }
+
+    /**
+     * Executes the given SQL update with parameters
+     * 
+     * @return the number of rows updated
+     */
+    public int executeUpdate(String sql, List params) throws SQLException {
+        Connection connection = createConnection();
+        PreparedStatement statement = null;
+        try {
+            log.fine(sql);
+            statement = connection.prepareStatement(sql);
+            setParameters(params, statement);
+            configure(statement);
+            this.updateCount = statement.executeUpdate();
+            return this.updateCount;
+        }
+        catch (SQLException e) {
+            log.log(Level.FINE, "Failed to execute: " + sql, e);
+            throw e;
+        }
+        finally {
+            closeResources(connection, statement);
+        }
+    }
+
+    /**
+     * Executes the given SQL statement with a particular list of
+     * parameter values. See {@link #executeInsert(GString)} for
+     * more details. 
+     * @param sql The SQL statement to execute.
+     * @param params The parameter values that will be substituted
+     * into the SQL statement's parameter slots.
+     * @return A list of the auto-generated column values for each
+     * inserted row.
+     */
+    public List executeInsert(String sql, List params) throws SQLException {
+        // Now send the SQL to the database.
+        Connection connection = createConnection();
+        PreparedStatement statement = null;
+        try {
+            log.fine(sql);
+
+            // Prepare a statement for the SQL and then execute it.
+            statement = connection.prepareStatement(sql);
+            setParameters(params, statement);
+            configure(statement);
+            boolean hasResultSet = statement.execute(sql, Statement.RETURN_GENERATED_KEYS);
+
+            // Prepare a list to contain the auto-generated column
+            // values, and then fetch them from the statement.
+            List autoKeys = new ArrayList();
+        	ResultSet keys = statement.getGeneratedKeys();
+        	int count = keys.getMetaData().getColumnCount();
+
+        	// Copy the column values into a list of a list.
+        	while (keys.next()) {
+        		List rowKeys = new ArrayList(count);
+        		for (int i = 1; i <= count; i++) {
+        			rowKeys.add(keys.getObject(i));
+        		}
+
+        		autoKeys.add(rowKeys);
+        	}
+
+        	// Store the update count so that it can be retrieved by
+        	// clients, and then return the list of auto-generated
+        	// values.
+        	this.updateCount = statement.getUpdateCount();
+        	return autoKeys;
+        }
+        catch (SQLException e) {
+            log.log(Level.FINE, "Failed to execute: " + sql, e);
+            throw e;
+        }
+        finally {
+            closeResources(connection, statement);
+        }
+    }
+
+    /**
+     * Executes the given SQL with embedded expressions inside
+     */
+    public boolean execute(GString gstring) throws SQLException {
+        List params = getParameters(gstring);
+        String sql = asSql(gstring, params);
+        return execute(sql, params);
+    }
+
+    /**
+     * Executes the given SQL update with embedded expressions inside
+     * 
+     * @return the number of rows updated
+     */
+    public int executeUpdate(GString gstring) throws SQLException {
+        List params = getParameters(gstring);
+        String sql = asSql(gstring, params);
+        return executeUpdate(sql, params);
+    }
+
+    /**
+     * <p>Executes the given SQL with embedded expressions inside, and
+     * returns the values of any auto-generated colums, such as an
+     * autoincrement ID field. These values can be accessed using
+     * array notation. For example, to return the second auto-generated
+     * column value of the third row, use <code>keys[3][1]</code>. The
+     * method is designed to be used with SQL INSERT statements, but is
+     * not limited to them.</p>
+     * <p>The standard use for this method is when a table has an
+     * autoincrement ID column and you want to know what the ID is for
+     * a newly inserted row. In this example, we insert a single row
+     * into a table in which the first column contains the autoincrement
+     * ID:</p>
+     * <pre>
+     *     def sql = Sql.newInstance("jdbc:mysql://localhost:3306/groovy",
+     *                               "user", 
+     *                               "password",
+     *                               "com.mysql.jdbc.Driver")
+     *
+     *     def keys = sql.insert("insert into test_table (INT_DATA, STRING_DATA) "
+     *                           + "VALUES (1, 'Key Largo')")
+     *
+     *     def id = keys[0][0]
+     *
+     *     // 'id' now contains the value of the new row's ID column.
+     *     // It can be used to update an object representation's
+     *     // id attribute for example.
+     *     ...
+     * </pre>
+     * @return A list of column values representing each row's
+     * auto-generated keys.
+     */
+    public List executeInsert(GString gstring) throws SQLException {
+        List params = getParameters(gstring);
+        String sql = asSql(gstring, params);
+        return executeInsert(sql, params);
+    }
+
+    /**
+     * Performs a stored procedure call
+     */
+    public int call(String sql) throws Exception {
+        return call(sql, Collections.EMPTY_LIST);
+    }
+
+    /**
+     * Performs a stored procedure call with the given parameters
+     */
+    public int call(String sql, List params) throws Exception {
+        Connection connection = createConnection();
+        CallableStatement statement = connection.prepareCall(sql);
+        try {
+            log.fine(sql);
+            setParameters(params, statement);
+            configure(statement);
+            return statement.executeUpdate();
+        }
+        catch (SQLException e) {
+            log.log(Level.FINE, "Failed to execute: " + sql, e);
+            throw e;
+        }
+        finally {
+            closeResources(connection, statement);
+        }
+    }
+
+    /**
+     * Performs a stored procedure call with the given parameters.  The closure
+     * is called once with all the out parameters.
+     */
+    public void call(String sql, List params, Closure closure) throws Exception {
+        Connection connection = createConnection();
+        CallableStatement statement = connection.prepareCall(sql);
+        try {
+            log.fine(sql);
+            setParameters(params, statement);
+            statement.execute();
+            List results = new ArrayList();
+            int indx = 0;
+            int inouts = 0;
+            for (Iterator iter = params.iterator(); iter.hasNext();) {
+                Object value = iter.next();
+                if(value instanceof OutParameter){
+                    if(value instanceof ResultSetOutParameter){
+                        results.add(new CallResultSet(statement,indx));
+                    }else{
+                        Object o = statement.getObject(indx+1);
+                        if(o instanceof ResultSet){
+                            results.add(new GroovyResultSet((ResultSet)o));
+                        }else{
+                            results.add(o);
+                        }
+                    }
+                    inouts++;
+                }
+                indx++;
+            }
+            closure.call(results.toArray(new Object[inouts]));
+        } catch (SQLException e) {
+            log.log(Level.WARNING, "Failed to execute: " + sql, e);
+            throw e;
+        } finally {
+            closeResources(connection, statement);
+        }
+    }
+    
+    /**
+     * Performs a stored procedure call with the given parameters
+     */
+    public int call(GString gstring) throws Exception {
+        List params = getParameters(gstring);
+        String sql = asSql(gstring, params);
+        return call(sql, params);
+    }
+
+
+    /**
+     * Performs a stored procedure call with the given parameters,
+     * calling the closure once with all result objects.
+     */
+    public void call(GString gstring, Closure closure) throws Exception {
+        List params = getParameters(gstring);
+        String sql = asSql(gstring,params);
+        call(sql, params,closure);
+    }
+    
+    /**
+     * If this SQL object was created with a Connection then this method closes
+     * the connection. If this SQL object was created from a DataSource then
+     * this method does nothing.
+     * 
+     * @throws SQLException
+     */
+    public void close() throws SQLException {
+        if (useConnection != null) {
+            useConnection.close();
+        }
+    }
+
+    public DataSource getDataSource() {
+        return dataSource;
+    }
+
+
+    public void commit() {
+        try {
+            this.useConnection.commit();
+        }
+        catch (SQLException e) {
+            log.log(Level.SEVERE, "Caught exception commiting connection: " + e, e);
+        }
+    }
+
+    public void rollback() {
+        try {
+            this.useConnection.rollback();
+        }
+        catch (SQLException e) {
+            log.log(Level.SEVERE, "Caught exception rollbacking connection: " + e, e);
+        }
+    }
+
+    /**
+     * @return Returns the updateCount.
+     */
+    public int getUpdateCount() {
+        return updateCount;
+    }
+
+    /**
+     * If this instance was created with a single Connection then the connection
+     * is returned. Otherwise if this instance was created with a DataSource
+     * then this method returns null
+     *
+     * @return the connection wired into this object, or null if this object
+     *         uses a DataSource
+     */
+    public Connection getConnection() {
+        return useConnection;
+    }
+
+
+    /**
+     * Allows a closure to be passed in to configure the JDBC statements before they are executed
+     * to do things like set the query size etc.
+     *
+     * @param configureStatement
+     */
+    public void withStatement(Closure configureStatement) {
+        this.configureStatement = configureStatement;
+    }
+
+    // Implementation methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * @return the SQL version of the given query using ? instead of any
+     *         parameter
+     */
+    protected String asSql(GString gstring, List values) {
+        String[] strings = gstring.getStrings();
+        if (strings.length <= 0) {
+            throw new IllegalArgumentException("No SQL specified in GString: " + gstring);
+        }
+        boolean nulls = false;
+        StringBuffer buffer = new StringBuffer();
+        boolean warned = false;
+        Iterator iter = values.iterator();
+        for (int i = 0; i < strings.length; i++) {
+            String text = strings[i];
+            if (text != null) {
+                buffer.append(text);
+            }
+            if (iter.hasNext()) {
+                Object value = iter.next();
+                if (value != null) {
+                    if(value instanceof ExpandedVariable){
+                        buffer.append(((ExpandedVariable)value).getObject());
+                        iter.remove();
+                    }else{
+                        boolean validBinding = true;
+                        if (i < strings.length - 1) {
+                            String nextText = strings[i + 1];
+                            if ((text.endsWith("\"") || text.endsWith("'")) && (nextText.startsWith("'") || nextText.startsWith("\""))) {
+                                if (!warned) {
+                                    log.warning("In Groovy SQL please do not use quotes around dynamic expressions " +
+                                            "(which start with $) as this means we cannot use a JDBC PreparedStatement " +
+                                            "and so is a security hole. Groovy has worked around your mistake but the security hole is still there. " +
+                                            "The expression so far is: " + buffer.toString() + "?" + nextText);
+                                    warned = true;
+                                }
+                                buffer.append(value);
+                                iter.remove();
+                                validBinding = false;
+                            }
+                        }
+                        if (validBinding) {
+                            buffer.append("?");
+                        }
+                    }
+                }
+                else {
+                    nulls = true;
+                    buffer.append("?'\"?"); // will replace these with nullish
+                    // values
+                }
+            }
+        }
+        String sql = buffer.toString();
+        if (nulls) {
+            sql = nullify(sql);
+        }
+        return sql;
+    }
+
+    /**
+     * replace ?'"? references with NULLish
+     * 
+     * @param sql
+     */
+    protected String nullify(String sql) {
+        /*
+         * Some drivers (Oracle classes12.zip) have difficulty resolving data
+         * type if setObject(null). We will modify the query to pass 'null', 'is
+         * null', and 'is not null'
+         */
+        //could be more efficient by compiling expressions in advance.
+        int firstWhere = findWhereKeyword(sql);
+        if (firstWhere >= 0) {
+            Pattern[] patterns = { Pattern.compile("(?is)^(.{" + firstWhere + "}.*?)!=\\s{0,1}(\\s*)\\?'\"\\?(.*)"),
+                    Pattern.compile("(?is)^(.{" + firstWhere + "}.*?)<>\\s{0,1}(\\s*)\\?'\"\\?(.*)"),
+                    Pattern.compile("(?is)^(.{" + firstWhere + "}.*?[^<>])=\\s{0,1}(\\s*)\\?'\"\\?(.*)"), };
+            String[] replacements = { "$1 is not $2null$3", "$1 is not $2null$3", "$1 is $2null$3", };
+            for (int i = 0; i < patterns.length; i++) {
+                Matcher matcher = patterns[i].matcher(sql);
+                while (matcher.matches()) {
+                    sql = matcher.replaceAll(replacements[i]);
+                    matcher = patterns[i].matcher(sql);
+                }
+            }
+        }
+        return sql.replaceAll("\\?'\"\\?", "null");
+    }
+
+    /**
+     * Find the first 'where' keyword in the sql.
+     * 
+     * @param sql
+     */
+    protected int findWhereKeyword(String sql) {
+        char[] chars = sql.toLowerCase().toCharArray();
+        char[] whereChars = "where".toCharArray();
+        int i = 0;
+        boolean inString = false; //TODO: Cater for comments?
+        boolean noWhere = true;
+        int inWhere = 0;
+        while (i < chars.length && noWhere) {
+            switch (chars[i]) {
+                case '\'':
+                    if (inString) {
+                        inString = false;
+                    }
+                    else {
+                        inString = true;
+                    }
+                    break;
+                default:
+                    if (!inString && chars[i] == whereChars[inWhere]) {
+                        inWhere++;
+                        if (inWhere == whereChars.length) {
+                            return i;
+                        }
+                    }
+            }
+            i++;
+        }
+        return -1;
+    }
+
+    /**
+     * @return extracts the parameters from the expression as a List
+     */
+    protected List getParameters(GString gstring) {
+        Object[] values = gstring.getValues();
+        List answer = new ArrayList(values.length);
+        for (int i = 0; i < values.length; i++) {
+            if (values[i] != null) {
+                answer.add(values[i]);
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Appends the parameters to the given statement
+     */
+    protected void setParameters(List params, PreparedStatement statement) throws SQLException {
+        int i = 1;
+        for (Iterator iter = params.iterator(); iter.hasNext();) {
+            Object value = iter.next();
+            setObject(statement, i++, value);
+        }
+    }
+
+    /**
+     * Strategy method allowing derived classes to handle types differently
+     * such as for CLOBs etc.
+     */
+    protected void setObject(PreparedStatement statement, int i, Object value)
+        throws SQLException {
+        if (value instanceof InParameter  || value instanceof OutParameter) {
+            if(value instanceof InParameter){
+                InParameter in = (InParameter) value;
+                Object val = in.getValue();
+                if (null == val) {
+                    statement.setNull(i, in.getType());
+                } else {
+                    statement.setObject(i, val, in.getType());
+                }
+            }
+            if(value instanceof OutParameter){
+                try{
+                    OutParameter out = (OutParameter)value;
+                    ((CallableStatement)statement).registerOutParameter(i,out.getType());
+                }catch(ClassCastException e){
+                    throw new SQLException("Cannot register out parameter.");
+                }
+            }
+        } else {
+            statement.setObject(i, value);
+        }
+    }
+
+    protected Connection createConnection() throws SQLException {
+        if (dataSource != null) {
+            //Use a doPrivileged here as many different properties need to be
+            // read, and the policy
+            //shouldn't have to list them all.
+            Connection con = null;
+            try {
+                con = (Connection) AccessController.doPrivileged(new PrivilegedExceptionAction() {
+                    public Object run() throws SQLException {
+                        return dataSource.getConnection();
+                    }
+                });
+            }
+            catch (PrivilegedActionException pae) {
+                Exception e = pae.getException();
+                if (e instanceof SQLException) {
+                    throw (SQLException) e;
+                }
+                else {
+                    throw (RuntimeException) e;
+                }
+            }
+            return con;
+        }
+        else {
+            //System.out.println("createConnection returning: " +
+            // useConnection);
+            return useConnection;
+        }
+    }
+
+    protected void closeResources(Connection connection, Statement statement, ResultSet results) {
+        if (results != null) {
+            try {
+                results.close();
+            }
+            catch (SQLException e) {
+                log.log(Level.SEVERE, "Caught exception closing resultSet: " + e, e);
+            }
+        }
+        closeResources(connection, statement);
+    }
+
+    protected void closeResources(Connection connection, Statement statement) {
+        if (statement != null) {
+            try {
+                statement.close();
+            }
+            catch (SQLException e) {
+                log.log(Level.SEVERE, "Caught exception closing statement: " + e, e);
+            }
+        }
+        if (dataSource != null) {
+            try {
+                connection.close();
+            }
+            catch (SQLException e) {
+                log.log(Level.SEVERE, "Caught exception closing connection: " + e, e);
+            }
+        }
+    }
+
+    private void warnDeprecated() {
+        if (!warned) {
+            warned = true;
+            log.warning("queryEach() is deprecated, please use eachRow() instead");
+        }
+    }
+
+    /**
+     * Provides a hook to be able to configure JDBC statements, such as to configure
+     *
+     * @param statement
+     */
+    protected void configure(Statement statement) {
+        if (configureStatement != null) {
+            configureStatement.call(statement);
+        }
+    }
+}
diff --git a/groovy-core/src/main/groovy/sql/SqlWhereVisitor.java b/groovy-core/src/main/groovy/sql/SqlWhereVisitor.java
new file mode 100644
index 0000000..865dc4b
--- /dev/null
+++ b/groovy-core/src/main/groovy/sql/SqlWhereVisitor.java
@@ -0,0 +1,76 @@
+package groovy.sql;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
+
+/**
+ * @author James Strachan
+ * @version $Revision$
+ */
+public class SqlWhereVisitor extends CodeVisitorSupport {
+
+    private StringBuffer buffer = new StringBuffer();
+    private List parameters = new ArrayList();
+
+    public String getWhere() {
+        return buffer.toString();
+    }
+
+    public void visitReturnStatement(ReturnStatement statement) {
+        statement.getExpression().visit(this);
+    }
+
+    public void visitBinaryExpression(BinaryExpression expression) {
+        Expression left = expression.getLeftExpression();
+        Expression right = expression.getRightExpression();
+
+        left.visit(this);
+        buffer.append(" ");
+
+        Token token = expression.getOperation();
+        buffer.append(tokenAsSql(token));
+
+        buffer.append(" ");
+        right.visit(this);
+    }
+
+    public void visitBooleanExpression(BooleanExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitConstantExpression(ConstantExpression expression) {
+        getParameters().add(expression.getValue());
+        buffer.append("?");
+    }
+
+    public void visitPropertyExpression(PropertyExpression expression) {
+        buffer.append(expression.getPropertyAsString());
+    }
+    
+    public List getParameters() {
+        return parameters;
+    }
+    
+    protected String tokenAsSql(Token token) {
+        switch (token.getType()) {
+            case Types.COMPARE_EQUAL :
+                return "=";
+            case Types.LOGICAL_AND :
+                return "and";
+            case Types.LOGICAL_OR :
+                return "or";
+            default :
+                return token.getText();
+        }
+    }
+}
diff --git a/groovy-core/src/main/groovy/sql/package.html b/groovy-core/src/main/groovy/sql/package.html
new file mode 100644
index 0000000..1fd3885
--- /dev/null
+++ b/groovy-core/src/main/groovy/sql/package.html
@@ -0,0 +1,10 @@
+<html>
+  <head>
+    <title>package groovy.sql.*</title>
+  </head>
+  <body>
+    <p>
+      Groovy helper classes for working with SQL data as Groovy objects
+    </p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/groovy/swing/SwingBuilder.java b/groovy-core/src/main/groovy/swing/SwingBuilder.java
new file mode 100644
index 0000000..b386de7
--- /dev/null
+++ b/groovy-core/src/main/groovy/swing/SwingBuilder.java
@@ -0,0 +1,906 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.swing;
+
+import groovy.lang.Closure;
+import groovy.lang.MissingMethodException;
+
+import groovy.model.DefaultTableModel;
+import groovy.model.ValueHolder;
+import groovy.model.ValueModel;
+
+import groovy.swing.impl.ComponentFacade;
+import groovy.swing.impl.ContainerFacade;
+import groovy.swing.impl.DefaultAction;
+import groovy.swing.impl.Factory;
+import groovy.swing.impl.Startable;
+import groovy.swing.impl.TableLayout;
+import groovy.swing.impl.TableLayoutCell;
+import groovy.swing.impl.TableLayoutRow;
+
+import groovy.util.BuilderSupport;
+
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Dialog;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.GridLayout;
+import java.awt.LayoutManager;
+import java.awt.Window;
+
+import java.text.Format;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.swing.AbstractButton;
+import javax.swing.Action;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.DefaultBoundedRangeModel;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JColorChooser;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JDesktopPane;
+import javax.swing.JDialog;
+import javax.swing.JEditorPane;
+import javax.swing.JFileChooser;
+import javax.swing.JFormattedTextField;
+import javax.swing.JFrame;
+import javax.swing.JInternalFrame;
+import javax.swing.JLabel;
+import javax.swing.JLayeredPane;
+import javax.swing.JList;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JPopupMenu;
+import javax.swing.JProgressBar;
+import javax.swing.JRadioButton;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.JScrollBar;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JSlider;
+import javax.swing.JSpinner;
+import javax.swing.JSplitPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTable;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.JTextPane;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+import javax.swing.JToolTip;
+import javax.swing.JTree;
+import javax.swing.JViewport;
+import javax.swing.JWindow;
+import javax.swing.KeyStroke;
+import javax.swing.OverlayLayout;
+import javax.swing.RootPaneContainer;
+import javax.swing.SpinnerDateModel;
+import javax.swing.SpinnerListModel;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.SpringLayout;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableModel;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * A helper class for creating Swing widgets using GroovyMarkup
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class SwingBuilder extends BuilderSupport {
+
+    private Logger log = Logger.getLogger(getClass().getName());
+    private Map factories = new HashMap();
+    private Object constraints;
+    private Map passThroughNodes = new HashMap();
+    private Map widgets = new HashMap();
+    // tracks all containing windows, for auto-owned dialogs
+    private LinkedList containingWindows = new LinkedList();
+
+    public SwingBuilder() {
+        registerWidgets();
+    }
+
+    public Object getProperty(String name) {
+        Object widget = widgets.get(name);
+        if (widget == null) {
+            return super.getProperty(name);
+        }
+        return widget;
+    }
+
+    protected void setParent(Object parent, Object child) {
+        if (child instanceof Action) {
+            Action action = (Action) child;
+            try {
+                InvokerHelper.setProperty(parent, "action", action);
+            } catch (RuntimeException re) {
+                // must not have an action property...
+                // so we ignore it and go on
+            }
+            Object keyStroke = action.getValue("KeyStroke");
+            //System.out.println("keystroke: " + keyStroke + " for: " + action);
+            if (parent instanceof JComponent) {
+                JComponent component = (JComponent) parent;
+                KeyStroke stroke = null;
+                if (keyStroke instanceof String) {
+                    stroke = KeyStroke.getKeyStroke((String) keyStroke);
+                }
+                else if (keyStroke instanceof KeyStroke) {
+                    stroke = (KeyStroke) keyStroke;
+                }
+                if (stroke != null) {
+                    String key = action.toString();
+                    component.getInputMap().put(stroke, key);
+                    component.getActionMap().put(key, action);
+                }
+            }
+        }
+        else if (child instanceof LayoutManager) {
+            if (parent instanceof RootPaneContainer) {
+                RootPaneContainer rpc = (RootPaneContainer) parent;
+                parent = rpc.getContentPane();
+            }
+            InvokerHelper.setProperty(parent, "layout", child);
+        }
+        else if (child instanceof JToolTip && parent instanceof JComponent) {
+            ((JToolTip)child).setComponent((JComponent)parent);
+        }
+        else if (parent instanceof JTable && child instanceof TableColumn) {
+            JTable table = (JTable) parent;
+            TableColumn column = (TableColumn) child;
+            table.addColumn(column);
+        }
+        else if (parent instanceof JTabbedPane && child instanceof Component) {
+            JTabbedPane tabbedPane = (JTabbedPane) parent;
+            tabbedPane.add((Component)child);
+        } 
+        else if (child instanceof Window) {
+            // do nothing.  owner of window is set elsewhere, and this 
+            // shouldn't get added to any parent as a child 
+            // if it is a top level component anyway
+        }
+        else { 
+            Component component = null;
+            if (child instanceof Component) {
+                component = (Component) child;
+            }
+            else if (child instanceof ComponentFacade) {
+                ComponentFacade facade = (ComponentFacade) child;
+                component = facade.getComponent();
+            }
+            if (component != null) {
+                if (parent instanceof JFrame && component instanceof JMenuBar) {
+                    JFrame frame = (JFrame) parent;
+                    frame.setJMenuBar((JMenuBar) component);
+                }
+                else if (parent instanceof RootPaneContainer) {
+                    RootPaneContainer rpc = (RootPaneContainer) parent;
+                    if (constraints != null) {
+                    	rpc.getContentPane().add(component, constraints);
+                    } else {
+                    	rpc.getContentPane().add(component);
+                    }
+                }
+                else if (parent instanceof JScrollPane) {
+                    JScrollPane scrollPane = (JScrollPane) parent;
+                    if (child instanceof JViewport) {
+                        scrollPane.setViewport((JViewport)component);
+                    } 
+                    else {
+                        scrollPane.setViewportView(component);
+                    }
+                }
+                else if (parent instanceof JSplitPane) {
+                    JSplitPane splitPane = (JSplitPane) parent;
+                    if (splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
+                        if (splitPane.getTopComponent() == null) {
+                            splitPane.setTopComponent(component);
+                        }
+                        else {
+                            splitPane.setBottomComponent(component);
+                        }
+                    }
+                    else {
+                        if (splitPane.getLeftComponent() == null) {
+                            splitPane.setLeftComponent(component);
+                        }
+                        else {
+                            splitPane.setRightComponent(component);
+                        }
+                    }
+                }
+                else if (parent instanceof JMenuBar && component instanceof JMenu) {
+                    JMenuBar menuBar = (JMenuBar) parent;
+                    menuBar.add((JMenu) component);
+                }
+                else if (parent instanceof Container) {
+                    Container container = (Container) parent;
+                    if (constraints != null) {
+                        container.add(component, constraints);
+                    }
+                    else {
+                        container.add(component);
+                    }
+                }
+                else if (parent instanceof ContainerFacade) {
+                    ContainerFacade facade = (ContainerFacade) parent;
+                    facade.addComponent(component);
+                }
+            }
+        }
+    }
+
+    protected void nodeCompleted(Object parent, Object node) {
+        // set models after the node has been completed
+        if (node instanceof TableModel && parent instanceof JTable) {
+            JTable table = (JTable) parent;
+            TableModel model = (TableModel) node;
+            table.setModel(model);
+        }
+        if (node instanceof Startable) {
+            Startable startable = (Startable) node;
+            startable.start();
+        }
+        if (node instanceof Window) {
+            if (!containingWindows.isEmpty() && containingWindows.getLast() == node) {
+                containingWindows.removeLast();
+            }
+        }
+    }
+
+    protected Object createNode(Object name) {
+        return createNode(name, Collections.EMPTY_MAP);
+    }
+
+    protected Object createNode(Object name, Object value) {
+        if (passThroughNodes.containsKey(name) && (value != null) && ((Class)passThroughNodes.get(name)).isAssignableFrom(value.getClass())) {
+            // value may need to go into containing windows list
+            if (value instanceof Window) {
+                containingWindows.add(value);
+            }
+            return value;
+        }
+        else if (value instanceof String) {
+            Object widget = createNode(name);
+            if (widget != null) {
+                InvokerHelper.invokeMethod(widget, "setText", value);
+            }
+            return widget;
+        }
+        else {
+        	throw new MissingMethodException((String) name, getClass(), new Object[] {value}, false);
+        }
+    }
+
+    protected Object createNode(Object name, Map attributes, Object value) {
+        if (passThroughNodes.containsKey(name) && (value != null) && ((Class)passThroughNodes.get(name)).isAssignableFrom(value.getClass())) {
+            // value may need to go into containing windows list
+            if (value instanceof Window) {
+                containingWindows.add(value);
+            }
+            handleWidgetAttributes(value, attributes);
+            return value;
+        }
+        else { 
+            Object widget = createNode(name, attributes);
+            if (widget != null) {
+                InvokerHelper.invokeMethod(widget, "setText", value.toString());
+            }
+            return widget;
+        }
+    }
+    
+    protected Object createNode(Object name, Map attributes) {
+        String widgetName = (String) attributes.remove("id");
+        constraints = attributes.remove("constraints");
+        Object widget = null;
+        if (passThroughNodes.containsKey(name)) {
+            widget = attributes.get(name);
+            if ((widget != null) && ((Class)passThroughNodes.get(name)).isAssignableFrom(widget.getClass())) {
+                // value may need to go into containing windows list
+                if (widget instanceof Window) {
+                    containingWindows.add(widget);
+                }
+                attributes.remove(name);
+            }
+            else {
+                widget = null;
+            }
+        }
+        if (widget == null) {
+            Factory factory = (Factory) factories.get(name);
+            if (factory != null) {
+                try {
+                    widget = factory.newInstance(attributes);
+                    if (widgetName != null) {
+                        widgets.put(widgetName, widget);
+                    }
+                    if (widget == null) {
+                        log.log(Level.WARNING, "Factory for name: " + name + " returned null");
+                    }
+                    else {
+                        if (log.isLoggable(Level.FINE)) {
+                            log.fine("For name: " + name + " created widget: " + widget);
+                        }
+                    }
+                }
+                catch (Exception e) {
+                    throw new RuntimeException("Failed to create component for" + name + " reason: " + e, e);
+                }
+            }
+            else {
+                log.log(Level.WARNING, "Could not find match for name: " + name);
+            }
+        }
+        handleWidgetAttributes(widget, attributes);
+        return widget;
+    }
+
+    protected void handleWidgetAttributes(Object widget, Map attributes) {
+        if (widget != null) {
+            if (widget instanceof Action) {
+                /** @todo we could move this custom logic into the MetaClass for Action */
+                Action action = (Action) widget;
+
+                Closure closure = (Closure) attributes.remove("closure");
+                if (closure != null && action instanceof DefaultAction) {
+                    DefaultAction defaultAction = (DefaultAction) action;
+                    defaultAction.setClosure(closure);
+                }
+
+                Object accel = attributes.remove("accelerator");
+                KeyStroke stroke = null;
+                if (accel instanceof KeyStroke) {
+                    stroke = (KeyStroke) accel;
+                } else if (accel != null) {
+                    stroke = KeyStroke.getKeyStroke(accel.toString());
+                }
+                action.putValue(Action.ACCELERATOR_KEY, stroke);
+
+                Object mnemonic = attributes.remove("mnemonic");
+                if ((mnemonic != null) && !(mnemonic instanceof Number)) {
+                    mnemonic = new Integer(mnemonic.toString().charAt(0));
+                }
+                action.putValue(Action.MNEMONIC_KEY, mnemonic);
+
+                for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
+                    Map.Entry entry = (Map.Entry) iter.next();
+                    String actionName = (String) entry.getKey();    // todo dk: misleading naming. this can be any property name
+
+                    // typically standard Action names start with upper case, so lets upper case it            
+                    actionName = capitalize(actionName);            // todo dk: in general, this shouldn't be capitalized
+                    Object value = entry.getValue();
+
+                    action.putValue(actionName, value);
+                }
+
+            }
+            else {
+                // some special cases...
+                if (attributes.containsKey("buttonGroup")) {
+                    Object o = attributes.get("buttonGroup");
+                    if ((o instanceof ButtonGroup) && (widget instanceof AbstractButton)) {
+                        ((AbstractButton)widget).getModel().setGroup((ButtonGroup)o);
+                        attributes.remove("buttonGroup");
+                    }
+                }
+
+                // this next statement nd if/else is a workaround until GROOVY-305 is fixed
+                Object mnemonic = attributes.remove("mnemonic");
+                if ((mnemonic != null) && (mnemonic instanceof Number)) {
+                    InvokerHelper.setProperty(widget, "mnemonic", new Character((char)((Number)mnemonic).intValue()));
+                } 
+                else if (mnemonic != null) {
+                    InvokerHelper.setProperty(widget, "mnemonic", new Character(mnemonic.toString().charAt(0)));
+                } 
+
+                // set the properties
+                for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
+                    Map.Entry entry = (Map.Entry) iter.next();
+                    String property = entry.getKey().toString();
+                    Object value = entry.getValue();
+                    InvokerHelper.setProperty(widget, property, value);
+                }
+            }
+        }
+    }
+
+    protected String capitalize(String text) {
+        char ch = text.charAt(0);
+        if (Character.isUpperCase(ch)) {
+            return text;
+        }
+        StringBuffer buffer = new StringBuffer(text.length());
+        buffer.append(Character.toUpperCase(ch));
+        buffer.append(text.substring(1));
+        return buffer.toString();
+    }
+
+    protected void registerWidgets() {
+        //
+        // non-widget support classes
+        //
+        registerBeanFactory("action", DefaultAction.class);
+        passThroughNodes.put("action", javax.swing.Action.class);
+        registerBeanFactory("buttonGroup", ButtonGroup.class);
+        registerFactory("map", new Factory() {      // todo dk: is that still needed?
+            public Object newInstance(Map properties)
+                throws InstantiationException, InstantiationException, IllegalAccessException {
+                return properties;
+            }
+        });
+        // ulimate pass through type
+        passThroughNodes.put("widget", java.awt.Component.class);
+
+        //
+        // standalone window classes
+        //
+        registerFactory("dialog", new Factory() {
+            public Object newInstance(Map properties)
+                throws InstantiationException, InstantiationException, IllegalAccessException {
+                return createDialog(properties);
+            }
+        });
+        registerFactory("frame", new Factory() {
+            public Object newInstance(Map properties)
+                throws InstantiationException, InstantiationException, IllegalAccessException {
+                return createFrame(properties);
+            }
+        });
+        registerBeanFactory("fileChooser", JFileChooser.class);
+        registerFactory("frame", new Factory() {        // todo dk: frame registered twice ???
+            public Object newInstance(Map properties)
+                throws InstantiationException, InstantiationException, IllegalAccessException {
+                return createFrame(properties);
+            }
+        });
+        registerBeanFactory("optionPane", JOptionPane.class);
+        registerFactory("window", new Factory() {
+            public Object newInstance(Map properties)
+                throws InstantiationException, InstantiationException, IllegalAccessException {
+                return createWindow(properties);
+            }
+        });
+        
+        //
+        // widgets
+        //
+        registerBeanFactory("button", JButton.class);
+        registerBeanFactory("checkBox", JCheckBox.class);
+        registerBeanFactory("checkBoxMenuItem", JCheckBoxMenuItem.class);
+        registerBeanFactory("colorChooser", JColorChooser.class);
+        registerFactory("comboBox", new Factory() {
+            public Object newInstance(Map properties)
+                throws InstantiationException, InstantiationException, IllegalAccessException {
+                return createComboBox(properties);
+            }
+        });
+        registerBeanFactory("desktopPane", JDesktopPane.class);
+        registerBeanFactory("editorPane", JEditorPane.class);
+        registerFactory("formattedTextField", new Factory() {
+            public Object newInstance(Map properties)
+                throws InstantiationException, InstantiationException, IllegalAccessException {
+                return createFormattedTextField(properties);
+            }
+        });
+        registerBeanFactory("internalFrame", JInternalFrame.class);
+        registerBeanFactory("label", JLabel.class);
+        registerBeanFactory("layeredPane", JLayeredPane.class);
+        registerBeanFactory("list", JList.class);
+        registerBeanFactory("menu", JMenu.class);
+        registerBeanFactory("menuBar", JMenuBar.class);
+        registerBeanFactory("menuItem", JMenuItem.class);
+        registerBeanFactory("panel", JPanel.class);
+        registerBeanFactory("passwordField", JPasswordField.class);
+        registerBeanFactory("popupMenu", JPopupMenu.class);
+        registerBeanFactory("progressBar", JProgressBar.class);
+        registerBeanFactory("radioButton", JRadioButton.class);
+        registerBeanFactory("radioButtonMenuItem", JRadioButtonMenuItem.class);
+        registerBeanFactory("scrollBar", JScrollBar.class);
+        registerBeanFactory("scrollPane", JScrollPane.class);
+        registerBeanFactory("separator", JSeparator.class);
+        registerBeanFactory("slider", JSlider.class);
+        registerBeanFactory("spinner", JSpinner.class);
+        registerFactory("splitPane", new Factory() {
+            public Object newInstance(Map properties) {
+                JSplitPane answer = new JSplitPane();
+                answer.setLeftComponent(null);
+                answer.setRightComponent(null);
+                answer.setTopComponent(null);
+                answer.setBottomComponent(null);
+                return answer;
+            }
+        });
+        registerBeanFactory("tabbedPane", JTabbedPane.class);
+        registerBeanFactory("table", JTable.class);
+        registerBeanFactory("textArea", JTextArea.class);
+        registerBeanFactory("textPane", JTextPane.class);
+        registerBeanFactory("textField", JTextField.class);
+        registerBeanFactory("toggleButton", JToggleButton.class);
+        registerBeanFactory("toolBar", JToolBar.class);
+        //registerBeanFactory("tooltip", JToolTip.class); // doens't work, user toolTipText property
+        registerBeanFactory("tree", JTree.class);
+        registerBeanFactory("viewport", JViewport.class); // sub class?
+
+        //
+        // MVC models   
+        //
+        registerBeanFactory("boundedRangeModel", DefaultBoundedRangeModel.class);
+
+        // spinner models
+	registerBeanFactory("spinnerDateModel", SpinnerDateModel.class);
+        registerBeanFactory("spinnerListModel", SpinnerListModel.class);
+        registerBeanFactory("spinnerNumberModel", SpinnerNumberModel.class);
+
+	// table models
+        registerFactory("tableModel", new Factory() {
+            public Object newInstance(Map properties) {
+                ValueModel model = (ValueModel) properties.remove("model");
+                if (model == null) {
+                    Object list = properties.remove("list");
+                    if (list == null) {
+                        list = new ArrayList();
+                    }
+                    model = new ValueHolder(list);
+                }
+                return new DefaultTableModel(model);
+            }
+        });
+        passThroughNodes.put("tableModel", javax.swing.table.TableModel.class);
+
+        registerFactory("propertyColumn", new Factory() {
+            public Object newInstance(Map properties) {
+                Object current = getCurrent();
+                if (current instanceof DefaultTableModel) {
+                    DefaultTableModel model = (DefaultTableModel) current;
+                    Object header = properties.remove("header");
+                    if (header == null) {
+                        header = "";
+                    }
+                    String property = (String) properties.remove("propertyName");
+                    if (property == null) {
+                        throw new IllegalArgumentException("Must specify a property for a propertyColumn");
+                    }
+                    Class type = (Class) properties.remove("type");
+                    if (type == null) {
+                        type = Object.class;
+                    }
+                    return model.addPropertyColumn(header, property, type);
+                }
+                else {
+                    throw new RuntimeException("propertyColumn must be a child of a tableModel");
+                }
+            }
+        });
+
+        registerFactory("closureColumn", new Factory() {
+            public Object newInstance(Map properties) {
+                Object current = getCurrent();
+                if (current instanceof DefaultTableModel) {
+                    DefaultTableModel model = (DefaultTableModel) current;
+                    Object header = properties.remove("header");
+                    if (header == null) {
+                        header = "";
+                    }
+                    Closure readClosure = (Closure) properties.remove("read");
+                    if (readClosure == null) {
+                        throw new IllegalArgumentException("Must specify 'read' Closure property for a closureColumn");
+                    }
+                    Closure writeClosure = (Closure) properties.remove("write");
+                    Class type = (Class) properties.remove("type");
+                    if (type == null) {
+                        type = Object.class;
+                    }
+                    return model.addClosureColumn(header, readClosure, writeClosure, type);
+                }
+                else {
+                    throw new RuntimeException("propertyColumn must be a child of a tableModel");
+                }
+            }
+        });
+
+
+        //Standard Layouts
+        registerBeanFactory("borderLayout", BorderLayout.class);
+        registerBeanFactory("cardLayout", CardLayout.class);
+        registerBeanFactory("flowLayout", FlowLayout.class);
+        registerBeanFactory("gridBagLayout", GridBagLayout.class);
+        registerBeanFactory("gridLayout", GridLayout.class);
+        registerBeanFactory("overlayLayout", OverlayLayout.class);
+        registerBeanFactory("springLayout", SpringLayout.class);
+        registerBeanFactory("gridBagConstraints", GridBagConstraints.class);
+        registerBeanFactory("gbc", GridBagConstraints.class); // shortcut name
+
+        // box layout
+        registerFactory("boxLayout", new Factory() {
+            public Object newInstance(Map properties)
+                throws InstantiationException, InstantiationException, IllegalAccessException {
+                return createBoxLayout(properties);
+            }
+        });
+
+        // Box related layout components
+        registerFactory("hbox", new Factory() {
+            public Object newInstance(Map properties) {
+                return Box.createHorizontalBox();
+            }
+        });
+        registerFactory("hglue", new Factory() {
+            public Object newInstance(Map properties) {
+                return Box.createHorizontalGlue();
+            }
+        });
+        registerFactory("hstrut", new Factory() {
+            public Object newInstance(Map properties) {
+                try {
+                Object num = properties.remove("width");
+                if (num instanceof Number) {
+                    return Box.createHorizontalStrut(((Number)num).intValue());
+                } else {
+                    return Box.createHorizontalStrut(6);
+                }
+                } catch (RuntimeException re) {
+                    re.printStackTrace(System.out);
+                    throw re;
+                }
+            }
+        });
+        registerFactory("vbox", new Factory() {
+            public Object newInstance(Map properties) {
+                return Box.createVerticalBox();
+            }
+        });
+        registerFactory("vglue", new Factory() {
+            public Object newInstance(Map properties) {
+                return Box.createVerticalGlue();
+            }
+        });
+        registerFactory("vstrut", new Factory() {
+            public Object newInstance(Map properties) {
+                Object num = properties.remove("height");
+                if (num instanceof Number) {
+                    return Box.createVerticalStrut(((Number)num).intValue());
+                } else {
+                    return Box.createVerticalStrut(6);
+                }
+            }
+        });
+        registerFactory("glue", new Factory() {
+            public Object newInstance(Map properties) {
+                return Box.createGlue();
+            }
+        });
+        registerFactory("rigidArea", new Factory() {
+            public Object newInstance(Map properties) {
+                Dimension dim;
+                Object o = properties.remove("size");
+                if (o instanceof Dimension) {
+                    dim = (Dimension) o;
+                } else {
+                    int w, h;
+                    o = properties.remove("width");
+                    w = ((o instanceof Number)) ? ((Number)o).intValue() : 6;
+                    o = properties.remove("height");
+                    h = ((o instanceof Number)) ? ((Number)o).intValue() : 6;
+                    dim = new Dimension(w, h);
+                }
+                return Box.createRigidArea(dim);
+            }
+        });
+        
+        // table layout
+        registerBeanFactory("tableLayout", TableLayout.class);
+        registerFactory("tr", new Factory() {
+            public Object newInstance(Map properties) {
+                Object parent = getCurrent();
+                if (parent instanceof TableLayout) {
+                    return new TableLayoutRow((TableLayout) parent);
+                }
+                else {
+                    throw new RuntimeException("'tr' must be within a 'tableLayout'");
+                }
+            }
+        });
+        registerFactory("td", new Factory() {
+            public Object newInstance(Map properties) {
+                Object parent = getCurrent();
+                if (parent instanceof TableLayoutRow) {
+                    return new TableLayoutCell((TableLayoutRow) parent);
+                }
+                else {
+                    throw new RuntimeException("'td' must be within a 'tr'");
+                }
+            }
+        });
+    }
+
+    protected Object createBoxLayout(Map properties) {
+        Object parent = getCurrent();
+        if (parent instanceof Container) {
+            Object axisObject = properties.remove("axis");
+            int axis = BoxLayout.X_AXIS;
+            if (axisObject != null) {
+                Integer i = (Integer) axisObject;
+                axis = i.intValue();
+            }
+            
+            Container target = (Container) parent;
+            if (target instanceof RootPaneContainer) {
+            	target = ((RootPaneContainer) target).getContentPane();
+            }
+            BoxLayout answer = new BoxLayout(target, axis);
+            
+            // now lets try set the layout property
+            InvokerHelper.setProperty(parent, "layout", answer);
+            return answer;
+        }
+        else {
+            throw new RuntimeException("Must be nested inside a Container");
+        }
+    }
+
+    protected Object createDialog(Map properties) {
+        JDialog dialog;
+        Object owner = properties.remove("owner");
+        // if owner not explicit, use the last window type in the list
+        if ((owner == null) && !containingWindows.isEmpty()) {
+            owner = containingWindows.getLast();
+        }
+        if (owner instanceof Frame) {
+            dialog = new JDialog((Frame) owner);
+        }
+        else if (owner instanceof Dialog) {
+            dialog = new JDialog((Dialog) owner);
+        }
+        else {
+            dialog = new JDialog();
+        }
+        containingWindows.add(dialog);
+        return dialog;
+    }
+    
+    /**
+     * Uses 'format," or "value,"  (in order)
+     *
+     */
+    protected Object createFormattedTextField(Map properties) {
+        JFormattedTextField ftf;
+        if (properties.containsKey("format")) {
+            ftf = new JFormattedTextField((Format) properties.remove("format"));
+        }
+        else if (properties.containsKey("value")) {
+            ftf = new JFormattedTextField(properties.remove("value"));
+        }
+        else {
+            ftf = new JFormattedTextField();
+        }
+        return ftf;
+    }
+
+    protected Object createFrame(Map properties) {
+        JFrame frame = new JFrame();
+        containingWindows.add(frame);
+        return frame;
+    }
+    
+    protected Object createWindow(Map properties) {
+        JWindow window;
+        Object owner = properties.remove("owner");
+        // if owner not explicit, use the last window type in the list
+        if ((owner == null) && !containingWindows.isEmpty()) {
+            owner = containingWindows.getLast();
+        }
+        if (owner instanceof Frame) {
+            window = new JWindow((Frame) owner);
+        }
+        else if (owner instanceof Window) {
+            window = new JWindow((Window) owner);
+        }
+        else {
+            window = new JWindow();
+        }
+        containingWindows.add(window);
+        return window;
+    }
+
+    protected Object createComboBox(Map properties) {
+        Object items = properties.remove("items");
+        if (items instanceof Vector) {
+            return new JComboBox((Vector) items);
+        }
+        else if (items instanceof List) {
+            List list = (List) items;
+            return new JComboBox(list.toArray());
+        }
+        else if (items instanceof Object[]) {
+            return new JComboBox((Object[]) items);
+        }
+        else {
+            return new JComboBox();
+        }
+    }
+
+    protected void registerBeanFactory(String name, final Class beanClass) {
+        registerFactory(name, new Factory() {
+            public Object newInstance(Map properties) throws InstantiationException, IllegalAccessException {
+                return beanClass.newInstance();
+            }
+        });
+
+    }
+
+    protected void registerFactory(String name, Factory factory) {
+        factories.put(name, factory);
+    }
+}
diff --git a/groovy-core/src/main/groovy/swing/impl/ComponentFacade.java b/groovy-core/src/main/groovy/swing/impl/ComponentFacade.java
new file mode 100644
index 0000000..722fc33
--- /dev/null
+++ b/groovy-core/src/main/groovy/swing/impl/ComponentFacade.java
@@ -0,0 +1,59 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.swing.impl;
+
+import java.awt.Component;
+
+/** 
+ * A facade to an object which contains a component
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public interface ComponentFacade {
+
+    public Component getComponent();
+}
diff --git a/groovy-core/src/main/groovy/swing/impl/ContainerFacade.java b/groovy-core/src/main/groovy/swing/impl/ContainerFacade.java
new file mode 100644
index 0000000..70a8843
--- /dev/null
+++ b/groovy-core/src/main/groovy/swing/impl/ContainerFacade.java
@@ -0,0 +1,59 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.swing.impl;
+
+import java.awt.Component;
+
+/** 
+ * A facade to an object to which components can be added
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public interface ContainerFacade {
+    
+    public void addComponent(Component component);
+}
diff --git a/groovy-core/src/main/groovy/swing/impl/DefaultAction.java b/groovy-core/src/main/groovy/swing/impl/DefaultAction.java
new file mode 100644
index 0000000..f74c752
--- /dev/null
+++ b/groovy-core/src/main/groovy/swing/impl/DefaultAction.java
@@ -0,0 +1,79 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.swing.impl;
+
+import groovy.lang.Closure;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+
+/** 
+ * A default action implementation
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class DefaultAction extends AbstractAction {
+
+    private Closure closure;
+
+    public void actionPerformed(ActionEvent event) {
+        if (closure == null) {
+            throw new NullPointerException("No closure has been configured for this Action");
+        }
+        closure.call(event);
+    }
+
+    public Closure getClosure() {
+        return closure;
+    }
+
+    public void setClosure(Closure closure) {
+        this.closure = closure;
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/swing/impl/Factory.java b/groovy-core/src/main/groovy/swing/impl/Factory.java
new file mode 100644
index 0000000..627f4bd
--- /dev/null
+++ b/groovy-core/src/main/groovy/swing/impl/Factory.java
@@ -0,0 +1,62 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.swing.impl;
+
+import java.util.Map;
+
+/** 
+ * An interface to represent a factory of beans
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public interface Factory {
+
+    /**
+     * Create a new instance
+     */    
+    public Object newInstance(Map properties) throws InstantiationException, InstantiationException, IllegalAccessException;
+}
diff --git a/groovy-core/src/main/groovy/swing/impl/Startable.java b/groovy-core/src/main/groovy/swing/impl/Startable.java
new file mode 100644
index 0000000..47133a9
--- /dev/null
+++ b/groovy-core/src/main/groovy/swing/impl/Startable.java
@@ -0,0 +1,58 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.swing.impl;
+
+
+/** 
+ * A simple lifecycle method called when an object is fully constructed
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public interface Startable {
+
+    public void start();
+}
diff --git a/groovy-core/src/main/groovy/swing/impl/TableLayout.java b/groovy-core/src/main/groovy/swing/impl/TableLayout.java
new file mode 100644
index 0000000..e606b72
--- /dev/null
+++ b/groovy-core/src/main/groovy/swing/impl/TableLayout.java
@@ -0,0 +1,109 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.swing.impl;
+
+import java.awt.Component;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+
+import javax.swing.JPanel;
+
+/** 
+ * Represents a HTML style table layout
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class TableLayout implements ComponentFacade {
+
+    private JPanel panel = new JPanel();
+    private int rowCount;
+    private int cellpadding;
+
+    public TableLayout() {
+        panel.setLayout(createLayoutManager());
+    }
+
+    public Component getComponent() {
+        return panel;
+    }
+    
+    public int getCellpadding() {
+        return cellpadding;
+    }
+
+    public void setCellpadding(int cellpadding) {
+        this.cellpadding = cellpadding;
+    }
+
+    /**
+     * Adds a new cell to the current grid
+     */
+    public void addCell(TableLayoutCell cell) {
+        GridBagConstraints constraints = cell.getConstraints();
+        constraints.insets = new Insets(cellpadding, cellpadding, cellpadding, cellpadding);
+        panel.add(cell.getComponent(), constraints);
+    }
+
+    /**
+     * Creates a new row index for child <tr> tags 
+     */
+    public int nextRowIndex() {
+        return rowCount++;
+    }
+
+    // Implementation methods
+    //-------------------------------------------------------------------------                    
+
+    /**
+     * Creates a GridBagLayout
+     */
+    protected LayoutManager createLayoutManager() {
+        return new GridBagLayout();
+    }
+}
diff --git a/groovy-core/src/main/groovy/swing/impl/TableLayoutCell.java b/groovy-core/src/main/groovy/swing/impl/TableLayoutCell.java
new file mode 100644
index 0000000..5e88472
--- /dev/null
+++ b/groovy-core/src/main/groovy/swing/impl/TableLayoutCell.java
@@ -0,0 +1,231 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.swing.impl;
+
+import java.awt.Component;
+import java.awt.GridBagConstraints;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/** 
+ * Represents a cell in a table layout
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class TableLayoutCell implements ContainerFacade {
+
+    protected static final Logger log = Logger.getLogger(TableLayoutCell.class.getName());
+    
+    private TableLayoutRow parent;
+    private Component component;
+    private GridBagConstraints constraints;
+    private String align;
+    private String valign;
+    private int colspan = 1;
+    private int rowspan = 1;
+    private boolean colfill = false;
+    private boolean rowfill = false;
+
+        
+    public TableLayoutCell(TableLayoutRow parent) {
+        this.parent = parent;
+    }
+
+    public void addComponent(Component component)  {
+        if (this.component != null) {
+            log.log(Level.WARNING, "This td cell already has a component: " + component);
+        }
+        this.component = component;
+        parent.addCell(this);
+    }
+    
+    public Component getComponent() {
+        return component;
+    }
+
+    /**
+     * Sets the horizontal alignment to a case insensitive value of {LEFT, CENTER, RIGHT}
+     */
+    public void setAlign(String align) {
+        this.align = align;
+    }
+
+    /**
+     * Sets the vertical alignment to a case insensitive value of {TOP, MIDDLE, BOTTOM}
+     */
+    public void setValign(String valign) {
+        this.valign = valign;
+    }
+
+    
+    /**
+     * Sets the number of columns that this cell should span. The default value is 1
+     */
+    public void setColspan(int colspan) {
+        this.colspan = colspan;
+    }
+
+    /**
+     * Sets the number of rows that this cell should span. The default value is 1
+     */
+    public void setRowspan(int rowspan) {
+        this.rowspan = rowspan;
+    }
+
+    /**
+     * Returns the colfill.
+     * @return boolean
+     */
+    public boolean isColfill() {
+        return colfill;
+    }
+
+    /**
+     * Returns the rowfill.
+     * @return boolean
+     */
+    public boolean isRowfill() {
+        return rowfill;
+    }
+
+    /**
+     * Sets whether or not this column should allow its component to stretch to fill the space available
+     */
+    public void setColfill(boolean colfill) {
+        this.colfill = colfill;
+    }
+
+    /**
+     * Sets whether or not this row should allow its component to stretch to fill the space available
+     */
+    public void setRowfill(boolean rowfill) {
+        this.rowfill = rowfill;
+    }
+
+
+    /**
+     * @return the constraints of this cell
+     */
+    public GridBagConstraints getConstraints() {
+        if (constraints == null) {
+            constraints = createConstraints();
+        }
+        return constraints;
+    }
+    
+    // Implementation methods
+    //-------------------------------------------------------------------------                    
+    
+    protected GridBagConstraints createConstraints() {
+        GridBagConstraints answer = new GridBagConstraints();
+        answer.anchor = getAnchor();
+        if (colspan < 1) {
+            colspan = 1;
+        }
+        if (rowspan < 1) {
+            rowspan = 1;
+        }
+        if (isColfill())  {
+            answer.fill = isRowfill()
+                ? GridBagConstraints.BOTH 
+                : GridBagConstraints.HORIZONTAL;
+        }
+        else {
+            answer.fill = isRowfill()
+                ? GridBagConstraints.VERTICAL 
+                : GridBagConstraints.NONE;
+        }
+        answer.weightx = 0.2;
+        answer.weighty = 0;
+        answer.gridwidth = colspan;
+        answer.gridheight = rowspan;
+        return answer;
+    }
+    
+    /**
+     * @return the GridBagConstraints enumeration for achor
+     */
+    protected int getAnchor() {
+        boolean isTop = "top".equalsIgnoreCase(valign);
+        boolean isBottom = "bottom".equalsIgnoreCase(valign);
+        
+        if ("center".equalsIgnoreCase(align)) {
+            if (isTop) {
+                return GridBagConstraints.NORTH;
+            }
+            else if (isBottom) {
+                return GridBagConstraints.SOUTH;
+            }
+            else {
+                return GridBagConstraints.CENTER;
+            }
+        }
+        else if ("right".equalsIgnoreCase(align)) {
+            if (isTop) {
+                return GridBagConstraints.NORTHEAST;
+            }
+            else if (isBottom) {
+                return GridBagConstraints.SOUTHEAST;
+            }
+            else {
+                return GridBagConstraints.EAST;
+            }
+        }
+        else {
+            // defaults to left
+            if (isTop) {
+                return GridBagConstraints.NORTHWEST;
+            }
+            else if (isBottom) {
+                return GridBagConstraints.SOUTHWEST;
+            }
+            else {
+                return GridBagConstraints.WEST;
+            }
+        }
+    }
+}
diff --git a/groovy-core/src/main/groovy/swing/impl/TableLayoutRow.java b/groovy-core/src/main/groovy/swing/impl/TableLayoutRow.java
new file mode 100644
index 0000000..93e008e
--- /dev/null
+++ b/groovy-core/src/main/groovy/swing/impl/TableLayoutRow.java
@@ -0,0 +1,111 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.swing.impl;
+
+import java.awt.GridBagConstraints;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/** 
+ * Represents a row in a table layout
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class TableLayoutRow implements Startable {
+
+    private TableLayout parent;
+    private List cells = new ArrayList();
+    private int rowIndex;
+    
+    public TableLayoutRow(TableLayout tableLayoutTag) {
+        this.parent = tableLayoutTag;
+    }
+
+    /**
+     * Adds a new cell to this row
+     */
+    public void addCell(TableLayoutCell tag) {
+        tag.getConstraints().gridx = cells.size();
+        cells.add(tag);
+    }        
+    
+    public void start() {
+        rowIndex = parent.nextRowIndex();
+        
+        // now iterate through the rows and add each one to the layout...
+        for (Iterator iter = cells.iterator(); iter.hasNext(); ) {
+            TableLayoutCell cell = (TableLayoutCell) iter.next();
+            GridBagConstraints c = cell.getConstraints();
+
+            // are we the last cell in the row
+            if ( iter.hasNext() ) {
+                // not last in row
+                c.gridwidth = GridBagConstraints.RELATIVE;                
+            }
+            else {
+                // end of row
+                c.gridwidth = GridBagConstraints.REMAINDER;
+            }
+            c.gridy = rowIndex;
+            
+            // now lets add the cell to the table
+            parent.addCell(cell);
+        }        
+    }
+    
+    // Properties
+    //-------------------------------------------------------------------------                    
+    
+    /**
+     * @return the row index of this row
+     */
+    public int getRowIndex() {
+        return rowIndex;
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/swing/impl/package.html b/groovy-core/src/main/groovy/swing/impl/package.html
new file mode 100644
index 0000000..64d5705
--- /dev/null
+++ b/groovy-core/src/main/groovy/swing/impl/package.html
@@ -0,0 +1,10 @@
+<html>
+  <head>
+    <title>package groovy.swing.impl.*</title>
+  </head>
+  <body>
+    <p>
+      Implementation classes for the Swing GroovyMarkup builder
+    </p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/groovy/swing/package.html b/groovy-core/src/main/groovy/swing/package.html
new file mode 100644
index 0000000..451766f
--- /dev/null
+++ b/groovy-core/src/main/groovy/swing/package.html
@@ -0,0 +1,10 @@
+<html>
+  <head>
+    <title>package groovy.swing.*</title>
+  </head>
+  <body>
+    <p>
+      A GroovyMarkup builder for creating Swing user interfaces
+    </p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/groovy/text/GStringTemplateEngine.java b/groovy-core/src/main/groovy/text/GStringTemplateEngine.java
new file mode 100644
index 0000000..01eea0f
--- /dev/null
+++ b/groovy-core/src/main/groovy/text/GStringTemplateEngine.java
@@ -0,0 +1,263 @@
+/* $Id$
+
+Copyright 2004 (C) John Wilson. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+package groovy.text;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyCodeSource;
+import groovy.lang.GroovyObject;
+import groovy.lang.Writable;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Map;
+
+import org.codehaus.groovy.control.CompilationFailedException;
+
+
+/**
+* @author tug@wilson.co.uk
+*
+*/
+public class GStringTemplateEngine extends TemplateEngine {
+    /* (non-Javadoc)
+     * @see groovy.text.TemplateEngine#createTemplate(java.io.Reader)
+     */
+    public Template createTemplate(final Reader reader) throws CompilationFailedException, ClassNotFoundException, IOException {
+        return new GStringTemplate(reader);
+    }
+
+    private static class GStringTemplate implements Template {
+        final Closure template;
+
+        /**
+         * Turn the template into a writable Closure
+         * When executed the closure evaluates all the code embedded in the
+         * template and then writes a GString containing the fixed and variable items
+         * to the writer passed as a paramater
+         *
+         * For example:
+         *
+         * '<%= "test" %> of expr and <% test = 1 %>${test} script.'
+         *
+         * would compile into:
+         *
+         * { |out| out << "${"test"} of expr and "; test = 1 ; out << "${test} script."}.asWritable()
+         *
+         * @param reader
+         * @throws CompilationFailedException
+         * @throws ClassNotFoundException
+         * @throws IOException
+         */
+        public GStringTemplate(final Reader reader) throws CompilationFailedException, ClassNotFoundException, IOException {
+        final StringBuffer templateExpressions = new StringBuffer("package groovy.tmp.templates\n def getTemplate() { return { out -> delegate = new Binding(delegate); out << \"\"\"");
+        boolean writingString = true;
+       
+            while(true) {
+                int c = reader.read();
+
+                    if (c == -1) break;
+
+                if (c == '<') {
+                    c = reader.read();
+
+                    if (c == '%') {
+                        c = reader.read();
+
+                        if (c == '=') {
+                                parseExpression(reader, writingString, templateExpressions);
+                                writingString = true;
+                                continue;
+                        } else {
+                                parseSection(c, reader, writingString, templateExpressions);
+                                writingString = false;
+                                continue;
+                        }
+                    } else {
+                        appendCharacter('<', templateExpressions, writingString);
+                        writingString = true;
+                    }
+                } else if (c == '"') {
+                        appendCharacter('\\', templateExpressions, writingString);
+                        writingString = true;
+                   }
+
+                    appendCharacter((char)c, templateExpressions, writingString);
+                    writingString = true;
+            }
+
+            if (writingString) {
+                    templateExpressions.append("\"\"\"");
+            }
+
+            templateExpressions.append("}.asWritable()}");
+
+//            System.out.println(templateExpressions.toString());
+
+            final ClassLoader parentLoader = getClass().getClassLoader();
+            final GroovyClassLoader loader =
+                (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
+                    public Object run() {
+                        return new GroovyClassLoader(parentLoader);
+                    }
+                });
+            final Class groovyClass = loader.parseClass(new GroovyCodeSource(templateExpressions.toString(), "C", "x"));
+
+            try {
+                final GroovyObject object = (GroovyObject) groovyClass.newInstance();
+
+                this.template = (Closure)object.invokeMethod("getTemplate", null);
+            } catch (InstantiationException e) {
+                throw new ClassNotFoundException(e.getMessage());
+            } catch (IllegalAccessException e) {
+                throw new ClassNotFoundException(e.getMessage());
+            }
+        }
+
+        private static void appendCharacter(final char c,
+                                            final StringBuffer templateExpressions,
+                                            final boolean writingString)
+        {
+            if (!writingString) {
+                templateExpressions.append("out << \"\"\"");
+            }
+
+            templateExpressions.append(c);
+        }
+
+        /**
+         * Parse a <% .... %> section
+         * if we are writing a GString close and append ';'
+         * then write the section as a statement
+         *
+         * @param pendingC
+         * @param reader
+         * @param writingString
+         * @param templateExpressions
+         * @throws IOException
+         */
+        private static void parseSection(final int pendingC,
+                                         final Reader reader,
+                                         final boolean writingString,
+                                         final StringBuffer templateExpressions)
+            throws IOException
+        {
+            if (writingString) {
+                templateExpressions.append("\"\"\"; ");
+            }
+            templateExpressions.append((char)pendingC);
+
+                while (true) {
+                    int c = reader.read();
+
+                    if (c == -1) break;
+
+                    if (c =='%') {
+                        c = reader.read();
+
+                        if (c == '>') break;
+                        
+                        templateExpressions.append('%');
+                    }
+
+                    templateExpressions.append((char)c);
+                }
+
+                templateExpressions.append(";\n ");
+        }
+
+        /**
+         * Parse a <%= .... %> expression
+         *
+         * @param reader
+         * @param writingString
+         * @param templateExpressions
+         * @throws IOException
+         */
+        private static void parseExpression(final Reader reader,
+                                          final boolean writingString,
+                                          final StringBuffer templateExpressions)
+            throws IOException
+        {
+            if (!writingString) {
+                templateExpressions.append("out << \"\"\"");
+            }
+
+            templateExpressions.append("${");
+
+                while (true) {
+                    int c = reader.read();
+
+                    if (c == -1) break;
+
+                    if (c =='%') {
+                        c = reader.read();
+
+                        if (c == '>') break;
+                        
+                        templateExpressions.append('%');
+                    }
+
+                    templateExpressions.append((char)c);
+                }
+
+            templateExpressions.append('}');
+        }
+
+        public Writable make() {
+           return make(null);
+       }
+
+       public Writable make(final Map map) {
+       final Closure template = (Closure)this.template.clone();
+           
+           template.setDelegate(map);
+           
+           return (Writable)template;
+       }
+    }
+}
diff --git a/groovy-core/src/main/groovy/text/SimpleTemplateEngine.java b/groovy-core/src/main/groovy/text/SimpleTemplateEngine.java
new file mode 100644
index 0000000..16fbc03
--- /dev/null
+++ b/groovy-core/src/main/groovy/text/SimpleTemplateEngine.java
@@ -0,0 +1,253 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package groovy.text;
+
+import groovy.lang.Binding;
+import groovy.lang.GroovyShell;
+import groovy.lang.Script;
+import groovy.lang.Writable;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Map;
+
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * This simple template engine uses JSP <% %> script and <%= %> expression syntax.  It also lets you use normal groovy expressions in
+ * the template text much like the new JSP EL functionality.  The variable 'out' is bound to the writer that the template is being written to.
+ * 
+ * @author sam
+ * @author Christian Stein
+ */
+public class SimpleTemplateEngine extends TemplateEngine {
+
+    private final boolean verbose;
+
+    public SimpleTemplateEngine() {
+        this(false);
+    }
+
+    public SimpleTemplateEngine(boolean verbose) {
+        this.verbose = verbose;
+    }
+
+    public Template createTemplate(Reader reader) throws CompilationFailedException, IOException {
+        SimpleTemplate template = new SimpleTemplate();
+        GroovyShell shell = new GroovyShell();
+        String script = template.parse(reader);
+        if (verbose) {
+            System.out.println("\n-- script source --");
+            System.out.print(script);
+            System.out.println("\n-- script end --\n");
+        }
+        template.script = shell.parse(script);
+        return template;
+    }
+
+    private static class SimpleTemplate implements Template {
+
+        protected Script script;
+
+        public Writable make() {
+            return make(null);
+        }
+
+        public Writable make(final Map map) {
+            return new Writable() {
+                /**
+                 * Write the template document with the set binding applied to the writer.
+                 *
+                 * @see groovy.lang.Writable#writeTo(java.io.Writer)
+                 */
+                public Writer writeTo(Writer writer) {
+                    Binding binding;
+                    if (map == null)
+                        binding = new Binding();
+                    else
+                        binding = new Binding(map);
+                    Script scriptObject = InvokerHelper.createScript(script.getClass(), binding);
+                    PrintWriter pw = new PrintWriter(writer);
+                    scriptObject.setProperty("out", pw);
+                    scriptObject.run();
+                    pw.flush();
+                    return writer;
+                }
+
+                /**
+                 * Convert the template and binding into a result String.
+                 *
+                 * @see java.lang.Object#toString()
+                 */
+                public String toString() {
+                    try {
+                        StringWriter sw = new StringWriter();
+                        writeTo(sw);
+                        return sw.toString();
+                    } catch (Exception e) {
+                        return e.toString();
+                    }
+                }
+            };
+        }
+
+        /**
+         * Parse the text document looking for <% or <%= and then call out to the appropriate handler, otherwise copy the text directly
+         * into the script while escaping quotes.
+         * 
+         * @param reader
+         * @throws IOException
+         */
+        protected String parse(Reader reader) throws IOException {
+            if (!reader.markSupported()) {
+                reader = new BufferedReader(reader);
+            }
+            StringWriter sw = new StringWriter();
+            startScript(sw);
+            boolean start = false;
+            int c;
+            while ((c = reader.read()) != -1) {
+                if (c == '<') {
+                    reader.mark(1);
+                    c = reader.read();
+                    if (c != '%') {
+                        sw.write('<');
+                        reader.reset();
+                    } else {
+                        reader.mark(1);
+                        c = reader.read();
+                        if (c == '=') {
+                            groovyExpression(reader, sw);
+                        } else {
+                            reader.reset();
+                            groovySection(reader, sw);
+                        }
+                    }
+                    continue; // at least '<' is consumed ... read next chars.
+                }
+                if (c == '\"') {
+                    sw.write('\\');
+                }
+                /*
+                 * Handle raw new line characters.
+                 */
+                if (c == '\n' || c == '\r') {
+                    if (c == '\r') { // on Windows, "\r\n" is a new line.
+                        reader.mark(1);
+                        c = reader.read();
+                        if (c != '\n') {
+                            reader.reset();
+                        }
+                    }
+                    sw.write("\\n\");\nout.print(\"");
+                    continue;
+                }
+                sw.write(c);
+            }
+            endScript(sw);
+            String result = sw.toString();
+            return result;
+        }
+
+        private void startScript(StringWriter sw) {
+            sw.write("/* Generated by SimpleTemplateEngine */\n");
+            sw.write("out.print(\"");
+        }
+
+        private void endScript(StringWriter sw) {
+            sw.write("\");\n");
+        }
+
+        /**
+         * Closes the currently open write and writes out the following text as a GString expression until it reaches an end %>.
+         * 
+         * @param reader
+         * @param sw
+         * @throws IOException
+         */
+        private void groovyExpression(Reader reader, StringWriter sw) throws IOException {
+            sw.write("\");out.print(\"${");
+            int c;
+            while ((c = reader.read()) != -1) {
+                if (c == '%') {
+                    c = reader.read();
+                    if (c != '>') {
+                        sw.write('%');
+                    } else {
+                        break;
+                    }
+                }
+                if (c != '\n' && c != '\r') {
+                    sw.write(c);
+                }
+            }
+            sw.write("}\");\nout.print(\"");
+        }
+
+        /**
+         * Closes the currently open write and writes the following text as normal Groovy script code until it reaches an end %>.
+         * 
+         * @param reader
+         * @param sw
+         * @throws IOException
+         */
+        private void groovySection(Reader reader, StringWriter sw) throws IOException {
+            sw.write("\");");
+            int c;
+            while ((c = reader.read()) != -1) {
+                if (c == '%') {
+                    c = reader.read();
+                    if (c != '>') {
+                        sw.write('%');
+                    } else {
+                        break;
+                    }
+                }
+                /* Don't eat EOL chars in sections - as they are valid instruction separators.
+                 * See http://jira.codehaus.org/browse/GROOVY-980
+                 */
+                // if (c != '\n' && c != '\r') {
+                sw.write(c);
+                //}
+            }
+            sw.write(";\nout.print(\"");
+        }
+
+    }
+}
diff --git a/groovy-core/src/main/groovy/text/Template.java b/groovy-core/src/main/groovy/text/Template.java
new file mode 100644
index 0000000..c6a9401
--- /dev/null
+++ b/groovy-core/src/main/groovy/text/Template.java
@@ -0,0 +1,49 @@
+/*
+ * $Id$version Mar 7, 2004 8:44:50 PM $user Exp $
+ * 
+ * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package groovy.text;
+
+import groovy.lang.Writable;
+
+import java.util.Map;
+
+
+/**
+ * A template is a block of text with an associated binding that can be output to a writer or evaluated to a string.
+ * 
+ * @author sam
+ */
+public interface Template {
+    Writable make();
+    Writable make(Map binding);
+}
diff --git a/groovy-core/src/main/groovy/text/TemplateEngine.java b/groovy-core/src/main/groovy/text/TemplateEngine.java
new file mode 100644
index 0000000..7a1e645
--- /dev/null
+++ b/groovy-core/src/main/groovy/text/TemplateEngine.java
@@ -0,0 +1,66 @@
+/*
+ * $Id$version Mar 8, 2004 2:08:49 AM $user Exp $
+ * 
+ * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package groovy.text;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.net.URL;
+
+import org.codehaus.groovy.control.CompilationFailedException;
+
+/**
+ * Represents an API to any template engine which is basically a factory of Template instances from a given text input.
+ * 
+ * @author sam
+ */
+public abstract class TemplateEngine {
+    public abstract Template createTemplate(Reader reader) throws CompilationFailedException, ClassNotFoundException, IOException;
+    
+    public Template createTemplate(String templateText) throws CompilationFailedException, FileNotFoundException, ClassNotFoundException, IOException {
+        return createTemplate(new StringReader(templateText));
+    }
+    
+    public Template createTemplate(File file) throws CompilationFailedException, FileNotFoundException, ClassNotFoundException, IOException {
+        return createTemplate(new FileReader(file));
+    }
+
+    public Template createTemplate(URL url) throws CompilationFailedException, ClassNotFoundException, IOException {
+        return createTemplate(new InputStreamReader(url.openStream()));
+    }
+}
diff --git a/groovy-core/src/main/groovy/text/XmlTemplateEngine.java b/groovy-core/src/main/groovy/text/XmlTemplateEngine.java
new file mode 100644
index 0000000..fb51e91
--- /dev/null
+++ b/groovy-core/src/main/groovy/text/XmlTemplateEngine.java
@@ -0,0 +1,212 @@
+package groovy.text;
+
+import groovy.lang.Binding;
+import groovy.lang.GroovyShell;
+import groovy.lang.Script;
+import groovy.lang.Writable;
+import groovy.util.IndentPrinter;
+import groovy.util.Node;
+import groovy.util.XmlNodePrinter;
+import groovy.util.XmlParser;
+import groovy.xml.QName;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.xml.sax.SAXException;
+
+/**
+ * Template engine for xml data input.
+ *
+ * @author Christian Stein
+ */
+public class XmlTemplateEngine extends TemplateEngine {
+
+    private static class GspPrinter extends XmlNodePrinter {
+
+        public GspPrinter(PrintWriter out, String indent) {
+            this(new IndentPrinter(out, indent));
+        }
+
+        public GspPrinter(IndentPrinter out) {
+            super(out, "\\\"");
+        }
+
+        protected void printGroovyTag(String tag, String text) {
+            if (tag.equals("scriptlet")) {
+                out.print(text);
+                out.print("\n");
+                return;
+            }
+            if (tag.equals("expression")) {
+                printLineBegin();
+                out.print("${");
+                out.print(text);
+                out.print("}");
+                printLineEnd();
+                return;
+            }
+            throw new RuntimeException("Unsupported tag named \"" + tag + "\".");
+        }
+
+        protected void printLineBegin() {
+            out.print("out.print(\"");
+            out.printIndent();
+        }
+
+        protected void printLineEnd(String comment) {
+            out.print("\\n\");");
+            if (comment != null) {
+                out.print(" // ");
+                out.print(comment);
+            }
+            out.print("\n");
+        }
+
+        protected boolean printSpecialNode(Node node) {
+            Object name = node.name();
+            if (name != null && name instanceof QName) {
+                /*
+                 * FIXME Somethings wrong with the SAX- or XMLParser. Prefix should only contain 'gsp'?!
+                 */
+                String s = ((QName) name).getPrefix();
+                if (s.startsWith("gsp:")) {
+                    s = s.substring(4); // 4 = "gsp:".length()
+                    if (s.length() == 0) {
+                        throw new RuntimeException("No local part after 'gsp:' given in node " + node);
+                    }
+                    printGroovyTag(s, node.text());
+                    return true;
+                }
+            }
+            return false;
+        }
+
+    }
+
+    private static class XmlTemplate implements Template {
+
+        private final Script script;
+
+        public XmlTemplate(Script script) {
+            this.script = script;
+        }
+
+        public Writable make() {
+            return make(new HashMap());
+        }
+
+        public Writable make(Map map) {
+            if (map == null) {
+                throw new IllegalArgumentException("map must not be null");
+            }
+            return new XmlWritable(script, new Binding(map));
+        }
+
+    }
+
+    private static class XmlWritable implements Writable {
+
+        private final Binding binding;
+        private final Script script;
+        private WeakReference result;
+
+        public XmlWritable(Script script, Binding binding) {
+            this.script = script;
+            this.binding = binding;
+            this.result = new WeakReference(null);
+        }
+
+        public Writer writeTo(Writer out) {
+            Script scriptObject = InvokerHelper.createScript(script.getClass(), binding);
+            PrintWriter pw = new PrintWriter(out);
+            scriptObject.setProperty("out", pw);
+            scriptObject.run();
+            pw.flush();
+            return out;
+        }
+
+        public String toString() {
+            if (result.get() != null) {
+                return result.get().toString();
+            }
+            String string = writeTo(new StringWriter(1024)).toString();
+            result = new WeakReference(string);
+            return string;
+        }
+
+    }
+
+    public static final String DEFAULT_INDENTION = "  ";
+
+    private final GroovyShell groovyShell;
+    private final XmlParser xmlParser;
+    private String indention;
+
+    public XmlTemplateEngine() throws SAXException, ParserConfigurationException {
+        this(DEFAULT_INDENTION, false);
+    }
+
+    public XmlTemplateEngine(String indention, boolean validating) throws SAXException, ParserConfigurationException {
+        this(new XmlParser(validating, true), new GroovyShell(), indention);
+    }
+
+    public XmlTemplateEngine(XmlParser xmlParser, GroovyShell groovyShell, String indention) {
+        this.groovyShell = groovyShell;
+        this.xmlParser = xmlParser;
+        this.indention = indention;
+    }
+
+    public Template createTemplate(Reader reader) throws CompilationFailedException, ClassNotFoundException, IOException {
+        Node root = null;
+        try {
+            root = xmlParser.parse(reader);
+        } catch (SAXException e) {
+            throw new RuntimeException("Parsing XML source failed.", e);
+        }
+
+        if (root == null) {
+            throw new IOException("Parsing XML source failed: root node is null.");
+        }
+
+        // new NodePrinter().print(root);
+        // new XmlNodePrinter().print(root);
+
+        StringWriter writer = new StringWriter(1024);
+        writer.write("/* Generated by XmlTemplateEngine */\n");
+        new GspPrinter(new PrintWriter(writer), DEFAULT_INDENTION).print(root);
+        String scriptText = writer.toString();
+
+        // System.err.println("\n-\n" + scriptText + "\n-\n");
+
+        Script script = groovyShell.parse(scriptText);
+        Template template = new XmlTemplate(script);
+        return template;
+    }
+
+    public String getIndention() {
+        return indention;
+    }
+
+    public void setIndention(String indention) {
+        if (indention == null) {
+            indention = DEFAULT_INDENTION;
+        }
+        this.indention = indention;
+    }
+
+    public String toString() {
+        return "XmlTemplateEngine";
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/text/package.html b/groovy-core/src/main/groovy/text/package.html
new file mode 100644
index 0000000..bd68506
--- /dev/null
+++ b/groovy-core/src/main/groovy/text/package.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>package groovy.text.*</title>
+  </head>
+  <body>
+    <p>Contains the text processing utilities in particular the template engine API and default implementation.</p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/groovy/ui/Console.groovy b/groovy-core/src/main/groovy/ui/Console.groovy
new file mode 100644
index 0000000..550715e
--- /dev/null
+++ b/groovy-core/src/main/groovy/ui/Console.groovy
@@ -0,0 +1,605 @@
+package groovy.ui
+
+import groovy.swing.SwingBuilder
+import groovy.inspect.swingui.ObjectBrowser
+
+import java.awt.BorderLayout
+import java.awt.EventQueue
+import java.awt.Color
+import java.awt.Font
+import java.awt.Insets
+import java.awt.Toolkit
+import java.awt.event.KeyEvent
+import java.io.PrintWriter
+import java.io.StringWriter
+import java.util.EventObject
+
+import javax.swing.*
+import javax.swing.text.*
+import javax.swing.event.*
+
+import org.codehaus.groovy.runtime.InvokerHelper
+
+/**
+ * Groovy Swing console.
+ *
+ * Allows user to interactively enter and execute Groovy. 
+ *
+ * @author Danno Ferrin
+ * @author Dierk Koenig, changed Layout, included Selection sensitivity, included ObjectBrowser
+ * @author Alan Green more features: history, System.out capture, bind result to _
+ */
+class Console implements CaretListener {
+
+	// Whether or not std output should be captured to the console
+	def captureStdOut = true
+
+	// Maximum size of history
+	int maxHistory = 10
+	
+	// Maximum number of characters to show on console at any time
+	int maxOutputChars = 10000
+
+	// UI
+    SwingBuilder swing
+    JFrame frame
+    JTextArea inputArea
+    JTextPane outputArea
+    JLabel statusLabel
+    JDialog runWaitDialog
+    
+    // Styles for output area
+    Style promptStyle;
+    Style commandStyle;
+    Style outputStyle;
+    Style resultStyle;
+    
+	// Internal history
+    List history = []
+    int historyIndex = 1 // valid values are 0..history.length()
+
+	// Current editor state
+    boolean dirty
+    int textSelectionStart  // keep track of selections in inputArea
+    int textSelectionEnd
+    def scriptFile
+
+	// Running scripts
+	GroovyShell shell
+    int scriptNameCounter = 0
+    def systemOutInterceptor
+    def runThread = null
+    
+
+    static void main(args) {
+        def console = new Console()
+        console.run()
+    }
+    
+    Console() {
+    	shell = new GroovyShell()
+    }
+    
+    Console(Binding binding) {
+    	shell = new GroovyShell(binding)
+    }
+    
+    Console(ClassLoader parent, Binding binding) {
+    	shell = new GroovyShell(parent,binding)	
+    }
+
+    void run() {
+        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
+        // if menu modifier is two keys we are out of luck as the javadocs
+        // indicates it returns "Control+Shift" instead of "Control Shift"
+        def menuModifier = KeyEvent.getKeyModifiersText(
+            Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()).toLowerCase() + ' '
+
+        swing = new SwingBuilder()
+        frame = swing.frame(
+            title:'GroovyConsole',
+            location:[100,100],
+            size:[500,400],
+            defaultCloseOperation:javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE) {
+            def newFileAction = action(
+                name:'New File', closure: this.&fileNewFile, mnemonic: 'N', 
+                accelerator: menuModifier + 'Q'
+            )
+            def newWindowAction = action(
+                name:'New Window', closure: this.&fileNewWindow, mnemonic: 'W'
+            )
+            def openAction = action(
+                name:'Open', closure: this.&fileOpen, mnemonic: 'O', accelerator: menuModifier + 'O'
+            )
+            def saveAction = action(
+                name:'Save', closure: this.&fileSave, mnemonic: 'S', accelerator: menuModifier + 'S'
+            )
+            def exitAction = action(
+                name:'Exit', closure: this.&exit, mnemonic: 'x', accelerator: 'alt F4'
+            )	            
+            def historyPrevAction = action(
+                name:'Previous', closure: this.&historyPrev, mnemonic: 'P', accelerator: 'ctrl P'
+            )            
+            def historyNextAction = action(
+            	name: 'Next', closure: this.&historyNext, mnemonic: 'N', accelerator: 'ctrl N'
+            )            
+            def clearOutputAction = action(
+                name:'Clear Output', closure: this.&clearOutput, mnemonic: 'l', keyStroke: 'ctrl W',
+                accelerator: 'ctrl W'
+            )
+            def runAction = action(
+                name:'Run', closure: this.&runScript, mnemonic: 'R', keyStroke: 'ctrl ENTER',
+                accelerator: 'ctrl R'
+            )
+            def inspectLastAction = action(
+                name:'Inspect Last', closure: this.&inspectLast, mnemonic: 'I', keyStroke: 'ctrl I',
+                accelerator: 'ctrl I'
+            )
+            def inspectVariablesAction = action(
+            	name:'Inspect Variables', closure: this.&inspectVariables, mnemonic: 'V', keyStroke: 'ctrl J',
+                accelerator: 'ctrl J'
+            )
+            def captureStdOutAction = action(
+            	name:'Capture Standard Output', closure: this.&captureStdOut, mnemonic: 'C'
+            )
+            def largerFontAction = action(
+                name:'Larger Font', closure: this.&largerFont, mnemonic: 'L', keyStroke: 'alt shift L',
+                accelerator: 'alt shift L'
+            )
+            def smallerFontAction = action(
+                name:'Smaller Font', closure: this.&smallerFont, mnemonic: 'S', keyStroke: 'alt shift S',
+                accelerator: 'alt shift S'
+            )
+            def aboutAction = action(name:'About', closure: this.&showAbout, mnemonic: 'A')
+            menuBar {
+                menu(text:'File', mnemonic: 'F') {
+                    menuItem() { action(newFileAction) }
+                    menuItem() { action(newWindowAction) }
+                    menuItem() { action(openAction) }
+                    separator()
+                    menuItem() { action(saveAction) }
+                    separator()
+                    menuItem() { action(exitAction) }
+                }
+                menu(text:'Edit', mnemonic: 'E') {
+                	menuItem() { action(historyNextAction) }
+                	menuItem() { action(historyPrevAction) }
+                	separator()
+                	menuItem() { action(clearOutputAction) }
+                }
+                menu(text:'Actions', mnemonic: 'A') {
+                    menuItem() { action(runAction) }
+                    menuItem() { action(inspectLastAction) }
+                    menuItem() { action(inspectVariablesAction) }
+                    separator()
+                    checkBoxMenuItem(selected: captureStdOut) { action(captureStdOutAction) }
+                    separator()
+                    menuItem() { action(largerFontAction) }
+                    menuItem() { action(smallerFontAction) }
+                }
+                menu(text:'Help', mnemonic: 'H') {
+                    menuItem() { action(aboutAction) }
+                }
+            }
+            
+            borderLayout()
+            
+            splitPane(id:'splitPane', resizeWeight:0.50F, 
+            	orientation:JSplitPane.VERTICAL_SPLIT, constraints: BorderLayout.CENTER) 
+            {
+                scrollPane {
+                    inputArea = textArea(
+                        margin: new Insets(3,3,3,3), font: new Font('Monospaced',Font.PLAIN,12)
+                    ) { action(runAction) }
+                }
+                scrollPane {
+                    outputArea = textPane(editable:false, background: new Color(255,255,218))
+                    addStylesToDocument(outputArea)
+                }
+            }
+            
+            statusLabel = label(id:'status', text: 'Welcome to the Groovy.', constraints: BorderLayout.SOUTH,
+            	border: BorderFactory.createLoweredBevelBorder())
+        }   // end of frame
+        
+        runWaitDialog = swing.dialog(title: 'Groovy executing', owner: frame, modal: true) {
+        	//boxLayout(axis: BoxLayout.Y_AXIS)  // todo mittie: dialog.setLayout -> dialog.contentPane.setLayout()
+        	label(text: "Groovy is now executing. Please wait.", 
+        		border: BorderFactory.createEmptyBorder(10, 10, 10, 10), alignmentX: 0.5f)
+        	button(action: action(name: 'Interrupt', closure: this.&confirmRunInterrupt),
+	        	border: BorderFactory.createEmptyBorder(10, 10, 10, 10), alignmentX: 0.5f)
+        } // end of runWaitDialog
+
+        // add listeners
+        frame.windowClosing = this.&exit
+        inputArea.addCaretListener(this)
+        inputArea.document.undoableEditHappened = { setDirty(true) }
+        
+        systemOutInterceptor = new SystemOutputInterceptor(this.&notifySystemOut)
+        systemOutInterceptor.start();
+        
+        bindResults()
+        
+        frame.show()
+        SwingUtilities.invokeLater({inputArea.requestFocus()});
+    }
+
+	void addStylesToDocument(JTextPane outputArea) {
+        StyledDocument doc = outputArea.getStyledDocument();
+
+        Style defStyle = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
+
+        Style regular = doc.addStyle("regular", defStyle);
+        StyleConstants.setFontFamily(regular, "Monospaced")
+
+        promptStyle = doc.addStyle("prompt", regular)
+        StyleConstants.setForeground(promptStyle, Color.BLUE)
+
+        commandStyle = doc.addStyle("command", regular);
+        StyleConstants.setForeground(commandStyle, Color.MAGENTA)
+
+        outputStyle = regular 
+        
+        resultStyle = doc.addStyle("result", regular)
+        StyleConstants.setBackground(resultStyle, Color.BLUE)
+        StyleConstants.setBackground(resultStyle, Color.YELLOW)
+    }
+    
+    void addToHistory(record) {
+    	history.add(record)
+    	// history.size here just retrieves method closure
+    	if (history.size() > maxHistory) {
+    		history.remove(0)
+    	}
+    	// history.size doesn't work here either
+    	historyIndex = history.size()
+    }
+    
+	// Append a string to the output area
+    void appendOutput(text, style){
+    	def doc = outputArea.styledDocument
+        doc.insertString(doc.length, text, style)
+        
+        // Ensure we don't have too much in console (takes too much memory)
+        if (doc.length > maxOutputChars) {
+        	doc.remove(0, doc.length - maxOutputChars)
+        }
+    }
+
+	// Append a string to the output area on a new line
+    void appendOutputNl(text, style){
+    	def doc = outputArea.styledDocument
+    	def len = doc.length
+    	if (len > 0 && doc.getText(len - 1, 1) != "\n") {
+    		appendOutput("\n", style);
+    	} 
+    	appendOutput(text, style)
+    }
+    
+    // Return false if use elected to cancel
+    boolean askToSaveFile() {
+    	if (scriptFile == null || !dirty) {
+    		return true
+    	}
+        switch (JOptionPane.showConfirmDialog(frame,
+            "Save changes to " + scriptFile.name + "?",
+            "GroovyConsole", JOptionPane.YES_NO_CANCEL_OPTION))
+        {
+            case JOptionPane.YES_OPTION:
+                return fileSave()
+            case JOptionPane.NO_OPTION:
+            	return true
+            default:
+            	return false
+        }
+    }
+
+    private static void beep() {
+    	Toolkit.defaultToolkit.beep()
+    }
+    
+    // Binds the "_" and "__" variables in the shell
+    void bindResults() {
+		shell.setVariable("_", getLastResult()) // lastResult doesn't seem to work
+		shell.setVariable("__", history.collect {it.result})
+    }
+    
+    // Handles menu event
+    void captureStdOut(EventObject evt) {
+    	captureStdOut = evt.source.selected
+    }
+
+    void caretUpdate(CaretEvent e){
+        textSelectionStart = Math.min(e.dot,e.mark)
+        textSelectionEnd = Math.max(e.dot,e.mark)
+    }
+
+    
+    void clearOutput(EventObject evt = null) {
+    	outputArea.setText('')
+    }
+    
+    // Confirm whether to interrupt the running thread
+    void confirmRunInterrupt(EventObject evt) {
+    	def rc = JOptionPane.showConfirmDialog(frame, "Attempt to interrupt script?",
+    		"GroovyConsole", JOptionPane.YES_NO_OPTION) 
+    	if (rc == JOptionPane.YES_OPTION && runThread != null) {
+    		runThread.interrupt()
+    	}
+    }
+    
+    void exit(EventObject evt = null) {
+    	if (askToSaveFile()) {
+            frame.hide()
+            frame.dispose()
+        }
+    }
+    
+    void fileNewFile(EventObject evt = null) {
+    	if (askToSaveFile()) {
+	    	scriptFile = null
+	    	setDirty(false)
+	    	inputArea.text = ''
+    	}
+    }
+    
+    // Start a new window with a copy of current variables
+    void fileNewWindow(EventObject evt = null) {
+      (new Console(new Binding(new HashMap(shell.context.variables)))).run()
+    }
+
+    void fileOpen(EventObject evt = null) {
+        scriptFile = selectFilename();
+        if (scriptFile != null) {
+            inputArea.text = scriptFile.readLines().join('\n');
+            setDirty(false)
+            inputArea.caretPosition = 0
+        }
+    }
+
+	// Save file - return false if user cancelled save
+    boolean fileSave(EventObject evt = null) {
+        if (scriptFile == null) {
+            scriptFile = selectFilename("Save");
+        }
+        if (scriptFile != null) {
+            scriptFile.write(inputArea.text)
+            setDirty(false);
+            return true
+        } else {
+            return false
+        }
+    }
+    
+    def finishException(Throwable t) {
+    	statusLabel.text = 'Execution terminated with exception.'
+    	history[-1].exception = t
+
+		appendOutputNl("Exception thrown: ", promptStyle)
+		appendOutput(t.toString(), resultStyle)
+
+		StringWriter sw = new StringWriter()
+		new PrintWriter(sw).withWriter { pw -> t.printStackTrace(pw) }
+
+		appendOutputNl("\n${sw.buffer}\n", outputStyle)
+		bindResults()
+    }
+    
+    def finishNormal(Object result) {
+    	// Take down the wait/cancel dialog
+    	history[-1].result = result
+    	if (result != null) {
+	    	statusLabel.text = 'Execution complete.'
+	    	appendOutputNl("Result: ", promptStyle)
+			appendOutput("${InvokerHelper.inspect(result)}", resultStyle)
+		} else {
+	    	statusLabel.text = 'Execution complete. Result was null.'
+		}
+		bindResults()	
+    }
+    
+    // Gets the last, non-null result
+    def getLastResult() {
+    	// runtime bugs in here history.reverse produces odd lookup
+    	// return history.reverse.find {it != null}
+    	if (!history) {
+    		return
+    	}
+    	for (i in (history.size() - 1)..0) {
+    		if (history[i].result != null) {
+    			return history[i].result
+    		}
+    	}
+    	return null
+    }
+
+	// Allow access to shell from outside console 
+	// (useful for configuring shell before startup)
+    GroovyShell getShell() {
+		return shell
+    }
+    
+    void historyNext(EventObject evt = null) {
+    	if (historyIndex < history.size()) {
+    		historyIndex++;
+    		setInputTextFromHistory()
+    	} else {
+    		statusLabel.text = "Can't go past end of history (time travel not allowed)"
+    		beep()
+    	}
+    }
+
+    void historyPrev(EventObject evt = null) {
+    	if (historyIndex > 0) {
+    		historyIndex--;
+    		setInputTextFromHistory()
+    	} else {
+    		statusLabel.text = "Can't go past start of history"
+    		beep()
+    	}
+    }
+    
+    void inspectLast(EventObject evt = null){
+        if (null == lastResult) {
+        	JOptionPane.showMessageDialog(frame, "The last result is null.", 
+        		"Cannot Inspect", JOptionPane.INFORMATION_MESSAGE)
+        	return
+        }
+        ObjectBrowser.inspect(lastResult)
+    }
+
+    void inspectVariables(EventObject evt = null) {
+        ObjectBrowser.inspect(shell.context.variables)    
+    }
+    
+    void largerFont(EventObject evt = null) {
+        if (inputArea.font.size > 40) return
+        def newFont = new Font('Monospaced', Font.PLAIN, inputArea.font.size + 2)
+        inputArea.font = newFont
+        outputArea.font = newFont
+    }
+    
+    Boolean notifySystemOut(String str) {
+    	if (!captureStdOut) {
+    		// Output as normal
+	    	return true
+	    }
+	    
+	    // Put onto GUI
+    	if (EventQueue.isDispatchThread()) {
+    		appendOutput(str, outputStyle)
+    	} 
+    	else {
+	    	SwingUtilities.invokeLater {
+		    	appendOutput(str, outputStyle)
+		    }
+		}
+    	return false
+    }
+    
+    // actually run the
+    void runScript(EventObject evt = null) {
+    	def record = new HistoryRecord( allText: inputArea.getText(),
+    		selectionStart: textSelectionStart, selectionEnd: textSelectionEnd)
+    	addToHistory(record)
+
+		// Print the input text    	
+        for (line in record.textToRun.tokenize("\n")) {
+            appendOutputNl('groovy> ', promptStyle)
+            appendOutput(line, commandStyle)
+        }
+        
+        //appendOutputNl("") - with wrong number of args, causes StackOverFlowError;
+        appendOutputNl("\n", promptStyle)
+        
+        // Kick off a new thread to do the evaluation
+        statusLabel.text = 'Running Script...'
+        
+        // Run in separate thread, so that System.out can be captured
+    	runThread = Thread.start {
+    		try {
+    			SwingUtilities.invokeLater { showRunWaitDialog() }
+		        String name = "Script${scriptNameCounter++}"
+				def result = shell.evaluate(record.textToRun, name);
+				SwingUtilities.invokeLater { finishNormal(result) }
+	    	} catch (Throwable t) {
+	    		SwingUtilities.invokeLater { finishException(t) }
+	    	} finally {
+                SwingUtilities.invokeLater {
+                	runWaitDialog.hide();
+                	runThread = null
+                }
+	    	}
+    	}
+    }
+    
+    def selectFilename(name = "Open") {
+        def fc = new JFileChooser()
+        fc.fileSelectionMode = JFileChooser.FILES_ONLY
+        fc.acceptAllFileFilterUsed = true
+        if (fc.showDialog(frame, name) == JFileChooser.APPROVE_OPTION) {
+            return fc.selectedFile
+        } else {
+            return null
+        }
+    }
+
+    void setDirty(boolean newDirty) {
+        dirty = newDirty
+        updateTitle()
+    }
+    
+    private void setInputTextFromHistory() {
+		if (historyIndex < history.size()) {
+			def record = history[historyIndex]
+			inputArea.text = record.allText
+			inputArea.selectionStart = record.selectionStart
+			inputArea.selectionEnd = record.selectionEnd
+			setDirty(true) // Should calculate dirty flag properly (hash last saved/read text in each file)
+			statusLabel.text = "command history ${history.size() - historyIndex}"
+		} else {
+			inputArea.text = ""
+			statusLabel.text = 'at end of history'
+		}    	
+    }
+    
+    // Adds a variable to the binding
+    // Useful for adding variables before openning the console
+    void setVariable(String name, Object value) {
+    	shell.context.setVariable(name, value)
+    }
+    
+    void showAbout(EventObject evt = null) {
+        def version = InvokerHelper.getVersion()
+        def pane = swing.optionPane()
+         // work around GROOVY-1048
+        pane.setMessage('Welcome to the Groovy Console for evaluating Groovy scripts\nVersion ' + version)
+        def dialog = pane.createDialog(frame, 'About GroovyConsole')
+        dialog.show()
+    }
+
+    // Shows the 'wait' dialog
+    void showRunWaitDialog() {
+    	runWaitDialog.pack()
+    	int x = frame.x + (frame.width - runWaitDialog.width) / 2
+    	int y = frame.y + (frame.height - runWaitDialog.height) / 2
+    	runWaitDialog.setLocation(x, y)
+    	runWaitDialog.show()
+    }
+
+    void smallerFont(EventObject evt = null){
+        if (inputArea.font.size < 5) return
+        def newFont = new Font('Monospaced', Font.PLAIN, inputArea.font.size - 2)
+        inputArea.font = newFont
+        outputArea.font = newFont
+    }
+
+    void updateTitle() {
+        if (scriptFile != null) {
+            frame.title = scriptFile.name + (dirty?" * ":"") + " - GroovyConsole"
+        } else {
+            frame.title = "GroovyConsole"
+        }
+    }
+}
+
+/** A single time when the user selected "run" */
+class HistoryRecord {
+	def allText
+	def selectionStart
+	def selectionEnd
+	def scriptName
+	def result
+	def exception
+	
+	def getTextToRun() {
+        if (selectionStart != selectionEnd) {   
+            return allText[selectionStart ..< selectionEnd]
+        }
+        return allText
+	}
+	
+	def getValue() {
+		return exception ? exception : result
+	}
+}
diff --git a/groovy-core/src/main/groovy/ui/ConsoleSupport.java b/groovy-core/src/main/groovy/ui/ConsoleSupport.java
new file mode 100644
index 0000000..cae7b93
--- /dev/null
+++ b/groovy-core/src/main/groovy/ui/ConsoleSupport.java
@@ -0,0 +1,121 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+ statements and notices.  Redistributions must also contain a
+ copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+ above copyright notice, this list of conditions and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+ products derived from this Software without prior written
+ permission of The Codehaus.  For written permission,
+ please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+ nor may "groovy" appear in their names without prior written
+ permission of The Codehaus. "groovy" is a registered
+ trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+ http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.ui;
+
+import groovy.lang.GroovyShell;
+
+import java.awt.Color;
+
+import javax.swing.JTextPane;
+import javax.swing.text.Style;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyleContext;
+import javax.swing.text.StyledDocument;
+
+/**
+ * Base class for console
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public abstract class ConsoleSupport {
+
+    Style promptStyle;
+    Style commandStyle;
+    Style outputStyle;
+    private GroovyShell shell;
+    int counter;
+
+    protected void addStylesToDocument(JTextPane outputArea) {
+        StyledDocument doc = outputArea.getStyledDocument();
+
+        Style def = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
+
+        Style regular = doc.addStyle("regular", def);
+        StyleConstants.setFontFamily(def, "Monospaced");
+
+        promptStyle = doc.addStyle("prompt", regular);
+        StyleConstants.setForeground(promptStyle, Color.BLUE);
+
+        commandStyle = doc.addStyle("command", regular);
+        StyleConstants.setForeground(commandStyle, Color.MAGENTA);
+
+        outputStyle = doc.addStyle("output", regular);
+        StyleConstants.setBold(outputStyle, true);
+    }
+
+    public Style getCommandStyle() {
+        return commandStyle;
+    }
+
+    public Style getOutputStyle() {
+        return outputStyle;
+    }
+
+    public Style getPromptStyle() {
+        return promptStyle;
+    }
+
+    public GroovyShell getShell() {
+        if (shell == null) {
+            shell = new GroovyShell();
+        }
+        return shell;
+    }
+
+    protected Object evaluate(String text) {
+        String name = "Script" + counter++;
+        try {
+            return getShell().evaluate(text, name);
+        }
+        catch (Exception e) {
+            handleException(text, e);
+            return null;
+        }
+    }
+    
+    protected abstract void handleException(String text, Exception e);
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/ui/GroovyMain.java b/groovy-core/src/main/groovy/ui/GroovyMain.java
new file mode 100644
index 0000000..ad3e279
--- /dev/null
+++ b/groovy-core/src/main/groovy/ui/GroovyMain.java
@@ -0,0 +1,487 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+ statements and notices.  Redistributions must also contain a
+ copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+ above copyright notice, this list of conditions and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+ products derived from this Software without prior written
+ permission of The Codehaus.  For written permission,
+ please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+ nor may "groovy" appear in their names without prior written
+ permission of The Codehaus. "groovy" is a registered
+ trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+ http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.ui;
+
+import groovy.lang.GroovyShell;
+import groovy.lang.MetaClass;
+import groovy.lang.Script;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.List;
+import java.math.BigInteger;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.PosixParser;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.InvokerInvocationException;
+
+/**
+ * A Command line to execute groovy.
+ *
+ * @author Jeremy Rayner
+ * @author Yuri Schimke
+ * @version $Revision$
+ */
+public class GroovyMain {
+    // arguments to the script
+    private List args;
+
+    // is this a file on disk
+    private boolean isScriptFile;
+
+    // filename or content of script
+    private String script;
+
+    // process args as input files
+    private boolean processFiles;
+
+    // edit input files in place
+    private boolean editFiles;
+
+    // automatically output the result of each script
+    private boolean autoOutput;
+
+    // automatically split each line using the splitpattern
+    private boolean autoSplit;
+
+    // The pattern used to split the current line
+    private String splitPattern = " ";
+
+    // process sockets
+    private boolean processSockets;
+
+    // port to listen on when processing sockets
+    private int port;
+
+    // backup input files with extension
+    private String backupExtension;
+
+    // do you want full stack traces in script exceptions?
+    private boolean debug = false;
+
+    // Compiler configuration, used to set the encodings of the scripts/classes
+    private CompilerConfiguration conf = new CompilerConfiguration();
+
+    /**
+     * Main CLI interface.
+     *
+     * @param args all command line args.
+     */
+    public static void main(String args[]) {
+        MetaClass.setUseReflection(true);
+
+        Options options = buildOptions();
+
+        try {
+            CommandLine cmd = parseCommandLine(options, args);
+
+            if (cmd.hasOption('h')) {
+                HelpFormatter formatter = new HelpFormatter();
+                formatter.printHelp("groovy", options);
+            } else if (cmd.hasOption('v')) {
+                String version = InvokerHelper.getVersion();
+                System.out.println("Groovy Version: " + version + " JVM: " + System.getProperty("java.vm.version"));
+            } else {
+                // If we fail, then exit with an error so scripting frameworks can catch it
+                if (!process(cmd)) {
+                    System.exit(1);
+                }
+            }
+        } catch (ParseException pe) {
+            System.out.println("error: " + pe.getMessage());
+            HelpFormatter formatter = new HelpFormatter();
+            formatter.printHelp("groovy", options);
+        }
+    }
+
+    /**
+     * Parse the command line.
+     *
+     * @param options the options parser.
+     * @param args    the command line args.
+     * @return parsed command line.
+     * @throws ParseException if there was a problem.
+     */
+    private static CommandLine parseCommandLine(Options options, String[] args) throws ParseException {
+        CommandLineParser parser = new PosixParser();
+        CommandLine cmd = parser.parse(options, args, true);
+        return cmd;
+    }
+
+    /**
+     * Build the options parser.  Has to be synchronized because of the way Options are constructed.
+     *
+     * @return an options parser.
+     */
+    private static synchronized Options buildOptions() {
+        Options options = new Options();
+
+        options.addOption(
+            OptionBuilder.hasArg(false)
+            .withDescription("usage information")
+            .withLongOpt("help")
+            .create('h'));
+        options.addOption(
+            OptionBuilder.hasArg(false)
+            .withDescription("debug mode will print out full stack traces")
+            .withLongOpt("debug")
+            .create('d'));
+        options.addOption(
+            OptionBuilder.hasArg(false)
+            .withDescription("display the Groovy and JVM versions")
+            .withLongOpt("version")
+            .create('v'));
+        options.addOption(
+            OptionBuilder.withArgName("charset")
+            .hasArg()
+            .withDescription("specify the encoding of the files")
+            .withLongOpt("encoding")
+            .create('c'));
+        options.addOption(
+            OptionBuilder.withArgName("script")
+            .hasArg()
+            .withDescription("specify a command line script")
+            .create('e'));
+        options.addOption(
+            OptionBuilder.withArgName("extension")
+            .hasOptionalArg()
+            .withDescription("modify files in place, create backup if extension is given (e.g. \'.bak\')")
+            .create('i'));
+        options.addOption(
+            OptionBuilder.hasArg(false)
+            .withDescription("process files line by line")
+            .create('n'));
+        options.addOption(
+            OptionBuilder.hasArg(false)
+            .withDescription("process files line by line and print result")
+            .create('p'));
+        options.addOption(
+            OptionBuilder.withArgName("port")
+            .hasOptionalArg()
+            .withDescription("listen on a port and process inbound lines")
+            .create('l'));
+        options.addOption(
+                OptionBuilder.withArgName("splitPattern")
+                .hasOptionalArg()
+                .withDescription("automatically split current line (defaults to '\\s'")
+                .withLongOpt("autosplit")
+                .create('a'));
+        return options;
+    }
+
+    /**
+     * Process the users request.
+     *
+     * @param line the parsed command line.
+     * @throws ParseException if invalid options are chosen
+     */
+    private static boolean process(CommandLine line) throws ParseException {
+        GroovyMain main = new GroovyMain();
+
+        List args = line.getArgList();
+
+        // add the ability to parse scripts with a specified encoding
+        if (line.hasOption('c')) {
+            main.conf.setSourceEncoding(line.getOptionValue("encoding"));
+        }
+
+        main.isScriptFile = !line.hasOption('e');
+        main.debug = line.hasOption('d');
+        main.conf.setDebug(main.debug);
+        main.processFiles = line.hasOption('p') || line.hasOption('n');
+        main.autoOutput = line.hasOption('p');
+        main.editFiles = line.hasOption('i');
+        if (main.editFiles) {
+            main.backupExtension = line.getOptionValue('i');
+        }
+        main.autoSplit = line.hasOption('a');
+        String sp = line.getOptionValue('a');
+        if (sp != null)
+            main.splitPattern = sp;
+
+        if (main.isScriptFile) {
+            if (args.isEmpty())
+                throw new ParseException("neither -e or filename provided");
+
+            main.script = (String) args.remove(0);
+            if (main.script.endsWith(".java"))
+                throw new ParseException("error: cannot compile file with .java extension: " + main.script);
+        } else {
+            main.script = line.getOptionValue('e');
+        }
+
+        main.processSockets = line.hasOption('l');
+        if (main.processSockets) {
+            String p = line.getOptionValue('l', "1960"); // default port to listen to
+            main.port = new Integer(p).intValue();
+        }
+        main.args = args;
+
+        return main.run();
+    }
+
+
+    /**
+     * Run the script.
+     */
+    private boolean run() {
+        try {
+            if (processSockets) {
+                processSockets();
+            } else if (processFiles) {
+                processFiles();
+            } else {
+                processOnce();
+            }
+            return true;
+        } catch (CompilationFailedException e) {
+            System.err.println(e);
+            return false;
+        } catch (Throwable e) {
+            if (e instanceof InvokerInvocationException) {
+                InvokerInvocationException iie = (InvokerInvocationException) e;
+                e = iie.getCause();
+            }
+            System.err.println("Caught: " + e);
+            if (debug) {
+                e.printStackTrace();
+            } else {
+                StackTraceElement[] stackTrace = e.getStackTrace();
+                for (int i = 0; i < stackTrace.length; i++) {
+                    StackTraceElement element = stackTrace[i];
+                    String fileName = element.getFileName();
+                    if (fileName!=null && !fileName.endsWith(".java")) {
+                        System.err.println("\tat " + element);
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Process Sockets.
+     */
+    private void processSockets() throws CompilationFailedException, IOException {
+        GroovyShell groovy = new GroovyShell(conf);
+        //check the script is currently valid before starting a server against the script
+        if (isScriptFile) {
+            groovy.parse(new FileInputStream(huntForTheScriptFile(script)));
+        } else {
+            groovy.parse(script);
+        }
+        new GroovySocketServer(groovy, isScriptFile, script, autoOutput, port);
+    }
+
+    /**
+     * Hunt for the script file, doesn't bother if it is named precisely.
+     *
+     * Tries in this order:
+     * - actual supplied name
+     * - name.groovy
+     * - name.gvy
+     * - name.gy
+     * - name.gsh
+     */
+    public File huntForTheScriptFile(String scriptFileName) {
+        File scriptFile = new File(scriptFileName);
+        String[] standardExtensions = {".groovy",".gvy",".gy",".gsh"};
+        int i = 0;
+        while (i < standardExtensions.length && !scriptFile.exists()) {
+            scriptFile = new File(scriptFileName + standardExtensions[i]);
+            i++;
+        }
+        // if we still haven't found the file, point back to the originally specified filename
+        if (!scriptFile.exists()) {
+            scriptFile = new File(scriptFileName);
+        }
+        return scriptFile;
+    }
+
+    /**
+     * Process the input files.
+     */
+    private void processFiles() throws CompilationFailedException, IOException {
+        GroovyShell groovy = new GroovyShell(conf);
+
+        Script s = null;
+
+        if (isScriptFile) {
+            s = groovy.parse(huntForTheScriptFile(script));
+        } else {
+            s = groovy.parse(script, "main");
+        }
+
+        if (args.isEmpty()) {
+            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
+            PrintWriter writer = new PrintWriter(System.out);
+
+            try {
+                processReader(s, reader, writer);
+            } finally {
+                reader.close();
+                writer.close();
+            }
+
+        } else {
+            Iterator i = args.iterator();
+            while (i.hasNext()) {
+                String filename = (String) i.next();
+                File file = huntForTheScriptFile(filename);
+                processFile(s, file);
+            }
+        }
+    }
+
+    /**
+     * Process a single input file.
+     *
+     * @param s    the script to execute.
+     * @param file the input file.
+     */
+    private void processFile(Script s, File file) throws IOException {
+        if (!file.exists())
+            throw new FileNotFoundException(file.getName());
+
+        if (!editFiles) {
+            BufferedReader reader = new BufferedReader(new FileReader(file));
+            try {
+                PrintWriter writer = new PrintWriter(System.out);
+                processReader(s, reader, writer);
+                writer.flush();
+            } finally {
+                reader.close();
+            }
+        } else {
+            File backup = null;
+            if (backupExtension == null) {
+                backup = File.createTempFile("groovy_", ".tmp");
+                backup.deleteOnExit();
+            } else {
+                backup = new File(file.getPath() + backupExtension);
+            }
+            backup.delete();
+            if (!file.renameTo(backup))
+                throw new IOException("unable to rename " + file + " to " + backup);
+
+            BufferedReader reader = new BufferedReader(new FileReader(backup));
+            try {
+                PrintWriter writer = new PrintWriter(new FileWriter(file));
+                try {
+                    processReader(s, reader, writer);
+                } finally {
+                    writer.close();
+                }
+            } finally {
+                reader.close();
+            }
+        }
+    }
+
+    /**
+     * Process a script against a single input file.
+     *
+     * @param s      script to execute.
+     * @param reader input file.
+     * @param pw     output sink.
+     */
+    private void processReader(Script s, BufferedReader reader, PrintWriter pw) throws IOException {
+        String line = null;
+        String lineCountName = "count";
+        s.setProperty(lineCountName, BigInteger.ZERO);
+        String autoSplitName = "split";
+        s.setProperty("out", pw);
+        while ((line = reader.readLine()) != null) {
+            s.setProperty("line", line);
+            s.setProperty(lineCountName,
+                    ((BigInteger)s.getProperty(lineCountName)).add(BigInteger.ONE));
+            if(autoSplit)
+                s.setProperty(autoSplitName, line.split(splitPattern));
+            Object o = s.run();
+
+            if (autoOutput) {
+                pw.println(o);
+            }
+        }
+    }
+
+    private static ClassLoader getLoader(ClassLoader cl) {
+        if (cl!=null) return cl;
+        cl = Thread.currentThread().getContextClassLoader();
+        if (cl!=null) return cl;
+        cl = GroovyMain.class.getClassLoader();
+        if (cl!=null) return cl;
+        return null;
+    }
+
+    /**
+     * Process the standard, single script with args.
+     */
+    private void processOnce() throws CompilationFailedException, IOException {
+        GroovyShell groovy = new GroovyShell(conf);
+
+        if (isScriptFile)
+            groovy.run(huntForTheScriptFile(script), args);
+        else
+            groovy.run(script, "script_from_command_line", args);
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/ui/GroovySocketServer.java b/groovy-core/src/main/groovy/ui/GroovySocketServer.java
new file mode 100644
index 0000000..b2cdfae
--- /dev/null
+++ b/groovy-core/src/main/groovy/ui/GroovySocketServer.java
@@ -0,0 +1,162 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.ui;
+
+import groovy.lang.GroovyShell;
+import groovy.lang.Script;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URL;
+
+/**
+ * Simple server that executes supplied script against a socket
+ * @author Jeremy Rayner
+ */
+
+public class GroovySocketServer implements Runnable {
+    private URL url;
+    private GroovyShell groovy;
+    private boolean isScriptFile;
+    private String scriptFilenameOrText;
+    private boolean autoOutput;
+    
+    public GroovySocketServer(GroovyShell groovy, boolean isScriptFile, String scriptFilenameOrText, boolean autoOutput, int port) {
+        this.groovy = groovy;
+        this.isScriptFile = isScriptFile;
+        this.scriptFilenameOrText = scriptFilenameOrText;
+        this.autoOutput = autoOutput;
+        try {
+            url = new URL("http", InetAddress.getLocalHost().getHostAddress(), port, "/");
+            System.out.println("groovy is listening on port " + port);
+        } catch (IOException e) { 
+            e.printStackTrace();
+        }
+        new Thread(this).start();
+    }
+
+    public void run() {
+        try {
+            ServerSocket serverSocket = new ServerSocket(url.getPort());
+            while (true) {
+                // Create one script per socket connection.
+                // This is purposefully not caching the Script
+                // so that the script source file can be changed on the fly,
+                // as each connection is made to the server.
+                Script script;
+                if (isScriptFile) {
+                    GroovyMain gm = new GroovyMain();
+                    script = groovy.parse(new FileInputStream(gm.huntForTheScriptFile(scriptFilenameOrText)));
+                } else {
+                    script = groovy.parse(scriptFilenameOrText);
+                }
+                new GroovyClientConnection(script, autoOutput, serverSocket.accept());
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+    
+    class GroovyClientConnection implements Runnable {
+        private Script script;
+        private Socket socket;
+        private BufferedReader reader;
+        private PrintWriter writer;
+        private boolean autoOutputFlag;
+    
+        GroovyClientConnection(Script script, boolean autoOutput,Socket socket) throws IOException {
+            this.script = script;
+            this.autoOutputFlag = autoOutput;
+            this.socket = socket;
+            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+            writer = new PrintWriter(socket.getOutputStream());
+            new Thread(this, "Groovy client connection - " + socket.getInetAddress().getHostAddress()).start();
+        }
+        public void run() {
+            try {
+                String line = null;
+                script.setProperty("out", writer);
+                script.setProperty("socket", socket);
+                script.setProperty("init", Boolean.TRUE);
+                while ((line = reader.readLine()) != null) {
+                    // System.out.println(line);
+                    script.setProperty("line", line);
+                    Object o = script.run();
+                    script.setProperty("init", Boolean.FALSE);
+                    if (o != null) {
+                        if ("success".equals(o)) {
+                            break; // to close sockets gracefully etc...
+                        } else {
+                            if (autoOutputFlag) {
+                                writer.println(o);
+                            }
+                        }
+                    }
+                    writer.flush();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            } finally {
+                try {
+                    writer.flush();
+                    writer.close();
+                } finally {
+                    try {
+                        socket.close();
+                    } catch (IOException e3) {
+                        e3.printStackTrace();
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/groovy-core/src/main/groovy/ui/InteractiveShell.java b/groovy-core/src/main/groovy/ui/InteractiveShell.java
new file mode 100644
index 0000000..315b9d2
--- /dev/null
+++ b/groovy-core/src/main/groovy/ui/InteractiveShell.java
@@ -0,0 +1,569 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.ui;
+
+import groovy.lang.Binding;
+import groovy.lang.GroovyShell;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.InvokerInvocationException;
+import org.codehaus.groovy.sandbox.ui.Prompt;
+import org.codehaus.groovy.sandbox.ui.PromptFactory;
+import org.codehaus.groovy.tools.ErrorReporter;
+
+/**
+ * A simple interactive shell for evaluating groovy expressions
+ * on the command line
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author <a href="mailto:cpoirier@dreaming.org"   >Chris Poirier</a>
+ * @author Yuri Schimke
+ * @author Brian McCallistair
+ * @author Guillaume Laforge
+ * @author Dierk Koenig, include the inspect command, June 2005
+ * @version $Revision$
+ */
+public class InteractiveShell {
+    private final GroovyShell shell;
+    private final Prompt prompt;
+    private final InputStream in;
+    private final PrintStream out;
+    private final PrintStream err;
+    private Object lastResult;
+
+
+    /**
+     * Entry point when called directly.
+     */
+    public static void main(String args[]) {
+        try {
+            final InteractiveShell groovy = new InteractiveShell();
+            groovy.run(args);
+        }
+        catch (Exception e) {
+            System.err.println("Caught: " + e);
+            e.printStackTrace();
+        }
+    }
+
+
+    /**
+     * Default constructor.
+     */
+    public InteractiveShell() {
+        this(System.in, System.out, System.err);
+    }
+
+
+    public InteractiveShell(final InputStream in, final PrintStream out, final PrintStream err) {
+        this(null,new Binding(), in, out, err);
+    }
+
+    /**
+     * Constructs a new InteractiveShell instance
+     * 
+     * @param binding The binding instance
+     * @param in The input stream to use
+     * @param out The output stream to use
+     * @param err The error stream to use
+     */    
+    public InteractiveShell(Binding binding, final InputStream in, final PrintStream out, final PrintStream err) {
+    	this(null,binding,in,out,err);
+    }
+    
+    /**
+     * Constructs a new InteractiveShell instance
+     * 
+     * @param parent The parent ClassLoader
+     * @param binding The binding instance
+     * @param in The input stream to use
+     * @param out The output stream to use
+     * @param err The error stream to use
+     */
+    public InteractiveShell(ClassLoader parent,Binding binding, final InputStream in, final PrintStream out, final PrintStream err) {
+        this.in = in;
+        this.out = out;
+        this.err = err;
+        prompt = PromptFactory.buildPrompt(in, out, err);
+        prompt.setPrompt("groovy> ");
+        if(parent!= null) {
+        	shell = new GroovyShell(parent,binding);	
+        }
+        else {
+        	shell = new GroovyShell(binding);
+        }        
+        Map map = shell.getContext().getVariables();
+        if (map.get("shell") != null) {
+            map.put("shell", shell);
+        }
+    }    
+
+    //---------------------------------------------------------------------------
+    // COMMAND LINE PROCESSING LOOP
+
+    /**
+     * Reads commands and statements from input stream and processes them.
+     */
+    public void run(String[] args) throws Exception {
+        final String version = InvokerHelper.getVersion();
+
+        out.println("Let's get Groovy!");
+        out.println("================");
+        out.println("Version: " + version + " JVM: " + System.getProperty("java.vm.version"));
+        out.println("Type 'exit' to terminate the shell");
+        out.println("Type 'help' for command help");
+        out.println("Type 'go' to execute the statements");
+
+        boolean running = true;
+        while (running) {
+            // Read a single top-level statement from the command line,
+            // trapping errors as they happen.  We quit on null.
+            final String command = read();
+            if (command == null) {
+                close();
+                break;
+            }
+
+            reset();
+
+            if (command.length() > 0) {
+                // We have a command that parses, so evaluate it.
+                try {
+                    lastResult = shell.evaluate(command, "CommandLine.groovy");
+                    out.println("\n===> " + lastResult);
+                } catch (CompilationFailedException e) {
+                    err.println(e);
+                } catch (Throwable e) {
+                    if (e instanceof InvokerInvocationException) {
+                        InvokerInvocationException iie = (InvokerInvocationException) e;
+                        e = iie.getCause();
+                    }
+                    filterAndPrintStackTrace(e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Filter stacktraces to show only relevant lines of the exception thrown.
+     *
+     * @param e the throwable whose stacktrace needs to be filtered
+     */
+    private void filterAndPrintStackTrace(Throwable e) {
+        err.println("Caught: " + e);
+        StackTraceElement[] stackTrace = e.getStackTrace();
+        for (int i = 0; i < stackTrace.length; i++) {
+            StackTraceElement element = stackTrace[i];
+            String fileName = element.getFileName();
+            if ((fileName==null || (!fileName.endsWith(".java")) && (!element.getClassName().startsWith("gjdk")))) {
+                err.println("\tat " + element);
+            }
+        }
+    }
+
+    protected void close() {
+        prompt.close();
+    }
+
+
+    //---------------------------------------------------------------------------
+    // COMMAND LINE PROCESSING MACHINERY
+
+
+    private StringBuffer accepted = new StringBuffer(); // The statement text accepted to date
+    private String pending = null;                      // A line of statement text not yet accepted
+    private int line = 1;                               // The current line number
+
+    private boolean stale = false;                      // Set to force clear of accepted
+
+    private SourceUnit parser = null;                   // A SourceUnit used to check the statement
+    private Exception error = null;                     // Any actual syntax error caught during parsing
+
+
+    /**
+     * Resets the command-line processing machinery after use.
+     */
+
+    protected void reset() {
+        stale = true;
+        pending = null;
+        line = 1;
+
+        parser = null;
+        error = null;
+    }
+
+
+    /**
+     * Reads a single statement from the command line.  Also identifies
+     * and processes command shell commands.  Returns the command text
+     * on success, or null when command processing is complete.
+     * <p/>
+     * NOTE: Changed, for now, to read until 'execute' is issued.  At
+     * 'execute', the statement must be complete.
+     */
+
+    protected String read() {
+        reset();
+        out.println("");
+
+        boolean complete = false;
+        boolean done = false;
+
+        while (/* !complete && */ !done) {
+
+            // Read a line.  If IOException or null, or command "exit", terminate
+            // processing.
+
+            try {
+                pending = prompt.readLine();
+            }
+            catch (IOException e) {
+            }
+
+            if (pending == null || (COMMAND_MAPPINGS.containsKey(pending) && ((Integer) COMMAND_MAPPINGS.get(pending)).intValue() == COMMAND_ID_EXIT)) {
+                return null;                                  // <<<< FLOW CONTROL <<<<<<<<
+            }
+
+            // First up, try to process the line as a command and proceed accordingly.
+            if (COMMAND_MAPPINGS.containsKey(pending)) {
+                int code = ((Integer) COMMAND_MAPPINGS.get(pending)).intValue();
+                switch (code) {
+                    case COMMAND_ID_HELP:
+                        displayHelp();
+                        break;
+
+                    case COMMAND_ID_DISCARD:
+                        reset();
+                        done = true;
+                        break;
+
+                    case COMMAND_ID_DISPLAY:
+                        displayStatement();
+                        break;
+
+                    case COMMAND_ID_EXPLAIN:
+                        explainStatement();
+                        break;
+
+                    case COMMAND_ID_BINDING:
+                        displayBinding();
+                        break;
+
+                    case COMMAND_ID_EXECUTE:
+                        if (complete) {
+                            done = true;
+                        }
+                        else {
+                            err.println("statement not complete");
+                        }
+                        break;
+                    case COMMAND_ID_DISCARD_LOADED_CLASSES:
+                        resetLoadedClasses();
+                        break;
+                    case COMMAND_ID_INSPECT:
+                        inspect();
+                        break;
+                }
+
+                continue;                                     // <<<< LOOP CONTROL <<<<<<<<
+            }
+
+            // Otherwise, it's part of a statement.  If it's just whitespace,
+            // we'll just accept it and move on.  Otherwise, parsing is attempted
+            // on the cumulated statement text, and errors are reported.  The
+            // pending input is accepted or rejected based on that parsing.
+
+            freshen();
+
+            if (pending.trim().length() == 0) {
+                accept();
+                continue;                                     // <<<< LOOP CONTROL <<<<<<<<
+            }
+
+            final String code = current();
+
+            if (parse(code, 1)) {
+                accept();
+                complete = true;
+            }
+            else if (error == null) {
+                accept();
+            }
+            else {
+                report();
+            }
+
+        }
+
+        // Get and return the statement.
+        return accepted(complete);
+    }
+
+    private void inspect() {
+        if (null == lastResult){
+            err.println("nothing to inspect (preceding \"go\" missing?)");
+            return;
+        }
+        // this should read: groovy.inspect.swingui.ObjectBrowser.inspect(lastResult)
+        // but this doesnt compile since ObjectBrowser.groovy is compiled after this class.
+        try {
+            Class browserClass = Class.forName("groovy.inspect.swingui.ObjectBrowser");
+            Method inspectMethod = browserClass.getMethod("inspect", new Class[]{Object.class});
+            inspectMethod.invoke(browserClass, new Object[]{lastResult});
+        } catch (Exception e) {
+            err.println("cannot invoke ObjectBrowser");
+            e.printStackTrace();
+        }
+    }
+
+
+    /**
+     * Returns the accepted statement as a string.  If not <code>complete</code>,
+     * returns the empty string.
+     */
+    private String accepted(boolean complete) {
+        if (complete) {
+            return accepted.toString();
+        }
+        return "";
+    }
+
+
+    /**
+     * Returns the current statement, including pending text.
+     */
+    private String current() {
+        return accepted.toString() + pending + "\n";
+    }
+
+
+    /**
+     * Accepts the pending text into the statement.
+     */
+    private void accept() {
+        accepted.append(pending).append("\n");
+        line += 1;
+    }
+
+
+    /**
+     * Clears accepted if stale.
+     */
+    private void freshen() {
+        if (stale) {
+            accepted.setLength(0);
+            stale = false;
+        }
+    }
+
+
+    //---------------------------------------------------------------------------
+    // SUPPORT ROUTINES
+
+
+    /**
+     * Attempts to parse the specified code with the specified tolerance.
+     * Updates the <code>parser</code> and <code>error</code> members
+     * appropriately.  Returns true if the text parsed, false otherwise.
+     * The attempts to identify and suppress errors resulting from the
+     * unfinished source text.
+     */
+    private boolean parse(String code, int tolerance) {
+        boolean parsed = false;
+
+        parser = null;
+        error = null;
+
+        // Create the parser and attempt to parse the text as a top-level statement.
+        try {
+            parser = SourceUnit.create("groovysh script", code, tolerance);
+            parser.parse();
+
+            parsed = true;
+        }
+
+        // We report errors other than unexpected EOF to the user.
+        catch (CompilationFailedException e) {
+            if (parser.getErrorCollector().getErrorCount() > 1 || !parser.failedWithUnexpectedEOF()) {
+                error = e;
+            }
+        }
+        catch (Exception e) {
+            error = e;
+        }
+
+        return parsed;
+    }
+
+
+    /**
+     * Reports the last parsing error to the user.
+     */
+
+    private void report() {
+        err.println("Discarding invalid text:");
+        new ErrorReporter(error, false).write(err);
+    }
+
+    //-----------------------------------------------------------------------
+    // COMMANDS
+
+    private static final int COMMAND_ID_EXIT = 0;
+    private static final int COMMAND_ID_HELP = 1;
+    private static final int COMMAND_ID_DISCARD = 2;
+    private static final int COMMAND_ID_DISPLAY = 3;
+    private static final int COMMAND_ID_EXPLAIN = 4;
+    private static final int COMMAND_ID_EXECUTE = 5;
+    private static final int COMMAND_ID_BINDING = 6;
+    private static final int COMMAND_ID_DISCARD_LOADED_CLASSES = 7;
+    private static final int COMMAND_ID_INSPECT = 8;
+
+    private static final int LAST_COMMAND_ID = 8;
+
+    private static final String[] COMMANDS = { "exit", "help", "discard", "display", "explain", "execute", "binding", "discardclasses", "inspect" };
+
+    private static final Map COMMAND_MAPPINGS = new HashMap();
+
+    static {
+        for (int i = 0; i <= LAST_COMMAND_ID; i++) {
+            COMMAND_MAPPINGS.put(COMMANDS[i], new Integer(i));
+        }
+
+        // A few synonyms
+
+        COMMAND_MAPPINGS.put("quit", new Integer(COMMAND_ID_EXIT));
+        COMMAND_MAPPINGS.put("go", new Integer(COMMAND_ID_EXECUTE));
+    }
+
+    private static final Map COMMAND_HELP = new HashMap();
+
+    static {
+        COMMAND_HELP.put(COMMANDS[COMMAND_ID_EXIT],    "exit/quit         - terminates processing");
+        COMMAND_HELP.put(COMMANDS[COMMAND_ID_HELP],    "help              - displays this help text");
+        COMMAND_HELP.put(COMMANDS[COMMAND_ID_DISCARD], "discard           - discards the current statement");
+        COMMAND_HELP.put(COMMANDS[COMMAND_ID_DISPLAY], "display           - displays the current statement");
+        COMMAND_HELP.put(COMMANDS[COMMAND_ID_EXPLAIN], "explain           - explains the parsing of the current statement (currently disabled)");
+        COMMAND_HELP.put(COMMANDS[COMMAND_ID_EXECUTE], "execute/go        - temporary command to cause statement execution");
+        COMMAND_HELP.put(COMMANDS[COMMAND_ID_BINDING], "binding           - shows the binding used by this interactive shell");
+        COMMAND_HELP.put(COMMANDS[COMMAND_ID_DISCARD_LOADED_CLASSES],
+                                                       "discardclasses    - discards all former unbound class definitions");
+        COMMAND_HELP.put(COMMANDS[COMMAND_ID_INSPECT], "inspect           - opens ObjectBrowser on expression returned from previous \"go\"");
+    }
+
+
+    /**
+     * Displays help text about available commands.
+     */
+    private void displayHelp() {
+        out.println("Available commands (must be entered without extraneous characters):");
+        for (int i = 0; i <= LAST_COMMAND_ID; i++) {
+            out.println((String) COMMAND_HELP.get(COMMANDS[i]));
+        }
+    }
+
+
+    /**
+     * Displays the accepted statement.
+     */
+    private void displayStatement() {
+        final String[] lines = accepted.toString().split("\n");
+        for (int i = 0; i < lines.length; i++) {
+            out.println((i + 1) + "> " + lines[i]);
+        }
+    }
+
+    /**
+     * Displays the current binding used when instanciating the shell.
+     */
+    private void displayBinding() {
+        out.println("Available variables in the current binding");
+        Binding context = shell.getContext();
+        Map variables = context.getVariables();
+        Set set = variables.keySet();
+        if (set.isEmpty()) {
+            out.println("The current binding is empty.");
+        }
+        else {
+            for (Iterator it = set.iterator(); it.hasNext();) {
+                String key = (String) it.next();
+                out.println(key + " = " + variables.get(key));
+            }
+        }
+    }
+
+
+    /**
+     * Attempts to parse the accepted statement and display the
+     * parse tree for it.
+     */
+    private void explainStatement() {
+        if (parse(accepted(true), 10) || error == null) {
+            out.println("Parse tree:");
+            //out.println(tree);
+        }
+        else {
+            out.println("Statement does not parse");
+        }
+    }
+
+    private void resetLoadedClasses() {
+        shell.resetLoadedClasses();
+        out.println("all former unbound class definitions are discarded");
+    }
+}
+
diff --git a/groovy-core/src/main/groovy/ui/ShellCompleter.java b/groovy-core/src/main/groovy/ui/ShellCompleter.java
new file mode 100644
index 0000000..db0096a
--- /dev/null
+++ b/groovy-core/src/main/groovy/ui/ShellCompleter.java
@@ -0,0 +1,121 @@
+/*
+$Id$
+
+Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+package groovy.ui;
+
+import groovy.lang.GroovyShell;
+import groovy.lang.MetaMethod;
+import org.codehaus.groovy.sandbox.ui.Completer;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Readline completion for InteractiveShell.
+ *
+ * @author Yuri Schimke
+ * @version $Revision$
+ */
+public class ShellCompleter implements Completer {
+    // The shell being handled
+    private GroovyShell shell;
+    private List completions = new ArrayList();
+
+    public ShellCompleter(GroovyShell shell) {
+        this.shell = shell;
+    }
+
+    // @TODO add optimisations like check for . and rule out variables etc
+    public List findCompletions(String token) {
+        completions.clear();
+
+        if (token.length() == 0) {
+            return completions;
+        }
+
+        // completions of local variable names
+        findLocalVariables(token);
+
+        // completions of local fields.
+
+        // completions of local methods
+        findShellMethods(token);
+
+        // completions of methods invoked on a target
+        //findTargetCompletions(complete);
+
+        // completion of keywords.
+
+        return completions;
+    }
+
+    private void findShellMethods(String complete) {
+        List methods = shell.getMetaClass().getMetaMethods();
+        for (Iterator i = methods.iterator(); i.hasNext();) {
+            MetaMethod method = (MetaMethod) i.next();
+            if (method.getName().startsWith(complete)) {
+                if (method.getParameterTypes().length > 0) {
+                    completions.add(method.getName() + "(");
+                }
+                else {
+                    completions.add(method.getName() + "()");
+                }
+            }
+        }
+    }
+
+    private void findLocalVariables(String complete) {
+        Set names = shell.getContext().getVariables().keySet();
+
+        for (Iterator i = names.iterator(); i.hasNext();) {
+            String name = (String) i.next();
+            if (name.startsWith(complete)) {
+                completions.add(name);
+            }
+        }
+    }
+}
diff --git a/groovy-core/src/main/groovy/ui/SystemOutputInterceptor.java b/groovy-core/src/main/groovy/ui/SystemOutputInterceptor.java
new file mode 100644
index 0000000..29f30f0
--- /dev/null
+++ b/groovy-core/src/main/groovy/ui/SystemOutputInterceptor.java
@@ -0,0 +1,63 @@
+package groovy.ui;
+
+import groovy.lang.Closure;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+
+/**
+ * Intercepts System.out. Implementation helper for Console.groovy.
+ */
+class SystemOutputInterceptor extends FilterOutputStream {
+
+	private Closure callback;
+
+	/**
+	 * Constructor
+	 * 
+	 * @param callback
+	 *            accepts a string to be sent to std out and returns a Boolean.
+	 *            If the return value is true, output will be sent to
+	 *            System.out, otherwise it will not.
+	 */
+	public SystemOutputInterceptor(Closure callback) {
+		super(System.out);
+		this.callback = callback;
+	}
+
+	/**
+	 * Starts intercepting System.out
+	 */
+	public void start() {
+		System.setOut(new PrintStream(this));
+	}
+
+	/**
+	 * Stops intercepting System.out, sending output to whereever it was
+	 * going when this interceptor was created.
+	 */
+	public void stop() {
+		System.setOut((PrintStream) out);
+	}
+
+	/**
+	 * Intercepts output - moret common case of byte[]
+	 */
+	public void write(byte[] b, int off, int len) throws IOException {
+		Boolean result = (Boolean) callback.call(new String(b, off, len));
+		if (result.booleanValue()) {
+			out.write(b, off, len);
+		}
+	}
+
+	/**
+	 * Intercepts output - single characters
+	 */
+	public void write(int b) throws IOException {
+		Boolean result = (Boolean) callback.call(String.valueOf((char) b));
+		if (result.booleanValue()) {
+			out.write(b);
+		}
+	}
+}
diff --git a/groovy-core/src/main/groovy/ui/package.html b/groovy-core/src/main/groovy/ui/package.html
new file mode 100644
index 0000000..f50b9c9
--- /dev/null
+++ b/groovy-core/src/main/groovy/ui/package.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>package groovy.ui.*</title>
+  </head>
+  <body>
+    <p>An interactive command line terminal along with a Swing console for evaluating Groovy scripts.</p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/groovy/util/AllTestSuite.java b/groovy-core/src/main/groovy/util/AllTestSuite.java
new file mode 100644
index 0000000..50ea124
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/AllTestSuite.java
@@ -0,0 +1,101 @@
+package groovy.util;
+
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.Script;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.runtime.ScriptTestAdapter;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.logging.Logger;
+
+/**
+ * AllTestSuite can be used in extension of GroovyTestSuite to execute TestCases written in Groovy
+ * from inside a Java IDE.
+ * AllTestSuite collects all files below a given directory that comply to a given pattern.
+ * From these files, a TestSuite is constructed that can be run via an IDE graphical Test runner.
+ * The files are assumed to be Groovy source files and be either a TestCase or a Script that can
+ * be wrapped transparently into a TestCase.
+ * The directory and the pattern can be set via System properties (see this classes' constants for details.)
+ *
+ * When setting the loglevel of this class to FINEST, all file loading will be logged.
+ *
+ * See also groovy.util.AllTestSuiteTest.groovy
+ * @author Dierk Koenig based on a prototype by Andrew Glover
+ * todo: dk: make FileNameFinder injectable
+ */
+public class AllTestSuite extends TestSuite {
+
+    /** The System Property to set as base directory for collection of Test Cases.
+     * The pattern will be used as an Ant fileset include basedir.
+     * Key is "groovy.test.dir".
+     * Default value is "./test/".
+     */
+    public static final String SYSPROP_TEST_DIR = "groovy.test.dir";
+
+    /** The System Property to set as the filename pattern for collection of Test Cases.
+     * The pattern will be used as Regualar Expression pattern applied with the find
+     * operator agains each candidate file.path.
+     * Key is "groovy.test.pattern".
+     * Default value is "Test.groovy".
+     */
+    public static final String SYSPROP_TEST_PATTERN = "groovy.test.pattern";
+
+    private static Logger LOG = Logger.getLogger(AllTestSuite.class.getName());
+    private static ClassLoader JAVA_LOADER = AllTestSuite.class.getClassLoader();
+    private static GroovyClassLoader GROOVY_LOADER = new GroovyClassLoader(JAVA_LOADER);
+
+    private static final String[] EMPTY_ARGS = new String[]{};
+    private static IFileNameFinder FINDER = null;
+
+    static { // this is only needed since the Groovy Build compiles *.groovy files after *.java files
+        try {
+            Class finderClass = Class.forName("groovy.util.FileNameFinder");
+            FINDER = (IFileNameFinder) finderClass.newInstance();
+        } catch (Exception e) {
+            throw new RuntimeException("Cannot find and instantiate class FileNameFinder", e);
+        }
+    }
+
+    public static Test suite() {
+        String basedir = System.getProperty(SYSPROP_TEST_DIR, "./test/");
+        String pattern = System.getProperty(SYSPROP_TEST_PATTERN, "**/*Test.groovy");
+        return suite(basedir, pattern);
+    }    
+
+    public static Test suite(String basedir, String pattern) {
+        AllTestSuite suite = new AllTestSuite();
+        String fileName = "";
+        try {
+            Collection filenames = FINDER.getFileNames(basedir, pattern);
+            for (Iterator iter = filenames.iterator(); iter.hasNext();) {
+                fileName = (String) iter.next();
+                LOG.finest("trying to load "+ fileName);
+                suite.loadTest(fileName);
+            }
+        } catch (CompilationFailedException e1) {
+            e1.printStackTrace();
+            throw new RuntimeException("CompilationFailedException when loading "+fileName, e1);
+        } catch (IOException e2) {
+            throw new RuntimeException("IOException when loading "+fileName, e2);
+        }
+        return suite;
+    }
+
+    protected void loadTest(String fileName) throws CompilationFailedException, IOException {
+        Class type = compile(fileName);
+        if (!Test.class.isAssignableFrom(type) && Script.class.isAssignableFrom(type)) {
+            addTest(new ScriptTestAdapter(type, EMPTY_ARGS));
+        } else {
+            addTestSuite(type);
+        }
+    }
+
+    protected Class compile(String fileName) throws CompilationFailedException, IOException {
+        return GROOVY_LOADER.parseClass(new File(fileName));
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/AntBuilder.java b/groovy-core/src/main/groovy/util/AntBuilder.java
new file mode 100644
index 0000000..969ef78
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/AntBuilder.java
@@ -0,0 +1,284 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.tools.ant.BuildLogger;
+import org.apache.tools.ant.NoBannerLogger;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.RuntimeConfigurable;
+import org.apache.tools.ant.Target;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.UnknownElement;
+import org.apache.tools.ant.helper.AntXMLContext;
+import org.apache.tools.ant.helper.ProjectHelper2;
+import org.codehaus.groovy.ant.FileScanner;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.AttributesImpl;
+import groovy.xml.QName;
+
+/**
+ * Allows Ant tasks to be used with GroovyMarkup 
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>, changes by Dierk Koenig (dk)
+ * @version $Revision$
+ */
+public class AntBuilder extends BuilderSupport {
+
+    private static final Class[] addTaskParamTypes = { String.class };
+
+    private Logger log = Logger.getLogger(getClass().getName());
+    private Project project;
+    private final AntXMLContext antXmlContext;
+    private final ProjectHelper2.ElementHandler antElementHandler = new ProjectHelper2.ElementHandler();
+    private final Target collectorTarget;
+    private Object lastCompletedNode;
+
+
+
+    public AntBuilder() {
+        this(createProject());
+    }
+
+    public AntBuilder(final Project project) {
+        this(project, new Target());
+    }
+
+    public AntBuilder(final Project project, final Target owningTarget) {
+        this.project = project;
+
+        collectorTarget = owningTarget;
+        
+        antXmlContext = new AntXMLContext(project);
+        collectorTarget.setProject(project);
+        antXmlContext.setCurrentTarget(collectorTarget);
+        antXmlContext.setLocator(new AntBuilderLocator());
+        
+        // FileScanner is a Groovy hack (utility?)
+        project.addDataTypeDefinition("fileScanner", FileScanner.class);
+    }
+
+    // dk: introduced for convenience in subclasses
+    protected Project getProject() {
+        return project;
+    }
+
+    /**
+     * @return Factory method to create new Project instances
+     */
+    protected static Project createProject() {
+        Project project = new Project();
+        BuildLogger logger = new NoBannerLogger();
+
+        logger.setMessageOutputLevel(org.apache.tools.ant.Project.MSG_INFO);
+        logger.setOutputPrintStream(System.out);
+        logger.setErrorPrintStream(System.err);
+
+        project.addBuildListener(logger);
+
+        project.init();
+        project.getBaseDir();
+        return project;
+    }
+
+    protected void setParent(Object parent, Object child) {
+    }
+
+    
+    /**
+     * We don't want to return the node as created in {@link #createNode(Object, Map, Object)}
+     * but the one made ready by {@link #nodeCompleted(Object, Object)}
+     * @see groovy.util.BuilderSupport#doInvokeMethod(java.lang.String, java.lang.Object, java.lang.Object)
+     */
+    protected Object doInvokeMethod(String methodName, Object name, Object args) {
+    	super.doInvokeMethod(methodName, name, args);
+    	
+
+    	// return the completed node
+    	return lastCompletedNode;
+    }
+
+    /**
+     * Determines, when the ANT Task that is represented by the "node" should perform.
+     * Node must be an ANT Task or no "perform" is called.
+     * If node is an ANT Task, it performs right after complete contstruction.
+     * If node is nested in a TaskContainer, calling "perform" is delegated to that
+     * TaskContainer.
+     * @param parent note: null when node is root
+     * @param node the node that now has all its children applied
+     */
+    protected void nodeCompleted(final Object parent, final Object node) {
+
+    	antElementHandler.onEndElement(null, null, antXmlContext);
+
+    	lastCompletedNode = node;
+        if (parent != null) {
+            log.finest("parent is not null: no perform on nodeCompleted");
+            return; // parent will care about when children perform
+        }
+        
+        // as in Target.execute()
+        if (node instanceof Task) {
+            Object task = node;
+            // "Unwrap" the UnknownElement to return the real task to the calling code
+            if (node instanceof UnknownElement) {
+            	final UnknownElement unknownElement = (UnknownElement) node;
+            	unknownElement.maybeConfigure();
+                task = unknownElement.getRealThing();
+            }
+            
+            lastCompletedNode = task;
+            // UnknownElement may wrap everything: task, path, ...
+            if (task instanceof Task) {
+            	((Task) task).perform();
+            }
+        }
+        else {
+            final RuntimeConfigurable r = (RuntimeConfigurable) node;
+            r.maybeConfigure(project);
+        }
+    }
+
+    protected Object createNode(Object tagName) {
+        return createNode(tagName, Collections.EMPTY_MAP);
+    }
+
+    protected Object createNode(Object name, Object value) {
+        Object task = createNode(name);
+        setText(task, value.toString());
+        return task;
+    }
+
+    protected Object createNode(Object name, Map attributes, Object value) {
+        Object task = createNode(name, attributes);
+        setText(task, value.toString());
+        return task;
+    }
+    
+    /**
+     * Builds an {@link Attributes} from a {@link Map}
+     * @param attributes the attributes to wrap
+     */
+    protected static Attributes buildAttributes(final Map attributes) {
+    	final AttributesImpl attr = new AttributesImpl();
+    	for (final Iterator iter=attributes.entrySet().iterator(); iter.hasNext(); ) {
+    		final Map.Entry entry = (Map.Entry) iter.next();
+    		final String attributeName = (String) entry.getKey();
+    		final String attributeValue = String.valueOf(entry.getValue());
+    		attr.addAttribute(null, attributeName, attributeName, "CDATA", attributeValue);
+    	}
+    	return attr;
+    }
+
+    protected Object createNode(final Object name, final Map attributes) {
+
+        String tagName = name.toString();
+        String ns = "";
+
+        if(name instanceof QName) {
+            QName q = (QName)name;
+            tagName = q.getLocalPart();
+            ns = q.getNamespaceURI();
+        }
+
+        try
+		{
+			antElementHandler.onStartElement(ns, tagName, tagName, buildAttributes(attributes), antXmlContext);
+		}
+		catch (final SAXParseException e)
+		{
+            log.log(Level.SEVERE, "Caught: " + e, e);
+		}
+    	
+		final RuntimeConfigurable wrapper = (RuntimeConfigurable) antXmlContext.getWrapperStack().lastElement();
+    	return wrapper.getProxy();
+    }
+
+    protected void setText(Object task, String text) {
+    	final char[] characters = text.toCharArray();
+        try {
+          	antElementHandler.characters(characters, 0, characters.length, antXmlContext);
+        }
+        catch (final SAXParseException e) {
+            log.log(Level.WARNING, "SetText failed: " + task + ". Reason: " + e, e);
+        }
+    }
+
+    public Project getAntProject() {
+        return project;
+    }
+}
+
+/**
+ * Would be nice to retrieve location information (from AST?).
+ * In a first time, without info
+ */
+class AntBuilderLocator implements Locator {
+	public int getColumnNumber()
+	{
+		return 0;
+	}
+	public int getLineNumber()
+	{
+		return 0;
+	}
+	public String getPublicId()
+	{
+		return "";
+	}
+	public String getSystemId()
+	{
+		return "";
+	}
+}
diff --git a/groovy-core/src/main/groovy/util/BuilderSupport.java b/groovy-core/src/main/groovy/util/BuilderSupport.java
new file mode 100644
index 0000000..b6fb722
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/BuilderSupport.java
@@ -0,0 +1,236 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyObjectSupport;
+import groovy.lang.MissingMethodException;
+
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * An abstract base class for creating arbitrary nested trees of objects
+ * or events
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public abstract class BuilderSupport extends GroovyObjectSupport {
+
+    private Object current;
+    private Closure nameMappingClosure;
+    private BuilderSupport proxyBuilder;
+
+    public BuilderSupport() {
+        this.proxyBuilder = this;
+    }
+
+    public BuilderSupport(BuilderSupport proxyBuilder) {
+        this(null, proxyBuilder);
+    }
+
+    public BuilderSupport(Closure nameMappingClosure, BuilderSupport proxyBuilder) {
+        this.nameMappingClosure = nameMappingClosure;
+        this.proxyBuilder = proxyBuilder;
+    }
+
+    /**
+     * Convenience method when no arguments are required
+     * @return the result of the call
+     * @param methodName the name of the method to invoke
+     */
+    public Object invokeMethod(String methodName) {
+        return invokeMethod(methodName, null);
+    }
+
+    public Object invokeMethod(String methodName, Object args) {
+        Object name = getName(methodName);
+        return doInvokeMethod(methodName, name, args);
+    }
+
+    protected Object doInvokeMethod(String methodName, Object name, Object args) {
+        Object node = null;
+        Closure closure = null;
+        List list = InvokerHelper.asList(args);
+
+        //System.out.println("Called invokeMethod with name: " + name + " arguments: " + list);
+
+        switch (list.size()) {
+        		case 0:
+	    	            node = proxyBuilder.createNode(name);
+        		    break;
+        	    	case 1:
+        	    	{
+        	    	    	Object object = list.get(0);
+        	    	    	if (object instanceof Map) {
+        	    	    	    node = proxyBuilder.createNode(name, (Map) object);
+        	    	    	} else if (object instanceof Closure) {
+        	    	    	    closure = (Closure) object;
+        	    	    	    node = proxyBuilder.createNode(name);
+        	    	    	} else {
+        	    	    	    node = proxyBuilder.createNode(name, object);
+        	    	    	}
+        	    	}
+        	    	break;
+        	    	case 2:
+        	    	{
+        	    	    Object object1 = list.get(0);
+    	    	        Object object2 = list.get(1);
+        	    	    if (object1 instanceof Map) {
+        	    	        if (object2 instanceof Closure) {
+        	    	            closure = (Closure) object2;
+        	    	            node = proxyBuilder.createNode(name, (Map) object1);
+        	    	        } else {
+        	    	            node = proxyBuilder.createNode(name, (Map) object1, object2);
+        	    	        }
+        	    	    } else {
+        	    	        if (object2 instanceof Closure) {
+        	    	            closure = (Closure) object2;
+        	    	            node = proxyBuilder.createNode(name, object1);
+				} else if (object2 instanceof Map) {
+				    node = proxyBuilder.createNode(name, (Map) object2, object1);
+        	    	        } else {
+				    throw new MissingMethodException(name.toString(), getClass(), list.toArray(), false);
+				}
+        	    	    }
+        	    	}
+        	    	break;
+        	    	case 3:
+        	    	{
+        	    	    Object arg0 = list.get(0);
+        	    	    Object arg1 = list.get(1);
+        	    	    Object arg2 = list.get(2);
+        	    	    if (arg0 instanceof Map && arg2 instanceof Closure) {
+        	    	        closure = (Closure) arg2;
+        	    	        node = proxyBuilder.createNode(name, (Map) arg0, arg1);
+			    } else if (arg1 instanceof Map && arg2 instanceof Closure) {
+        	    	        closure = (Closure) arg2;
+        	    	        node = proxyBuilder.createNode(name, (Map) arg1, arg0);
+			    } else {
+				throw new MissingMethodException(name.toString(), getClass(), list.toArray(), false);
+			   }
+        	    	}
+        	    	break;
+        	    	default:
+        	    	{
+			    throw new MissingMethodException(name.toString(), getClass(), list.toArray(), false);
+			}
+
+        }
+
+        if (current != null) {
+            proxyBuilder.setParent(current, node);
+        }
+
+        if (closure != null) {
+            // push new node on stack
+            Object oldCurrent = current;
+            current = node;
+
+            // lets register the builder as the delegate
+            setClosureDelegate(closure, node);
+            closure.call();
+
+            current = oldCurrent;
+        }
+
+        proxyBuilder.nodeCompleted(current, node);
+        return node;
+    }
+
+    /**
+     * A strategy method to allow derived builders to use
+     * builder-trees and switch in different kinds of builders.
+     * This method should call the setDelegate() method on the closure
+     * which by default passes in this but if node is-a builder
+     * we could pass that in instead (or do something wacky too)
+     *
+     * @param closure the closure on which to call setDelegate()
+     * @param node the node value that we've just created, which could be
+     * a builder
+     */
+    protected void setClosureDelegate(Closure closure, Object node) {
+        closure.setDelegate(this);
+    }
+
+    protected abstract void setParent(Object parent, Object child);
+    protected abstract Object createNode(Object name);
+    protected abstract Object createNode(Object name, Object value);
+    protected abstract Object createNode(Object name, Map attributes);
+    protected abstract Object createNode(Object name, Map attributes, Object value);
+
+    /**
+     * A hook to allow names to be converted into some other object
+     * such as a QName in XML or ObjectName in JMX
+     * @param methodName
+     */
+    protected Object getName(String methodName) {
+        if (nameMappingClosure != null) {
+            return nameMappingClosure.call(methodName);
+        }
+        return methodName;
+    }
+
+
+    /**
+     * A hook to allow nodes to be processed once they have had all of their
+     * children applied
+     */
+    protected void nodeCompleted(Object parent, Object node) {
+    }
+
+    protected Object getCurrent() {
+        return current;
+    }
+
+    protected void setCurrent(Object current) {
+        this.current = current;
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/CharsetToolkit.java b/groovy-core/src/main/groovy/util/CharsetToolkit.java
new file mode 100644
index 0000000..f019026
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/CharsetToolkit.java
@@ -0,0 +1,425 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) Guillaume Laforge. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+package groovy.util;
+
+import java.io.*;
+import java.nio.charset.Charset;
+import java.util.*;
+
+/**
+ * <p>Utility class to guess the encoding of a given text file.</p>
+ *
+ * <p>Unicode files encoded in UTF-16 (low or big endian) or UTF-8 files
+ * with a Byte Order Marker are correctly discovered. For UTF-8 files with no BOM, if the buffer
+ * is wide enough, the charset should also be discovered.</p>
+ *
+ * <p>A byte buffer of 4KB is usually sufficient to be able to guess the encoding.</p>
+ *
+ * <p>Usage:</p>
+ * <pre>
+ * // guess the encoding
+ * Charset guessedCharset = CharsetToolkit.guessEncoding(file, 4096);
+ *
+ * // create a reader with the correct charset
+ * CharsetToolkit toolkit = new CharsetToolkit(file);
+ * BufferedReader reader = toolkit.getReader();
+ *
+ * // read the file content
+ * String line;
+ * while ((line = br.readLine())!= null)
+ * {
+ *     System.out.println(line);
+ * }
+ * </pre>
+ *
+ * @author Guillaume Laforge
+ */
+public class CharsetToolkit {
+    private byte[] buffer;
+    private Charset defaultCharset;
+    private Charset charset;
+    private boolean enforce8Bit = true;
+    private File file;
+
+    /**
+     * Constructor of the <code>CharsetToolkit</code> utility class.
+     *
+     * @param file of which we want to know the encoding.
+     */
+    public CharsetToolkit(File file) throws IOException {
+        this.file = file;
+        this.defaultCharset = getDefaultSystemCharset();
+        this.charset = null;
+        InputStream input = new FileInputStream(file);
+        try {
+            byte[] bytes = new byte[4096];
+            int bytesRead = input.read(bytes);
+            if (bytesRead == -1) {
+                this.buffer = new byte[0];
+            }
+            else if (bytesRead < 4096) {
+                byte[] bytesToGuess = new byte[bytesRead];
+                System.arraycopy(bytes, 0, bytesToGuess, 0, bytesRead);
+                this.buffer = bytesToGuess;
+            }
+            else {
+                this.buffer = bytes;
+            }
+        } finally {
+            try {input.close();} catch (IOException e){}
+        }
+    }
+
+    /**
+     * Defines the default <code>Charset</code> used in case the buffer represents
+     * an 8-bit <code>Charset</code>.
+     *
+     * @param defaultCharset the default <code>Charset</code> to be returned by <code>guessEncoding()</code>
+     * if an 8-bit <code>Charset</code> is encountered.
+     */
+    public void setDefaultCharset(Charset defaultCharset) {
+        if (defaultCharset != null)
+            this.defaultCharset = defaultCharset;
+        else
+            this.defaultCharset = getDefaultSystemCharset();
+    }
+
+    public Charset getCharset() {
+        if (this.charset == null)
+            this.charset = guessEncoding();
+        return charset;
+    }
+
+    /**
+     * If US-ASCII is recognized, enforce to return the default encoding, rather than US-ASCII.
+     * It might be a file without any special character in the range 128-255, but that may be or become
+     * a file encoded with the default <code>charset</code> rather than US-ASCII.
+     *
+     * @param enforce a boolean specifying the use or not of US-ASCII.
+     */
+    public void setEnforce8Bit(boolean enforce) {
+        this.enforce8Bit = enforce;
+    }
+
+    /**
+     * Gets the enforce8Bit flag, in case we do not want to ever get a US-ASCII encoding.
+     *
+     * @return a boolean representing the flag of use of US-ASCII.
+     */
+    public boolean getEnforce8Bit() {
+        return this.enforce8Bit;
+    }
+
+    /**
+     * Retrieves the default Charset
+     */
+    public Charset getDefaultCharset() {
+        return defaultCharset;
+    }
+
+    /**
+     * <p>Guess the encoding of the provided buffer.</p>
+     * If Byte Order Markers are encountered at the beginning of the buffer, we immidiately
+     * return the charset implied by this BOM. Otherwise, the file would not be a human
+     * readable text file.</p>
+     *
+     * <p>If there is no BOM, this method tries to discern whether the file is UTF-8 or not.
+     * If it is not UTF-8, we assume the encoding is the default system encoding
+     * (of course, it might be any 8-bit charset, but usually, an 8-bit charset is the default one).</p>
+     *
+     * <p>It is possible to discern UTF-8 thanks to the pattern of characters with a multi-byte sequence.</p>
+     * <pre>
+     * UCS-4 range (hex.)        UTF-8 octet sequence (binary)
+     * 0000 0000-0000 007F       0xxxxxxx
+     * 0000 0080-0000 07FF       110xxxxx 10xxxxxx
+     * 0000 0800-0000 FFFF       1110xxxx 10xxxxxx 10xxxxxx
+     * 0001 0000-001F FFFF       11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+     * 0020 0000-03FF FFFF       111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+     * 0400 0000-7FFF FFFF       1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+     * </pre>
+     * <p>With UTF-8, 0xFE and 0xFF never appear.</p>
+     *
+     * @return the Charset recognized.
+     */
+    private Charset guessEncoding() {
+        // if the file has a Byte Order Marker, we can assume the file is in UTF-xx
+        // otherwise, the file would not be human readable
+        if (hasUTF8Bom())
+            return Charset.forName("UTF-8");
+        if (hasUTF16LEBom())
+            return Charset.forName("UTF-16LE");
+        if (hasUTF16BEBom())
+            return Charset.forName("UTF-16BE");
+
+        // if a byte has its most significant bit set, the file is in UTF-8 or in the default encoding
+        // otherwise, the file is in US-ASCII
+        boolean highOrderBit = false;
+
+        // if the file is in UTF-8, high order bytes must have a certain value, in order to be valid
+        // if it's not the case, we can assume the encoding is the default encoding of the system
+        boolean validU8Char = true;
+
+        // TODO the buffer is not read up to the end, but up to length - 6
+
+        int length = buffer.length;
+        int i = 0;
+        while (i < length - 6) {
+            byte b0 = buffer[i];
+            byte b1 = buffer[i + 1];
+            byte b2 = buffer[i + 2];
+            byte b3 = buffer[i + 3];
+            byte b4 = buffer[i + 4];
+            byte b5 = buffer[i + 5];
+            if (b0 < 0) {
+                // a high order bit was encountered, thus the encoding is not US-ASCII
+                // it may be either an 8-bit encoding or UTF-8
+                highOrderBit = true;
+                // a two-bytes sequence was encoutered
+                if (isTwoBytesSequence(b0)) {
+                    // there must be one continuation byte of the form 10xxxxxx,
+                    // otherwise the following characteris is not a valid UTF-8 construct
+                    if (!isContinuationChar(b1))
+                        validU8Char = false;
+                    else
+                        i++;
+                }
+                // a three-bytes sequence was encoutered
+                else if (isThreeBytesSequence(b0)) {
+                    // there must be two continuation bytes of the form 10xxxxxx,
+                    // otherwise the following characteris is not a valid UTF-8 construct
+                    if (!(isContinuationChar(b1) && isContinuationChar(b2)))
+                        validU8Char = false;
+                    else
+                        i += 2;
+                }
+                // a four-bytes sequence was encoutered
+                else if (isFourBytesSequence(b0)) {
+                    // there must be three continuation bytes of the form 10xxxxxx,
+                    // otherwise the following characteris is not a valid UTF-8 construct
+                    if (!(isContinuationChar(b1) && isContinuationChar(b2) && isContinuationChar(b3)))
+                        validU8Char = false;
+                    else
+                        i += 3;
+                }
+                // a five-bytes sequence was encoutered
+                else if (isFiveBytesSequence(b0)) {
+                    // there must be four continuation bytes of the form 10xxxxxx,
+                    // otherwise the following characteris is not a valid UTF-8 construct
+                    if (!(isContinuationChar(b1)
+                        && isContinuationChar(b2)
+                        && isContinuationChar(b3)
+                        && isContinuationChar(b4)))
+                        validU8Char = false;
+                    else
+                        i += 4;
+                }
+                // a six-bytes sequence was encoutered
+                else if (isSixBytesSequence(b0)) {
+                    // there must be five continuation bytes of the form 10xxxxxx,
+                    // otherwise the following characteris is not a valid UTF-8 construct
+                    if (!(isContinuationChar(b1)
+                        && isContinuationChar(b2)
+                        && isContinuationChar(b3)
+                        && isContinuationChar(b4)
+                        && isContinuationChar(b5)))
+                        validU8Char = false;
+                    else
+                        i += 5;
+                }
+                else
+                    validU8Char = false;
+            }
+            if (!validU8Char)
+                break;
+            i++;
+        }
+        // if no byte with an high order bit set, the encoding is US-ASCII
+        // (it might have been UTF-7, but this encoding is usually internally used only by mail systems)
+        if (!highOrderBit) {
+            // returns the default charset rather than US-ASCII if the enforce8Bit flag is set.
+            if (this.enforce8Bit)
+                return this.defaultCharset;
+            else
+                return Charset.forName("US-ASCII");
+        }
+        // if no invalid UTF-8 were encountered, we can assume the encoding is UTF-8,
+        // otherwise the file would not be human readable
+        if (validU8Char)
+            return Charset.forName("UTF-8");
+        // finally, if it's not UTF-8 nor US-ASCII, let's assume the encoding is the default encoding
+        return this.defaultCharset;
+    }
+
+    /**
+     * If the byte has the form 10xxxxx, then it's a continuation byte of a multiple byte character;
+     *
+     * @param b a byte.
+     * @return true if it's a continuation char.
+     */
+    private static boolean isContinuationChar(byte b) {
+        return -128 <= b && b <= -65;
+    }
+
+    /**
+     * If the byte has the form 110xxxx, then it's the first byte of a two-bytes sequence character.
+     *
+     * @param b a byte.
+     * @return true if it's the first byte of a two-bytes sequence.
+     */
+    private static boolean isTwoBytesSequence(byte b) {
+        return -64 <= b && b <= -33;
+    }
+
+    /**
+     * If the byte has the form 1110xxx, then it's the first byte of a three-bytes sequence character.
+     *
+     * @param b a byte.
+     * @return true if it's the first byte of a three-bytes sequence.
+     */
+    private static boolean isThreeBytesSequence(byte b) {
+        return -32 <= b && b <= -17;
+    }
+
+    /**
+     * If the byte has the form 11110xx, then it's the first byte of a four-bytes sequence character.
+     *
+     * @param b a byte.
+     * @return true if it's the first byte of a four-bytes sequence.
+     */
+    private static boolean isFourBytesSequence(byte b) {
+        return -16 <= b && b <= -9;
+    }
+
+    /**
+     * If the byte has the form 11110xx, then it's the first byte of a five-bytes sequence character.
+     *
+     * @param b a byte.
+     * @return true if it's the first byte of a five-bytes sequence.
+     */
+    private static boolean isFiveBytesSequence(byte b) {
+        return -8 <= b && b <= -5;
+    }
+
+    /**
+     * If the byte has the form 1110xxx, then it's the first byte of a six-bytes sequence character.
+     *
+     * @param b a byte.
+     * @return true if it's the first byte of a six-bytes sequence.
+     */
+    private static boolean isSixBytesSequence(byte b) {
+        return -4 <= b && b <= -3;
+    }
+
+    /**
+     * Retrieve the default charset of the system.
+     *
+     * @return the default <code>Charset</code>.
+     */
+    public static Charset getDefaultSystemCharset() {
+        return Charset.forName(System.getProperty("file.encoding"));
+    }
+
+    /**
+     * Has a Byte Order Marker for UTF-8 (Used by Microsoft's Notepad and other editors).
+     *
+     * @return true if the buffer has a BOM for UTF8.
+     */
+    public boolean hasUTF8Bom() {
+        if (buffer.length >= 3)
+            return (buffer[0] == -17 && buffer[1] == -69 && buffer[2] == -65);
+        else
+            return false;
+    }
+
+    /**
+     * Has a Byte Order Marker for UTF-16 Low Endian
+     * (ucs-2le, ucs-4le, and ucs-16le).
+     *
+     * @return true if the buffer has a BOM for UTF-16 Low Endian.
+     */
+    public boolean hasUTF16LEBom() {
+        if (buffer.length >= 2)
+            return (buffer[0] == -1 && buffer[1] == -2);
+        else
+            return false;
+    }
+
+    /**
+     * Has a Byte Order Marker for UTF-16 Big Endian
+     * (utf-16 and ucs-2).
+     *
+     * @return true if the buffer has a BOM for UTF-16 Big Endian.
+     */
+    public boolean hasUTF16BEBom() {
+        if (buffer.length >= 2)
+            return (buffer[0] == -2 && buffer[1] == -1);
+        else
+            return false;
+    }
+
+    /**
+     * Gets a <code>BufferedReader</code> (indeed a <code>LineNumberReader</code>) from the <code>File</code>
+     * specified in the constructor of <code>CharsetToolkit</code> using the charset discovered by the
+     * method <code>guessEncoding()</code>.
+     *
+     * @return a <code>BufferedReader</code>
+     * @throws FileNotFoundException if the file is not found.
+     */
+    public BufferedReader getReader() throws FileNotFoundException {
+        LineNumberReader reader = new LineNumberReader(new InputStreamReader(new FileInputStream(file), getCharset()));
+        if (hasUTF8Bom() || hasUTF16LEBom() || hasUTF16BEBom()) {
+            try {
+                reader.read();
+            }
+            catch (IOException e) {
+                // should never happen, as a file with no content
+                // but with a BOM has at least one char
+            }
+        }
+        return reader;
+    }
+
+    /**
+     * Retrieves all the available <code>Charset</code>s on the platform,
+     * among which the default <code>charset</code>.
+     *
+     * @return an array of <code>Charset</code>s.
+     */
+    public static Charset[] getAvailableCharsets() {
+        Collection collection = Charset.availableCharsets().values();
+        return (Charset[]) collection.toArray(new Charset[collection.size()]);
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/CliBuilder.groovy b/groovy-core/src/main/groovy/util/CliBuilder.groovy
new file mode 100644
index 0000000..c741dd5
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/CliBuilder.groovy
@@ -0,0 +1,105 @@
+package groovy.util
+
+import org.apache.commons.cli.*
+import org.codehaus.groovy.runtime.InvokerHelper
+
+
+/**
+    Supported Option Properties:
+    argName:        String
+    longOpt:        String
+    args:           int
+    optionalArg:    boolean
+    required:       boolean
+    type:           Object
+    valueSeparator: char
+
+    @see org.apache.commons.cli.Option for meaning of the parameters.
+    @see CliBuilderTest for example usages.
+    @author Dierk Koenig
+*/
+
+class CliBuilder {
+
+    // default settings: use setters to override
+    String usage             = 'groovy'
+    CommandLineParser parser = new PosixParser()
+    HelpFormatter formatter  = new HelpFormatter()
+    PrintWriter writer       = new PrintWriter(System.out)
+
+    Options options          = new Options()
+
+    /**
+        Recognize all one-character method calls as option specifications.
+    */
+    def invokeMethod(String name, Object args){
+        if (1 == name.size()) {
+            options.addOption(option(name, args[0], args[1]))
+            return null
+        }
+        return InvokerHelper.getMetaClass(this).invokeMethod(this, name, args)
+    }
+
+    /**
+        Make options accessible from command line args with parser (default: Posix).
+        Returns null on bad command lines.
+    */
+    OptionAccessor parse(args) {
+        try {
+            return new OptionAccessor( parser.parse(options, args as String[], true) )
+        } catch (ParseException pe) {
+            writer.println("error: " + pe.getMessage())
+            usage()
+            return null
+        }
+    }
+
+    /**
+        Print the usage message with writer (default: System.out) and formatter (default: HelpFormatter)
+    */
+    void usage(){
+        formatter.printHelp(writer, formatter.defaultWidth, usage, '', options, formatter.defaultLeftPad, formatter.defaultDescPad, '')
+        writer.flush()
+    }
+
+    // implementation details -------------------------------------
+
+    /**
+        How to create an option from the specification.
+    */
+    Option option (shortname, Map details, info){
+        Option option = new Option( shortname, info)
+        details.each { key, value ->
+            if (key == 'optionalArg')       // surprising that this extra handling is needed
+                option.setOptionalArg(value)
+            else
+                option[key] = value
+        }
+        return option
+    }
+}
+
+class OptionAccessor {
+    CommandLine inner
+    OptionAccessor(CommandLine inner){
+        this.inner = inner
+    }
+    def invokeMethod(String name, Object args){
+        return InvokerHelper.getMetaClass(inner).invokeMethod(inner, name, args)
+    }
+    def getProperty(String name) {
+        def methodname = 'getOptionValue'
+        if (name.size() > 1 && name.endsWith('s')) {
+            name = name[0..-2]
+            methodname += 's'
+        }
+        if (name.size() == 1) name = name as char
+        def result = InvokerHelper.getMetaClass(inner).invokeMethod(inner, methodname, name)
+        if (null == result) result = inner.hasOption(name)
+        if (result instanceof String[]) result = result.toList()
+        return result
+    }
+    List arguments() {
+        inner.getArgs().toList()
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/ClosureComparator.java b/groovy-core/src/main/groovy/util/ClosureComparator.java
new file mode 100644
index 0000000..3f353b3
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/ClosureComparator.java
@@ -0,0 +1,70 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+import groovy.lang.Closure;
+import java.util.Comparator;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+/**
+ * A Comparator which uses a closure to compare 2 values being equal
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ClosureComparator implements Comparator {
+
+    Closure closure;
+
+    public ClosureComparator(Closure closure) {
+        this.closure = closure;
+    }
+
+    public int compare(Object object1, Object object2) {
+        Object value = closure.call(new Object[] {object1, object2});
+        return DefaultTypeTransformation.intUnbox(value);
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/Eval.java b/groovy-core/src/main/groovy/util/Eval.java
new file mode 100644
index 0000000..d4481ca
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/Eval.java
@@ -0,0 +1,75 @@
+package groovy.util;
+
+import org.codehaus.groovy.control.CompilationFailedException;
+
+import groovy.lang.Binding;
+import groovy.lang.GroovyShell;
+
+/**
+ * Allow easy integration from Groovy into Java through convenience methods.
+ * @see EvalTest
+ * @author Dierk Koenig
+ */
+
+public class Eval {
+    /**
+     * @param expression the Groovy expression to evaluate
+     * @return the result of the expression
+     * @throws CompilationFailedException if expression is no proper Groovy
+     */
+    public static Object me(final String expression) throws CompilationFailedException {
+        return me(null, null, expression);
+    }
+
+    /**
+     * evaluate expression and make object available inside the expression as 'symbol'
+     * @param expression the Groovy expression to evaluate
+     * @return the result of the expression
+     * @throws CompilationFailedException if expression is no proper Groovy
+     */
+    public static Object me(final String symbol, final Object object, final String expression) throws CompilationFailedException {
+        Binding b = new Binding();
+        b.setVariable(symbol, object);
+        GroovyShell sh = new GroovyShell(b);
+        return sh.evaluate(expression);
+    }
+
+    /**
+     * evaluate expression and make x available inside the expression as 'x'
+     * @param expression the Groovy expression to evaluate
+     * @return the result of the expression
+     * @throws CompilationFailedException if expression is no proper Groovy
+     */
+    public static Object x(final Object x, final String expression) throws CompilationFailedException {
+        return me("x", x, expression);
+    }
+
+    /**
+     * evaluate expression and make x and y available inside the expression as 'x' and 'y'
+     * @param expression the Groovy expression to evaluate
+     * @return the result of the expression
+     * @throws CompilationFailedException if expression is no proper Groovy
+     */
+    public static Object xy(final Object x, final Object y, final String expression) throws CompilationFailedException {
+        Binding b = new Binding();
+        b.setVariable("x", x);
+        b.setVariable("y", y);
+        GroovyShell sh = new GroovyShell(b);
+        return sh.evaluate(expression);
+    }
+
+    /**
+     * evaluate expression and make x,y,z available inside the expression as 'x','y','z'
+     * @param expression the Groovy expression to evaluate
+     * @return the result of the expression
+     * @throws CompilationFailedException if expression is no proper Groovy
+     */
+    public static Object xyz(final Object x, final Object y, final Object z, final String expression) throws CompilationFailedException {
+        Binding b = new Binding();
+        b.setVariable("x", x);
+        b.setVariable("y", y);
+        b.setVariable("z", z);
+        GroovyShell sh = new GroovyShell(b);
+        return sh.evaluate(expression);
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/Expando.java b/groovy-core/src/main/groovy/util/Expando.java
new file mode 100644
index 0000000..566e70e
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/Expando.java
@@ -0,0 +1,202 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyObjectSupport;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.MetaExpandoProperty;
+import groovy.lang.MissingPropertyException;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+
+/**
+ * Represents a dynamically expandable bean.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Hein Meling
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+public class Expando extends GroovyObjectSupport {
+
+    private Map expandoProperties;
+
+    public Expando() {
+    }
+
+    public Expando(Map expandoProperties) {
+        this.expandoProperties = expandoProperties;
+    }
+
+    /**
+     * @return the dynamically expanded properties
+     */
+    public Map getProperties() {
+        if (expandoProperties == null) {
+            expandoProperties = createMap();
+        }
+        return expandoProperties;
+    }
+
+    public List getMetaPropertyValues() {
+        // run through all our current properties and create MetaProperty objects
+        List ret = new ArrayList();
+        Iterator itr = getProperties().entrySet().iterator();
+        while(itr.hasNext()) {
+            Entry entry = (Entry) itr.next();
+            ret.add(new MetaExpandoProperty(entry));
+        }
+		
+        return ret;
+    }
+
+    public Object getProperty(String property) {
+        // always use the expando properties first
+        Object result = getProperties().get(property);
+        if (result!=null) return result;
+        try {
+            return super.getProperty(property);
+        }
+        catch (MissingPropertyException e) {}
+        return null;
+    }
+
+    public void setProperty(String property, Object newValue) {
+        // always use the expando properties
+        getProperties().put(property, newValue);
+    }
+
+    public Object invokeMethod(String name, Object args) {
+        try {
+            return super.invokeMethod(name, args);
+        }
+        catch (GroovyRuntimeException e) {
+            // br should get a "native" property match first. getProperty includes such fall-back logic
+            Object value = this.getProperty(name);
+            if (value instanceof Closure) {
+                Closure closure = (Closure) value;
+                closure.setDelegate(this);
+                return closure.call((Object[]) args);
+            }
+            else {
+                throw e;
+            }
+        }
+        
+    }
+    
+    /**
+     * This allows toString to be overridden by a closure <i>field</i> method attached
+     * to the expando object.
+     * 
+     * @see java.lang.Object#toString()
+     */
+     public String toString() {
+        Object method = getProperties().get("toString");
+        if (method != null && method instanceof Closure) {
+            // invoke overridden toString closure method
+            Closure closure = (Closure) method;
+            closure.setDelegate(this);
+            return closure.call().toString();
+        } else {
+            return expandoProperties.toString();
+        }
+     }
+
+    /**
+     * This allows equals to be overridden by a closure <i>field</i> method attached
+     * to the expando object.
+     *
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals(Object obj) {
+        Object method = getProperties().get("equals");
+        if (method != null && method instanceof Closure) {
+            // invoke overridden equals closure method
+            Closure closure = (Closure) method;
+            closure.setDelegate(this);
+            Boolean ret = (Boolean) closure.call(obj);
+            return ret.booleanValue();
+        } else {
+            return super.equals(obj);
+        }
+    }
+
+    /**
+     * This allows hashCode to be overridden by a closure <i>field</i> method attached
+     * to the expando object.
+     *
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        Object method = getProperties().get("hashCode");
+        if (method != null && method instanceof Closure) {
+            // invoke overridden hashCode closure method
+            Closure closure = (Closure) method;
+            closure.setDelegate(this);
+            Integer ret = (Integer) closure.call();
+            return ret.intValue();
+        } else {
+            return super.hashCode();
+        }
+    }
+
+    /**
+     * Factory method to create a new Map used to store the expando properties map
+     * @return a newly created Map implementation
+     */
+    protected Map createMap() {
+        return new HashMap();
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/util/FileNameByRegexFinder.groovy b/groovy-core/src/main/groovy/util/FileNameByRegexFinder.groovy
new file mode 100644
index 0000000..d9bd6eb
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/FileNameByRegexFinder.groovy
@@ -0,0 +1,12 @@
+package groovy.util
+
+class FileNameByRegexFinder implements IFileNameFinder{
+
+   List getFileNames(String basedir, String pattern){
+      def result = []
+      new File(basedir).eachFileRecurse {
+          if (it.path =~ pattern) result << it.absolutePath
+      }
+      return result
+   }
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/util/FileNameFinder.groovy b/groovy-core/src/main/groovy/util/FileNameFinder.groovy
new file mode 100644
index 0000000..6846f34
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/FileNameFinder.groovy
@@ -0,0 +1,16 @@
+package groovy.util
+
+class FileNameFinder implements IFileNameFinder{
+
+   List getFileNames(String basedir, String pattern){
+      def ant = new AntBuilder()
+      def scanner = ant.fileScanner {
+          fileset(dir:basedir, includes:pattern)
+      }
+      def fls = []
+      for(f in scanner){
+	      fls << f.getAbsolutePath()
+      }
+      return fls
+   }
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/util/GroovyLog.java b/groovy-core/src/main/groovy/util/GroovyLog.java
new file mode 100644
index 0000000..fa68ce7
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/GroovyLog.java
@@ -0,0 +1,87 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+import groovy.lang.GroovyObjectSupport;
+
+
+
+/**
+ * Represents an arbitrary logging service. By default this outputs to
+ * System.out though derivations of this class could log to Jakarta Commons Logging
+ * or log4j or JDK 1.5 logging etc
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class GroovyLog extends GroovyObjectSupport {
+
+    String prefix;
+
+    /** 
+     * Factory method to create new instances 
+     */
+    public static GroovyLog newInstance(Class aClass) {
+        return new GroovyLog(aClass);
+    }
+    
+    public GroovyLog() {
+        this("");
+    }
+
+    public GroovyLog(Class owner) {
+        this(owner.getName());
+    }
+
+    public GroovyLog(String prefix) {
+        this.prefix = (prefix != null && prefix.length() > 0) ? "[" + prefix + ":" : "[";
+    }
+
+    public Object invokeMethod(String name, Object args) {
+        System.out.println(prefix + name + "] " + args);
+        return null;
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/GroovyMBean.java b/groovy-core/src/main/groovy/util/GroovyMBean.java
new file mode 100644
index 0000000..f6d81f5
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/GroovyMBean.java
@@ -0,0 +1,421 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+import groovy.lang.GroovyObjectSupport;
+import groovy.lang.GroovyRuntimeException;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Collection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Iterator;
+import java.io.IOException;
+
+import javax.management.Attribute;
+import javax.management.JMException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.ObjectName;
+import javax.management.MBeanServerConnection;
+import javax.management.MBeanAttributeInfo;
+
+
+/**
+ * A GroovyObject facade for an underlying MBean which acts like a normal
+ * groovy object but which is actually implemented via
+ * an underlying JMX MBean.
+ * Properties and normal method invocations
+ * delegate to the MBeanServer to the actual MBean.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Steve Button
+ * @version $Revision$
+ */
+public class GroovyMBean extends GroovyObjectSupport {
+
+    private MBeanServerConnection server;
+    private ObjectName name;
+    private MBeanInfo beanInfo;
+    private Map operations = new HashMap();
+
+
+    public GroovyMBean(MBeanServerConnection server, ObjectName name) throws JMException, IOException {
+        this.server = server;
+        this.name = name;
+        this.beanInfo = server.getMBeanInfo(name);
+
+
+        MBeanOperationInfo[] operationInfos = beanInfo.getOperations();
+        for (int i = 0; i < operationInfos.length; i++) {
+            MBeanOperationInfo info = operationInfos[i];
+            String signature[] = createSignature(info);
+
+            // Include a simple fix here to support overloaded operations on the MBean.
+            // Construct a simple key for an operation by adding the number of parameters it uses
+            String operationKey = createOperationKey(info.getName(), signature.length);
+            operations.put(operationKey, signature);
+        }
+
+    }
+
+    public MBeanServerConnection server() {
+        return server;
+    }
+
+    public ObjectName name() {
+        return name;
+    }
+
+    public MBeanInfo info() {
+        return beanInfo;
+    }
+
+    public Object getProperty(String property) {
+        try {
+            return server.getAttribute(name, property);
+        }
+        catch (MBeanException e) {
+            throw new GroovyRuntimeException("Could not access property: " + property + ". Reason: " + e, e.getTargetException());
+        }
+        catch (Exception e) {
+            throw new GroovyRuntimeException("Could not access property: " + property + ". Reason: " + e, e);
+        }
+    }
+
+    public void setProperty(String property, Object value) {
+        try {
+            server.setAttribute(name, new Attribute(property, value));
+        }
+        catch (MBeanException e) {
+            throw new GroovyRuntimeException("Could not set property: " + property + ". Reason: " + e, e.getTargetException());
+        }
+        catch (Exception e) {
+            throw new GroovyRuntimeException("Could not set property: " + property + ". Reason: " + e, e);
+        }
+    }
+
+    public Object invokeMethod(String method, Object arguments) {
+        // Moved this outside the try block so we can obtain the number of parameters
+        // specified in the arguments array, which is needed to find the correct method.
+        Object[] argArray = null;
+        if (arguments instanceof Object[]) {
+            argArray = (Object[]) arguments;
+        } else {
+            argArray = new Object[]{arguments};
+        }
+        // Locate the specific method based on the name and number of parameters
+        String operationKey = createOperationKey(method, argArray.length);
+        String[] signature = (String[]) operations.get(operationKey);
+
+        if (signature != null) {
+            try {
+                return server.invoke(name, method, argArray, signature);
+            }
+            catch (MBeanException e) {
+                throw new GroovyRuntimeException("Could not invoke method: " + method + ". Reason: " + e, e.getTargetException());
+            }
+            catch (Exception e) {
+                throw new GroovyRuntimeException("Could not invoke method: " + method + ". Reason: " + e, e);
+            }
+        } else {
+            return super.invokeMethod(method, arguments);
+        }
+    }
+
+    protected String[] createSignature(MBeanOperationInfo info) {
+        MBeanParameterInfo[] params = info.getSignature();
+        String[] answer = new String[params.length];
+        for (int i = 0; i < params.length; i++) {
+            answer[i] = params[i].getType();
+        }
+        return answer;
+    }
+
+    /**
+     * Construct a simple key based on the method name and the number of parameters
+     *
+     * @param operation - the mbean operation name
+     * @param params    - the number of parameters the operation supports
+     * @return simple unique identifier for a method
+     */
+    protected String createOperationKey(String operation, int params) {
+        // This could be changed to support some hash of the parameter types, etc.
+        return operation + "_" + params;
+    }
+
+    /**
+     * List of the names of each of the attributes on the MBean
+     *
+     * @return list of attribute names
+     */
+    public Collection listAttributeNames() {
+        ArrayList list = new ArrayList();
+        try {
+            MBeanAttributeInfo[] attrs = beanInfo.getAttributes();
+            for (int i = 0; i < attrs.length; i++) {
+                MBeanAttributeInfo attr = attrs[i];
+                list.add(attr.getName());
+            }
+        }
+        catch (Throwable t) {
+        }
+        finally {
+        }
+        return list;
+    }
+
+    /**
+     * The values of each of the attributes on the MBean
+     *
+     * @return list of values of each attribute
+     */
+    public List listAttributeValues() {
+        ArrayList list = new ArrayList();
+        Collection names = listAttributeNames();
+        for (Iterator iterator = names.iterator(); iterator.hasNext();) {
+            String name = (String) iterator.next();
+            try {
+                Object val = this.getProperty(name);
+                if (val != null) {
+                    list.add(name + " : " + val.toString());
+                }
+            }
+            catch (RuntimeException e) {
+                // todo: fix this behaviour properly
+                // Do nothing here, just handle the error silently.
+                //e.printStackTrace();
+            }
+        }
+        return list;
+    }
+
+
+    /**
+     * List of string representations of all of the attributes on the MBean.
+     *
+     * @return list of descriptions of each attribute on the mbean
+     */
+    public Collection listAttributeDescriptions() {
+        ArrayList list = new ArrayList();
+        try {
+            MBeanAttributeInfo[] attrs = beanInfo.getAttributes();
+            for (int i = 0; i < attrs.length; i++) {
+                MBeanAttributeInfo attr = attrs[i];
+                list.add(describeAttribute(attr));
+            }
+        }
+        catch (Throwable t) {
+        }
+        finally {
+        }
+        return list;
+    }
+
+    /**
+     * Description of the specified attribute name.
+     *
+     * @param attr - the attribute
+     * @return String the description
+     */
+    protected String describeAttribute(MBeanAttributeInfo attr) {
+        StringBuffer buf = new StringBuffer();
+        buf.append("(");
+        if (attr.isReadable()) {
+            buf.append("r");
+        }
+        if (attr.isWritable()) {
+            buf.append("w");
+        }
+        buf.append(") ")
+                .append(attr.getType())
+                .append(" ")
+                .append(attr.getName());
+        return buf.toString();
+    }
+
+    /**
+     * Description of the specified attribute name.
+     *
+     * @param attributeName - stringified name of the attribute
+     * @return the description
+     */
+    public String describeAttribute(String attributeName) {
+        String ret = "Attribute not found";
+        try {
+            MBeanAttributeInfo[] attributes = beanInfo.getAttributes();
+            for (int i = 0; i < attributes.length; i++) {
+                MBeanAttributeInfo attribute = attributes[i];
+                if (attribute.getName().equals(attributeName)) {
+                    return describeAttribute(attribute);
+                }
+            }
+        }
+        catch (Throwable t) {
+        }
+        return ret;
+    }
+
+    /**
+     * Names of all the operations available on the MBean.
+     *
+     * @return all the operations on the MBean
+     */
+    public Collection listOperationNames() {
+        ArrayList list = new ArrayList();
+        try {
+            MBeanOperationInfo[] operations = beanInfo.getOperations();
+            for (int i = 0; i < operations.length; i++) {
+                MBeanOperationInfo operation = operations[i];
+                list.add(operation.getName());
+            }
+        }
+        catch (Throwable t) {
+        }
+        return list;
+    }
+
+
+    /**
+     * Description of all of the operations available on the MBean.
+     *
+     * @return full description of each operation on the MBean
+     */
+    public Collection listOperationDescriptions() {
+        ArrayList list = new ArrayList();
+        try {
+            MBeanOperationInfo[] operations = beanInfo.getOperations();
+            for (int i = 0; i < operations.length; i++) {
+                MBeanOperationInfo operation = operations[i];
+                list.add(describeOperation(operation));
+            }
+        }
+        catch (Throwable t) {
+        }
+        return list;
+    }
+
+    /**
+     * Get the dessciptions of the named operation.  This returns a Collection since
+     * operations can be overloaded and one operationName can have multiple forms.
+     *
+     * @param operationName
+     * @return Collection of operation description
+     */
+    public List describeOperation(String operationName) {
+        ArrayList list = new ArrayList();
+        try {
+            MBeanOperationInfo[] operations = beanInfo.getOperations();
+            for (int i = 0; i < operations.length; i++) {
+                MBeanOperationInfo operation = operations[i];
+                if (operation.getName().equals(operationName)) {
+                    list.add(describeOperation(operation));
+                }
+            }
+        }
+        catch (Throwable t) {
+        }
+        return list;
+    }
+
+    /**
+     * Dessciption of the named operation.
+     *
+     * @param operation
+     * @return description
+     */
+    protected String describeOperation(MBeanOperationInfo operation) {
+        StringBuffer buf = new StringBuffer();
+        buf.append(operation.getReturnType())
+                .append(" ")
+                .append(operation.getName())
+                .append("(");
+
+        MBeanParameterInfo[] params = operation.getSignature();
+        for (int j = 0; j < params.length; j++) {
+            MBeanParameterInfo param = params[j];
+            if (j != 0) {
+                buf.append(", ");
+            }
+            buf.append(param.getType())
+                    .append(" ")
+                    .append(param.getName());
+        }
+        buf.append(")");
+        return buf.toString();
+    }
+
+
+    /**
+     * Return an end user readable representation of the underlying MBean
+     * @return the user readable description
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+        buf.append("MBean Name:")
+                .append("\n  ")
+                .append(name.getCanonicalName())
+                .append("\n  ");
+        if (!listAttributeDescriptions().isEmpty()) {
+            buf.append("\nAttributes:");
+            for (Iterator iterator = listAttributeDescriptions().iterator(); iterator.hasNext();) {
+                buf.append("\n  ")
+                        .append((String) iterator.next());
+            }
+        }
+        if (!listOperationDescriptions().isEmpty()) {
+            buf.append("\nOperations:");
+            for (Iterator iterator = listOperationDescriptions().iterator(); iterator.hasNext();) {
+                buf.append("\n  ")
+                        .append((String) iterator.next());
+            }
+        }
+        return buf.toString();
+  }
+}
diff --git a/groovy-core/src/main/groovy/util/GroovyScriptEngine.java b/groovy-core/src/main/groovy/util/GroovyScriptEngine.java
new file mode 100644
index 0000000..0cd3608
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/GroovyScriptEngine.java
@@ -0,0 +1,380 @@
+/*
+ * $Id$version Jan 9, 2004 12:19:58 PM $user Exp $
+ * 
+ * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package groovy.util;
+
+import groovy.lang.Binding;
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.Script;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * Specific script engine able to reload modified scripts as well as dealing properly with dependent scripts.
+ *
+ * @author sam
+ * @author Marc Palmer
+ * @author Guillaume Laforge
+ */
+public class GroovyScriptEngine implements ResourceConnector {
+
+    /**
+     * Simple testing harness for the GSE. Enter script roots as arguments and
+     * then input script names to run them.
+     *
+     * @param urls
+     * @throws Exception
+     */
+    public static void main(String[] urls) throws Exception {
+        URL[] roots = new URL[urls.length];
+        for (int i = 0; i < roots.length; i++) {
+            roots[i] = new File(urls[i]).toURL();
+        }
+        GroovyScriptEngine gse = new GroovyScriptEngine(roots);
+        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+        String line;
+        while (true) {
+            System.out.print("groovy> ");
+            if ((line = br.readLine()) == null || line.equals("quit"))
+                break;
+            try {
+                System.out.println(gse.run(line, new Binding()));
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private URL[] roots;
+    private Map scriptCache = Collections.synchronizedMap(new HashMap());
+    private ResourceConnector rc;
+    private ClassLoader parentClassLoader = getClass().getClassLoader();
+
+    private static class ScriptCacheEntry {
+        private Class scriptClass;
+        private long lastModified;
+        private Map dependencies = new HashMap();
+    }
+
+    /**
+     * Get a resource connection as a <code>URLConnection</code> to retrieve a script
+     * from the <code>ResourceConnector</code>
+     *
+     * @param resourceName name of the resource to be retrieved
+     * @return a URLConnection to the resource
+     * @throws ResourceException
+     */
+    public URLConnection getResourceConnection(String resourceName) throws ResourceException {
+        // Get the URLConnection
+        URLConnection groovyScriptConn = null;
+
+        ResourceException se = null;
+        for (int i = 0; i < roots.length; i++) {
+            URL scriptURL = null;
+            try {
+                scriptURL = new URL(roots[i], resourceName);
+
+                groovyScriptConn = scriptURL.openConnection();
+
+                // Make sure we can open it, if we can't it doesn't exist.
+                // Could be very slow if there are any non-file:// URLs in there
+                groovyScriptConn.getInputStream();
+
+                break; // Now this is a bit unusual
+
+            } catch (MalformedURLException e) {
+                String message = "Malformed URL: " + roots[i] + ", " + resourceName;
+                if (se == null) {
+                    se = new ResourceException(message);
+                } else {
+                    se = new ResourceException(message, se);
+                }
+            } catch (IOException e1) {
+                String message = "Cannot open URL: " + scriptURL;
+                if (se == null) {
+                    se = new ResourceException(message);
+                } else {
+                    se = new ResourceException(message, se);
+                }
+            }
+        }
+
+        // If we didn't find anything, report on all the exceptions that occurred.
+        if (groovyScriptConn == null) {
+            throw se;
+        }
+
+        return groovyScriptConn;
+    }
+
+    /**
+     * The groovy script engine will run groovy scripts and reload them and
+     * their dependencies when they are modified. This is useful for embedding
+     * groovy in other containers like games and application servers.
+     *
+     * @param roots This an array of URLs where Groovy scripts will be stored. They should
+     * be layed out using their package structure like Java classes 
+     */
+    public GroovyScriptEngine(URL[] roots) {
+        this.roots = roots;
+        this.rc = this;
+    }
+
+    public GroovyScriptEngine(URL[] roots, ClassLoader parentClassLoader) {
+        this(roots);
+        this.parentClassLoader = parentClassLoader;
+    }
+
+    public GroovyScriptEngine(String[] urls) throws IOException {
+        roots = new URL[urls.length];
+        for (int i = 0; i < roots.length; i++) {
+            roots[i] = new File(urls[i]).toURL();
+        }
+        this.rc = this;
+    }
+
+    public GroovyScriptEngine(String[] urls, ClassLoader parentClassLoader) throws IOException {
+        this(urls);
+        this.parentClassLoader = parentClassLoader;
+    }
+
+    public GroovyScriptEngine(String url) throws IOException {
+        roots = new URL[1];
+        roots[0] = new File(url).toURL();
+        this.rc = this;
+    }
+
+    public GroovyScriptEngine(String url, ClassLoader parentClassLoader) throws IOException {
+        this(url);
+        this.parentClassLoader = parentClassLoader;
+    }
+
+    public GroovyScriptEngine(ResourceConnector rc) {
+        this.rc = rc;
+    }
+
+    public GroovyScriptEngine(ResourceConnector rc, ClassLoader parentClassLoader) {
+        this(rc);
+        this.parentClassLoader = parentClassLoader;
+    }
+
+    /**
+     * Get the <code>ClassLoader</code> that will serve as the parent ClassLoader of the
+     * {@link GroovyClassLoader} in which scripts will be executed. By default, this is the
+     * ClassLoader that loaded the <code>GroovyScriptEngine</code> class.
+     *
+     * @return parent classloader used to load scripts
+     */
+    public ClassLoader getParentClassLoader() {
+        return parentClassLoader;
+    }
+
+    /**
+     * @param parentClassLoader ClassLoader to be used as the parent ClassLoader for scripts executed by the engine
+     */
+    public void setParentClassLoader(ClassLoader parentClassLoader) {
+        if (parentClassLoader == null) {
+            throw new IllegalArgumentException("The parent class loader must not be null.");
+        }
+        this.parentClassLoader = parentClassLoader;
+    }
+
+    /**
+     * Get the class of the scriptName in question, so that you can instantiate Groovy objects with caching and reloading.
+     *
+     * @param scriptName
+     * @return the loaded scriptName as a compiled class
+     * @throws ResourceException
+     * @throws ScriptException
+     */
+    public Class loadScriptByName(String scriptName) throws ResourceException, ScriptException {
+        return loadScriptByName( scriptName, getClass().getClassLoader());
+    }
+
+
+    /**
+     * Get the class of the scriptName in question, so that you can instantiate Groovy objects with caching and reloading.
+     *
+     * @param scriptName
+     * @return the loaded scriptName as a compiled class
+     * @throws ResourceException
+     * @throws ScriptException
+     */
+    public Class loadScriptByName(String scriptName, ClassLoader parentClassLoader)
+            throws ResourceException, ScriptException {
+        scriptName = scriptName.replace('.', File.separatorChar) + ".groovy";
+        ScriptCacheEntry entry = updateCacheEntry(scriptName, parentClassLoader);
+        return entry.scriptClass;
+    }
+
+    /**
+     * Locate the class and reload it or any of its dependencies
+     *
+     * @param scriptName
+     * @param parentClassLoader
+     * @return the scriptName cache entry
+     * @throws ResourceException
+     * @throws ScriptException
+     */
+    private ScriptCacheEntry updateCacheEntry(String scriptName, final ClassLoader parentClassLoader)
+            throws ResourceException, ScriptException
+    {
+        ScriptCacheEntry entry;
+
+        scriptName = scriptName.intern();
+        synchronized (scriptName) {
+
+            URLConnection groovyScriptConn = rc.getResourceConnection(scriptName);
+
+            // URL last modified
+            long lastModified = groovyScriptConn.getLastModified();
+            // Check the cache for the scriptName
+            entry = (ScriptCacheEntry) scriptCache.get(scriptName);
+            // If the entry isn't null check all the dependencies
+
+            boolean dependencyOutOfDate = false;
+            if (entry != null) {
+
+                for (Iterator i = entry.dependencies.keySet().iterator(); i.hasNext();) {
+                    URLConnection urlc = null;
+                    URL url = (URL) i.next();
+                    try {
+                        urlc = url.openConnection();
+                        urlc.setDoInput(false);
+                        urlc.setDoOutput(false);
+                        long dependentLastModified = urlc.getLastModified();
+                        if (dependentLastModified > ((Long) entry.dependencies.get(url)).longValue()) {
+                            dependencyOutOfDate = true;
+                            break;
+                        }
+                    } catch (IOException ioe) {
+                        dependencyOutOfDate = true;
+                        break;
+                    }
+                }
+            }
+
+            if (entry == null || entry.lastModified < lastModified || dependencyOutOfDate) {
+                // Make a new entry
+                entry = new ScriptCacheEntry();
+
+                // Closure variable
+                final ScriptCacheEntry finalEntry = entry;
+
+                // Compile the scriptName into an object
+                GroovyClassLoader groovyLoader =
+                        (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
+                            public Object run() {
+                                return new GroovyClassLoader(parentClassLoader) {
+                                    protected Class findClass(String className) throws ClassNotFoundException {
+                                        String filename = className.replace('.', File.separatorChar) + ".groovy";
+                                        URLConnection dependentScriptConn = null;
+                                        try {
+                                            dependentScriptConn = rc.getResourceConnection(filename);
+                                            finalEntry.dependencies.put(
+                                                    dependentScriptConn.getURL(),
+                                                    new Long(dependentScriptConn.getLastModified()));
+                                        } catch (ResourceException e1) {
+                                            throw new ClassNotFoundException("Could not read " + className + ": " + e1);
+                                        }
+                                        try {
+                                            return parseClass(dependentScriptConn.getInputStream(), filename);
+                                        } catch (CompilationFailedException e2) {
+                                            throw new ClassNotFoundException("Syntax error in " + className + ": " + e2);
+                                        } catch (IOException e2) {
+                                            throw new ClassNotFoundException("Problem reading " + className + ": " + e2);
+                                        }
+                                    }
+                                };
+                            }
+                        });
+
+                try {
+                    entry.scriptClass = groovyLoader.parseClass(groovyScriptConn.getInputStream(), scriptName);
+                } catch (Exception e) {
+                    throw new ScriptException("Could not parse scriptName: " + scriptName, e);
+                }
+                entry.lastModified = lastModified;
+                scriptCache.put(scriptName, entry);
+            }
+        }
+        return entry;
+    }
+
+    /**
+     * Run a script identified by name.
+     *
+     * @param scriptName name of the script to run
+     * @param argument a single argument passed as a variable named <code>arg</code> in the binding
+     * @return a <code>toString()</code> representation of the result of the execution of the script
+     * @throws ResourceException
+     * @throws ScriptException
+     */
+    public String run(String scriptName, String argument) throws ResourceException, ScriptException {
+        Binding binding = new Binding();
+        binding.setVariable("arg", argument);
+        Object result = run(scriptName, binding);
+        return result == null ? "" : result.toString();
+    }
+
+    /**
+     * Run a script identified by name.
+     *
+     * @param scriptName name of the script to run
+     * @param binding binding to pass to the script
+     * @return an object
+     * @throws ResourceException
+     * @throws ScriptException
+     */
+    public Object run(String scriptName, Binding binding) throws ResourceException, ScriptException {
+
+        ScriptCacheEntry entry = updateCacheEntry(scriptName, getParentClassLoader());
+        Script scriptObject = InvokerHelper.createScript(entry.scriptClass, binding);
+        return scriptObject.run();
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/GroovyTestCase.java b/groovy-core/src/main/groovy/util/GroovyTestCase.java
new file mode 100644
index 0000000..dd94d74
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/GroovyTestCase.java
@@ -0,0 +1,394 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.GroovyShell;
+
+import java.util.logging.Logger;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import junit.framework.TestCase;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * A default JUnit TestCase in Groovy. This provides a number of helper methods
+ * plus avoids the JUnit restriction of requiring all test* methods to be void
+ * return type.
+ *
+ * @author <a href="mailto:bob@werken.com">bob mcwhirter</a>
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Dierk Koenig (the notYetImplemented feature, changes to shouldFail)
+ * @version $Revision$
+ */
+public class GroovyTestCase extends TestCase {
+
+    protected static Logger log = Logger.getLogger(GroovyTestCase.class.getName());
+    private static int counter;
+    private boolean useAgileDoxNaming = false;
+
+    public GroovyTestCase() {
+    }
+
+    /**
+     * Overload the getName() method to make the test cases look more like AgileDox
+     * (thanks to Joe Walnes for this tip!)
+     */
+    public String getName() {
+        if (useAgileDoxNaming) {
+            return super.getName().substring(4).replaceAll("([A-Z])", " $1").toLowerCase();
+        }
+        else {
+            return super.getName();
+        }
+    }
+
+    public String getMethodName() {
+        return super.getName();
+    }
+
+    /**
+     * Asserts that the arrays are equivalent and contain the same values
+     *
+     * @param expected
+     * @param value
+     */
+    protected void assertArrayEquals(Object[] expected, Object[] value) {
+        String message =
+            "expected array: " + InvokerHelper.toString(expected) + " value array: " + InvokerHelper.toString(value);
+        assertNotNull(message + ": expected should not be null", expected);
+        assertNotNull(message + ": value should not be null", value);
+        assertEquals(message, expected.length, value.length);
+        for (int i = 0, size = expected.length; i < size; i++) {
+            assertEquals("value[" + i + "] when " + message, expected[i], value[i]);
+        }
+    }
+
+    /**
+     * Asserts that the array of characters has a given length
+     *
+     * @param length expected length
+     * @param array the array
+     */
+    protected void assertLength(int length, char[] array) {
+        assertEquals(length, array.length);
+    }
+
+    /**
+     * Asserts that the array of ints has a given length
+     *
+     * @param length expected length
+     * @param array the array
+     */
+    protected void assertLength(int length, int[] array) {
+        assertEquals(length, array.length);
+    }
+
+    /**
+     * Asserts that the array of objects has a given length
+     *
+     * @param length expected length
+     * @param array the array
+     */
+    protected void assertLength(int length, Object[] array) {
+        assertEquals(length, array.length);
+    }
+
+    /**
+     * Asserts that the array of characters contains a given char
+     *
+     * @param expected expected character to be found
+     * @param array the array
+     */
+    protected void assertContains(char expected, char[] array) {
+        for (int i = 0; i < array.length; ++i) {
+            if (array[i] == expected) {
+                return;
+            }
+        }
+
+        StringBuffer message = new StringBuffer();
+
+        message.append(expected).append(" not in {");
+
+        for (int i = 0; i < array.length; ++i) {
+            message.append("'").append(array[i]).append("'");
+
+            if (i < (array.length - 1)) {
+                message.append(", ");
+            }
+        }
+
+        message.append(" }");
+
+        fail(message.toString());
+    }
+
+    /**
+     * Asserts that the array of ints contains a given int
+     *
+     * @param expected expected int
+     * @param array the array
+     */
+    protected void assertContains(int expected, int[] array) {
+        for (int i = 0; i < array.length; ++i) {
+            if (array[i] == expected) {
+                return;
+            }
+        }
+
+        StringBuffer message = new StringBuffer();
+
+        message.append(expected).append(" not in {");
+
+        for (int i = 0; i < array.length; ++i) {
+            message.append("'").append(array[i]).append("'");
+
+            if (i < (array.length - 1)) {
+                message.append(", ");
+            }
+        }
+
+        message.append(" }");
+
+        fail(message.toString());
+    }
+
+    /**
+     * Asserts that the value of toString() on the given object matches the
+     * given text string
+     *
+     * @param value the object to be output to the console
+     * @param expected the expected String representation
+     */
+    protected void assertToString(Object value, String expected) {
+        Object console = InvokerHelper.invokeMethod(value, "toString", null);
+        assertEquals("toString() on value: " + value, expected, console);
+    }
+
+    /**
+     * Asserts that the value of inspect() on the given object matches the
+     * given text string
+     *
+     * @param value the object to be output to the console
+     * @param expected the expected String representation
+     */
+    protected void assertInspect(Object value, String expected) {
+        Object console = InvokerHelper.invokeMethod(value, "inspect", null);
+        assertEquals("inspect() on value: " + value, expected, console);
+    }
+
+    /**
+     * Asserts that the script runs without any exceptions
+     *
+     * @param script the script that should pass without any exception thrown
+     */
+    protected void assertScript(final String script) throws Exception {
+        GroovyShell shell = new GroovyShell();
+        shell.evaluate(script, getTestClassName());
+    }
+
+    protected String getTestClassName() {
+        return "TestScript" + getMethodName() + (counter++) + ".groovy";
+    }
+
+    /**
+     * Asserts that the given code closure fails when it is evaluated
+     *
+     * @param code
+     * @return the message of the thrown Throwable
+     */
+    protected String shouldFail(Closure code) {
+        boolean failed = false;
+        String result = null;
+        try {
+            code.call();
+        }
+        catch (Throwable e) {
+                failed = true;
+                result = e.getMessage();
+        }
+        assertTrue("Closure " + code + " should have failed", failed);
+        return result;
+    }
+
+    /**
+     * Asserts that the given code closure fails when it is evaluated
+     * and that a particular exception is thrown.
+     *
+     * @param clazz the class of the expected exception
+     * @param code the closure that should fail
+     * @return the message of the expected Throwable
+     */
+    protected String shouldFail(Class clazz, Closure code) {
+        Throwable th = null;
+        try {
+            code.call();
+        } catch (GroovyRuntimeException gre) {
+            th = gre;
+            while (th.getCause()!=null && th.getCause()!=gre){ // if wrapped, find the root cause
+                th=th.getCause();
+                if (th!=gre && (th instanceof GroovyRuntimeException)) {
+                    gre = (GroovyRuntimeException) th;
+                }
+            }            
+        } catch (Throwable e) {
+            th = e;
+        }
+
+        if (th==null) {
+            fail("Closure " + code + " should have failed with an exception of type " + clazz.getName());
+        } else if (! clazz.isInstance(th)) {
+            fail("Closure " + code + " should have failed with an exception of type " + clazz.getName() + ", instead got Exception " + th);
+        }
+        return th.getMessage();
+    }
+
+    /**
+     *  Returns a copy of a string in which all EOLs are \n.
+     */
+    protected String fixEOLs( String value )
+    {
+        return value.replaceAll( "(\\r\\n?)|\n", "\n" );
+    }
+
+    /**
+     * Runs the calling JUnit test again and fails only if it unexpectedly runs.<br/>
+     * This is helpful for tests that don't currently work but should work one day,
+     * when the tested functionality has been implemented.<br/>
+     * The right way to use it is:
+     * <pre>
+     * public void testXXX() {
+     *   if (GroovyTestCase.notYetImplemented(this)) return;
+     *   ... the real (now failing) unit test
+     * }
+     * </pre>
+     * Idea copied from HtmlUnit (many thanks to Marc Guillemot).
+     * Future versions maybe available in the JUnit distro.
+     * The purpose of providing a 'static' version is such that you can use the
+     * feature even if not subclassing GroovyTestCase.
+     * @return <false> when not itself already in the call stack
+     */
+    public static boolean notYetImplemented(TestCase caller) {
+        if (notYetImplementedFlag.get() != null) {
+            return false;
+        }
+        notYetImplementedFlag.set(Boolean.TRUE);
+
+        final Method testMethod = findRunningJUnitTestMethod(caller.getClass());
+        try {
+            log.info("Running " + testMethod.getName() + " as not yet implemented");
+            testMethod.invoke(caller, new Class[] {});
+            fail(testMethod.getName() + " is marked as not yet implemented but passes unexpectedly");
+        }
+        catch (final Exception e) {
+            log.info(testMethod.getName() + " fails which is expected as it is not yet implemented");
+            // method execution failed, it is really "not yet implemented"
+        }
+        finally {
+            notYetImplementedFlag.set(null);
+        }
+        return true;
+    }
+
+    /**
+     * Convenience method for subclasses of GroovyTestCase, identical to
+     * <pre> GroovyTestCase.notYetImplemented(this); </pre>.
+     * @see #notYetImplemented(junit.framework.TestCase)
+     * @return  <false> when not itself already in the call stack
+     */
+    public boolean notYetImplemented() {
+        return notYetImplemented(this);
+    }
+
+    /**
+     * From JUnit. Finds from the call stack the active running JUnit test case
+     * @return the test case method
+     * @throws RuntimeException if no method could be found.
+     */
+    private static Method findRunningJUnitTestMethod(Class caller) {
+        final Class[] args = new Class[] {};
+
+        // search the inial junit test
+        final Throwable t = new Exception();
+        for (int i=t.getStackTrace().length-1; i>=0; --i) {
+            final StackTraceElement element = t.getStackTrace()[i];
+            if (element.getClassName().equals(caller.getName())) {
+                try {
+                    final Method m = caller.getMethod(element.getMethodName(), args);
+                    if (isPublicTestMethod(m)) {
+                        return m;
+                    }
+                }
+                catch (final Exception e) {
+                    // can't access, ignore it
+                }
+            }
+        }
+        throw new RuntimeException("No JUnit test case method found in call stack");
+    }
+
+
+    /**
+     * From Junit. Test if the method is a junit test.
+     * @param method the method
+     * @return <code>true</code> if this is a junit test.
+     */
+    private static boolean isPublicTestMethod(final Method method) {
+        final String name = method.getName();
+        final Class[] parameters = method.getParameterTypes();
+        final Class returnType = method.getReturnType();
+
+        return parameters.length == 0 && name.startsWith("test")
+            && returnType.equals(Void.TYPE)
+            && Modifier.isPublic(method.getModifiers());
+    }
+
+    private static final ThreadLocal notYetImplementedFlag = new ThreadLocal();
+}
diff --git a/groovy-core/src/main/groovy/util/GroovyTestSuite.java b/groovy-core/src/main/groovy/util/GroovyTestSuite.java
new file mode 100644
index 0000000..d2f2eb0
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/GroovyTestSuite.java
@@ -0,0 +1,111 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package groovy.util;
+
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.Script;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+import org.codehaus.groovy.runtime.ScriptTestAdapter;
+
+import java.io.File;
+
+
+/**
+ * A TestSuite which will run a Groovy unit test case inside any Java IDE
+ * either as a unit test case or as an application.
+ * <p/>
+ * You can specify the GroovyUnitTest to run by running this class as an appplication
+ * and specifying the script to run on the command line.
+ * <p/>
+ * <code>
+ * java groovy.util.GroovyTestSuite src/test/Foo.groovy
+ * </code>
+ * <p/>
+ * Or to run the test suite as a unit test suite in an IDE you can use
+ * the 'test' system property to define the test script to run.
+ * e.g. pass this into the JVM when the unit test plugin runs...
+ * <p/>
+ * <code>
+ * -Dtest=src/test/Foo.groovy
+ * </code>
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class GroovyTestSuite extends TestSuite {
+
+    protected static String file = null;
+
+    protected GroovyClassLoader loader = new GroovyClassLoader(GroovyTestSuite.class.getClassLoader());
+
+    public static void main(String[] args) {
+        if (args.length > 0) {
+            file = args[0];
+        }
+        TestRunner.run(suite());
+    }
+
+    public static Test suite() {
+        GroovyTestSuite suite = new GroovyTestSuite();
+        try {
+            suite.loadTestSuite();
+        } catch (Exception e) {
+            throw new RuntimeException("Could not create the test suite: " + e, e);
+        }
+        return suite;
+    }
+
+    public void loadTestSuite() throws Exception {
+        String fileName = System.getProperty("test", file);
+        if (fileName == null) {
+            throw new RuntimeException("No filename given in the 'test' system property so cannot run a Groovy unit test");
+        }
+        System.out.println("Compiling: " + fileName);
+        Class type = compile(fileName);
+        String[] args = {};
+        if (!Test.class.isAssignableFrom(type) && Script.class.isAssignableFrom(type)) {
+            // lets treat the script as a Test
+            addTest(new ScriptTestAdapter(type, args));
+        } else {
+            addTestSuite(type);
+        }
+    }
+
+    public Class compile(String fileName) throws Exception {
+        return loader.parseClass(new File(fileName));
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/IFileNameFinder.java b/groovy-core/src/main/groovy/util/IFileNameFinder.java
new file mode 100644
index 0000000..96ca0c4
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/IFileNameFinder.java
@@ -0,0 +1,7 @@
+package groovy.util;
+
+import java.util.List;
+
+public interface IFileNameFinder {
+    List getFileNames(String basedir, String pattern);
+}
diff --git a/groovy-core/src/main/groovy/util/IndentPrinter.java b/groovy-core/src/main/groovy/util/IndentPrinter.java
new file mode 100644
index 0000000..37a7ca6
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/IndentPrinter.java
@@ -0,0 +1,118 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+import java.io.PrintWriter;
+
+/**
+ * A helper class for printing indented text
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class IndentPrinter {
+
+    private int indentLevel;
+    private String indent;
+    private PrintWriter out;
+
+    public IndentPrinter() {
+        this(new PrintWriter(System.out), "  ");
+    }
+
+    public IndentPrinter(PrintWriter out) {
+        this(out, "  ");
+    }
+
+    public IndentPrinter(PrintWriter out, String indent) {
+        if (out == null) {
+            /** @todo temporary hack */
+            out = new PrintWriter(System.out);
+            //throw new IllegalArgumentException("Must specify a PrintWriter");
+        }
+        this.out = out;
+        this.indent = indent;
+    }
+
+    public void println(String text) {
+        out.print(text);
+        out.println();
+    }
+
+    public void print(String text) {
+        out.print(text);
+    }
+
+    public void printIndent() {
+        for (int i = 0; i < indentLevel; i++) {
+            out.print(indent);
+        }
+    }
+
+    public void println() {
+        out.println();
+    }
+
+    public void incrementIndent() {
+        ++indentLevel;
+    }
+
+    public void decrementIndent() {
+        --indentLevel;
+    }
+
+    public int getIndentLevel() {
+        return indentLevel;
+    }
+
+    public void setIndentLevel(int indentLevel) {
+        this.indentLevel = indentLevel;
+    }
+
+    public void flush() {
+        out.flush();
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/MapEntry.java b/groovy-core/src/main/groovy/util/MapEntry.java
new file mode 100644
index 0000000..347cfe9
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/MapEntry.java
@@ -0,0 +1,112 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived key this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived key this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+import java.util.Map;
+
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+/**
+ * Represents a list of Integer objects key a specified Object up to but not including
+ * a given and to.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MapEntry implements Map.Entry {
+
+    private Object key;
+    private Object value;
+
+    public MapEntry(Object key, Object value) {
+        this.key = key;
+        this.value = value;
+    }
+
+    public boolean equals(Object that) {
+        if (that instanceof MapEntry) {
+            return equals((MapEntry) that);
+        }
+        return false;
+    }
+
+    public boolean equals(MapEntry that) {
+        return DefaultTypeTransformation.compareEqual(this.key, that.key) && DefaultTypeTransformation.compareEqual(this.value, that.value);
+    }
+
+    public int hashCode() {
+        return hash(key) ^ hash(value);
+    }
+
+    public String toString() {
+        return "" + key + ":" + value;
+    }
+
+    public Object getKey() {
+        return key;
+    }
+
+    public void setKey(Object key) {
+        this.key = key;
+    }
+
+    public Object getValue() {
+        return value;
+    }
+
+    public Object setValue(Object value) {
+        this.value = value;
+        return value;
+    }
+
+    /**
+     * Helper method to handle object hashes for possibly null values
+     */
+    protected int hash(Object object) {
+        return (object == null) ? 0xbabe : object.hashCode();
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/util/Node.java b/groovy-core/src/main/groovy/util/Node.java
new file mode 100644
index 0000000..e8b6500
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/Node.java
@@ -0,0 +1,318 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import groovy.xml.QName;
+
+import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents an arbitrary tree node which can be used for structured metadata or any arbitrary XML-like tree.
+ * A node can have a name, a value and an optional Map of attributes.
+ * Typically the name is a String and a value is either a String or a List of other Nodes,
+ * though the types are extensible to provide a flexible structure, e.g. you could use a
+ * QName as the name which includes a namespace URI and a local name. Or a JMX ObjectName etc.
+ * So this class can represent metadata like {foo a=1 b="abc"} or nested metadata like {foo a=1 b="123" { bar x=12 text="hello" }}
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class Node implements java.io.Serializable {
+
+    private static final long serialVersionUID = 4121134753270542643L;
+    private Node parent;
+    private Object name;
+    private Map attributes;
+    private Object value;
+
+    public Node(Node parent, Object name) {
+        this(parent, name, Collections.EMPTY_MAP, Collections.EMPTY_LIST);
+    }
+
+    public Node(Node parent, Object name, Object value) {
+        this(parent, name, Collections.EMPTY_MAP, value);
+    }
+
+    public Node(Node parent, Object name, Map attributes) {
+        this(parent, name, attributes, Collections.EMPTY_LIST);
+    }
+
+    public Node(Node parent, Object name, Map attributes, Object value) {
+        this.parent = parent;
+        this.name = name;
+        this.attributes = attributes;
+        this.value = value;
+        
+        if (parent != null) {
+            Object parentValue = parent.value();
+            List parentList;
+            if (parentValue instanceof List) {
+                parentList = (List) parentValue;
+            } else {
+                parentList = new NodeList();
+                parentList.add(parentValue);
+                parent.setValue(parentList);
+            }
+            parentList.add(this);
+        }
+    }
+
+    public String text() {
+        if (value instanceof String) {
+            return (String) value;
+        }
+        else if (value instanceof Collection) {
+            Collection coll = (Collection) value;
+            String previousText = null;
+            StringBuffer buffer = null;
+            for (Iterator iter = coll.iterator(); iter.hasNext();) {
+                Object child = iter.next();
+                if (child instanceof String) {
+                    String childText = (String) child;
+                    if (previousText == null) {
+                        previousText = childText;
+                    }
+                    else {
+                        if (buffer == null) {
+                            buffer = new StringBuffer();
+                            buffer.append(previousText);
+                        }
+                        buffer.append(childText);
+                    }
+                }
+            }
+            if (buffer != null) {
+                return buffer.toString();
+            }
+            else {
+                if (previousText != null) {
+                    return previousText;
+                }
+            }
+        }
+        return "";
+    }
+
+    
+    public Iterator iterator() {
+        return children().iterator();
+    }
+    
+    public List children() {
+        if (value == null) {
+            return Collections.EMPTY_LIST;
+        }
+        else if (value instanceof List) {
+            return (List) value;
+        }
+        else {
+            // we're probably just a String
+            return Collections.singletonList(value);
+        }
+    }
+
+    public Map attributes() {
+        return attributes;
+    }
+
+    public Object attribute(Object key) {
+        return (attributes != null) ? attributes.get(key) : null;
+    }
+    
+    public Object name() {
+        return name;
+    }
+
+    public Object value() {
+        return value;
+    }
+
+    public void setValue(Object value) {
+        this.value = value;
+    }
+
+    public Node parent() {
+        return parent;
+    }
+
+    /**
+     * Provides lookup of elements by non-namespaced name
+     * @param key the name (or shortcut key) of the node(s) of interest
+     * @return the nodes which match key
+     */
+    public Object get(String key) {
+        if (key != null && key.charAt(0) == '@') {
+            String attributeName = key.substring(1);
+            return attributes().get(attributeName);
+        }
+        if ("..".equals(key)) {
+            return parent();
+        }
+        if ("*".equals(key)) {
+            return children();
+        }
+        if ("**".equals(key)) {
+            return depthFirst();
+        }
+        // iterate through list looking for node with name 'key'
+        List answer = new NodeList();
+        for (Iterator iter = children().iterator(); iter.hasNext();) {
+            Object child = iter.next();
+            if (child instanceof Node) {
+                Node childNode = (Node) child;
+                Object childNodeName = childNode.name();
+                if (childNodeName != null && childNodeName.equals(key)) {
+                    answer.add(childNode);
+                }
+            }
+        }
+        return answer;
+    }
+    
+    /**
+     * Provides lookup of elements by QName.
+     *
+     * @param name the QName of interest
+     * @return the nodes matching name
+     */
+    public NodeList getAt(QName name) {
+        NodeList answer = new NodeList();
+        for (Iterator iter = children().iterator(); iter.hasNext();) {
+            Object child = iter.next();
+            if (child instanceof Node) {
+                Node childNode = (Node) child;
+                Object childNodeName = childNode.name();
+                if (childNodeName != null && childNodeName.equals(name)) {
+                    answer.add(childNode);
+                }
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Provide a collection of all the nodes in the tree
+     * using a depth first traversal.
+     *
+     * @return the list of (depth-first) ordered nodes
+     */
+    public List depthFirst() {
+        List answer = new NodeList();
+        answer.add(this);
+        answer.addAll(depthFirstRest());
+        return answer;
+    }
+    
+    private List depthFirstRest() {
+        List answer = new NodeList();
+        for (Iterator iter = InvokerHelper.asIterator(value); iter.hasNext(); ) {
+            Object child = iter.next();
+            if (child instanceof Node) {
+                Node childNode = (Node) child;
+                List children = childNode.depthFirstRest();
+                answer.add(childNode);
+                answer.addAll(children);
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Provide a collection of all the nodes in the tree
+     * using a breadth-first traversal.
+     *
+     * @return the list of (breadth-first) ordered nodes
+     */
+    public List breadthFirst() {
+        List answer = new NodeList();
+        answer.add(this);
+        answer.addAll(breadthFirstRest());
+        return answer;
+    }
+    
+    private List breadthFirstRest() {
+        List answer = new NodeList();
+        List nextLevelChildren = getDirectChildren();
+        while (!nextLevelChildren.isEmpty()) {
+            List working = new NodeList(nextLevelChildren);
+            nextLevelChildren = new NodeList();
+            for (Iterator iter = working.iterator(); iter.hasNext(); ) {
+                Node childNode = (Node) iter.next();
+                answer.add(childNode);
+                List children = childNode.getDirectChildren();
+                nextLevelChildren.addAll(children);
+            }
+        }
+        return answer;
+    }
+
+    private List getDirectChildren() {
+        List answer = new NodeList();
+        for (Iterator iter = InvokerHelper.asIterator(value); iter.hasNext(); ) {
+            Object child = iter.next();
+            if (child instanceof Node) {
+                Node childNode = (Node) child;
+                answer.add(childNode);
+            }
+        }
+        return answer;
+    }
+
+    public String toString() {
+        return name + "[attributes=" + attributes + "; value=" + value + "]";
+    }
+
+    public void print(PrintWriter out) {
+        new NodePrinter(out).print(this);
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/NodeBuilder.java b/groovy-core/src/main/groovy/util/NodeBuilder.java
new file mode 100644
index 0000000..19a69ec
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/NodeBuilder.java
@@ -0,0 +1,86 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+/**
+ * A helper class for creating nested trees of Node objects for 
+ * handling arbitrary data
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class NodeBuilder extends BuilderSupport {
+
+    public static NodeBuilder newInstance() {
+        return new NodeBuilder();
+    }
+
+    protected void setParent(Object parent, Object child) {
+    }
+
+    protected Object createNode(Object name) {
+        return new Node(getCurrentNode(), name, new ArrayList());
+    }
+
+    protected Object createNode(Object name, Object value) {
+        return new Node(getCurrentNode(), name, value);
+    }
+
+    protected Object createNode(Object name, Map attributes) {
+        return new Node(getCurrentNode(), name, attributes, new ArrayList());
+    }
+
+    protected Object createNode(Object name, Map attributes, Object value) {
+        return new Node(getCurrentNode(), name, attributes, value);
+    }
+
+    protected Node getCurrentNode() {
+        return (Node) getCurrent();
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/NodeList.java b/groovy-core/src/main/groovy/util/NodeList.java
new file mode 100644
index 0000000..6c90b03
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/NodeList.java
@@ -0,0 +1,124 @@
+/**
+ * 
+ * Copyright 2005 LogicBlaze, Inc. http://www.logicblaze.com
+ * 
+ * Licensed 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.util;
+
+import groovy.xml.QName;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * A List implementation which is returned by queries on a {@link Node}
+ * which provides some XPath like helper methods for GPath.
+ */
+public class NodeList extends ArrayList {
+
+    public NodeList() {
+    }
+
+    public NodeList(Collection collection) {
+        super(collection);
+    }
+
+    public NodeList(int size) {
+        super(size);
+    }
+    
+    /**
+     * Provides lookup of elements by non-namespaced name.
+     *
+     * @return the nodes of interest which match name
+     * @param name the name or shortcut key for nodes of interest
+     */
+    public NodeList getAt(String name) {
+        NodeList answer = new NodeList();
+        for (Iterator iter = iterator(); iter.hasNext();) {
+            Object child = iter.next();
+            if (child instanceof Node) {
+                Node childNode = (Node) child;
+                Object temp = childNode.get(name);
+                if (temp instanceof Collection) {
+                    answer.addAll((Collection) temp);
+                }
+                else {
+                    answer.add(temp);
+                }
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Provides lookup of elements by QName.
+     *
+     * @return the nodes of interest which match name
+     * @param name the name or shortcut key for nodes of interest
+     */
+    public NodeList getAt(QName name) {
+        NodeList answer = new NodeList();
+        for (Iterator iter = iterator(); iter.hasNext();) {
+            Object child = iter.next();
+            if (child instanceof Node) {
+                Node childNode = (Node) child;
+                NodeList temp = childNode.getAt(name);
+                answer.addAll(temp);
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Returns the text value of all of the elements in the collection.
+     * 
+     * @return the text value of all the elements in the collection or null
+     */
+    public String text() {
+        String previousText = null;
+        StringBuffer buffer = null;
+        for (Iterator iter = this.iterator(); iter.hasNext();) {
+            Object child = iter.next();
+            String text = null;
+            if (child instanceof String) {
+                text = (String) child;
+            }
+            else if (child instanceof Node) {
+                text = ((Node) child).text();
+            }
+            if (text != null) {
+                if (previousText == null) {
+                    previousText = text;
+                }
+                else {
+                    if (buffer == null) {
+                        buffer = new StringBuffer();
+                        buffer.append(previousText);
+                    }
+                    buffer.append(text);
+                }
+            }
+        }
+        if (buffer != null) {
+            return buffer.toString();
+        }
+        if (previousText != null) {
+            return previousText;
+        }
+        return "";
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/NodePrinter.java b/groovy-core/src/main/groovy/util/NodePrinter.java
new file mode 100644
index 0000000..06e46bd
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/NodePrinter.java
@@ -0,0 +1,170 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A helper class for creating nested trees of data
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Christian Stein
+ * @version $Revision$
+ */
+public class NodePrinter {
+
+    protected final IndentPrinter out;
+
+    public NodePrinter() {
+        this(new IndentPrinter(new PrintWriter(new OutputStreamWriter(System.out))));
+    }
+
+    public NodePrinter(PrintWriter out) {
+        this(new IndentPrinter(out));
+    }
+
+    public NodePrinter(IndentPrinter out) {
+        if (out == null) {
+            throw new NullPointerException("IndentPrinter 'out' must not be null!");
+        }
+        this.out = out;
+    }
+
+    public void print(Node node) {
+        out.printIndent();
+        printName(node);
+        Map attributes = node.attributes();
+        boolean hasAttributes = attributes != null && !attributes.isEmpty();
+        if (hasAttributes) {
+            printAttributes(attributes);
+        }
+        Object value = node.value();
+        if (value instanceof List) {
+            if (!hasAttributes) {
+                out.print("()");
+            }
+            printList((List) value);
+        }
+        else {
+            if (value instanceof String) {
+                out.print("('");
+                out.print((String) value);
+                out.println("')");
+            }
+            else {
+                out.println("()");
+            }
+        }
+        out.flush();
+    }
+
+    protected void printName(Node node) {
+        Object name = node.name();
+        if (name != null) {
+            out.print(name.toString());
+        }
+        else {
+            out.print("null");
+        }
+    }
+
+    protected void printList(List list) {
+        if (list.isEmpty()) {
+            out.println("");
+        }
+        else {
+            out.println(" {");
+            out.incrementIndent();
+            for (Iterator iter = list.iterator(); iter.hasNext();) {
+                Object value = iter.next();
+                if (value instanceof Node) {
+                    print((Node) value);
+                }
+                else {
+                    out.printIndent();
+                    out.print("builder.append(");
+                    out.print(InvokerHelper.toString(value));
+                    out.println(")");
+                }
+            }
+            out.decrementIndent();
+            out.printIndent();
+            out.println("}");
+        }
+    }
+
+
+    protected void printAttributes(Map attributes) {
+        out.print("(");
+        boolean first = true;
+        for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            if (first) {
+                first = false;
+            }
+            else {
+                out.print(", ");
+            }
+            out.print(entry.getKey().toString());
+            out.print(":");
+            if (entry.getValue() instanceof String) {
+                out.print("'" + entry.getValue() + "'");
+            }
+            else {
+                out.print(InvokerHelper.toString(entry.getValue()));
+            }
+        }
+        out.print(")");
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/util/OrderBy.java b/groovy-core/src/main/groovy/util/OrderBy.java
new file mode 100644
index 0000000..d321ef7
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/OrderBy.java
@@ -0,0 +1,106 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+import groovy.lang.Closure;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A helper class for sorting objects via a closure to return the field
+ * or operation on which to sort.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class OrderBy implements Comparator {
+
+    List closures;
+
+    public OrderBy() {
+        this.closures = new ArrayList();
+    }
+
+    public OrderBy(Closure closure) {
+        this();
+        closures.add(closure);
+    }
+
+    public OrderBy(List closures) {
+        this.closures = closures;
+    }
+
+    public void add(Closure closure) {
+        closures.add(closure);
+    }
+
+    public int compare(Object object1, Object object2) {
+        for (Iterator iter = closures.iterator(); iter.hasNext();) {
+            Closure closure = (Closure) iter.next();
+            Object value1 = closure.call(object1);
+            Object value2 = closure.call(object2);
+
+            if (value1 == value2) {
+                continue;
+            }
+            if (value1 == null) {
+                return -1;
+            }
+            if (value1 instanceof Comparable) {
+                Comparable c1 = (Comparable) value1;
+                return c1.compareTo(value2);
+            }
+            if (value1.equals(value2)) {
+                continue;
+            }
+            return value1.hashCode() - value2.hashCode();
+        }
+        return 0;
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/Proxy.java b/groovy-core/src/main/groovy/util/Proxy.java
new file mode 100644
index 0000000..9305ed3
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/Proxy.java
@@ -0,0 +1,85 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package groovy.util;
+
+import java.util.Iterator;
+
+import groovy.lang.GroovyObjectSupport;
+import groovy.lang.MissingMethodException;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * Dynamic groovy proxy for another object.  All method
+ * invocations get forwarded to actual object, unless the proxy overrides it.
+ * See groovy/util/ProxyTest.groovy for usage details.
+ *
+ * @author Troy Heninger
+ * @author Dierk Koenig
+ */
+public class Proxy extends GroovyObjectSupport {
+
+    private Object adaptee = null;
+
+    /**
+     * This method is for convenience.
+     * It allows to get around the need for defining dump ctors is subclasses.
+     * See unit tests for details.
+     */
+    public Proxy wrap(Object adaptee){
+        setAdaptee(adaptee);
+        return this;
+    }
+
+    public Object getAdaptee() {
+        return adaptee;
+    }
+
+    public void setAdaptee(Object adaptee) {
+        this.adaptee = adaptee;
+    }
+
+    public Object invokeMethod(String name, Object args) {
+        try {
+            return super.invokeMethod(name, args);
+        }
+        catch (MissingMethodException e) {
+            return InvokerHelper.getMetaClass(adaptee).invokeMethod(adaptee, name, args);
+        }
+    }
+    
+    public Iterator iterator() {
+        return InvokerHelper.asIterator(adaptee);
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/util/ResourceConnector.java b/groovy-core/src/main/groovy/util/ResourceConnector.java
new file mode 100644
index 0000000..cbad5f0
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/ResourceConnector.java
@@ -0,0 +1,52 @@
+/*
+ * $Id$version Jan 9, 2004 4:37:14 PM $user Exp $
+ * 
+ * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package groovy.util;
+
+import java.net.URLConnection;
+
+/**
+ * Base interface for customizing where resources can be found for the <code>GroovyScriptEngine</code>.
+ *
+ * @author sam
+ */
+public interface ResourceConnector {
+
+    /**
+     * Retrieve a URLConnection to a script referenced by name.
+     *
+     * @param name
+     * @throws ResourceException
+     */
+    public URLConnection getResourceConnection(String name) throws ResourceException;
+}
diff --git a/groovy-core/src/main/groovy/util/ResourceException.java b/groovy-core/src/main/groovy/util/ResourceException.java
new file mode 100644
index 0000000..03b635d
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/ResourceException.java
@@ -0,0 +1,74 @@
+/*
+ * $Id$version Jan 9, 2004 12:43:51 PM $user Exp $
+ * 
+ * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+ package groovy.util;
+
+/**
+ * @author sam
+ *
+ * To change the template for this generated type comment go to
+ * Window - Preferences - Java - Code Generation - Code and Comments
+ */
+public class ResourceException extends Exception {
+
+	/**
+	 * 
+	 */
+	public ResourceException() {
+		super();
+		// TODO Auto-generated constructor stub
+	}
+
+	/**
+	 * @param message
+	 */
+	public ResourceException(String message) {
+		super(message);
+	}
+
+	/**
+	 * @param message
+	 * @param cause
+	 */
+	public ResourceException(String message, Throwable cause) {
+		super(message, cause);
+	}
+
+	/**
+	 * @param cause
+	 */
+	public ResourceException(Throwable cause) {
+		super(cause);
+	}
+
+}
diff --git a/groovy-core/src/main/groovy/util/ScriptException.java b/groovy-core/src/main/groovy/util/ScriptException.java
new file mode 100644
index 0000000..e2c7563
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/ScriptException.java
@@ -0,0 +1,73 @@
+/*
+ * $Id$version Jan 9, 2004 12:36:48 PM $user Exp $
+ * 
+ * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+ package groovy.util;
+
+/**
+ * @author sam
+ *
+ * To change the template for this generated type comment go to
+ * Window - Preferences - Java - Code Generation - Code and Comments
+ */
+public class ScriptException extends Exception {
+
+	/**
+	 * 
+	 */
+	public ScriptException() {
+		super();
+	}
+
+	/**
+	 * @param message
+	 */
+	public ScriptException(String message) {
+		super(message);
+	}
+
+	/**
+	 * @param message
+	 * @param cause
+	 */
+	public ScriptException(String message, Throwable cause) {
+		super(message, cause);
+	}
+
+	/**
+	 * @param cause
+	 */
+	public ScriptException(Throwable cause) {
+		super(cause);
+	}
+
+}
diff --git a/groovy-core/src/main/groovy/util/XmlNodePrinter.java b/groovy-core/src/main/groovy/util/XmlNodePrinter.java
new file mode 100644
index 0000000..25ab8b0
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/XmlNodePrinter.java
@@ -0,0 +1,252 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+ statements and notices.  Redistributions must also contain a
+ copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+ above copyright notice, this list of conditions and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+ products derived from this Software without prior written
+ permission of The Codehaus.  For written permission,
+ please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+ nor may "groovy" appear in their names without prior written
+ permission of The Codehaus. "groovy" is a registered
+ trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+ http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.util;
+
+import groovy.xml.QName;
+
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * Prints a node with all childs in XML format.
+ * 
+ * @see groovy.util.NodePrinter
+ * @author Christian Stein
+ */
+public class XmlNodePrinter {
+
+    protected final IndentPrinter out;
+    private final String quote;
+
+    public XmlNodePrinter() {
+        this(new PrintWriter(new OutputStreamWriter(System.out)));
+    }
+
+    public XmlNodePrinter(PrintWriter out) {
+        this(out, "  ");
+    }
+
+    public XmlNodePrinter(PrintWriter out, String indent) {
+        this(out, indent, "\"");
+    }
+
+    public XmlNodePrinter(PrintWriter out, String indent, String quote) {
+        this(new IndentPrinter(out, indent), quote);
+    }
+
+    public XmlNodePrinter(IndentPrinter out, String quote) {
+        if (out == null) {
+            throw new IllegalArgumentException("Argument 'IndentPrinter out' must not be null!");
+        }
+        this.out = out;
+        this.quote = quote;
+    }
+
+    public String getNameOfNode(Node node) {
+        if (node == null) {
+            throw new IllegalArgumentException("Node must not be null!");
+        }
+        Object name = node.name();
+        if (name instanceof QName) {
+            QName qname = (QName) name;
+            return /* qname.getPrefix() + ":" + */qname.getLocalPart();
+        }
+        return name.toString();
+    }
+
+    public boolean isEmptyElement(Node node) {
+        if (node == null) {
+            throw new IllegalArgumentException("Node must not be null!");
+        }
+        if (!node.children().isEmpty()) {
+            return false;
+        }
+        String text = node.text();
+        if (text.length() > 0) {
+            return false;
+        }
+        return true;
+    }
+
+    public void print(Node node) {
+        /*
+         * Handle empty elements like '<br/>', '<img/> or '<hr noshade="noshade"/>.
+         */
+        if (isEmptyElement(node)) {
+            // System.err.println("empty-dead");
+            printLineBegin();
+            out.print("<");
+            out.print(getNameOfNode(node));
+            printNameAttributes(node.attributes());
+            out.print("/>");
+            printLineEnd(); // "node named '" + node.name() + "'"
+            out.flush();
+            return;
+        }
+
+        /*
+         * Handle GSP tag element!
+         */
+        if (printSpecialNode(node)) {
+            // System.err.println("special-dead");
+            out.flush();
+            return;
+        }
+
+        /*
+         * Handle normal element like <html> ... </html>.
+         */
+        Object value = node.value();
+        if (value instanceof List) {
+            printName(node, true);
+            printList((List) value);
+            printName(node, false);
+            out.flush();
+            return;
+        }
+
+        /*
+         * Still here?!
+         */
+        throw new RuntimeException("Unsupported node value: " + node.value());
+    }
+
+    protected void printLineBegin() {
+        out.printIndent();
+    }
+
+    protected void printLineEnd() {
+        printLineEnd(null);
+    }
+
+    protected void printLineEnd(String comment) {
+        if (comment != null) {
+            out.print(" <!-- ");
+            out.print(comment);
+            out.print(" -->");
+        }
+        out.print("\n");
+    }
+
+    protected void printList(List list) {
+        out.incrementIndent();
+        for (Iterator iter = list.iterator(); iter.hasNext();) {
+            Object value = iter.next();
+            /*
+             * If the current value is a node, recurse into that node.
+             */
+            if (value instanceof Node) {
+                print((Node) value);
+                continue;
+            }
+            /*
+             * Print out "simple" text nodes.
+             */
+            printLineBegin();
+            out.print(InvokerHelper.toString(value));
+            printLineEnd();
+        }
+        out.decrementIndent();
+    }
+
+    protected void printName(Node node, boolean begin) {
+        if (node == null) {
+            throw new NullPointerException("Node must not be null.");
+        }
+        Object name = node.name();
+        if (name == null) {
+            throw new NullPointerException("Name must not be null.");
+        }
+        printLineBegin();
+        out.print("<");
+        if (!begin) {
+            out.print("/");
+        }
+        out.print(getNameOfNode(node));
+        if (begin) {
+            printNameAttributes(node.attributes());
+        }
+        out.print(">");
+        printLineEnd();
+    }
+
+    protected void printNameAttributes(Map attributes) {
+        if (attributes == null || attributes.isEmpty()) {
+            return;
+        }
+        out.print(" ");
+        boolean first = true;
+        for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            if (first) {
+                first = false;
+            } else {
+                out.print(" ");
+            }
+            out.print(entry.getKey().toString());
+            out.print("=");
+            Object value = entry.getValue();
+            if (value instanceof String) {
+                out.print(quote);
+                out.print((String) value);
+                out.print(quote);
+                continue;
+            }
+            out.print(InvokerHelper.toString(value));
+        }
+    }
+
+    protected boolean printSpecialNode(Node node) {
+        return false;
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/util/XmlParser.java b/groovy-core/src/main/groovy/util/XmlParser.java
new file mode 100644
index 0000000..6f688e4
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/XmlParser.java
@@ -0,0 +1,336 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+import groovy.xml.QName;
+import groovy.xml.FactorySupport;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.*;
+
+/**
+ * A helper class for parsing XML into a tree of Node instances for 
+ * a simple way of processing XML. This parser does not preserve the
+ * XML InfoSet - if thats what you need try using W3C DOM, dom4j, JDOM, XOM etc.
+ * This parser ignores comments and processing instructions and converts the
+ * XML into a Node for each element in the XML with attributes
+ * and child Nodes and Strings. This simple model is sufficient for
+ * most simple use cases of processing XML.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class XmlParser implements ContentHandler {
+
+    private StringBuffer bodyText = new StringBuffer();
+    private List stack = new ArrayList();
+    private Locator locator;
+    private XMLReader reader;
+    private Node parent;
+    private boolean trimWhitespace = true;
+
+    public XmlParser() throws ParserConfigurationException, SAXException {
+        this(false, true);
+    }
+
+    public XmlParser(boolean validating, boolean namespaceAware) throws ParserConfigurationException, SAXException {
+        SAXParserFactory factory = FactorySupport.createSaxParserFactory();
+        factory.setNamespaceAware(namespaceAware);
+        factory.setValidating(validating);
+        reader = factory.newSAXParser().getXMLReader();
+    }
+
+    public XmlParser(XMLReader reader) {
+        this.reader = reader;
+    }
+
+    public XmlParser(SAXParser parser) throws SAXException {
+        reader = parser.getXMLReader();
+    }
+
+
+    /**
+     * Parses the content of the given file as XML turning it into a tree
+     * of Nodes
+     */
+    public Node parse(File file) throws IOException, SAXException {
+        InputSource input = new InputSource(new FileInputStream(file));
+        input.setSystemId("file://" + file.getAbsolutePath());
+        getXMLReader().parse(input);
+        return parent;
+
+    }
+
+    /**
+     * Parse the content of the specified input source into a tree of Nodes.
+     */
+    public Node parse(InputSource input) throws IOException, SAXException {
+        getXMLReader().parse(input);
+        return parent;
+    }
+
+    /**
+     * Parse the content of the specified input stream into a tree of Nodes.
+     * Note that using this method will not provide the parser with any URI
+     * for which to find DTDs etc
+     */
+    public Node parse(InputStream input) throws IOException, SAXException {
+        InputSource is = new InputSource(input);
+        getXMLReader().parse(is);
+        return parent;
+    }
+
+    /**
+     * Parse the content of the specified reader into a tree of Nodes.
+     * Note that using this method will not provide the parser with any URI
+     * for which to find DTDs etc
+     */
+    public Node parse(Reader in) throws IOException, SAXException {
+        InputSource is = new InputSource(in);
+        getXMLReader().parse(is);
+        return parent;
+    }
+
+    /**
+     * Parse the content of the specified URI into a tree of Nodes
+     */
+    public Node parse(String uri) throws IOException, SAXException {
+        InputSource is = new InputSource(uri);
+        getXMLReader().parse(is);
+        return parent;
+    }
+
+    /**
+     * A helper method to parse the given text as XML
+     * 
+     * @param text
+     */
+    public Node parseText(String text) throws IOException, SAXException {
+        return parse(new StringReader(text));
+    }
+    // Delegated XMLReader methods
+    //------------------------------------------------------------------------
+
+    /* (non-Javadoc)
+     * @see org.xml.sax.XMLReader#getDTDHandler()
+     */
+    public DTDHandler getDTDHandler() {
+        return this.reader.getDTDHandler();
+    }
+
+    /* (non-Javadoc)
+     * @see org.xml.sax.XMLReader#getEntityResolver()
+     */
+    public EntityResolver getEntityResolver() {
+        return this.reader.getEntityResolver();
+    }
+
+    /* (non-Javadoc)
+     * @see org.xml.sax.XMLReader#getErrorHandler()
+     */
+    public ErrorHandler getErrorHandler() {
+        return this.reader.getErrorHandler();
+    }
+
+    /* (non-Javadoc)
+     * @see org.xml.sax.XMLReader#getFeature(java.lang.String)
+     */
+    public boolean getFeature(final String uri) throws SAXNotRecognizedException, SAXNotSupportedException {
+        return this.reader.getFeature(uri);
+    }
+
+    /* (non-Javadoc)
+     * @see org.xml.sax.XMLReader#getProperty(java.lang.String)
+     */
+    public Object getProperty(final String uri) throws SAXNotRecognizedException, SAXNotSupportedException {
+        return this.reader.getProperty(uri);
+    }
+
+    /* (non-Javadoc)
+     * @see org.xml.sax.XMLReader#setDTDHandler(org.xml.sax.DTDHandler)
+     */
+    public void setDTDHandler(final DTDHandler dtdHandler) {
+        this.reader.setDTDHandler(dtdHandler);
+    }
+
+    /* (non-Javadoc)
+     * @see org.xml.sax.XMLReader#setEntityResolver(org.xml.sax.EntityResolver)
+     */
+    public void setEntityResolver(final EntityResolver entityResolver) {
+        this.reader.setEntityResolver(entityResolver);
+    }
+
+    /* (non-Javadoc)
+     * @see org.xml.sax.XMLReader#setErrorHandler(org.xml.sax.ErrorHandler)
+     */
+    public void setErrorHandler(final ErrorHandler errorHandler) {
+        this.reader.setErrorHandler(errorHandler);
+    }
+
+    /* (non-Javadoc)
+     * @see org.xml.sax.XMLReader#setFeature(java.lang.String, boolean)
+     */
+    public void setFeature(final String uri, final boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
+        this.reader.setFeature(uri, value);
+    }
+
+    /* (non-Javadoc)
+     * @see org.xml.sax.XMLReader#setProperty(java.lang.String, java.lang.Object)
+     */
+    public void setProperty(final String uri, final Object value) throws SAXNotRecognizedException, SAXNotSupportedException {
+         this.reader.setProperty(uri, value);
+    }
+
+    // ContentHandler interface
+    //-------------------------------------------------------------------------                    
+    public void startDocument() throws SAXException {
+        parent = null;
+    }
+
+    public void endDocument() throws SAXException {
+        stack.clear();
+    }
+
+    public void startElement(String namespaceURI, String localName, String qName, Attributes list)
+        throws SAXException {
+        addTextToNode();
+
+        Object name = getElementName(namespaceURI, localName, qName);
+
+        int size = list.getLength();
+        Map attributes = new HashMap(size);
+        for (int i = 0; i < size; i++) {
+            Object attributeName = getElementName(list.getURI(i), list.getLocalName(i), list.getQName(i));
+            String value = list.getValue(i);
+            attributes.put(attributeName, value);
+        }
+        parent = new Node(parent, name, attributes, new ArrayList());
+        stack.add(parent);
+    }
+
+    public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
+        addTextToNode();
+
+        if (!stack.isEmpty()) {
+            stack.remove(stack.size() - 1);
+            if (!stack.isEmpty()) {
+                parent = (Node) stack.get(stack.size() - 1);
+            }
+        }
+    }
+
+    public void characters(char buffer[], int start, int length) throws SAXException {
+        bodyText.append(buffer, start, length);
+    }
+
+    public void startPrefixMapping(String prefix, String namespaceURI) throws SAXException {
+    }
+
+    public void endPrefixMapping(String prefix) throws SAXException {
+    }
+
+    public void ignorableWhitespace(char buffer[], int start, int len) throws SAXException {
+    }
+
+    public void processingInstruction(String target, String data) throws SAXException {
+    }
+
+    public Locator getDocumentLocator() {
+        return locator;
+    }
+
+    public void setDocumentLocator(Locator locator) {
+        this.locator = locator;
+    }
+
+    public void skippedEntity(String name) throws SAXException {
+    }
+
+    // Implementation methods
+    //-------------------------------------------------------------------------           
+    protected XMLReader getXMLReader() {
+        reader.setContentHandler(this);
+        return reader;
+    }
+
+    protected void addTextToNode() {
+        String text = bodyText.toString();
+        if (trimWhitespace) {
+            text = text.trim();
+        }
+        if (text.length() > 0) {
+            parent.children().add(text);
+        }
+        bodyText = new StringBuffer();
+    }
+
+    protected Object getElementName(String namespaceURI, String localName, String qName) throws SAXException {
+        String name = localName;
+        if ((name == null) || (name.length() < 1)) {
+            name = qName;
+        }
+        if (namespaceURI == null || namespaceURI.length() <= 0) {
+            return name;
+        }
+        else {
+            return new QName(namespaceURI, name, qName);
+        }
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/XmlSlurper.java b/groovy-core/src/main/groovy/util/XmlSlurper.java
new file mode 100644
index 0000000..9297bc1
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/XmlSlurper.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.util;
+
+import groovy.util.slurpersupport.GPathResult;
+import groovy.util.slurpersupport.Node;
+import groovy.util.slurpersupport.NodeChild;
+import groovy.xml.FactorySupport;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Stack;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.DTDHandler;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class XmlSlurper extends DefaultHandler {
+  private final XMLReader reader;
+  private Node currentNode = null;
+  private final Stack stack = new Stack();
+  private final StringBuffer charBuffer = new StringBuffer();
+  private final Map namespaceTagHints = new Hashtable();
+  private boolean keepWhitespace = false;
+
+  public XmlSlurper() throws ParserConfigurationException, SAXException {
+    this(false, true);
+  }
+  
+  public XmlSlurper(final boolean validating, final boolean namespaceAware) throws ParserConfigurationException, SAXException {
+    SAXParserFactory factory = FactorySupport.createSaxParserFactory();
+    factory.setNamespaceAware(namespaceAware);
+    factory.setValidating(validating);
+    this.reader = factory.newSAXParser().getXMLReader();
+  }
+  
+  public XmlSlurper(final XMLReader reader) {
+    this.reader = reader;
+  }
+  
+  public XmlSlurper(final SAXParser parser) throws SAXException {
+    this(parser.getXMLReader());
+  }
+  
+  /**
+   * @param keepWhitespace
+   * 
+   * If true then whitespace before elements is kept.
+   * The deafult is to discard the whitespace.
+   */
+  public void setKeepWhitespace(boolean keepWhitespace) {
+      this.keepWhitespace = keepWhitespace;
+  }
+  
+  /**
+   * @return The GPathResult instance created by consuming a stream of SAX events
+   * Note if one of the parse methods has been called then this returns null
+   * Note if this is called more than once all calls after the first will return null
+   *
+   */
+  public GPathResult getDocument() {
+    try {
+      return new NodeChild(this.currentNode, null, this.namespaceTagHints);
+    } finally {
+      this.currentNode = null;
+    }
+  }
+  
+  /**
+   * Parse the content of the specified input source into a GPathResult object
+   * 
+   * @param input
+   * @return An object which supports GPath expressions
+   * @throws IOException
+   * @throws SAXException
+   */
+  public GPathResult parse(final InputSource input) throws IOException, SAXException {
+    this.reader.setContentHandler(this);
+    this.reader.parse(input);
+    
+    return getDocument();
+    
+  }
+  
+  /**
+   * Parses the content of the given file as XML turning it into a GPathResult object
+   * 
+   * @param file
+   * @return An object which supports GPath expressions
+   * @throws IOException
+   * @throws SAXException
+   */
+  public GPathResult parse(final File file) throws IOException, SAXException {
+  final InputSource input = new InputSource(new FileInputStream(file));
+    
+    input.setSystemId("file://" + file.getAbsolutePath());
+    
+    return parse(input);
+    
+  }
+  
+  /**
+   * Parse the content of the specified input stream into an GPathResult Object.
+   * Note that using this method will not provide the parser with any URI
+   * for which to find DTDs etc
+   * 
+   * @param input
+   * @return An object which supports GPath expressions
+   * @throws IOException
+   * @throws SAXException
+   */
+  public GPathResult parse(final InputStream input) throws IOException, SAXException {
+    return parse(new InputSource(input));
+  }
+  
+  /**
+   * Parse the content of the specified reader into a GPathResult Object.
+   * Note that using this method will not provide the parser with any URI
+   * for which to find DTDs etc
+   * 
+   * @param in
+   * @return An object which supports GPath expressions
+   * @throws IOException
+   * @throws SAXException
+   */
+  public GPathResult parse(final Reader in) throws IOException, SAXException {
+    return parse(new InputSource(in));
+  }
+  
+  /**
+   * Parse the content of the specified URI into a GPathResult Object
+   * 
+   * @param uri
+   * @return An object which supports GPath expressions
+   * @throws IOException
+   * @throws SAXException
+   */
+  public GPathResult parse(final String uri) throws IOException, SAXException {
+    return parse(new InputSource(uri));
+  }
+  
+  /**
+   * A helper method to parse the given text as XML
+   * 
+   * @param text
+   * @return An object which supports GPath expressions
+   */
+  public GPathResult parseText(final String text) throws IOException, SAXException {
+    return parse(new StringReader(text));
+  }
+  
+  // Delegated XMLReader methods
+  //------------------------------------------------------------------------
+
+  /* (non-Javadoc)
+   * @see org.xml.sax.XMLReader#getDTDHandler()
+   */
+  public DTDHandler getDTDHandler() {
+      return this.reader.getDTDHandler();
+  }
+
+  /* (non-Javadoc)
+   * @see org.xml.sax.XMLReader#getEntityResolver()
+   */
+  public EntityResolver getEntityResolver() {
+      return this.reader.getEntityResolver();
+  }
+
+  /* (non-Javadoc)
+   * @see org.xml.sax.XMLReader#getErrorHandler()
+   */
+  public ErrorHandler getErrorHandler() {
+      return this.reader.getErrorHandler();
+  }
+
+  /* (non-Javadoc)
+   * @see org.xml.sax.XMLReader#getFeature(java.lang.String)
+   */
+  public boolean getFeature(final String uri) throws SAXNotRecognizedException, SAXNotSupportedException {
+      return this.reader.getFeature(uri);
+  }
+
+  /* (non-Javadoc)
+   * @see org.xml.sax.XMLReader#getProperty(java.lang.String)
+   */
+  public Object getProperty(final String uri) throws SAXNotRecognizedException, SAXNotSupportedException {
+      return this.reader.getProperty(uri);
+  }
+
+  /* (non-Javadoc)
+   * @see org.xml.sax.XMLReader#setDTDHandler(org.xml.sax.DTDHandler)
+   */
+  public void setDTDHandler(final DTDHandler dtdHandler) {
+      this.reader.setDTDHandler(dtdHandler);
+  }
+
+  /* (non-Javadoc)
+   * @see org.xml.sax.XMLReader#setEntityResolver(org.xml.sax.EntityResolver)
+   */
+  public void setEntityResolver(final EntityResolver entityResolver) {
+      this.reader.setEntityResolver(entityResolver);
+  }
+
+  /**
+   * Resolves entities against using the suppied URL as the base for relative URLs
+   * 
+   * @param base
+   * The URL used to resolve relative URLs
+   */
+  public void setEntityBaseUrl(final URL base) {
+      this.reader.setEntityResolver(new EntityResolver() {
+          public InputSource resolveEntity(final String publicId, final String systemId) throws IOException {
+              return new InputSource(new URL(base, systemId).openStream());
+          }
+      });
+  }
+
+  /* (non-Javadoc)
+   * @see org.xml.sax.XMLReader#setErrorHandler(org.xml.sax.ErrorHandler)
+   */
+  public void setErrorHandler(final ErrorHandler errorHandler) {
+      this.reader.setErrorHandler(errorHandler);
+  }
+
+  /* (non-Javadoc)
+   * @see org.xml.sax.XMLReader#setFeature(java.lang.String, boolean)
+   */
+  public void setFeature(final String uri, final boolean value) throws SAXNotRecognizedException, SAXNotSupportedException {
+      this.reader.setFeature(uri, value);
+  }
+
+  /* (non-Javadoc)
+   * @see org.xml.sax.XMLReader#setProperty(java.lang.String, java.lang.Object)
+   */
+  public void setProperty(final String uri, final Object value) throws SAXNotRecognizedException, SAXNotSupportedException {
+       this.reader.setProperty(uri, value);
+  }
+  
+  
+  // ContentHandler interface
+  //-------------------------------------------------------------------------                    
+  
+  /* (non-Javadoc)
+   * @see org.xml.sax.ContentHandler#startDocument()
+   */
+  public void startDocument() throws SAXException {
+    this.currentNode = null;
+    this.charBuffer.setLength(0);
+  }
+  
+  /* (non-Javadoc)
+   * @see org.xml.sax.helpers.DefaultHandler#startPrefixMapping(java.lang.String, java.lang.String)
+   */
+  public void startPrefixMapping(final String tag, final String uri) throws SAXException {
+    this.namespaceTagHints.put(tag, uri);
+  }
+
+  /* (non-Javadoc)
+   * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
+   */
+  public void startElement(final String namespaceURI, final String localName, final String qName, final Attributes atts) throws SAXException {
+    addCdata();
+    
+    final Map attributes = new HashMap();
+    final Map attributeNamespaces = new HashMap();
+    
+    for (int i = atts.getLength() - 1; i != -1; i--) {
+      if (atts.getURI(i).length() == 0) {
+        attributes.put(atts.getQName(i), atts.getValue(i));
+      } else {
+        attributes.put(atts.getLocalName(i), atts.getValue(i));
+        attributeNamespaces.put(atts.getLocalName(i), atts.getURI(i));
+      }
+      
+    }
+    
+    final Node newElement;
+    
+    if (namespaceURI.length() == 0){
+      newElement = new Node(this.currentNode, qName, attributes, attributeNamespaces, namespaceURI);
+    } else {
+      newElement = new Node(this.currentNode, localName, attributes, attributeNamespaces, namespaceURI);
+    }
+    
+    if (this.currentNode != null) {
+      this.currentNode.addChild(newElement);
+    }
+    
+    this.stack.push(this.currentNode);
+    this.currentNode = newElement;
+  }
+  
+  /* (non-Javadoc)
+   * @see org.xml.sax.ContentHandler#characters(char[], int, int)
+   */
+  public void characters(final char[] ch, final int start, final int length) throws SAXException {
+    this.charBuffer.append(ch, start, length);
+  }
+  
+  /* (non-Javadoc)
+   * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
+   */
+  public void endElement(final String namespaceURI, final String localName, final String qName) throws SAXException {
+    addCdata();
+    
+    final Object oldCurrentNode = this.stack.pop();
+    
+    if (oldCurrentNode != null) {
+      this.currentNode = (Node)oldCurrentNode;
+    }
+  }
+  
+  /* (non-Javadoc)
+   * @see org.xml.sax.ContentHandler#endDocument()
+   */
+  public void endDocument() throws SAXException {
+  }
+  
+  // Implementation methods
+  //-------------------------------------------------------------------------           
+  
+  /**
+   * 
+   */
+  private void addCdata() {
+    if (this.charBuffer.length() != 0) {
+      //
+      // This element is preceeded by CDATA if keepWhitespace is false (the default setting) and 
+      // it's not whitespace add it to the body
+      // Note that, according to the XML spec, we should preserve the CDATA if it's all whitespace
+      // but for the sort of work I'm doing ignoring the whitespace is preferable
+      //
+      final String cdata = this.charBuffer.toString();
+      
+      this.charBuffer.setLength(0);
+      if (this.keepWhitespace || cdata.trim().length() != 0) {
+        this.currentNode.addChild(cdata);
+      }
+    }   
+  }
+}
diff --git a/groovy-core/src/main/groovy/util/package.html b/groovy-core/src/main/groovy/util/package.html
new file mode 100644
index 0000000..05b9ba9
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/package.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>package groovy.util.*</title>
+  </head>
+  <body>
+    <p>Various Groovy utilities for working with nodes, builders, logging, JUnit test cases, text expressions, Ant tasks or JMX MBeans.</p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/groovy/util/slurpersupport/Attribute.java b/groovy-core/src/main/groovy/util/slurpersupport/Attribute.java
new file mode 100644
index 0000000..d062d30
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/slurpersupport/Attribute.java
@@ -0,0 +1,118 @@
+/*
+ * Created on Jul 15, 2006
+ *
+ * Copyright 2006 John G. Wilson
+ *
+ *   Licensed 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.util.slurpersupport;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+public class Attribute extends GPathResult {
+    private final String value;
+
+    public Attribute(final String name, final String value, final GPathResult parent, final String namespacePrefix, final Map namespaceTagHints) {
+      super(parent, name, namespacePrefix, namespaceTagHints);
+      this.value = value;
+    }
+
+    public String name() {
+        // this name contains @name we need to return name
+        return this.name.substring(1);
+    }
+
+    public int size() {
+        return 1;
+    }
+
+    public String text() {
+         return this.value;
+    }
+
+    public GPathResult parents() {
+        // TODO Auto-generated method stub
+        throw new GroovyRuntimeException("parents() not implemented yet");
+    }
+
+    public Iterator childNodes() {
+        throw new GroovyRuntimeException("can't call childNodes() in the attribute " + this.name);
+    }
+
+    public Iterator iterator() {
+        return nodeIterator();
+    }
+
+    public GPathResult find(final Closure closure) {
+        if (DefaultTypeTransformation.castToBoolean(closure.call(new Object[]{this}))) {
+            return this;
+          } else {
+            return new NoChildren(this, "", this.namespaceTagHints);
+          }
+    }
+
+    public GPathResult findAll(final Closure closure) {
+        return find(closure);
+    }
+
+    public Iterator nodeIterator() {
+        return new Iterator() {
+            private boolean hasNext = true;
+            
+            public boolean hasNext() {
+              return this.hasNext;
+            }
+            
+            public Object next() {
+              try {
+                return (this.hasNext) ? Attribute.this : null;
+              } finally {
+                this.hasNext = false;
+              }
+            }
+            
+            public void remove() {
+              throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    public Writer writeTo(final Writer out) throws IOException {
+        out.write(this.value);
+        return out;
+    }
+
+    public void build(final GroovyObject builder) {
+        builder.getProperty("mkp");
+        builder.invokeMethod("yield", new Object[]{this.value});
+    }
+
+    protected void replaceNode(final Closure newValue) {
+    }
+
+    protected void replaceBody(final Object newValue) {
+    }
+
+    protected void appendNode(final Object newValue) {
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/slurpersupport/Attributes.java b/groovy-core/src/main/groovy/util/slurpersupport/Attributes.java
new file mode 100644
index 0000000..1c44971
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/slurpersupport/Attributes.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.util.slurpersupport;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Map;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @author John Wilson
+ */
+
+class Attributes extends NodeChildren {
+    final String attributeName;
+
+    public Attributes(final GPathResult parent, final String name, final String namespacePrefix, final Map namespaceTagHints) {
+        super(parent, name, namespacePrefix, namespaceTagHints);
+        this.attributeName = this.name.substring(1);
+    }
+
+    public Attributes(final GPathResult parent, final String name, final Map namespaceTagHints) {
+        this(parent, name, "*", namespaceTagHints);
+    }
+
+    public String name() {
+        // this name contains @name we need to return name
+        return this.name.substring(1);
+    }
+
+    public Iterator childNodes() {
+        throw new GroovyRuntimeException("Can't get the child nodes on a a GPath expression selecting attributes: ...." + this.parent.name() + "." + name() + ".childNodes()");
+    }
+
+    public Iterator iterator() {
+        return new NodeIterator(nodeIterator()) {
+            protected Object getNextNode(final Iterator iter) {
+                while (iter.hasNext()) {
+                    final Object next = iter.next();
+                    if (next instanceof Attribute) {
+                        return next;
+                    } else {
+                        final String value = (String) ((Node) next).attributes().get(Attributes.this.attributeName);
+                        if (value != null) {
+                            return new Attribute(Attributes.this.attributeName,
+                                    value,
+                                    new NodeChild((Node) next, Attributes.this.parent.parent, "", Attributes.this.namespaceTagHints),
+                                    "",
+                                    Attributes.this.namespaceTagHints);
+                        }
+                    }
+                }
+                return null;
+            }
+        };
+    }
+
+    public Iterator nodeIterator() {
+        return this.parent.nodeIterator();
+    }
+
+    public GPathResult parents() {
+        return super.parents();
+    }
+
+    public String text() {
+        final StringBuffer buf = new StringBuffer();
+        final Iterator iter = iterator();
+        while (iter.hasNext()) {
+            buf.append(iter.next());
+        }
+        return buf.toString();
+    }
+
+    public List list() {
+        final Iterator iter = iterator();
+        final List result = new ArrayList();
+        while (iter.hasNext()) {
+            result.add(iter.next());
+        }
+        return result;
+    }
+
+    public GPathResult findAll(final Closure closure) {
+        return new FilteredAttributes(this, closure, this.namespaceTagHints);
+    }
+
+    public Writer writeTo(final Writer out) throws IOException {
+        out.write(text());
+        return out;
+    }
+
+    public void build(final GroovyObject builder) {
+        builder.getProperty("mkp");
+        builder.invokeMethod("yield", new Object[]{text()});
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/slurpersupport/FilteredAttributes.java b/groovy-core/src/main/groovy/util/slurpersupport/FilteredAttributes.java
new file mode 100644
index 0000000..055ec58
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/slurpersupport/FilteredAttributes.java
@@ -0,0 +1,56 @@
+/*
+ /*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.util.slurpersupport;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import groovy.lang.Closure;
+
+/**
+ * Lazy evaluated representation of nodes filtered by attributes.
+ *
+ * @author John Wilson
+ */
+public class FilteredAttributes extends Attributes
+{
+    private final Closure closure;
+
+    public FilteredAttributes(final GPathResult parent, final Closure closure, final Map namespaceTagHints) {
+        super(parent, parent.name, namespaceTagHints);
+        this.closure = closure;
+    }
+
+    public Iterator nodeIterator() {
+        return new NodeIterator(this.parent.iterator())
+        {
+            protected Object getNextNode(final Iterator iter) {
+                while (iter.hasNext()) {
+                    final Object node = iter.next();
+                    if (DefaultTypeTransformation.castToBoolean(FilteredAttributes.this.closure.call(new Object[]{node}))) {
+                        return node;
+                    }
+                }
+                return null;
+            }
+        };
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/util/slurpersupport/FilteredNodeChildren.java b/groovy-core/src/main/groovy/util/slurpersupport/FilteredNodeChildren.java
new file mode 100644
index 0000000..de522ef
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/slurpersupport/FilteredNodeChildren.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.util.slurpersupport;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import groovy.lang.Closure;
+
+/**
+ * @author John Wilson
+ */
+
+public class FilteredNodeChildren extends NodeChildren {
+    private final Closure closure;
+
+    public FilteredNodeChildren(final GPathResult parent, final Closure closure, final Map namespaceTagHints) {
+        super(parent, parent.name, namespaceTagHints);
+        this.closure = closure;
+    }
+
+    public Iterator iterator() {
+        return new Iterator() {
+        final Iterator iter = FilteredNodeChildren.this.parent.iterator();
+        Object next = null;
+
+            public boolean hasNext() {
+                while (this.iter.hasNext()) {
+                final Object childNode = this.iter.next();
+                
+                    if (closureYieldsTrueForNode(childNode)) {
+                        this.next = childNode;
+                        return true;
+                    }
+                }
+                
+                return false;
+            }
+
+            public Object next() {
+                return this.next;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    public Iterator nodeIterator() {
+        return new NodeIterator(this.parent.nodeIterator()) {
+            protected Object getNextNode(final Iterator iter) {
+                while (iter.hasNext()) {
+                final Object node = iter.next();
+                
+                    if (closureYieldsTrueForNode(new NodeChild((Node) node, FilteredNodeChildren.this.parent, FilteredNodeChildren.this.namespaceTagHints))) {
+                        return node;
+                    }
+                }
+                return null;
+            }
+        };
+    }
+
+    private boolean closureYieldsTrueForNode(Object childNode) {
+        return DefaultTypeTransformation.castToBoolean(FilteredNodeChildren.this.closure.call(new Object[]{childNode}));
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/util/slurpersupport/GPathResult.java b/groovy-core/src/main/groovy/util/slurpersupport/GPathResult.java
new file mode 100644
index 0000000..c7b1953
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/slurpersupport/GPathResult.java
@@ -0,0 +1,451 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.util.slurpersupport;
+
+import groovy.lang.Buildable;
+import groovy.lang.Closure;
+import groovy.lang.DelegatingMetaClass;
+import groovy.lang.GString;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyObjectSupport;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.IntRange;
+import groovy.lang.MetaClass;
+import groovy.lang.Writable;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+
+
+/**
+ * @author John Wilson
+ */
+
+public abstract class GPathResult extends GroovyObjectSupport implements Writable, Buildable {
+    protected final GPathResult parent;
+    protected final String name;
+    protected final String namespacePrefix;
+    protected final Map namespaceMap = new HashMap();
+    protected final Map namespaceTagHints;
+
+    /**
+     * @param parent
+     * @param name
+     * @param namespacePrefix
+     * @param namespaceTagHints
+     */
+    public GPathResult(final GPathResult parent, final String name, final String namespacePrefix, final Map namespaceTagHints) {
+        if (parent == null) {
+            // we are the top of the tree
+            this.parent = this;
+            this.namespaceMap.put("xml", "http://www.w3.org/XML/1998/namespace");  // The XML namespace is always defined
+        } else {
+            this.parent = parent;
+            this.namespaceMap.putAll(parent.namespaceMap);
+        }
+        this.name = name;
+        this.namespacePrefix = namespacePrefix;
+        this.namespaceTagHints = namespaceTagHints;
+
+        setMetaClass(getMetaClass()); // wrap the standard MetaClass with the delegate
+    }
+
+    /* (non-Javadoc)
+     * @see groovy.lang.GroovyObjectSupport#setMetaClass(groovy.lang.MetaClass)
+     */
+    public void setMetaClass(final MetaClass metaClass) {
+        final MetaClass newMetaClass = new DelegatingMetaClass(metaClass) {
+            /* (non-Javadoc)
+            * @see groovy.lang.DelegatingMetaClass#getAttribute(java.lang.Object, java.lang.String)
+            */
+            public Object getAttribute(final Object object, final String attribute) {
+                return GPathResult.this.getProperty("@" + attribute);
+            }
+            
+            public void setAttribute(final Object object, final String attribute, final Object newValue) {
+                GPathResult.this.setProperty("@" + attribute, newValue);
+            }
+        };
+        super.setMetaClass(newMetaClass);
+    }
+
+    public Object getProperty(final String property) {
+        if ("..".equals(property)) {
+            return parent();
+        } else if ("*".equals(property)) {
+            return children();
+        } else if ("**".equals(property)) {
+            return depthFirst();
+        } else if (property.startsWith("@")) {
+            if (property.indexOf(":") != -1) {
+                final int i = property.indexOf(":");
+                return new Attributes(this, "@" + property.substring(i + 1), property.substring(1, i), this.namespaceTagHints);
+            } else {
+                return new Attributes(this, property, this.namespaceTagHints);
+            }
+        } else {
+            if (property.indexOf(":") != -1) {
+                final int i = property.indexOf(":");
+                return new NodeChildren(this, property.substring(i + 1), property.substring(0, i), this.namespaceTagHints);
+            } else {
+                return new NodeChildren(this, property, this.namespaceTagHints);
+            }
+        }
+    }
+
+    public void setProperty(final String property, final Object newValue) {
+        if (property.startsWith("@")) {
+            if (newValue instanceof String || newValue instanceof GString) {
+            final Iterator iter = iterator();
+            
+                while (iter.hasNext()) {
+                final NodeChild child = (NodeChild)iter.next();
+                
+                    child.attributes().put(property.substring(1), newValue);
+                }
+            }
+        } else {
+        final GPathResult result = new NodeChildren(this, property, this.namespaceTagHints);
+        
+            if (newValue instanceof Map) {
+            final Iterator iter = ((Map)newValue).entrySet().iterator();
+            
+                while (iter.hasNext()) {
+                final Map.Entry entry = (Map.Entry)iter.next();
+                
+                    result.setProperty("@" + entry.getKey(), entry.getValue());
+                }
+            } else {           
+              if (newValue instanceof Closure) {
+                  result.replaceNode((Closure)newValue);
+              } else {
+                  result.replaceBody(newValue);
+              }
+            }
+        }
+    }
+    
+    public Object leftShift(final Object newValue) {
+        appendNode(newValue);
+        return this;
+    }
+    
+    public Object plus(final Object newValue) {
+        this.replaceNode(new Closure(this) {
+            public void doCall(Object[] args) {
+            final GroovyObject delegate = (GroovyObject)getDelegate();
+             
+                delegate.getProperty("mkp");
+                delegate.invokeMethod("yield", args);
+                
+                delegate.getProperty("mkp");
+                delegate.invokeMethod("yield", new Object[]{newValue});
+            }
+        });
+        
+        return this;
+    }
+    
+    protected abstract void replaceNode(Closure newValue);
+    
+    protected abstract void replaceBody(Object newValue);
+    
+    protected abstract void appendNode(Object newValue);
+
+    public String name() {
+        return this.name;
+    }
+
+    public GPathResult parent() {
+        return this.parent;
+    }
+
+    public GPathResult children() {
+        return new NodeChildren(this, this.namespaceTagHints);
+    }
+    
+    public String lookupNamespace(final String prefix) {
+        return (String)this.namespaceTagHints.get(prefix);
+    }
+
+    public String toString() {
+        return text();
+    }
+
+    public Integer toInteger() {
+        return DefaultGroovyMethods.toInteger(text());
+    }
+
+    public Long toLong() {
+        return DefaultGroovyMethods.toLong(text());
+    }
+
+    public Float toFloat() {
+        return DefaultGroovyMethods.toFloat(text());
+    }
+
+    public Double toDouble() {
+        return DefaultGroovyMethods.toDouble(text());
+    }
+
+    public BigDecimal toBigDecimal() {
+        return DefaultGroovyMethods.toBigDecimal(text());
+    }
+
+    public BigInteger toBigInteger() {
+        return DefaultGroovyMethods.toBigInteger(text());
+    }
+
+    public URL toURL() throws MalformedURLException {
+        return DefaultGroovyMethods.toURL(text());
+    }
+
+    public URI toURI() throws URISyntaxException {
+        return DefaultGroovyMethods.toURI(text());
+    }
+
+    public Boolean toBoolean() {
+        return DefaultGroovyMethods.toBoolean(text());
+    }
+
+    public GPathResult declareNamespace(final Map newNamespaceMapping) {
+        this.namespaceMap.putAll(newNamespaceMapping);
+        return this;
+    }
+
+    /* (non-Javadoc)
+    * @see java.lang.Object#equals(java.lang.Object)
+    */
+    public boolean equals(Object obj) {
+        return text().equals(obj.toString());
+    }
+
+    public Object getAt(final int index) {
+        if (index < 0) throw new ArrayIndexOutOfBoundsException(index);
+        
+        final Iterator iter = iterator();
+        int count = 0;
+    
+        while (iter.hasNext()) {
+            if (count++ == index) {
+                return iter.next();
+            } else {
+                iter.next();
+            }
+        }
+        
+        return new NoChildren(this, this.name, this.namespaceTagHints);
+    }
+
+    public Object getAt(final IntRange range) {
+    final int from = range.getFromInt();
+    final int to = range.getToInt();
+    
+        if (range.isReverse()) {
+            throw new GroovyRuntimeException("Reverse ranges not supported, range supplied is ["+ to + ".." + from + "]");
+        } else if (from < 0 || to < 0) {
+            throw new GroovyRuntimeException("Negative range indexes not supported, range supplied is ["+ from + ".." + to + "]");
+        } else {
+            return new Iterator() {
+            final Iterator iter = iterator();
+            Object next;
+            int count = 0;
+            
+               public boolean hasNext() {
+                   if (count <= to) {
+                       while (iter.hasNext()) {
+                           if (count++ >= from) {
+                               this.next = iter.next();
+                               return true;
+                           } else {
+                               iter.next();
+                           }
+                       }
+                   }
+
+                   return false;
+                }
+
+                public Object next() {
+                    return next;
+                }
+
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+                
+            };
+        }
+     }
+
+    public void putAt(final int index, final Object newValue) {
+    final GPathResult result = (GPathResult)getAt(index);
+    
+        if (newValue instanceof Closure) {
+            result.replaceNode((Closure)newValue);
+        } else {
+            result.replaceBody(newValue);
+        }
+    }
+    
+    public Iterator depthFirst() {
+        return new Iterator() {
+            private final List list = new LinkedList();
+            private final Stack stack = new Stack();
+            private Iterator iter = iterator();
+            private GPathResult next = getNextByDepth();
+
+            public boolean hasNext() {
+                return this.next != null;
+            }
+
+            public Object next() {
+                try {
+                    return this.next;
+                } finally {
+                    this.next = getNextByDepth();
+                }
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+
+            private GPathResult getNextByDepth() {
+                while (this.iter.hasNext()) {
+                    final GPathResult node = (GPathResult) this.iter.next();
+                    this.list.add(node);
+                    this.stack.push(this.iter);
+                    this.iter = node.children().iterator();
+                }
+
+                if (this.list.isEmpty()) {
+                    return null;
+                } else {
+                    GPathResult result = (GPathResult) this.list.get(0);
+                    this.list.remove(0);
+                    this.iter = (Iterator) this.stack.pop();
+                    return result;
+                }
+            }
+        };
+    }
+
+    /**
+     * An iterator useful for traversing XML documents/fragments in breadth-first order.
+     *
+     * @return Iterator the iterator of GPathResult objects
+     */
+    public Iterator breadthFirst() {
+        return new Iterator() {
+            private final List list = new LinkedList();
+            private Iterator iter = iterator();
+            private GPathResult next = getNextByBreadth();
+
+            public boolean hasNext() {
+                return this.next != null;
+            }
+
+            public Object next() {
+                try {
+                    return this.next;
+                } finally {
+                    this.next = getNextByBreadth();
+                }
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+
+            private GPathResult getNextByBreadth() {
+                List children = new ArrayList();
+                while (this.iter.hasNext() || !children.isEmpty()) {
+                    if (this.iter.hasNext()) {
+                        final GPathResult node = (GPathResult) this.iter.next();
+                        this.list.add(node);
+                        this.list.add(this.iter);
+                        children.add(node.children());
+                    } else {
+                        List nextLevel = new ArrayList();
+                        for (int i = 0; i < children.size(); i++) {
+                            GPathResult next = (GPathResult) children.get(i);
+                            Iterator iterator = next.iterator();
+                            while (iterator.hasNext()) {
+                                nextLevel.add(iterator.next());
+                            }
+                        }
+                        this.iter = nextLevel.iterator();
+                        children = new ArrayList();
+                    }
+                }
+                if (this.list.isEmpty()) {
+                    return null;
+                } else {
+                    GPathResult result = (GPathResult) this.list.get(0);
+                    this.list.remove(0);
+                    this.iter = (Iterator) this.list.get(0);
+                    this.list.remove(0);
+                    return result;
+                }
+            }
+        };
+    }
+
+    public List list() {
+        final Iterator iter = nodeIterator();
+        final List result = new LinkedList();
+        while (iter.hasNext()) {
+            result.add(new NodeChild((Node) iter.next(), this.parent, this.namespacePrefix, this.namespaceTagHints));
+        }
+        return result;
+    }
+
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    public abstract int size();
+
+    public abstract String text();
+
+    public abstract GPathResult parents();
+
+    public abstract Iterator childNodes();
+
+    public abstract Iterator iterator();
+
+    public abstract GPathResult find(Closure closure);
+
+    public abstract GPathResult findAll(Closure closure);
+
+    public abstract Iterator nodeIterator();
+}
diff --git a/groovy-core/src/main/groovy/util/slurpersupport/NoChildren.java b/groovy-core/src/main/groovy/util/slurpersupport/NoChildren.java
new file mode 100644
index 0000000..77f8af6
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/slurpersupport/NoChildren.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.util.slurpersupport;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class NoChildren extends GPathResult {
+  /**
+   * @param parent
+   * @param name
+   */
+  public NoChildren(final GPathResult parent, final String name, final Map namespaceTagHints) {
+    super(parent, name, "*", namespaceTagHints);
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.sandbox.util.slurpersupport.GPathResult#size()
+   */
+  public int size() {
+    return 0;
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.sandbox.util.slurpersupport.GPathResult#text()
+   */
+  public String text() {
+    return "";
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.sandbox.util.slurpersupport.GPathResult#parents()
+   */
+  public GPathResult parents() {
+    // TODO Auto-generated method stub
+    throw new GroovyRuntimeException("parents() not implemented yet");
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.sandbox.util.slurpersupport.GPathResult#childNodes()
+   */
+  public Iterator childNodes() {
+    return iterator();
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.sandbox.util.slurpersupport.GPathResult#iterator()
+   */
+  public Iterator iterator() {
+    return new Iterator() {
+      public boolean hasNext() {
+        return false;
+      }
+      
+      public Object next() {
+        return null;
+      }
+      
+      public void remove() {
+        throw new UnsupportedOperationException();
+      }
+    };
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.sandbox.util.slurpersupport.GPathResult#find(groovy.lang.Closure)
+   */
+  public GPathResult find(final Closure closure) {
+    return this;
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.sandbox.util.slurpersupport.GPathResult#findAll(groovy.lang.Closure)
+   */
+  public GPathResult findAll(final Closure closure) {
+    return this;
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.sandbox.util.slurpersupport.GPathResult#nodeIterator()
+   */
+  public Iterator nodeIterator() {
+    return iterator();
+  }
+
+  /* (non-Javadoc)
+   * @see groovy.lang.Writable#writeTo(java.io.Writer)
+   */
+  public Writer writeTo(final Writer out) throws IOException {
+    return out;
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.sandbox.markup.Buildable#build(groovy.lang.GroovyObject)
+   */
+  public void build(final GroovyObject builder) {
+  }
+
+  protected void replaceNode(final Closure newValue) {
+    // No elements match GPath expression - do nothing
+  }
+
+  protected void replaceBody(final Object newValue) {
+    // No elements match GPath expression - do nothing   
+  }
+
+  protected void appendNode(final Object newValue) {
+    // TODO consider creating an element for this
+  }
+}
diff --git a/groovy-core/src/main/groovy/util/slurpersupport/Node.java b/groovy-core/src/main/groovy/util/slurpersupport/Node.java
new file mode 100644
index 0000000..37ac098
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/slurpersupport/Node.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.util.slurpersupport;
+
+import groovy.lang.Buildable;
+import groovy.lang.Closure;
+import groovy.lang.GroovyObject;
+import groovy.lang.Writable;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class Node implements Writable {
+  private final String name;
+  private final Map attributes;
+  private final Map attributeNamespaces;
+  private final String namespaceURI;
+  private final List children = new LinkedList();
+  private final Stack replacementNodeStack = new Stack();
+  
+  public Node(final Node parent, final String name, final Map attributes, final Map attributeNamespaces, final String namespaceURI) {
+    this.name = name;
+    this.attributes = attributes;
+    this.attributeNamespaces = attributeNamespaces;
+    this.namespaceURI = namespaceURI;
+  }
+  
+  public String name() {
+    return this.name;
+  }
+  
+  public String namespaceURI() {
+    return this.namespaceURI;
+  }
+  
+  public Map attributes() {
+    return this.attributes;
+  }
+
+  public List children() {
+    return this.children;
+  }
+
+  public void addChild(final Object child) {
+    this.children.add(child);
+  }
+  
+  public void replaceNode(final Closure replacementClosure, final GPathResult result) {
+      this.replacementNodeStack.push(new ReplacementNode() {
+                                          public void build(final GroovyObject builder, final Map namespaceMap, final Map namespaceTagHints) {
+                                              final Closure c = (Closure)replacementClosure.clone();
+                                              
+                                                  Node.this.replacementNodeStack.pop(); // disable the replacement whilst the closure is being executed 
+                                                  c.setDelegate(builder);
+                                                  c.call(new Object[]{result});
+                                                  Node.this.replacementNodeStack.push(this);
+                                              }
+                                          });
+  }
+  
+
+  protected void replaceBody(final Object newValue) {
+      this.children.clear();
+      this.children.add(newValue);
+  }
+
+  protected void appendNode(final Object newValue, final GPathResult result) {
+      if (newValue instanceof Closure) {
+          this.children.add(new ReplacementNode() {
+                              public void build(final GroovyObject builder, final Map namespaceMap, final Map namespaceTagHints) {
+                                  final Closure c = (Closure)((Closure)newValue).clone();
+                                  
+                                      c.setDelegate(builder);
+                                      c.call(new Object[]{result});
+                                  }
+                              });
+      } else {
+          this.children.add(newValue);
+      }
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.sandbox.util.slurpersupport.Node#text()
+   */
+  public String text() {
+  final StringBuffer buff = new StringBuffer();
+  final Iterator iter = this.children.iterator();
+  
+    while (iter.hasNext()) {
+    final Object child = iter.next();
+    
+        if (child instanceof Node) {
+            buff.append(((Node)child).text());
+        } else {
+            buff.append(child);
+        }
+    }
+  
+    return buff.toString();
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.sandbox.util.slurpersupport.Node#childNodes()
+   */
+  
+  public Iterator childNodes() {
+    return new Iterator() {
+      private final Iterator iter = Node.this.children.iterator();
+      private Object nextElementNodes = getNextElementNodes();
+      
+      public boolean hasNext() {
+        return this.nextElementNodes != null;
+      }
+      
+      public Object next() {
+        try {
+          return this.nextElementNodes;
+        } finally {
+          this.nextElementNodes = getNextElementNodes();
+        }
+      }
+      
+      public void remove() {
+        throw new UnsupportedOperationException();
+      }
+
+      private Object getNextElementNodes() {
+        while (iter.hasNext()) {
+        final Object node = iter.next();
+        
+          if (node instanceof Node) {
+            return node;
+          }
+        }
+        
+        return null;
+      }
+    };
+  }
+
+  /* (non-Javadoc)
+   * @see org.codehaus.groovy.sandbox.util.slurpersupport.Node#writeTo(java.io.Writer)
+   */
+  public Writer writeTo(final Writer out) throws IOException {
+      if (this.replacementNodeStack.empty()) {
+      final Iterator iter = this.children.iterator();
+      
+        while (iter.hasNext()) {
+        final Object child = iter.next();
+        
+          if (child instanceof Writable) {
+            ((Writable)child).writeTo(out);
+          } else {
+            out.write(child.toString());
+          }
+        }
+        
+        return out;
+        
+      } else {
+         return ((Writable)this.replacementNodeStack.peek()).writeTo(out); 
+      }
+  }
+  
+  public void build(final GroovyObject builder, final Map namespaceMap, final Map namespaceTagHints) {
+      if (this.replacementNodeStack.empty()) {
+      final Closure rest = new Closure(null) {
+                              public Object doCall(final Object o) {
+                                buildChildren(builder, namespaceMap, namespaceTagHints);
+                                
+                                return null;
+                              }
+                            };
+        
+        if (this.namespaceURI.length() == 0 && this.attributeNamespaces.isEmpty()) {
+          builder.invokeMethod(this.name, new Object[]{this.attributes, rest});
+        } else {
+          final List newTags = new LinkedList();
+          builder.getProperty("mkp");
+          final List namespaces = (List)builder.invokeMethod("getNamespaces", new Object[]{});
+          
+          final Map current = (Map)namespaces.get(0);
+          final Map pending = (Map)namespaces.get(1);
+          
+          if (this.attributeNamespaces.isEmpty()) {     
+            builder.getProperty(getTagFor(this.namespaceURI, current, pending, namespaceMap, namespaceTagHints, newTags, builder));
+            builder.invokeMethod(this.name, new Object[]{this.attributes, rest});
+          } else {
+          final Map attributesWithNamespaces = new HashMap(this.attributes);
+          final Iterator attrs = this.attributes.keySet().iterator();
+            
+            while (attrs.hasNext()) {
+            final Object key = attrs.next();
+            final Object attributeNamespaceURI = this.attributeNamespaces.get(key);
+              
+              if (attributeNamespaceURI != null) {
+                attributesWithNamespaces.put(getTagFor(attributeNamespaceURI, current, pending, namespaceMap, namespaceTagHints, newTags, builder) +
+                                             "$" + key, attributesWithNamespaces.remove(key));
+              }
+            }
+            
+            builder.getProperty(getTagFor(this.namespaceURI, current, pending, namespaceMap,namespaceTagHints,  newTags, builder));
+            builder.invokeMethod(this.name, new Object[]{attributesWithNamespaces, rest});
+          }
+          
+          // remove the new tags we had to define for this element
+          if (!newTags.isEmpty()) {
+          final Iterator iter = newTags.iterator();
+          
+            do {
+              pending.remove(iter.next());
+            } while (iter.hasNext());
+          }  
+        }   
+      } else {
+          ((ReplacementNode)this.replacementNodeStack.peek()).build(builder, namespaceMap, namespaceTagHints);
+      }
+  }
+  
+  private static String getTagFor(final Object namespaceURI, final Map current,
+                                  final Map pending, final Map local, final Map tagHints,
+                                  final List newTags, final GroovyObject builder) {
+  String tag = findNamespaceTag(pending, namespaceURI); // look in the namespaces whose declaration has already been emitted
+    
+    if (tag == null) {
+      tag = findNamespaceTag(current, namespaceURI);  // look in the namespaces who will be declared at the next element
+      
+      if (tag == null) {
+        // we have to declare the namespace - choose a tag
+        tag = findNamespaceTag(local, namespaceURI);  // If the namespace has been decared in the GPath expression use that tag
+        
+        if (tag == null || tag.length() == 0) {
+          tag = findNamespaceTag(tagHints, namespaceURI);  // If the namespace has been used in the parse documant use that tag         
+        }
+        
+        if (tag == null || tag.length() == 0) { // otherwise make up a new tag and check it has not been used before
+        int suffix = 0;
+        
+          do {
+            final String posibleTag = "tag" + suffix++;
+            
+            if (!pending.containsKey(posibleTag) && !current.containsKey(posibleTag) && !local.containsKey(posibleTag)) {
+              tag = posibleTag;
+            }
+          } while (tag == null);
+        }
+        
+        final Map newNamespace = new HashMap();
+        newNamespace.put(tag, namespaceURI);
+        builder.getProperty("mkp");
+        builder.invokeMethod("declareNamespace", new Object[]{newNamespace});
+        newTags.add(tag);
+      }
+    }
+    
+    return tag;
+  }
+  
+  private static String findNamespaceTag(final Map tagMap, final Object namespaceURI) {
+    if (tagMap.containsValue(namespaceURI)) {
+    final Iterator entries = tagMap.entrySet().iterator();
+      
+      while (entries.hasNext()) {
+        final Map.Entry entry = (Map.Entry)entries.next();
+        
+        if (namespaceURI.equals(entry.getValue())) {
+          return (String)entry.getKey();
+        }
+      }
+    }
+    
+    return null;
+  }
+  
+  private void buildChildren(final GroovyObject builder, final Map namespaceMap, final Map namespaceTagHints) {
+  final Iterator iter = this.children.iterator();
+  
+    while (iter.hasNext()) {
+    final Object child = iter.next();
+    
+      if (child instanceof Node) {
+        ((Node)child).build(builder, namespaceMap, namespaceTagHints);
+      } else if (child instanceof Buildable) {
+        ((Buildable)child).build(builder);
+      } else {
+        builder.getProperty("mkp");
+        builder.invokeMethod("yield", new Object[]{child});
+      }
+    }
+  }
+}
diff --git a/groovy-core/src/main/groovy/util/slurpersupport/NodeChild.java b/groovy-core/src/main/groovy/util/slurpersupport/NodeChild.java
new file mode 100644
index 0000000..40435ee
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/slurpersupport/NodeChild.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.util.slurpersupport;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+/**
+ * @author John Wilson
+ */
+
+public class NodeChild extends GPathResult {
+    private final Node node;
+
+    public NodeChild(final Node node, final GPathResult parent, final String namespacePrefix, final Map namespaceTagHints) {
+        super(parent, node.name(), namespacePrefix, namespaceTagHints);
+        this.node = node;
+    }
+
+    public NodeChild(final Node node, final GPathResult parent, final Map namespaceTagHints) {
+        this(node, parent, "*", namespaceTagHints);
+    }
+
+    public int size() {
+        return 1;
+    }
+
+    public String text() {
+        return this.node.text();
+    }
+
+    public GPathResult parents() {
+        // TODO Auto-generated method stub
+        throw new GroovyRuntimeException("parents() not implemented yet");
+    }
+
+    public Iterator iterator() {
+        return new Iterator() {
+            private boolean hasNext = true;
+
+            public boolean hasNext() {
+                return this.hasNext;
+            }
+
+            public Object next() {
+                try {
+                    return (this.hasNext) ? NodeChild.this : null;
+                } finally {
+                    this.hasNext = false;
+                }
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    public Iterator nodeIterator() {
+        return new Iterator() {
+            private boolean hasNext = true;
+
+            public boolean hasNext() {
+                return this.hasNext;
+            }
+
+            public Object next() {
+                try {
+                    return (this.hasNext) ? NodeChild.this.node : null;
+                } finally {
+                    this.hasNext = false;
+                }
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    public Object getAt(final int index) {
+        if (index == 0) {
+            return node;
+        } else {
+            throw new ArrayIndexOutOfBoundsException(index);
+        }
+    }
+
+    public Map attributes() {
+        return this.node.attributes();
+    }
+
+    public Iterator childNodes() {
+        return this.node.childNodes();
+    }
+
+    public GPathResult find(final Closure closure) {
+        if (DefaultTypeTransformation.castToBoolean(closure.call(new Object[]{this.node}))) {
+            return this;
+        } else {
+            return new NoChildren(this, "", this.namespaceTagHints);
+        }
+    }
+
+    public GPathResult findAll(final Closure closure) {
+        return find(closure);
+    }
+
+    public void build(final GroovyObject builder) {
+        this.node.build(builder, this.namespaceMap, this.namespaceTagHints);
+    }
+
+    public Writer writeTo(final Writer out) throws IOException {
+        return this.node.writeTo(out);
+    }
+
+    protected void replaceNode(final Closure newValue) {
+        this.node.replaceNode(newValue, this);
+    }
+
+    protected void replaceBody(final Object newValue) {
+        this.node.replaceBody(newValue);
+    }
+
+    protected void appendNode(final Object newValue) {
+        this.node.appendNode(newValue, this);
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/slurpersupport/NodeChildren.java b/groovy-core/src/main/groovy/util/slurpersupport/NodeChildren.java
new file mode 100644
index 0000000..033aa4a
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/slurpersupport/NodeChildren.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.util.slurpersupport;
+
+import groovy.lang.Buildable;
+import groovy.lang.Closure;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+/**
+ * @author John Wilson
+ */
+
+class NodeChildren extends GPathResult {
+    private int size = -1;
+
+    /**
+     * @param parent
+     * @param name
+     * @param namespacePrefix
+     * @param namespaceTagHints
+     */
+    public NodeChildren(final GPathResult parent, final String name, final String namespacePrefix, final Map namespaceTagHints) {
+        super(parent, name, namespacePrefix, namespaceTagHints);
+    }
+
+    /**
+     * @param parent
+     * @param name
+     * @param namespaceTagHints
+     */
+    public NodeChildren(final GPathResult parent, final String name, final Map namespaceTagHints) {
+        this(parent, name, "*", namespaceTagHints);
+    }
+
+    /**
+     * @param parent
+     * @param namespaceTagHints
+     */
+    public NodeChildren(final GPathResult parent, final Map namespaceTagHints) {
+        this(parent, "*", namespaceTagHints);
+    }
+
+    public Iterator childNodes() {
+        return new Iterator() {
+            private final Iterator iter = NodeChildren.this.parent.childNodes();
+            private Iterator childIter = nextChildIter();
+
+            /* (non-Javadoc)
+            * @see java.util.Iterator#hasNext()
+            */
+            public boolean hasNext() {
+                return this.childIter != null;
+            }
+
+            /* (non-Javadoc)
+            * @see java.util.Iterator#next()
+            */
+            public Object next() {
+                while (this.childIter != null) {
+                    try {
+                        if (this.childIter.hasNext()) {
+                            return this.childIter.next();
+                        }
+                    } finally {
+                        if (!this.childIter.hasNext()) {
+                            this.childIter = nextChildIter();
+                        }
+                    }
+                }
+
+                return null;
+            }
+
+            /* (non-Javadoc)
+            * @see java.util.Iterator#remove()
+            */
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+
+            private Iterator nextChildIter() {
+                while (this.iter.hasNext()) {
+                    final Node node = (Node) this.iter.next();
+
+                    if (NodeChildren.this.name.equals(node.name())) {
+                        final Iterator result = node.childNodes();
+
+                        if (result.hasNext()) {
+                            if ("*".equals(NodeChildren.this.namespacePrefix) ||
+                                    ("".equals(NodeChildren.this.namespacePrefix) && "".equals(node.namespaceURI())) ||
+                                    node.namespaceURI().equals(NodeChildren.this.namespaceMap.get(NodeChildren.this.namespacePrefix))) {
+                                return result;
+                            }
+                        }
+                    }
+                }
+
+                return null;
+            }
+        };
+    }
+
+    public Iterator iterator() {
+        return new Iterator() {
+        final Iterator iter = nodeIterator();
+
+            public boolean hasNext() {
+                return this.iter.hasNext();
+            }
+
+            public Object next() {
+                return new NodeChild((Node) this.iter.next(), NodeChildren.this.parent, NodeChildren.this.namespaceTagHints);
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    public Iterator nodeIterator() {
+        if ("*".equals(this.name)) {
+            return this.parent.childNodes();
+        } else {
+            return new NodeIterator(this.parent.childNodes()) {
+                /* (non-Javadoc)
+                * @see org.codehaus.groovy.sandbox.util.slurpersupport.NodeIterator#getNextNode(java.util.Iterator)
+                */
+                protected Object getNextNode(Iterator iter) {
+                    while (iter.hasNext()) {
+                        final Node node = (Node) iter.next();
+
+                        if (NodeChildren.this.name.equals(node.name())) {
+                            if ("*".equals(NodeChildren.this.namespacePrefix) ||
+                                    ("".equals(NodeChildren.this.namespacePrefix) && "".equals(node.namespaceURI())) ||
+                                    node.namespaceURI().equals(NodeChildren.this.namespaceMap.get(NodeChildren.this.namespacePrefix))) {
+                                return node;
+                            }
+                        }
+                    }
+
+                    return null;
+                }
+            };
+        }
+    }
+
+    public GPathResult parents() {
+        // TODO Auto-generated method stub
+        throw new GroovyRuntimeException("parents() not implemented yet");
+    }
+
+    public synchronized int size() {
+        if (this.size == -1) {
+            final Iterator iter = iterator();
+
+            this.size = 0;
+            while (iter.hasNext()) {
+                iter.next();
+                this.size++;
+            }
+        }
+
+        return this.size;
+    }
+
+    public String text() {
+    final StringBuffer buf = new StringBuffer();
+    final Iterator iter = nodeIterator();
+
+        while (iter.hasNext()) {
+            buf.append(((Node) iter.next()).text());
+        }
+
+        return buf.toString();
+    }
+
+    public GPathResult find(final Closure closure) {
+    final Iterator iter = iterator();
+
+        while (iter.hasNext()) {
+            final Object node = iter.next();
+
+            if (DefaultTypeTransformation.castToBoolean(closure.call(new Object[]{node}))) {
+                return (GPathResult) node;
+            }
+        }
+
+        return new NoChildren(this, this.name, this.namespaceTagHints);
+    }
+
+    public GPathResult findAll(final Closure closure) {
+        return new FilteredNodeChildren(this, closure, this.namespaceTagHints);
+    }
+
+    public void build(final GroovyObject builder) {
+        final Iterator iter = nodeIterator();
+
+        while (iter.hasNext()) {
+            final Object next = iter.next();
+
+            if (next instanceof Buildable) {
+                ((Buildable) next).build(builder);
+            } else {
+                ((Node) next).build(builder, this.namespaceMap, this.namespaceTagHints);
+            }
+        }
+    }
+
+    /* (non-Javadoc)
+    * @see groovy.lang.Writable#writeTo(java.io.Writer)
+    */
+    public Writer writeTo(final Writer out) throws IOException {
+    final Iterator iter = nodeIterator();
+
+        while (iter.hasNext()) {
+            ((Node) iter.next()).writeTo(out);
+        }
+
+        return out;
+    }
+
+    protected void replaceNode(final Closure newValue) {
+    final Iterator iter = iterator();
+
+        while (iter.hasNext()) {
+        final NodeChild result = (NodeChild)iter.next();
+            result.replaceNode(newValue);
+        }
+    }
+
+    protected void replaceBody(final Object newValue) {
+    final Iterator iter = iterator();
+
+        while (iter.hasNext()) {
+        final NodeChild result = (NodeChild)iter.next();
+            result.replaceBody(newValue);
+        }
+    }
+
+    protected void appendNode(final Object newValue) {
+    final Iterator iter = iterator();
+
+        while (iter.hasNext()) {
+        final NodeChild result = (NodeChild)iter.next();
+            result.appendNode(newValue);
+        }
+    }
+}
diff --git a/groovy-core/src/main/groovy/util/slurpersupport/NodeIterator.java b/groovy-core/src/main/groovy/util/slurpersupport/NodeIterator.java
new file mode 100644
index 0000000..04ff3e4
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/slurpersupport/NodeIterator.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.util.slurpersupport;
+
+import java.util.Iterator;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public abstract class NodeIterator implements Iterator {
+private final Iterator iter;
+private Object nextNode;
+
+  public NodeIterator(final Iterator iter) {
+    this.iter = iter;
+    this.nextNode = getNextNode(iter);
+  }
+  
+  public boolean hasNext() {
+    return this.nextNode != null;
+  }
+  
+  public Object next() {
+    try {
+      return this.nextNode;
+    } finally {
+      this.nextNode = getNextNode(this.iter);
+    }
+  }
+  
+  public void remove() {
+    throw new UnsupportedOperationException();
+  }
+  
+  protected abstract Object getNextNode(final Iterator iter);
+}
diff --git a/groovy-core/src/main/groovy/util/slurpersupport/ReplacementNode.java b/groovy-core/src/main/groovy/util/slurpersupport/ReplacementNode.java
new file mode 100644
index 0000000..8888bc8
--- /dev/null
+++ b/groovy-core/src/main/groovy/util/slurpersupport/ReplacementNode.java
@@ -0,0 +1,39 @@
+/*
+ * Created on Nov 27, 2006
+ *
+ * Copyright 2006 John G. Wilson
+ *
+ *   Licensed 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.util.slurpersupport;
+
+import groovy.lang.Buildable;
+import groovy.lang.GroovyObject;
+import groovy.lang.Writable;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Map;
+
+public abstract class ReplacementNode implements Buildable, Writable {
+    public abstract void build(GroovyObject builder, Map namespaceMap, Map namespaceTagHints);
+    
+    public void build(final GroovyObject builder) {
+        build(builder, null, null);
+    }
+    
+    public Writer writeTo(final Writer out) throws IOException {
+        return out;
+    }
+}
diff --git a/groovy-core/src/main/groovy/xml/DOMBuilder.java b/groovy-core/src/main/groovy/xml/DOMBuilder.java
new file mode 100644
index 0000000..71ef540
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/DOMBuilder.java
@@ -0,0 +1,190 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.xml;
+
+import groovy.util.BuilderSupport;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * A helper class for creating a W3C DOM tree
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class DOMBuilder extends BuilderSupport {
+
+    Document document;
+    DocumentBuilder documentBuilder;
+
+    public static DOMBuilder newInstance() throws ParserConfigurationException {
+        return newInstance(false, true);
+    }
+
+    public static DOMBuilder newInstance(boolean validating, boolean namespaceAware) throws ParserConfigurationException {
+        DocumentBuilderFactory factory = FactorySupport.createDocumentBuilderFactory();
+        factory.setNamespaceAware(namespaceAware);
+        factory.setValidating(validating);
+        return new DOMBuilder(factory.newDocumentBuilder());
+    }
+
+    public static Document parse(Reader reader) throws SAXException, IOException, ParserConfigurationException {
+        return parse(reader, false, true);
+    }
+
+    public static Document parse(Reader reader, boolean validating, boolean namespaceAware)
+            throws SAXException, IOException, ParserConfigurationException {
+        DocumentBuilderFactory factory = FactorySupport.createDocumentBuilderFactory();
+        factory.setNamespaceAware(namespaceAware);
+        factory.setValidating(validating);
+        DocumentBuilder documentBuilder = factory.newDocumentBuilder();
+        return documentBuilder.parse(new InputSource(reader));
+    }
+
+    public DOMBuilder(Document document) {
+        this.document = document;
+    }
+
+    public DOMBuilder(DocumentBuilder documentBuilder) {
+        this.documentBuilder = documentBuilder;
+    }
+
+    protected void setParent(Object parent, Object child) {
+        Node current = (Node) parent;
+        Node node = (Node) child;
+
+        current.appendChild(node);
+    }
+
+    protected Object createNode(Object name) {
+        if (document == null) {
+            document = createDocument();
+        }
+        if (name instanceof QName) {
+            QName qname = (QName) name;
+            return document.createElementNS(qname.getNamespaceURI(), qname.getQualifiedName());
+        } else {
+            return document.createElement(name.toString());
+        }
+    }
+
+    protected Document createDocument() {
+        if (documentBuilder == null) {
+            throw new IllegalArgumentException("No Document or DOMImplementation available so cannot create Document");
+        } else {
+            return documentBuilder.newDocument();
+        }
+    }
+
+    protected Object createNode(Object name, Object value) {
+        Element element = (Element) createNode(name);
+        element.appendChild(document.createTextNode(value.toString()));
+        return element;
+    }
+
+    protected Object createNode(Object name, Map attributes, Object value) {
+        Element element = (Element) createNode(name, attributes);
+        element.appendChild(document.createTextNode(value.toString()));
+        return element;
+    }
+
+    protected Object createNode(Object name, Map attributes) {
+        Element element = (Element) createNode(name);
+        for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            String attrName = entry.getKey().toString();
+            Object value = entry.getValue();
+            if ("xmlns".equals(attrName)) {
+                if (value instanceof Map) {
+                    appendNamespaceAttributes(element, (Map) value);
+                } else {
+                    throw new IllegalArgumentException("The value of the xmlns attribute must be a Map of QNames to String URIs");
+                }
+            } else {
+                // TODO handle null values and treat as ''
+                element.setAttribute(attrName, value.toString());
+            }
+        }
+        return element;
+    }
+
+    protected void appendNamespaceAttributes(Element element, Map attributes) {
+        for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            Object key = entry.getKey();
+            Object value = entry.getValue();
+            if (value == null) {
+                throw new IllegalArgumentException("The value of key: " + key + " cannot be null");
+            }
+            if (key instanceof String) {
+                String prefix = (String) key;
+
+                //System.out.println("Creating namespace for prefix: " + prefix + " with value: " + value);
+
+                //element.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xmlns:" + prefix, value.toString());
+                element.setAttributeNS("", prefix, value.toString());
+            } else if (key instanceof QName) {
+                QName qname = (QName) key;
+                element.setAttributeNS(qname.getNamespaceURI(), qname.getQualifiedName(), value.toString());
+            } else {
+                throw new IllegalArgumentException("The key: " + key + " should be an instanceof of " + QName.class);
+            }
+        }
+    }
+}
diff --git a/groovy-core/src/main/groovy/xml/FactorySupport.java b/groovy-core/src/main/groovy/xml/FactorySupport.java
new file mode 100644
index 0000000..5df021d
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/FactorySupport.java
@@ -0,0 +1,44 @@
+package groovy.xml;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.SAXParserFactory;
+import java.security.PrivilegedExceptionAction;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+
+/**
+ * Support class for creating XML Factories
+ */
+public class FactorySupport {
+    static Object createFactory(PrivilegedExceptionAction action) throws ParserConfigurationException {
+        Object factory;
+        try {
+            factory = AccessController.doPrivileged(action);
+        } catch (PrivilegedActionException pae) {
+            Exception e = pae.getException();
+            if (e instanceof ParserConfigurationException) {
+                throw(ParserConfigurationException) e;
+            } else {
+                throw new RuntimeException(e);
+            }
+        }
+        return factory;
+    }
+
+    public static DocumentBuilderFactory createDocumentBuilderFactory() throws ParserConfigurationException {
+        return (DocumentBuilderFactory) createFactory(new PrivilegedExceptionAction() {
+            public Object run() throws ParserConfigurationException {
+                return DocumentBuilderFactory.newInstance();
+            }
+        });
+    }
+
+    public static SAXParserFactory createSaxParserFactory() throws ParserConfigurationException {
+        return (SAXParserFactory) createFactory(new PrivilegedExceptionAction() {
+                public Object run() throws ParserConfigurationException {
+                    return SAXParserFactory.newInstance();
+                }
+            });
+    }
+}
diff --git a/groovy-core/src/main/groovy/xml/MarkupBuilder.java b/groovy-core/src/main/groovy/xml/MarkupBuilder.java
new file mode 100644
index 0000000..2c1f8f0
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/MarkupBuilder.java
@@ -0,0 +1,397 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.xml;
+
+import groovy.util.BuilderSupport;
+import groovy.util.IndentPrinter;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A helper class for creating XML or HTML markup
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Stefan Matthias Aust
+ * @author <a href="mailto:scottstirling@rcn.com">Scott Stirling</a>
+ * @version $Revision$
+ */
+public class MarkupBuilder extends BuilderSupport {
+    private IndentPrinter out;
+    private boolean nospace;
+    private int state;
+    private boolean nodeIsEmpty = true;
+    private boolean useDoubleQuotes = false;
+
+    public MarkupBuilder() {
+        this(new IndentPrinter());
+    }
+
+    public MarkupBuilder(PrintWriter writer) {
+        this(new IndentPrinter(writer));
+    }
+
+    public MarkupBuilder(Writer writer) {
+        this(new IndentPrinter(new PrintWriter(writer)));
+    }
+
+    public MarkupBuilder(IndentPrinter out) {
+        this.out = out;
+    }
+
+    /**
+     * Returns <code>true</code> if attribute values are output with
+     * double quotes; <code>false</code> if single quotes are used.
+     * By default, single quotes are used.
+     */
+    public boolean getDoubleQuotes() {
+        return this.useDoubleQuotes;
+    }
+
+    /**
+     * Sets whether the builder outputs attribute values in double
+     * quotes or single quotes.
+     * @param useDoubleQuotes If this parameter is <code>true</code>,
+     * double quotes are used; otherwise, single quotes are.
+     */
+    public void setDoubleQuotes(boolean useDoubleQuotes) {
+        this.useDoubleQuotes = useDoubleQuotes;
+    }
+
+    protected IndentPrinter getPrinter() {
+        return this.out;
+    }
+
+    protected void setParent(Object parent, Object child) { }
+
+    protected Object createNode(Object name) {
+        this.nodeIsEmpty = true;
+        toState(1, name);
+        return name;
+    }
+
+    protected Object createNode(Object name, Object value) {
+        toState(2, name);
+        this.nodeIsEmpty = false;
+        out.print(">");
+        out.print(escapeElementContent(value.toString()));
+        return name;
+    }
+
+    protected Object createNode(Object name, Map attributes, Object value) {
+        toState(1, name);
+        for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            out.print(" ");
+
+            // Output the attribute name,
+            print(entry.getKey().toString());
+
+            // Output the attribute value within quotes. Use whichever
+            // type of quotes are currently configured.
+            out.print(this.useDoubleQuotes ? "=\"" : "='");
+            print(escapeAttributeValue(entry.getValue().toString()));
+            out.print(this.useDoubleQuotes ? "\"" : "'");
+        }
+
+        if (value != null) {
+            nodeIsEmpty = false;
+            out.print(">" + escapeElementContent(value.toString()) + "</" + name + ">");
+        }
+        else {
+            nodeIsEmpty = true;
+        }
+
+        return name;
+    }
+
+    protected Object createNode(Object name, Map attributes) {
+        return createNode(name, attributes, null);
+    }
+    
+    protected void nodeCompleted(Object parent, Object node) {
+        toState(3, node);
+        out.flush();
+    }
+
+    protected void print(Object node) {
+        out.print(node == null ? "null" : node.toString());
+    }
+
+    protected Object getName(String methodName) {
+        return super.getName(methodName);
+    }
+
+    /**
+     * Returns a String with special XML characters escaped as entities so that
+     * output XML is valid. Escapes the following characters as corresponding 
+     * entities:
+     * <ul>
+     *   <li>\' as &amp;apos;</li>
+     *   <li>&amp; as &amp;amp;</li>
+     *   <li>&lt; as &amp;lt;</li>
+     *   <li>&gt; as &amp;gt;</li>
+     * </ul>
+     * 
+     * @param value to be searched and replaced for XML special characters.
+     * @return value with XML characters escaped
+     * @deprecated
+     * @see #escapeXmlValue(String, boolean)
+     */
+    protected String transformValue(String value) {
+        // & has to be checked and replaced before others
+        if (value.matches(".*&.*")) {
+            value = value.replaceAll("&", "&amp;");
+        }
+        if (value.matches(".*\\'.*")) {
+            value = value.replaceAll("\\'", "&apos;");
+        }
+        if (value.matches(".*<.*")) {
+            value = value.replaceAll("<", "&lt;");
+        }
+        if (value.matches(".*>.*")) {
+            value = value.replaceAll(">", "&gt;");
+        }
+        return value;
+    }
+
+    /**
+     * Escapes a string so that it can be used directly as an XML
+     * attribute value.
+     * @param value The string to escape.
+     * @return A new string in which all characters that require escaping
+     * have been replaced with the corresponding XML entities.
+     * @see #escapeXmlValue(String, boolean)
+     */
+    private String escapeAttributeValue(String value) {
+        return escapeXmlValue(value, true);
+    }
+
+    /**
+     * Escapes a string so that it can be used directly in XML element
+     * content.
+     * @param value The string to escape.
+     * @return A new string in which all characters that require escaping
+     * have been replaced with the corresponding XML entities.
+     * @see #escapeXmlValue(String, boolean)
+     */
+    private String escapeElementContent(String value) {
+        return escapeXmlValue(value, false);
+    }
+
+    /**
+     * Escapes a string so that it can be used in XML text successfully.
+     * It replaces the following characters with the corresponding XML
+     * entities:
+     * <ul>
+     *   <li>&amp; as &amp;amp;</li>
+     *   <li>&lt; as &amp;lt;</li>
+     *   <li>&gt; as &amp;gt;</li>
+     * </ul>
+     * If the string is to be added as an attribute value, these
+     * characters are also escaped:
+     * <ul>
+     *   <li>' as &amp;apos;</li>
+     * </ul>
+     * @param value The string to escape.
+     * @param isAttrValue <code>true</code> if the string is to be used
+     * as an attribute value, otherwise <code>false</code>.
+     * @return A new string in which all characters that require escaping
+     * have been replaced with the corresponding XML entities.
+     */
+    private String escapeXmlValue(String value, boolean isAttrValue) {
+        StringBuffer buffer = new StringBuffer(value);
+        for (int i = 0, n = buffer.length(); i < n; i++) {
+            switch (buffer.charAt(i)) {
+            case '&':
+                buffer.replace(i, i + 1, "&amp;");
+
+                // We're replacing a single character by a string of
+                // length 5, so we need to update the index variable
+                // and the total length.
+                i += 4;
+                n += 4;
+                break;
+
+            case '<':
+                buffer.replace(i, i + 1, "&lt;");
+
+                // We're replacing a single character by a string of
+                // length 4, so we need to update the index variable
+                // and the total length.
+                i += 3;
+                n += 3;
+                break;
+
+            case '>':
+                buffer.replace(i, i + 1, "&gt;");
+
+                // We're replacing a single character by a string of
+                // length 4, so we need to update the index variable
+                // and the total length.
+                i += 3;
+                n += 3;
+                break;
+
+            case '"':
+                // The double quote is only escaped if the value is for
+                // an attribute and the builder is configured to output
+                // attribute values inside double quotes.
+                if (isAttrValue && this.useDoubleQuotes) {
+                    buffer.replace(i, i + 1, "&quot;");
+
+                    // We're replacing a single character by a string of
+                    // length 6, so we need to update the index variable
+                    // and the total length.
+                    i += 5;
+                    n += 5;
+                }
+                break;
+
+            case '\'':
+                // The apostrophe is only escaped if the value is for an
+                // attribute, as opposed to element content, and if the
+                // builder is configured to surround attribute values with
+                // single quotes.
+                if (isAttrValue && !this.useDoubleQuotes){
+                    buffer.replace(i, i + 1, "&apos;");
+
+                    // We're replacing a single character by a string of
+                    // length 6, so we need to update the index variable
+                    // and the total length.
+                    i += 5;
+                    n += 5;
+                }
+                break;
+
+            default:
+                break;
+            }
+        }
+
+        return buffer.toString();
+    }
+
+    private void toState(int next, Object name) {
+        switch (state) {
+            case 0:
+                switch (next) {
+                    case 1:
+                    case 2:
+                        out.print("<");
+                        print(name);
+                        break;
+                    case 3:
+                        throw new Error();
+                }
+                break;
+            case 1:
+                switch (next) {
+                    case 1:
+                    case 2:
+                        out.print(">");
+                        if (nospace) {
+                            nospace = false;
+                        } else {
+                            out.println();
+                            out.incrementIndent();
+                            out.printIndent();
+                        }
+                        out.print("<");
+                        print(name);
+                        break;
+                    case 3:
+                        if (nodeIsEmpty) {
+                            out.print(" />");
+                        }
+                        break;
+                }
+                break;
+            case 2:
+                switch (next) {
+                    case 1:
+                    case 2:
+                        throw new Error();
+                    case 3:
+                        out.print("</");
+                        print(name);
+                        out.print(">");
+                        break;
+                }
+                break;
+            case 3:
+                switch (next) {
+                    case 1:
+                    case 2:
+                        if (nospace) {
+                            nospace = false;
+                        } else {
+                            out.println();
+                            out.printIndent();
+                        }
+                        out.print("<");
+                        print(name);
+                        break;
+                    case 3:
+                        if (nospace) {
+                            nospace = false;
+                        } else {
+                            out.println();
+                            out.decrementIndent();
+                            out.printIndent();
+                        }
+                        out.print("</");
+                        print(name);
+                        out.print(">");
+                        break;
+                }
+                break;
+        }
+        state = next;
+    }
+}
diff --git a/groovy-core/src/main/groovy/xml/Namespace.java b/groovy-core/src/main/groovy/xml/Namespace.java
new file mode 100644
index 0000000..ef61739
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/Namespace.java
@@ -0,0 +1,81 @@
+/**
+ * 
+ * Copyright 2005 LogicBlaze, Inc. http://www.logicblaze.com
+ * 
+ * Licensed 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.xml;
+
+/**
+ * A simple helper class which acts as a factory of {@link QName} instances.
+ * 
+ * @version $Revision$
+ */
+public class Namespace {
+
+    private String uri;
+    private String prefix;
+
+    public Namespace() {
+    }
+
+    public Namespace(String uri) {
+        this.uri = uri;
+    }
+
+    public Namespace(String uri, String prefix) {
+        this.uri = uri;
+        this.prefix = prefix;
+    }
+
+    /**
+     * Returns the QName for the given localName.
+     * 
+     * @param localName
+     *            the local name within this
+     */
+    public QName get(String localName) {
+        if (uri != null && uri.length() > 0) {
+            if (prefix != null) {
+                return new QName(uri, localName, prefix);
+            }
+            else {
+                return new QName(uri, localName);
+            }
+        }
+        else {
+            return new QName(localName);
+        }
+    }
+
+    /**
+     * Returns the prefix mapped to this namespace
+     * 
+     * @return the prefix assigned to this namespace or null if no namespace is
+     *         mapped.
+     */
+    public String getPrefix() {
+        return prefix;
+    }
+
+    /**
+     * Returns the URI of this namespace
+     * 
+     * @return the URI of this namespace
+     */
+    public String getUri() {
+        return uri;
+    }
+
+}
diff --git a/groovy-core/src/main/groovy/xml/NamespaceBuilder.java b/groovy-core/src/main/groovy/xml/NamespaceBuilder.java
new file mode 100644
index 0000000..8c44932
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/NamespaceBuilder.java
@@ -0,0 +1,79 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.xml;
+
+import groovy.util.BuilderSupport;
+
+/**
+ * A helper class for creating namespaces for GroovyMarkup
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class NamespaceBuilder {
+
+    private BuilderSupport builder;
+
+    public static NamespaceBuilderSupport newInstance(BuilderSupport builder, String uri) {
+        return new NamespaceBuilder(builder).namespace(uri);
+    }
+    
+    public static NamespaceBuilderSupport newInstance(BuilderSupport builder, String uri, String prefix) {
+        return new NamespaceBuilder(builder).namespace(uri, prefix);
+    }
+
+    public NamespaceBuilder(BuilderSupport builder) {
+        this.builder = builder;
+    }
+
+    public NamespaceBuilderSupport namespace(String uri) {
+        return namespace(uri, "");
+    }
+
+    public NamespaceBuilderSupport namespace(String uri, String prefix) {
+        return new NamespaceBuilderSupport(builder, uri, prefix);
+    }
+}
diff --git a/groovy-core/src/main/groovy/xml/NamespaceBuilderSupport.java b/groovy-core/src/main/groovy/xml/NamespaceBuilderSupport.java
new file mode 100644
index 0000000..69359fb
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/NamespaceBuilderSupport.java
@@ -0,0 +1,98 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.xml;
+
+import java.util.Map;
+
+import groovy.util.BuilderSupport;
+
+
+/**
+ * A helper class for creating namespaced GroovyMarkup
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class NamespaceBuilderSupport extends BuilderSupport {
+
+    private Object builder;
+    private String uri;
+    private String prefix;
+
+    public NamespaceBuilderSupport(BuilderSupport builder, String uri) {
+        this(builder, uri, "");
+    }
+
+    public NamespaceBuilderSupport(BuilderSupport builder, String uri, String prefix) {
+        super(builder);
+        this.builder = builder;
+        this.uri = uri;
+        this.prefix = prefix;
+    }
+
+    protected void setParent(Object parent, Object child) {
+    }
+
+    protected Object getName(String methodName) {
+        return new QName(uri, methodName, prefix);
+    }
+
+    protected Object createNode(Object name) {
+        return name;
+    }
+
+    protected Object createNode(Object name, Object value) {
+        return name;
+    }
+
+    protected Object createNode(Object name, Map attributes) {
+        return name;
+    }
+
+    protected Object createNode(Object name, Map attributes, Object value) {
+        return name;
+    }
+}
diff --git a/groovy-core/src/main/groovy/xml/QName.java b/groovy-core/src/main/groovy/xml/QName.java
new file mode 100644
index 0000000..d4d0f60
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/QName.java
@@ -0,0 +1,300 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation ( http://www.apache.org/ )."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Axis" and "Apache Software Foundation" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact apache@apache.org .
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    nor may "Apache" appear in their name, without prior written
+ *    permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * < http://www.apache.org/ >.
+ */
+package groovy.xml;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+
+/**
+ * <code>QName</code> class represents the value of a qualified name
+ * as specified in <a href=" http://www.w3.org/TR/xmlschema-2/#QName ">XML
+ * Schema Part2: Datatypes specification</a>.
+ * <p>
+ * The value of a QName contains a <b>namespaceURI</b>, a <b>localPart</b> and a <b>prefix</b>.
+ * The localPart provides the local part of the qualified name. The
+ * namespaceURI is a URI reference identifying the namespace.
+ *
+ * @version 1.1
+ */
+public class QName implements Serializable {
+
+    /** comment/shared empty string */
+    private static final String emptyString = "".intern();
+
+    /** Field namespaceURI */
+    private String namespaceURI;
+
+    /** Field localPart */
+    private String localPart;
+
+    /** Field prefix */
+    private String prefix;
+
+    /**
+     * Constructor for the QName.
+     *
+     * @param localPart Local part of the QName
+     */
+    public QName(String localPart) {
+        this(emptyString, localPart, emptyString);
+    }
+
+    /**
+     * Constructor for the QName.
+     *
+     * @param namespaceURI Namespace URI for the QName
+     * @param localPart Local part of the QName.
+     */
+    public QName(String namespaceURI, String localPart) {
+        this(namespaceURI, localPart, emptyString);
+    }
+
+    /**
+     * Constructor for the QName.
+     *
+     * @param namespaceURI Namespace URI for the QName
+     * @param localPart Local part of the QName.
+     * @param prefix Prefix of the QName.
+     */
+    public QName(String namespaceURI, String localPart, String prefix) {
+        this.namespaceURI = (namespaceURI == null)
+                ? emptyString
+                : namespaceURI.intern();
+        if (localPart == null) {
+            throw new IllegalArgumentException("invalid QName local part");
+        } else {
+            this.localPart = localPart.intern();
+        }
+
+        if (prefix == null) {
+            throw new IllegalArgumentException("invalid QName prefix");
+        } else {
+            this.prefix = prefix.intern();
+        }
+    }
+
+    /**
+     * Gets the Namespace URI for this QName
+     *
+     * @return Namespace URI
+     */
+    public String getNamespaceURI() {
+        return namespaceURI;
+    }
+
+    /**
+     * Gets the Local part for this QName
+     *
+     * @return Local part
+     */
+    public String getLocalPart() {
+        return localPart;
+    }
+
+    /**
+     * Gets the Prefix for this QName
+     *
+     * @return Prefix
+     */
+    public String getPrefix() {
+        return prefix;
+    }
+
+    /**
+     * Returns the fully qualified name of this QName
+     *
+     * @return  a string representation of the QName
+     */
+    public String getQualifiedName() {
+
+        return ((prefix.equals(emptyString))
+                ? localPart
+                : prefix + ':' + localPart);
+    }
+
+    /**
+     * Returns a string representation of this QName
+     *
+     * @return  a string representation of the QName
+     */
+    public String toString() {
+
+        return ((namespaceURI.equals(emptyString))
+                ? localPart
+                : '{' + namespaceURI + '}' + localPart);
+    }
+
+    /**
+     * Tests this QName for equality with another object.
+     * <p>
+     * If the given object is not a QName or String equivalent or is null then this method
+     * returns <tt>false</tt>.
+     * <p>
+     * For two QNames to be considered equal requires that both
+     * localPart and namespaceURI must be equal. This method uses
+     * <code>String.equals</code> to check equality of localPart
+     * and namespaceURI. Any class that extends QName is required
+     * to satisfy this equality contract.
+     *
+     * If the supplied object is a String, then it is split in two on the last colon
+     * and the first half is compared against the prefix || namespaceURI
+     * and the second half is compared against the localPart
+     *
+     * i.e. assert new QName("namespace","localPart").equals("namespace:localPart")
+     *
+     * Intended Usage: for gpath accessors, e.g. root.'urn:mynamespace:node'
+     *
+     * Warning: this equivalence is not commutative,
+     * i.e. qname.equals(string) may be true/false  but string.equals(qname) is always false
+     *
+     * <p>
+     * This method satisfies the general contract of the <code>Object.equals</code> method.
+     *
+     * @param o the reference object with which to compare
+     *
+     * @return <code>true</code> if the given object is identical to this
+     *      QName: <code>false</code> otherwise.
+     */
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null) return false;
+        if (o instanceof QName) {
+            final QName qName = (QName) o;
+            if (!namespaceURI.equals(qName.namespaceURI)) return false;
+            return localPart.equals(qName.localPart);
+
+        } else if (o instanceof String) {
+            final String string = (String)o;
+            if (string.length() == 0) return false;
+            int lastColonIndex = string.lastIndexOf(":");
+            if (lastColonIndex < 0 || lastColonIndex == string.length() - 1) return false;
+            final String stringPrefix = string.substring(0,lastColonIndex);
+            final String stringLocalPart = string.substring(lastColonIndex + 1);
+            if (stringPrefix.equals(prefix) || stringPrefix.equals(namespaceURI)) {
+                return localPart.equals(stringLocalPart);
+            }
+            return false;
+        }
+        return false;
+    }
+
+    /**
+     * Returns a QName holding the value of the specified String.
+     * <p>
+     * The string must be in the form returned by the QName.toString()
+     * method, i.e. "{namespaceURI}localPart", with the "{namespaceURI}"
+     * part being optional.
+     * <p>
+     * This method doesn't do a full validation of the resulting QName.
+     * In particular, it doesn't check that the resulting namespace URI
+     * is a legal URI (per RFC 2396 and RFC 2732), nor that the resulting
+     * local part is a legal NCName per the XML Namespaces specification.
+     *
+     * @param s the string to be parsed
+     * @throws java.lang.IllegalArgumentException If the specified String cannot be parsed as a QName
+     * @return QName corresponding to the given String
+     */
+    public static QName valueOf(String s) {
+
+        if ((s == null) || s.equals("")) {
+            throw new IllegalArgumentException("invalid QName literal");
+        }
+
+        if (s.charAt(0) == '{') {
+            int i = s.indexOf('}');
+
+            if (i == -1) {
+                throw new IllegalArgumentException("invalid QName literal");
+            }
+
+            if (i == s.length() - 1) {
+                throw new IllegalArgumentException("invalid QName literal");
+            } else {
+                return new QName(s.substring(1, i), s.substring(i + 1));
+            }
+        } else {
+            return new QName(s);
+        }
+    }
+
+    /**
+     * Returns a hash code value for this QName object. The hash code
+     * is based on both the localPart and namespaceURI parts of the
+     * QName. This method satisfies the  general contract of the
+     * <code>Object.hashCode</code> method.
+     *
+     * @return a hash code value for this Qname object
+     */
+    public int hashCode() {
+        int result;
+        result = namespaceURI.hashCode();
+        result = 29 * result + localPart.hashCode();
+        return result;
+    }
+
+    /**
+     * Ensure that deserialization properly interns the results.
+     * @param in the ObjectInputStream to be read
+     */
+    private void readObject(ObjectInputStream in) throws
+            IOException, ClassNotFoundException {
+        in.defaultReadObject();
+
+        namespaceURI = namespaceURI.intern();
+        localPart = localPart.intern();
+        prefix = prefix.intern();
+    }
+} 
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/xml/SAXBuilder.java b/groovy-core/src/main/groovy/xml/SAXBuilder.java
new file mode 100644
index 0000000..9a1e567
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/SAXBuilder.java
@@ -0,0 +1,184 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.xml;
+
+import groovy.util.BuilderSupport;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * A helper class for creating a W3C D
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class SAXBuilder extends BuilderSupport {
+
+    private ContentHandler handler;
+    private Attributes emptyAttributes = new AttributesImpl();
+
+    public SAXBuilder(ContentHandler handler) {
+        this.handler = handler;
+    }
+
+    protected void setParent(Object parent, Object child) {
+    }
+
+    protected Object createNode(Object name) {
+        doStartElement(name, emptyAttributes);
+        return name;
+    }
+
+    protected Object createNode(Object name, Object value) {
+        doStartElement(name, emptyAttributes);
+        doText(value);
+        return name;
+    }
+
+    /**
+     * @param value
+     */
+    private void doText(Object value) {
+        try {
+            char[] text = value.toString().toCharArray();
+            handler.characters(text, 0, text.length);
+        }
+        catch (SAXException e) {
+            handleException(e);
+        }
+    }
+
+    protected Object createNode(Object name, Map attributeMap, Object text) {
+        AttributesImpl attributes = new AttributesImpl();
+        for (Iterator iter = attributeMap.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            Object key = entry.getKey();
+            Object value = entry.getValue();
+            String uri = "";
+            String localName = null;
+            String qualifiedName = "";
+            String valueText = (value != null) ? value.toString() : "";
+            if (key instanceof QName) {
+                QName qname = (QName) key;
+                uri = qname.getNamespaceURI();
+                localName = qname.getLocalPart();
+                qualifiedName = qname.getQualifiedName();
+            }
+            else {
+                localName = key.toString();
+                qualifiedName = localName;
+            }
+
+            attributes.addAttribute(uri, localName, qualifiedName, "CDATA", valueText);
+        }
+        doStartElement(name, attributes);
+        if (text != null) {
+            doText(text);
+        }
+        return name;
+    }
+
+    protected void doStartElement(Object name, Attributes attributes) {
+        String uri = "";
+        String localName = null;
+        String qualifiedName = "";
+        if (name instanceof QName) {
+            QName qname = (QName) name;
+            uri = qname.getNamespaceURI();
+            localName = qname.getLocalPart();
+            qualifiedName = qname.getQualifiedName();
+        }
+        else {
+            localName = name.toString();
+            qualifiedName = localName;
+        }
+        try {
+            handler.startElement(uri, localName, qualifiedName, attributes);
+        }
+        catch (SAXException e) {
+            handleException(e);
+        }
+    }
+
+    protected void nodeCompleted(Object parent, Object name) {
+        String uri = "";
+        String localName = null;
+        String qualifiedName = "";
+        if (name instanceof QName) {
+            QName qname = (QName) name;
+            uri = qname.getNamespaceURI();
+            localName = qname.getLocalPart();
+            qualifiedName = qname.getQualifiedName();
+        }
+        else {
+            localName = name.toString();
+            qualifiedName = localName;
+        }
+        try {
+            handler.endElement(uri, localName, qualifiedName);
+        }
+        catch (SAXException e) {
+            handleException(e);
+        }
+    }
+
+    protected void handleException(SAXException e) {
+        throw new RuntimeException(e);
+    }
+
+    /* (non-Javadoc)
+     * @see groovy.util.BuilderSupport#createNode(java.lang.Object, java.util.Map, java.lang.Object)
+     */
+    protected Object createNode(Object name, Map attributes) {
+        return createNode(name, attributes, null);
+    }
+}
diff --git a/groovy-core/src/main/groovy/xml/StreamingDOMBuilder.groovy b/groovy-core/src/main/groovy/xml/StreamingDOMBuilder.groovy
new file mode 100644
index 0000000..01320e0
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/StreamingDOMBuilder.groovy
@@ -0,0 +1,233 @@
+package groovy.xml
+/*
+
+Copyright 2004 (C) John Wilson. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+import javax.xml.parsers.DocumentBuilderFactory
+import org.w3c.dom.Node
+
+import groovy.xml.streamingmarkupsupport.AbstractStreamingBuilder
+import groovy.xml.streamingmarkupsupport.StreamingMarkupWriter
+import groovy.xml.streamingmarkupsupport.BaseMarkupBuilder
+
+class StreamingDOMBuilder extends AbstractStreamingBuilder {
+    def pendingStack = []
+    def commentClosure = {doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, body, dom ->
+        def comment = dom.document.createComment(body)
+        if (comment != null) {
+            dom.element.appendChild(comment)
+        }
+    }
+    def piClosure = {doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, body, dom ->
+        attrs.each {target, instruction ->
+            def pi = null
+            if (instruction instanceof Map) {
+                def buf = new StringBuffer()
+                instruction.each { name, value ->
+                    if (value.toString().contains('"')) {
+                        buf.append(" $name='$value'")
+                    } else {
+                        buf.append(" $name=\"$value\"" )
+                    }
+                }
+                pi = dom.document.createProcessingInstruction(target, buf.toString())
+            } else {
+                pi =dom.document.createProcessingInstruction(target, instruction)
+            }
+            if (pi != null) {
+                dom.element.appendChild(pi)
+            }
+        }
+    }
+    def noopClosure = {doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, body, dom ->
+        if (body instanceof Closure) {
+            def body1 = body.clone()
+            body1.delegate = doc
+            body1(doc)
+        } else if (body instanceof Buildable) {
+            body.build(doc)
+        } else if (body != null) {
+            body.each {
+                if (it instanceof Closure) {
+                    def body1 = it.clone()
+                    body1.delegate = doc
+                    body1(doc)
+                } else if (it instanceof Buildable) {
+                    it.build(doc)
+                } else {
+                    dom.element.appendChild(dom.document.createTextNode(it))
+                }
+            }
+        }
+    }
+    def tagClosure = {tag, doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, body, dom ->
+                    def attributes = []
+                    def nsAttributes = []
+
+                    attrs.each {key, value ->
+                        if (key.contains('$')) {
+                            def parts = key.tokenize('$')
+                            def namespaceUri = null
+
+                            if (namespaces.containsKey(parts[0])) {
+                                namespaceUri = namespaces[parts[0]]
+
+                                nsAttributes.add([namespaceUri, "${parts[0]}:${parts[1]}", value])
+
+                            } else {
+                                throw new GroovyRuntimeException("bad attribute namespace tag in ${key}")
+                            }
+                        } else {
+                            attributes.add([key, value])
+                        }
+                    }
+
+                    def hiddenNamespaces = [:]
+
+                    pendingNamespaces.each {key, value ->
+                        hiddenNamespaces[key] = namespaces[key]
+                        namespaces[key] = value
+                        nsAttributes.add(["http://www.w3.org/2000/xmlns/", "xmlns:${key}", value])
+
+                    }
+
+                    // setup the tag info
+
+                    def uri = ""
+                    def qualifiedName = tag
+
+                    if (prefix != "") {
+                        if (namespaces.containsKey(prefix)) {
+                            uri = namespaces[prefix]
+                        } else if (pendingNamespaces.containsKey(prefix)) {
+                            uri = pendingNamespaces[prefix]
+                        } else {
+                            throw new GroovyRuntimeException("Namespace prefix: ${prefix} is not bound to a URI")
+                        }
+                        if (prefix != ":") {
+                            qualifiedName = prefix + ":" + tag
+                        }
+                    }
+
+                    def element = dom.document.createElementNS(uri, qualifiedName)
+
+                    nsAttributes.each {
+                        element.setAttributeNS(it[0], it[1], it[2])
+                    }
+                    attributes.each {
+                        element.setAttribute(it[0], it[1])
+                    }
+
+                    dom.element.appendChild(element)
+                    dom.element = element
+
+                    if (body != null) {
+                        pendingStack.add pendingNamespaces.clone()
+                        pendingNamespaces.clear()
+
+                        if (body instanceof Closure) {
+                          def body1 = body.clone()
+
+                          body1.delegate = doc
+                          body1(doc)
+                        } else if (body instanceof Buildable) {
+                              body.build(doc)
+                        } else {
+                          body.each {
+                            if (it instanceof Closure) {
+                              def body1 = it.clone()
+
+                              body1.delegate = doc
+                              body1(doc)
+                            } else if (it instanceof Buildable) {
+                              it.build(doc)
+                            } else {
+                              dom.element.appendChild(dom.document.createTextNode(it))
+                            }
+                          }
+                        }
+
+                        pendingNamespaces.clear()
+                        pendingNamespaces.putAll pendingStack.pop()
+                    }
+
+                    dom.element = dom.element.getParentNode()
+
+                    hiddenNamespaces.each {key, value ->
+                                                if (value == null) {
+                                                    namespaces.remove key
+                                                } else {
+                                                    namespaces[key] = value
+                                                }
+                    }
+    }
+
+    def builder = null
+
+    StreamingDOMBuilder() {
+        specialTags.putAll(['yield':noopClosure,
+                            'yieldUnescaped':noopClosure,
+                            'comment':commentClosure,
+                            'pi':piClosure])
+//        def nsSpecificTags = [':'                                          : [tagClosure, tagClosure, [:]],    // the default namespace
+//                          'http://www.w3.org/XML/1998/namespace'           : [tagClosure, tagClosure, [:]],
+//                          'http://www.codehaus.org/Groovy/markup/keywords' : [badTagClosure, tagClosure, specialTags]]
+//        this.builder = new BaseMarkupBuilder(nsSpecificTags)
+    }
+
+    def bind(closure) {
+        def boundClosure = this.builder.bind(closure)
+        return {
+            if (it instanceof Node) {
+                def document = it.getOwnerDocument()
+                boundClosure.trigger = ['document' : document, 'element' : it]
+                return document
+            } else {
+                def newDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()
+                boundClosure.trigger = ['document' : newDocument, 'element' : newDocument]
+                return newDocument
+            }
+        }
+    }
+}
diff --git a/groovy-core/src/main/groovy/xml/StreamingMarkupBuilder.groovy b/groovy-core/src/main/groovy/xml/StreamingMarkupBuilder.groovy
new file mode 100644
index 0000000..c68fc1a
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/StreamingMarkupBuilder.groovy
@@ -0,0 +1,219 @@
+package groovy.xml
+
+import groovy.xml.streamingmarkupsupport.AbstractStreamingBuilder
+import groovy.xml.streamingmarkupsupport.StreamingMarkupWriter
+import groovy.xml.streamingmarkupsupport.BaseMarkupBuilder
+
+
+/*
+
+Copyright 2004 (C) John Wilson. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+    class StreamingMarkupBuilder extends AbstractStreamingBuilder {
+        def pendingStack = []
+        def commentClosure = {doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, body, out ->
+                                        out.unescaped() << "<!--"
+                                        out.bodyText() << body
+                                        out.unescaped() << "-->"
+                                     }
+         def piClosure = {doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, body, out ->
+                                    attrs.each {target, instruction ->
+                                      out.unescaped() << "<?"
+                                      if (instruction instanceof Map) {
+                                        out.unescaped() << target
+                                        instruction.each { name, value ->
+                                          if (value.toString().contains('"')) {
+                                            out.unescaped() << " $name='$value'"
+                                          } else {
+                                            out.unescaped() << " $name=\"$value\""                                          
+                                          }
+                                        }
+                                      } else {
+                                        out.unescaped() << "$target $instruction"
+                                      }
+                                      out.unescaped() << "?>"
+                                    }
+                                 }
+        def declarationClosure = {doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, body, out ->
+                                     out.unescaped() << '<?xml version="1.0" encoding="'
+                                     out.bodyText() << "${out.encoding}"
+                                     out.unescaped() << '"?>\n'
+                                 }
+        def noopClosure = {doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, body, out ->
+                                      if (body instanceof Closure) {
+                                        def body1 = body.clone()
+                                        
+                                        body1.delegate = doc
+                                        body1(doc)
+                                      } else if (body instanceof Buildable) {
+                                          body.build(doc)
+                                      } else if (body != null) {
+                                          body.each {
+                                            if (it instanceof Closure) {
+                                              def body1 = it.clone()
+                                              
+                                              body1.delegate = doc
+                                              body1(doc)
+                                            } else if (it instanceof Buildable) {
+                                              it.build(doc)
+                                            } else {
+                                              out.bodyText() << it
+                                            }
+                                          }
+                                      }
+                                }
+        def unescapedClosure = {doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, body, out ->
+                                          out.unescaped() << body
+                                     }
+        def tagClosure = {tag, doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, body, out ->
+                                  if (prefix != "") {
+                                      if (!(namespaces.containsKey(prefix) || pendingNamespaces.containsKey(prefix))) {
+                                          throw new GroovyRuntimeException("Namespace prefix: ${prefix} is not bound to a URI")
+                                      }
+          
+                                      if (prefix != ":") tag = prefix + ":" + tag
+                                  }
+          
+                                  out = out.unescaped() << "<${tag}"
+          
+                                  attrs.each {key, value ->
+                                                  if (key.contains('$')) {
+                                                      def parts = key.tokenize('$')
+          
+                                                      if (namespaces.containsKey(parts[0]) || pendingNamespaces.containsKey(parts[0])) {
+                                                          key = parts[0] + ":" + parts[1]
+                                                      } else {
+                                                          throw new GroovyRuntimeException("bad attribute namespace tag: ${parts[0]} in ${key}")
+                                                      }
+                                                  }
+          
+                                                  out << " ${key}='"
+                                                  out.attributeValue() << "${value}"
+                                                  out << "'"
+                                                }
+          
+                                  def hiddenNamespaces = [:]
+          
+                                  pendingNamespaces.each {key, value ->
+                                      hiddenNamespaces[key] = namespaces[key]
+                                      namespaces[key] = value
+                                      out << ((key == ":") ? " xmlns='" : " xmlns:${key}='")
+                                      out.attributeValue() << "${value}"
+                                      out << "'"
+                                  }
+          
+                                  if (body == null) {
+                                      out << "/>"
+                                  } else {
+                                      out << ">"
+          
+                                      pendingStack.add pendingNamespaces.clone()
+                                      pendingNamespaces.clear()
+          
+                                      if (body instanceof Closure) {
+                                        def body1 = body.clone()
+                                        
+                                        body1.delegate = doc
+                                        body1(doc)
+                                      } else if (body instanceof Buildable) {
+                                          body.build(doc)
+                                      } else {
+                                          body.each {
+                                            if (it instanceof Closure) {
+                                              def body1 = it.clone()
+                                              
+                                              body1.delegate = doc
+                                              body1(doc)
+                                            } else if (it instanceof Buildable) {
+                                              it.build(doc)
+                                            } else {
+                                              out.bodyText() << it
+                                            }
+                                          }
+                                      }
+          
+                                      pendingNamespaces.clear()
+                                      pendingNamespaces.putAll pendingStack.pop()
+          
+                                      out << "</${tag}>"
+                                  }
+          
+                                  hiddenNamespaces.each {key, value ->
+                                                              if (value == null) {
+                                                                  namespaces.remove key
+                                                              } else {
+                                                                  namespaces[key] = value
+                                                              }
+                                                         }
+                              }
+
+        def builder = null
+
+        StreamingMarkupBuilder() {
+            specialTags.putAll(['yield':noopClosure,
+                                'yieldUnescaped':unescapedClosure,
+                                'xmlDeclaration':declarationClosure,
+                                'comment':commentClosure,
+                                'pi':piClosure])
+
+            def nsSpecificTags = [':'                                              : [tagClosure, tagClosure, [:]],    // the default namespace
+                                  'http://www.w3.org/XML/1998/namespace'           : [tagClosure, tagClosure, [:]],
+                                  'http://www.codehaus.org/Groovy/markup/keywords' : [badTagClosure, tagClosure, specialTags]]
+
+            this.builder = new BaseMarkupBuilder(nsSpecificTags)
+        }
+        
+        def encoding = null
+
+        public bind(closure) {
+            def boundClosure = this.builder.bind(closure);
+            def enc = encoding; // take a snapshot of the encoding when the closure is bound to the builder
+
+            {out ->
+                out = new StreamingMarkupWriter(out, enc)
+                boundClosure.trigger = out
+                out.flush()
+            }.asWritable()
+        }
+    }
diff --git a/groovy-core/src/main/groovy/xml/StreamingSAXBuilder.groovy b/groovy-core/src/main/groovy/xml/StreamingSAXBuilder.groovy
new file mode 100644
index 0000000..5b46ae5
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/StreamingSAXBuilder.groovy
@@ -0,0 +1,218 @@
+package groovy.xml
+
+import groovy.xml.streamingmarkupsupport.AbstractStreamingBuilder
+import groovy.xml.streamingmarkupsupport.StreamingMarkupWriter
+import groovy.xml.streamingmarkupsupport.BaseMarkupBuilder
+
+/*
+
+Copyright 2004 (C) John Wilson. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+import org.xml.sax.helpers.AttributesImpl
+import org.xml.sax.ext.LexicalHandler
+
+    class StreamingSAXBuilder extends AbstractStreamingBuilder {
+        def pendingStack = []
+        def commentClosure = {doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, body, contentHandler ->
+                                      if (contentHandler instanceof LexicalHandler) {
+                                          contentHandler.comment(body.toCharArray(), 0, body.size())
+                                      }
+                                   }
+        def piClosure = {doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, body, contentHandler ->
+                                  attrs.each {target, instruction ->
+                                     if (instruction instanceof Map) {
+                                     def buf = new StringBuffer()
+                                        
+                                        instruction.each { name, value ->
+                                          if (value.toString().contains('"')) {
+                                            buf.append(" $name='$value'")
+                                          } else {
+                                            buf.append(" $name=\"$value\"" )                                        
+                                          }
+                                        }
+                                        contentHandler.processingInstruction(target, buf.toString())
+                                      } else {
+                                        contentHandler.processingInstruction(target, instruction)
+                                      }
+                                    }
+                               }
+        def noopClosure = {doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, body, contentHandler ->
+                                  if (body instanceof Closure) {
+                                    def body1 = body.clone()
+                                    
+                                    body1.delegate = doc
+                                    body1(doc)
+                                  } else if (body instanceof Buildable) {
+                                    body.build(doc)
+                                  } else if (body != null) {
+                                    body.each {
+                                      if (it instanceof Closure) {
+                                        def body1 = it.clone()
+                                        
+                                        body1.delegate = doc
+                                        body1(doc)
+                                      } else if (it instanceof Buildable) {
+                                        it.build(doc)
+                                      } else {
+                                          def chars = it.toCharArray()
+                                          contentHandler.characters(chars, 0, chars.size())
+                                        }
+                                      }
+                                  }
+                                }
+        def tagClosure = {tag, doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, body, contentHandler ->
+                                  def attributes = new AttributesImpl()
+          
+                                  attrs.each {key, value ->
+                                          if (key.contains('$')) {
+                                              def parts = key.tokenize('$')
+          
+                                              if (namespaces.containsKey(parts[0])) {
+                                                  def namespaceUri = namespaces[parts[0]]          
+                                                  attributes.addAttribute(namespaceUri, parts[1], "${parts[0]}:${parts[1]}", "CDATA", value)
+                                              } else {
+                                                  throw new GroovyRuntimeException("bad attribute namespace tag in ${key}")
+                                              }
+                                          } else {
+                                              attributes.addAttribute("", key, key, "CDATA", value)
+                                          }
+                                    }
+          
+                                  def hiddenNamespaces = [:]
+          
+                                  pendingNamespaces.each {key, value ->
+                                      hiddenNamespaces[key] = namespaces[key]
+                                      namespaces[key] = value
+                                      attributes.addAttribute("http://www.w3.org/2000/xmlns/", key, "xmlns:${key}", "CDATA", value)
+                                      contentHandler.startPrefixMapping(key, value)
+                                  }
+          
+                                  // setup the tag info
+          
+                                  def uri = ""
+                                  def qualifiedName = tag
+          
+                                  if (prefix != "") {
+                                      if (namespaces.containsKey(prefix)) {
+                                          uri = namespaces[prefix]
+                                      } else if (pendingNamespaces.containsKey(prefix)) {
+                                          uri = pendingNamespaces[prefix]
+                                      } else {
+                                          throw new GroovyRuntimeException("Namespace prefix: ${prefix} is not bound to a URI")
+                                      }
+          
+                                      if (prefix != ":") {
+                                          qualifiedName = prefix + ":" + tag
+                                      }
+                                  }
+          
+                                  contentHandler.startElement(uri, tag, qualifiedName, attributes)
+          
+                                  if (body != null) {
+                                      pendingStack.add pendingNamespaces.clone()
+                                      pendingNamespaces.clear()
+          
+                                      if (body instanceof Closure) {
+                                        def body1 = body.clone()
+                                        
+                                        body1.delegate = doc
+                                        body1(doc)
+                                      } else if (body instanceof Buildable) {
+                                        body.build(doc)
+                                      } else {
+                                        body.each {
+                                          if (it instanceof Closure) {
+                                            def body1 = it.clone()
+                                            
+                                            body1.delegate = doc
+                                            body1(doc)
+                                          } else if (it instanceof Buildable) {
+                                            it.build(doc)
+                                          } else {
+                                              def chars = it.toCharArray()
+                                              contentHandler.characters(chars, 0, chars.size())
+                                            }
+                                          }
+                                      }
+          
+                                      pendingNamespaces.clear()
+                                      pendingNamespaces.putAll pendingStack.pop()
+                                  }
+          
+                                  contentHandler.endElement(uri, tag, qualifiedName)
+          
+                                  hiddenNamespaces.each {key, value ->
+                                                              contentHandler.endPrefixMapping(key)
+          
+                                                              if (value == null) {
+                                                                  namespaces.remove key
+                                                              } else {
+                                                                  namespaces[key] = value
+                                                              }
+                                                         }
+                              }
+
+        def builder = null
+
+        StreamingSAXBuilder() {
+            specialTags.putAll(['yield':noopClosure,
+                                'yieldUnescaped':noopClosure,
+                                'comment':commentClosure,
+                                'pi':piClosure])
+
+            def nsSpecificTags = [':'                                          : [tagClosure, tagClosure, [:]],    // the default namespace
+                                  'http://www.w3.org/XML/1998/namespace'           : [tagClosure, tagClosure, [:]],
+                                  'http://www.codehaus.org/Groovy/markup/keywords' : [badTagClosure, tagClosure, specialTags]]
+
+            this.builder = new BaseMarkupBuilder(nsSpecificTags)
+        }
+
+        public bind(closure) {
+            def boundClosure = this.builder.bind(closure)
+
+            return {contentHandler ->
+                boundClosure.trigger = contentHandler
+            }
+        }
+    }
diff --git a/groovy-core/src/main/groovy/xml/dom/DOMCategory.java b/groovy-core/src/main/groovy/xml/dom/DOMCategory.java
new file mode 100644
index 0000000..7bf333d
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/dom/DOMCategory.java
@@ -0,0 +1,364 @@
+/*
+ * $Id$version Apr 25, 2004 5:18:30 PM $user Exp $
+ * 
+ * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy of
+ * this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution. 3. The
+ * name "groovy" must not be used to endorse or promote products derived from
+ * this Software without prior written permission of The Codehaus. For written
+ * permission, please contact info@codehaus.org. 4. Products derived from this
+ * Software may not be called "groovy" nor may "groovy" appear in their names
+ * without prior written permission of The Codehaus. "groovy" is a registered
+ * trademark of The Codehaus. 5. Due credit should be given to The Codehaus -
+ * http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *  
+ */
+package groovy.xml.dom;
+
+import org.w3c.dom.*;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * @author sam
+ * @author paulk
+ */
+public class DOMCategory {
+
+    private static boolean trimWhitespace = true;
+
+    public static Object get(Object o, String elementName) {
+        if (o instanceof Element) {
+            return get((Element) o, elementName);
+        }
+        if (o instanceof NodeList) {
+            return get((NodeList) o, elementName);
+        }
+        if (o instanceof NamedNodeMap) {
+            return get((NamedNodeMap) o, elementName);
+        }
+        return null;
+    }
+
+    private static Object get(Element element, String elementName) {
+        return getAt(element, elementName);
+    }
+
+    private static Object get(NodeList nodeList, String elementName) {
+        return getAt(nodeList, elementName);
+    }
+
+    private static Object get(NamedNodeMap nodeMap, String elementName) {
+        return getAt(nodeMap, elementName);
+    }
+
+    private static Object getAt(Element element, String elementName) {
+        if ("..".equals(elementName)) {
+            return parent(element);
+        }
+        if ("**".equals(elementName)) {
+            return depthFirst(element);
+        }
+        if (elementName.startsWith("@")) {
+            return element.getAttribute(elementName.substring(1));
+        }
+        return getChildElements(element, elementName);
+    }
+
+    private static Object getAt(NodeList nodeList, String elementName) {
+        List results = new ArrayList();
+        for (int i = 0; i < nodeList.getLength(); i++) {
+            Node node = nodeList.item(i);
+            if (node instanceof Element) {
+                addResult(results, get(node, elementName));
+            }
+        }
+        if (elementName.startsWith("@")) {
+            return results;
+        }
+        return new NodeListsHolder(results);
+    }
+
+    public static NamedNodeMap attributes(Element element) {
+        return element.getAttributes();
+    }
+
+    private static String getAt(NamedNodeMap namedNodeMap, String elementName) {
+        Attr a = (Attr) namedNodeMap.getNamedItem(elementName);
+        return a.getValue();
+    }
+
+    public static int size(NamedNodeMap namedNodeMap) {
+        return namedNodeMap.getLength();
+    }
+
+    public static Node getAt(Node o, int i) {
+        return nodeGetAt(o, i);
+    }
+
+    public static Node getAt(NodeListsHolder o, int i) {
+        return nodeGetAt(o, i);
+    }
+
+    public static Node getAt(NodesHolder o, int i) {
+        return nodeGetAt(o, i);
+    }
+
+    private static Node nodeGetAt(Object o, int i) {
+        if (o instanceof Element) {
+            Node n = getAt((Element)o, i);
+            if (n != null) return n;
+        }
+        if (o instanceof NodeList) {
+            return getAt((NodeList)o, i);
+        }
+        return null;
+    }
+
+    private static Node getAt(Element element, int i) {
+        if (hasChildElements(element, "*")) {
+            NodeList nodeList = getChildElements(element, "*");
+            return nodeList.item(i);
+        }
+        return null;
+    }
+
+    private static Node getAt(NodeList nodeList, int i) {
+        if (i >= 0 && i < nodeList.getLength()) {
+            return nodeList.item(i);
+        }
+        return null;
+    }
+
+    public static String name(Element element) {
+        return element.getNodeName();
+    }
+
+    public static Node parent(Node node) {
+        return node.getParentNode();
+    }
+
+    public static String text(Object o) {
+        if (o instanceof Element) {
+            return text((Element) o);
+        }
+        if (o instanceof Node) {
+            Node n = (Node) o;
+            if (n.getNodeType() == Node.TEXT_NODE) {
+                return n.getNodeValue();
+            }
+        }
+        if (o instanceof NodeList) {
+            return text((NodeList) o);
+        }
+        return null;
+    }
+
+    private static String text(Element element) {
+        if (!element.hasChildNodes()) {
+            return "";
+        }
+        if (element.getFirstChild().getNodeType() != Node.TEXT_NODE) {
+            return "";
+        }
+        return element.getFirstChild().getNodeValue();
+    }
+
+    private static String text(NodeList nodeList) {
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < nodeList.getLength(); i++) {
+            sb.append(text(nodeList.item(i)));
+        }
+        return sb.toString();
+    }
+
+    public static List list(NodeList self) {
+        List answer = new ArrayList();
+        Iterator it = DefaultGroovyMethods.iterator(self);
+        while (it.hasNext()) {
+            answer.add(it.next());
+        }
+        return answer;
+    }
+
+    public static NodeList depthFirst(Element self) {
+        List result = new ArrayList();
+        result.add(createNodeList(self));
+        result.add(self.getElementsByTagName("*"));
+        return new NodeListsHolder(result);
+    }
+
+    private static NodeList createNodeList(Element self) {
+        List first = new ArrayList();
+        first.add(self);
+        return new NodesHolder(first);
+    }
+
+    public static NodeList breadthFirst(Element self) {
+        List result = new ArrayList();
+        NodeList thisLevel = createNodeList(self);
+        while (thisLevel.getLength() > 0) {
+            result.add(thisLevel);
+            thisLevel = getNextLevel(thisLevel);
+        }
+        return new NodeListsHolder(result);
+    }
+
+    private static NodeList getNextLevel(NodeList thisLevel) {
+        List result = new ArrayList();
+        for (int i = 0; i < thisLevel.getLength(); i++) {
+            Node n = thisLevel.item(i);
+            if (n instanceof Element) {
+                result.add(getChildElements((Element) n, "*"));
+            }
+        }
+        return new NodeListsHolder(result);
+    }
+
+    public static NodeList children(Element self) {
+        return getChildElements(self, "*");
+    }
+
+    private static boolean hasChildElements(Element self, String elementName) {
+        return getChildElements(self, elementName).getLength() > 0;
+    }
+
+    private static NodeList getChildElements(Element self, String elementName) {
+        List result = new ArrayList();
+        NodeList nodeList = self.getChildNodes();
+        for (int i = 0; i < nodeList.getLength(); i++) {
+            Node node = nodeList.item(i);
+            if (node.getNodeType() == Node.ELEMENT_NODE) {
+                Element child = (Element) node;
+                if ("*".equals(elementName) || child.getTagName().equals(elementName)) {
+                    result.add(child);
+                }
+            } else if (node.getNodeType() == Node.TEXT_NODE) {
+                String value = node.getNodeValue();
+                if (trimWhitespace) {
+                    value = value.trim();
+                }
+                if ("*".equals(elementName) && value.length() > 0) {
+                    node.setNodeValue(value);
+                    result.add(node);
+                }
+            }
+        }
+        return new NodesHolder(result);
+    }
+
+    public static String toString(Object o) {
+        if (o instanceof Node) {
+            if (((Node) o).getNodeType() == Node.TEXT_NODE) {
+                return ((Node) o).getNodeValue();
+            }
+        }
+        if (o instanceof NodeList) {
+            return toString((NodeList) o);
+        }
+        return o.toString();
+    }
+
+    private static String toString(NodeList self) {
+        StringBuffer sb = new StringBuffer();
+        sb.append("[");
+        Iterator it = DefaultGroovyMethods.iterator(self);
+        while (it.hasNext()) {
+            if (sb.length() > 1) sb.append(", ");
+            sb.append(it.next().toString());
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static int size(NodeList self) {
+        return self.getLength();
+    }
+
+    public static boolean isEmpty(NodeList self) {
+        return size(self) == 0;
+    }
+
+    private static void addResult(List results, Object result) {
+        if (result != null) {
+            if (result instanceof Collection) {
+                results.addAll((Collection) result);
+            } else {
+                results.add(result);
+            }
+        }
+    }
+
+    private static class NodeListsHolder implements NodeList {
+        private List nodeLists;
+
+        private NodeListsHolder(List nodeLists) {
+            this.nodeLists = nodeLists;
+        }
+
+        public int getLength() {
+            int length = 0;
+            for (int i = 0; i < nodeLists.size(); i++) {
+                NodeList nl = (NodeList) nodeLists.get(i);
+                length += nl.getLength();
+            }
+            return length;
+        }
+
+        public Node item(int index) {
+            int relativeIndex = index;
+            for (int i = 0; i < nodeLists.size(); i++) {
+                NodeList nl = (NodeList) nodeLists.get(i);
+                if (relativeIndex < nl.getLength()) {
+                    return nl.item(relativeIndex);
+                }
+                relativeIndex -= nl.getLength();
+            }
+            return null;
+        }
+
+        public String toString() {
+            return DOMCategory.toString(this);
+        }
+    }
+
+    private static class NodesHolder implements NodeList {
+        private List nodes;
+
+        private NodesHolder(List nodes) {
+            this.nodes = nodes;
+        }
+
+        public int getLength() {
+            return nodes.size();
+        }
+
+        public Node item(int index) {
+            if (index < 0 || index >= getLength()) {
+                return null;
+            }
+            return (Node) nodes.get(index);
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/groovy/xml/package.html b/groovy-core/src/main/groovy/xml/package.html
new file mode 100644
index 0000000..9a636eb
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/package.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>package groovy.xml.*</title>
+  </head>
+  <body>
+    <p>Groovy markup builder classes for working with SAX and W3C DOM and Groovy markup.</p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/groovy/xml/streamingmarkupsupport/AbstractStreamingBuilder.groovy b/groovy-core/src/main/groovy/xml/streamingmarkupsupport/AbstractStreamingBuilder.groovy
new file mode 100644
index 0000000..3974597
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/streamingmarkupsupport/AbstractStreamingBuilder.groovy
@@ -0,0 +1,97 @@
+package groovy.xml.streamingmarkupsupport
+
+/*
+
+Copyright 2004 (C) John Wilson. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+	
+class AbstractStreamingBuilder {
+    def badTagClosure = {tag, doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, Object[] rest ->
+        def uri = pendingNamespaces[prefix]
+        if (uri == null) {
+            uri = namespaces[prefix]
+        }
+        throw new GroovyRuntimeException("Tag ${tag} is not allowed in namespace ${uri}")
+    }
+    def namespaceSetupClosure = {doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, Object[] rest ->
+        attrs.each { key, value ->
+            if ( key == "") {
+                key = ":"    // marker for default namespace
+            }
+            value = value.toString()     // in case it's not a string
+            if (namespaces[key] != value) {
+                pendingNamespaces[key] = value
+            }
+            if (!namespaceSpecificTags.containsKey(value)) {
+                def baseEntry = namespaceSpecificTags[':']
+                namespaceSpecificTags[value] = [baseEntry[0], baseEntry[1], [:]].toArray()
+            }
+        }
+    }
+    def aliasSetupClosure = {doc, pendingNamespaces, namespaces, namespaceSpecificTags, prefix, attrs, Object[] rest ->
+        attrs.each { key, value ->
+            if (value instanceof Map) {
+                // key is a namespace prefix value is the mapping
+                def info = null
+                if (namespaces.containsKey(key)) {
+                    info = namespaceSpecificTags[namespaces[key]]
+                } else if (pendingNamespaces.containsKey(key)) {
+                    info = namespaceSpecificTags[pendingNamespaces[key]]
+                } else {
+                    throw new GroovyRuntimeException("namespace prefix ${key} has not been declared")
+                }
+                value.each { to, from -> info[2][to] = info[1].curry(from) }
+            } else {
+                def info = namespaceSpecificTags[':']
+                info[2][key] = info[1].curry(value)
+            }
+        }
+    }
+    def getNamespaceClosure = {doc, pendingNamespaces, namespaces, Object[] rest -> [namespaces, pendingNamespaces]}
+
+    def specialTags = ['declareNamespace':namespaceSetupClosure,
+                           'declareAlias':aliasSetupClosure,
+                          'getNamespaces':getNamespaceClosure]
+
+    def builder = null
+}
diff --git a/groovy-core/src/main/groovy/xml/streamingmarkupsupport/BaseMarkupBuilder.java b/groovy-core/src/main/groovy/xml/streamingmarkupsupport/BaseMarkupBuilder.java
new file mode 100644
index 0000000..f6a2938
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/streamingmarkupsupport/BaseMarkupBuilder.java
@@ -0,0 +1,208 @@
+package groovy.xml.streamingmarkupsupport;
+/*
+
+Copyright 2004 (C) John Wilson. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyInterceptable;
+import groovy.lang.GroovyObjectSupport;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public class BaseMarkupBuilder extends Builder {
+	public BaseMarkupBuilder(final Map namespaceMethodMap) {
+		super(namespaceMethodMap);
+	}
+	
+	public Object bind(final Closure root) {
+		return new Document(root, this.namespaceMethodMap);
+	}
+	
+	private static class Document extends Built implements GroovyInterceptable {
+		private Object out;
+		private final Map pendingNamespaces = new HashMap();
+		private final Map namespaces = new HashMap();
+         private final Map specialProperties = new HashMap();
+		private String prefix = "";
+        
+        {
+            
+            namespaces.put("xml", "http://www.w3.org/XML/1998/namespace");             // built in namespace
+            namespaces.put("mkp", "http://www.codehaus.org/Groovy/markup/keywords");   // pseudo namespace for markup keywords
+            
+            specialProperties.put("out", new OutputSink("out") {
+                public Object leftShift(final Object value) {
+                    return leftShift("yield", value);
+                }
+            });
+            specialProperties.put("unescaped", new OutputSink("unescaped") {
+                public Object leftShift(final Object value) {
+                    return leftShift("yieldUnescaped", value);
+                }
+            });
+            specialProperties.put("namespaces", new OutputSink("namespaces") {
+                public Object leftShift(final Object value) {
+                    return leftShift("declareNamespace", value);
+                }
+            });
+            specialProperties.put("pi", new OutputSink("pi") {
+                public Object leftShift(final Object value) {
+                    return leftShift("pi", value);
+                }
+            });
+            specialProperties.put("comment", new OutputSink("comment") {
+                public Object leftShift(final Object value) {
+                    return leftShift("comment", value);
+                }
+            });
+        }
+        
+        private abstract class OutputSink extends GroovyObjectSupport {
+            private final String name;
+            
+            public OutputSink(final String name) {
+                this.name = name;
+            }
+            
+            public Object invokeMethod(final String name, final Object args) {
+                Document.this.prefix = this.name;
+                return Document.this.invokeMethod(name, args);
+            }
+            
+            public abstract Object leftShift(Object item);
+            
+            protected Object leftShift(final String command, final Object value) {
+                Document.this.getProperty("mkp");
+                Document.this.invokeMethod(command, new Object[]{value});
+                return this;
+            }
+        }
+		
+		public Document(final Closure root, final Map namespaceMethodMap) {
+			super(root, namespaceMethodMap);
+		}
+		
+		/* (non-Javadoc)
+		 * @see groovy.lang.GroovyObject#invokeMethod(java.lang.String, java.lang.Object)
+		 */
+		public Object invokeMethod(final String name, final Object args) {
+			final Object[] arguments = (Object[]) args;
+			Map attrs = Collections.EMPTY_MAP;
+			Object body = null;
+			
+			
+			//
+			// Sort the parameters out
+			//
+			for (int i = 0; i != arguments.length; i++) {
+				final Object arg = arguments[i];
+				
+				if (arg instanceof Map) {
+					attrs = (Map)arg;
+				} else if (arg instanceof Closure) {
+					final Closure c = ((Closure) arg);
+					
+					c.setDelegate(this);
+					body = c.asWritable();
+				} else {
+					body = arg;
+				}
+			}
+			
+			//
+			// call the closure corresponding to the tag
+			//
+			final Object uri;
+			
+			if (this.pendingNamespaces.containsKey(this.prefix)) {
+				uri = this.pendingNamespaces.get(this.prefix);
+			} else if (this.namespaces.containsKey(this.prefix)) {
+				uri = this.namespaces.get(this.prefix);
+			} else {
+				uri = ":";
+			}
+			
+			final Object[] info  = (Object[])this.namespaceSpecificTags.get(uri);
+			final Map tagMap = (Map)info[2];
+			final Closure defaultTagClosure = (Closure)info[0];
+			
+			final String prefix = this.prefix;
+			this.prefix = "";
+			
+			if (tagMap.containsKey(name)) {
+				return ((Closure)tagMap.get(name)).call(new Object[]{this, this.pendingNamespaces, this.namespaces, this.namespaceSpecificTags, prefix, attrs, body, this.out});
+			} else {
+				return defaultTagClosure.call(new Object[]{name, this, this.pendingNamespaces, this.namespaces, this.namespaceSpecificTags, prefix, attrs, body, this.out});		
+			}
+		}
+		
+		/* (non-Javadoc)
+		 * @see groovy.lang.GroovyObject#getProperty(java.lang.String)
+		 */
+		public Object getProperty(final String property) {
+        final Object special = this.specialProperties.get(property);
+        
+            if (special == null) {
+        			this.prefix = property;
+        			return this;
+            } else {
+                return special;
+            }
+		}
+		
+		/* (non-Javadoc)
+		 * @see groovy.lang.GroovyObject#setProperty(java.lang.String, java.lang.Object)
+		 */
+		public void setProperty(String property, Object newValue) {
+			if ("trigger".equals(property)) {
+				this.out = newValue;
+				this.root.call(this);
+			} else {
+				super.setProperty(property, newValue);
+			}
+		}
+	}
+}
diff --git a/groovy-core/src/main/groovy/xml/streamingmarkupsupport/Builder.java b/groovy-core/src/main/groovy/xml/streamingmarkupsupport/Builder.java
new file mode 100644
index 0000000..442a5b1
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/streamingmarkupsupport/Builder.java
@@ -0,0 +1,102 @@
+package groovy.xml.streamingmarkupsupport;
+/*
+
+Copyright 2004 (C) John Wilson. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyObjectSupport;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public abstract class Builder extends GroovyObjectSupport {
+	protected final Map namespaceMethodMap = new HashMap();
+	
+	public Builder(final Map namespaceMethodMap) {
+	final Iterator keyIterator = namespaceMethodMap.keySet().iterator();
+		
+		while (keyIterator.hasNext()) {
+		final Object key = keyIterator.next();
+		final List value = (List)namespaceMethodMap.get(key);
+		final Closure dg = ((Closure)value.get(1)).asWritable();
+		
+			this.namespaceMethodMap.put(key, new Object[]{value.get(0), dg, fettleMethodMap(dg, (Map)value.get(2))});
+		}
+	}
+	
+	private static Map fettleMethodMap(final Closure defaultGenerator, final Map methodMap) {
+	final Map newMethodMap = new HashMap();
+	final Iterator keyIterator = methodMap.keySet().iterator();
+		
+		while (keyIterator.hasNext()) {
+		final Object key = keyIterator.next();
+		final Object value = methodMap.get(key);
+		
+			if ((value instanceof Closure)) {
+				newMethodMap.put(key, value);
+			} else {
+				newMethodMap.put(key, defaultGenerator.curry((Object[])value));
+			}
+		}
+		
+		return newMethodMap;
+	}
+	
+	abstract public Object bind(Closure root);
+	
+	protected static abstract class Built extends GroovyObjectSupport {
+	protected final Closure root;
+	protected final Map namespaceSpecificTags = new HashMap();
+		
+		public Built(final Closure root, final Map namespaceTagMap) {
+			this.namespaceSpecificTags.putAll(namespaceTagMap);
+		
+			this.root = (Closure)root.clone();
+			
+			this.root.setDelegate(this);
+		}
+	}
+}
diff --git a/groovy-core/src/main/groovy/xml/streamingmarkupsupport/StreamingMarkupWriter.java b/groovy-core/src/main/groovy/xml/streamingmarkupsupport/StreamingMarkupWriter.java
new file mode 100644
index 0000000..2024cff
--- /dev/null
+++ b/groovy-core/src/main/groovy/xml/streamingmarkupsupport/StreamingMarkupWriter.java
@@ -0,0 +1,230 @@
+package groovy.xml.streamingmarkupsupport;
+/*
+
+Copyright 2004 (C) John Wilson. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+
+public class StreamingMarkupWriter extends Writer {
+	protected final Writer writer;
+    protected final String encoding;
+    protected final CharsetEncoder encoder;
+	private final Writer bodyWriter =  new Writer() {
+											/* (non-Javadoc)
+											 * @see java.io.Writer#close()
+											 */
+											public void close() throws IOException {
+												StreamingMarkupWriter.this.close();
+											}
+											
+											/* (non-Javadoc)
+											 * @see java.io.Writer#flush()
+											 */
+											public void flush() throws IOException {
+												StreamingMarkupWriter.this.flush();
+											}
+		
+											/* (non-Javadoc)
+											 * @see java.io.Writer#write(int)
+											 */
+											public void write(final int c) throws IOException {
+												if (!StreamingMarkupWriter.this.encoder.canEncode((char)c)) {
+													StreamingMarkupWriter.this.writer.write("&#x");
+													StreamingMarkupWriter.this.writer.write(Integer.toHexString(c));
+													StreamingMarkupWriter.this.writer.write(';');
+												} else if (c == '<') {
+													StreamingMarkupWriter.this.writer.write("&lt;");
+												} else if (c == '>') {
+													StreamingMarkupWriter.this.writer.write("&gt;");
+												} else if (c == '&') {
+													StreamingMarkupWriter.this.writer.write("&amp;");
+												} else {
+													StreamingMarkupWriter.this.writer.write(c);
+												}
+											}
+											
+											/* (non-Javadoc)
+											 * @see java.io.Writer#write(char[], int, int)
+											 */
+											public void write(final char[] cbuf, int off, int len) throws IOException {
+												while (len-- > 0){
+													write(cbuf[off++]);
+												}
+											}
+											
+											public Writer attributeValue() {
+												return StreamingMarkupWriter.this.attributeWriter;
+											}
+											
+											public Writer bodyText() {
+												return bodyWriter;
+											}
+											
+											public Writer unescaped() {
+												return StreamingMarkupWriter.this;
+											}
+										};
+	
+	private final Writer attributeWriter =  new Writer() {
+												/* (non-Javadoc)
+												 * @see java.io.Writer#close()
+												 */
+												public void close() throws IOException {
+													StreamingMarkupWriter.this.close();
+												}
+										
+												/* (non-Javadoc)
+												 * @see java.io.Writer#flush()
+												 */
+												public void flush() throws IOException {
+													StreamingMarkupWriter.this.flush();
+												}
+		
+												/* (non-Javadoc)
+												 * @see java.io.Writer#write(int)
+												 */
+												public void write(final int c) throws IOException {
+													if (c == '\'') {
+														StreamingMarkupWriter.this.writer.write("&apos;");
+													} else {
+														StreamingMarkupWriter.this.bodyWriter.write(c);
+													}
+												}
+												
+												/* (non-Javadoc)
+												 * @see java.io.Writer#write(char[], int, int)
+												 */
+												public void write(final char[] cbuf, int off, int len) throws IOException {
+													while (len-- > 0){
+														write(cbuf[off++]);
+													}
+												}
+												
+												public Writer attributeValue() {
+													return attributeWriter;
+												}
+												
+												public Writer bodyText() {
+													return StreamingMarkupWriter.this.bodyWriter;
+												}
+												
+												public Writer unescaped() {
+													return StreamingMarkupWriter.this;
+												}
+											};
+
+    public StreamingMarkupWriter(final Writer writer, final String encoding) {
+        this.writer = writer;
+        
+        if (encoding != null) {
+            this.encoding = encoding;
+        } else if (writer instanceof OutputStreamWriter) {
+            this.encoding = ((OutputStreamWriter)writer).getEncoding();
+        } else {
+            this.encoding = "US-ASCII";
+        }
+        
+        this.encoder = Charset.forName(this.encoding).newEncoder();
+    }
+    
+    public StreamingMarkupWriter(final Writer writer) {
+        this(writer, null);
+    }
+    
+    /* (non-Javadoc)
+     * @see java.io.Writer#close()
+     */
+    public void close() throws IOException {
+        this.writer.close();
+    }
+    
+    /* (non-Javadoc)
+     * @see java.io.Writer#flush()
+     */
+    public void flush() throws IOException {
+        this.writer.flush();
+    }
+    
+    /* (non-Javadoc)
+     * @see java.io.Writer#write(int)
+     */
+    public void write(final int c) throws IOException {
+        if (!this.encoder.canEncode((char)c)) {
+            this.writer.write("&#x");
+            this.writer.write(Integer.toHexString(c));
+            this.writer.write(';');
+        } else {
+            this.writer.write(c);
+        }
+    }
+    
+    /* (non-Javadoc)
+     * @see java.io.Writer#write(char[], int, int)
+     */
+    public void write(final char[] cbuf, int off, int len) throws IOException {
+        while (len-- > 0){
+            write(cbuf[off++]);
+        }
+    }
+    
+    public Writer attributeValue() {
+        return this.attributeWriter;
+    }
+    
+    public Writer bodyText() {
+        return this.bodyWriter;
+    }
+    
+    public Writer unescaped() {
+        return this;
+    }
+    
+    public String getEncoding() {
+        return this.encoding;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/GroovyBugError.java b/groovy-core/src/main/org/codehaus/groovy/GroovyBugError.java
new file mode 100644
index 0000000..7f81e1b
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/GroovyBugError.java
@@ -0,0 +1,138 @@
+/*
+$Id$
+
+Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+package org.codehaus.groovy;
+
+/**
+ * This class represents an error that is thrown when a bug is 
+ * recognized inside the runtime. Basically it is thrown when
+ * a constraint is not fullfilled that should be fullfiled. 
+ * 
+ * @author Jochen Theodorou
+ */
+public class GroovyBugError extends AssertionError {
+    
+    // message string
+    private String    message;
+    // optional exception
+    private Exception exception;
+
+    /**
+     * constructs a bug error using the given text
+     * @param message the error message text
+     */
+    public GroovyBugError( String message ) {
+        this.message = message;
+    }
+    
+    /**
+     * Constructs a bug error using the given exception
+     * @param exception cause of this error
+     */
+    public GroovyBugError( Exception exception ) {
+        this.exception = exception;
+    }
+    
+    /**
+     * Constructs a bug error using the given exception and
+     * a text with additional information about the cause 
+     * @param msg additional information about this error
+     * @param exception cause of this error
+     */
+    public GroovyBugError( String msg, Exception exception )
+    {
+        this.exception = exception;
+        this.message = msg;
+    }
+
+    /**
+     * Returns a String representation of this class by calling <code>getMessage()</code>.  
+     * @see #getMessage()
+     */
+    public String toString() {
+        return getMessage();
+    }
+    
+    /**
+     * Returns the detail message string of this error. The message 
+     * will consist of the bug text prefixed by "BUG! " if there this
+     * isntance was created using a message. If this error was 
+     * constructed without using a bug text the message of the cause 
+     * is used prefixed by "BUG! UNCAUGHT EXCEPTION: "
+     *  
+     * @return the detail message string of this error.
+     */
+    public String getMessage() {
+        if( message != null )
+        {
+            return "BUG! "+message;
+        }
+        else
+        {
+            return "BUG! UNCAUGHT EXCEPTION: " + exception.getMessage();
+        }
+    }
+    
+    public Throwable getCause() {
+        return this.exception;
+    }    
+    
+    /**
+     * Returns the bug text to describe this error
+     */
+    public String getBugText(){
+        if( message != null ){
+            return message;
+        } else {
+            return exception.getMessage();
+        }
+    }
+    
+    /**
+     * Sets the bug text to describe this error
+     */
+    public void setBugText(String msg) {
+        this.message = msg;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/GroovyException.java b/groovy-core/src/main/org/codehaus/groovy/GroovyException.java
new file mode 100644
index 0000000..7355ff6
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/GroovyException.java
@@ -0,0 +1,79 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy;
+
+public class GroovyException extends Exception implements GroovyExceptionInterface {
+    private boolean fatal = true;
+
+    public GroovyException() {
+    }
+
+    public GroovyException(String message) {
+        super(message);
+    }
+
+    public GroovyException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public GroovyException(boolean fatal) {
+        super();
+        this.fatal = fatal;
+    }
+
+    public GroovyException(String message, boolean fatal) {
+        super(message);
+        this.fatal = fatal;
+    }
+
+    public boolean isFatal() {
+        return fatal;
+    }
+
+    public void setFatal(boolean fatal) {
+        this.fatal = fatal;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/GroovyExceptionInterface.java b/groovy-core/src/main/org/codehaus/groovy/GroovyExceptionInterface.java
new file mode 100644
index 0000000..892864b
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/GroovyExceptionInterface.java
@@ -0,0 +1,58 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy;
+
+/**
+ *  An interface for use by all Groovy compiler exceptions.
+ */
+
+public interface GroovyExceptionInterface {
+
+    public boolean isFatal();
+
+    public void setFatal( boolean fatal );
+    
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ant/AntProjectPropertiesDelegate.java b/groovy-core/src/main/org/codehaus/groovy/ant/AntProjectPropertiesDelegate.java
new file mode 100644
index 0000000..9b726c6
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ant/AntProjectPropertiesDelegate.java
@@ -0,0 +1,165 @@
+/*
+ $Id$
+
+ Copyright 2005 (C) Guillaume Laforge. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.ant;
+
+import org.apache.tools.ant.Project;
+
+import java.util.Hashtable;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.Set;
+import java.util.Iterator;
+
+/**
+ * @author Guillaume Laforge
+ */
+public class AntProjectPropertiesDelegate extends Hashtable {
+
+    private Project project;
+
+    public AntProjectPropertiesDelegate(Project project) {
+        super();
+        this.project = project;
+    }
+
+    public synchronized int hashCode() {
+        return project.getProperties().hashCode();
+    }
+
+    public synchronized int size() {
+        return project.getProperties().size();
+    }
+
+    /**
+     * @throws UnsupportedOperationException is always thrown when this method is invoked. The Project properties are immutable.
+     */    
+    public synchronized void clear() {
+        throw new UnsupportedOperationException("Impossible to clear the project properties.");
+    }
+
+    public synchronized boolean isEmpty() {
+        return project.getProperties().isEmpty();
+    }
+
+    public synchronized Object clone() {
+        return project.getProperties().clone();
+    }
+
+    public synchronized boolean contains(Object value) {
+        return project.getProperties().contains(value);
+    }
+
+    public synchronized boolean containsKey(Object key) {
+        return project.getProperties().containsKey(key);
+    }
+
+    public boolean containsValue(Object value) {
+        return project.getProperties().containsValue(value);
+    }
+
+    public synchronized boolean equals(Object o) {
+        return project.getProperties().equals(o);
+    }
+
+    public synchronized String toString() {
+        return project.getProperties().toString();
+    }
+
+    public Collection values() {
+        return project.getProperties().values();
+    }
+
+    public synchronized Enumeration elements() {
+        return project.getProperties().elements();
+    }
+
+    public synchronized Enumeration keys() {
+        return project.getProperties().keys();
+    }
+
+    public AntProjectPropertiesDelegate(Map t) {
+        super(t);
+    }
+
+    public synchronized void putAll(Map t) {
+        Set keySet = t.keySet();
+        for (Iterator iterator = keySet.iterator(); iterator.hasNext();) {
+            Object key = iterator.next();
+            Object value = t.get(key);
+            put(key, value);
+        }
+    }
+
+    public Set entrySet() {
+        return project.getProperties().entrySet();
+    }
+
+    public Set keySet() {
+        return project.getProperties().keySet();
+    }
+
+    public synchronized Object get(Object key) {
+        return project.getProperties().get(key);
+    }
+
+    /**
+     * @throws UnsupportedOperationException is always thrown when this method is invoked. The Project properties are immutable.
+     */
+    public synchronized Object remove(Object key) {
+        throw new UnsupportedOperationException("Impossible to remove a property from the project properties.");
+    }
+
+    public synchronized Object put(Object key, Object value) {
+        Object oldValue = null;
+        if (containsKey(key)) {
+            oldValue = get(key);
+        }
+        project.setProperty(key.toString(), value.toString());
+        return oldValue;
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/org/codehaus/groovy/ant/FileIterator.java b/groovy-core/src/main/org/codehaus/groovy/ant/FileIterator.java
new file mode 100644
index 0000000..524fc4c
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ant/FileIterator.java
@@ -0,0 +1,194 @@
+/*
+ * $Header$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowlegement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowlegement may appear in the software itself,
+ *    if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ * 
+ * $Id$
+ */
+package org.codehaus.groovy.ant;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.FileSet;
+
+/** 
+ * <p><code>FileIterator</code> is an iterator over a 
+ * over a number of files from a colleciton of FileSet instances.
+ *
+ * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
+ * @version $Revision$
+ */
+public class FileIterator implements Iterator {
+
+    /** The iterator over the FileSet objects */
+    private Iterator fileSetIterator;
+    
+    /** The Ant project */
+    private Project project;
+    
+    /** The directory scanner */
+    private DirectoryScanner ds;
+    
+    /** The file names in the current FileSet scan */
+    private String[] files;
+    
+    /** The current index into the file name array */
+    private int fileIndex = -1;
+    
+    /** The next File object we'll iterate over */
+    private File nextFile;
+
+    /** Have we set a next object? */
+    private boolean nextObjectSet = false;
+
+    /** Return only directories? */
+    private boolean iterateDirectories = false;
+
+    public FileIterator(Project project,
+                        Iterator fileSetIterator) {
+        this( project, fileSetIterator, false);
+    }
+
+    public FileIterator(Project project,
+                        Iterator fileSetIterator,
+                        boolean iterateDirectories) {
+        this.project = project;
+        this.fileSetIterator = fileSetIterator;
+        this.iterateDirectories = iterateDirectories;
+    }
+    
+    // Iterator interface
+    //-------------------------------------------------------------------------
+    
+    /** @return true if there is another object that matches the given predicate */
+    public boolean hasNext() {
+        if ( nextObjectSet ) {
+            return true;
+        } 
+        else {
+            return setNextObject();
+        }
+    }
+
+    /** @return the next object which matches the given predicate */
+    public Object next() {
+        if ( !nextObjectSet ) {
+            if (!setNextObject()) {
+                throw new NoSuchElementException();
+            }
+        }
+        nextObjectSet = false;
+        return nextFile;
+    }
+    
+    /**
+     * throws UnsupportedOperationException 
+     */
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+    // Implementation methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Set nextObject to the next object. If there are no more 
+     * objects then return false. Otherwise, return true.
+     */
+    private boolean setNextObject() {
+        while (true) {
+            while (ds == null) {
+                if ( ! fileSetIterator.hasNext() ) {
+                    return false;
+                }
+                FileSet fs = (FileSet) fileSetIterator.next();
+                ds = fs.getDirectoryScanner(project);
+                ds.scan();
+                if (iterateDirectories) {
+                    files = ds.getIncludedDirectories();
+                } 
+                else {
+                    files = ds.getIncludedFiles();
+                }
+                if ( files.length > 0 ) {
+                    fileIndex = -1;
+                    break;
+                }
+                else {
+                    ds = null;
+                }
+            }
+        
+            if ( ds != null && files != null ) {
+                if ( ++fileIndex < files.length ) {
+                    nextFile = new File( ds.getBasedir(), files[fileIndex] );
+                    nextObjectSet = true;
+                    return true;
+                }
+                else {
+                    ds = null;
+                }
+            }
+        }
+    }
+}
+
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/ant/FileScanner.java b/groovy-core/src/main/org/codehaus/groovy/ant/FileScanner.java
new file mode 100644
index 0000000..d4c01e7
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ant/FileScanner.java
@@ -0,0 +1,121 @@
+/*
+ * $Header$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ *    any, must include the following acknowlegement:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowlegement may appear in the software itself,
+ *    if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ *    Foundation" must not be used to endorse or promote products derived
+ *    from this software without prior written permission. For written
+ *    permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ *    nor may "Apache" appear in their names without prior written
+ *    permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ * 
+ * $Id$
+ */
+package org.codehaus.groovy.ant;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+
+/** 
+ * <p><code>FileScanner</code> is a bean which allows the iteration
+ * over a number of files from a colleciton of FileSet instances.
+ *
+ * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
+ * @author Marc Guillemot
+ * @version $Revision$
+ */
+public class FileScanner extends Task {
+
+    /** FileSets */
+    private List filesets = new ArrayList();
+
+    public FileScanner() {
+    }
+    
+    public FileScanner(final Project project) {
+        setProject(project);
+    }
+    
+    public Iterator iterator() {
+        return new FileIterator(getProject(), filesets.iterator());
+    }
+
+    public Iterator directories() {
+        return new FileIterator(getProject(), filesets.iterator(), true);
+    }
+
+    public boolean hasFiles() {
+        return filesets.size() > 0;
+    }
+
+    /**
+     * Clears any file sets that have been added to this scanner
+     */
+    public void clear() {
+        filesets.clear();
+    }
+
+    // Properties
+    //-------------------------------------------------------------------------
+
+    /**
+     * Adds a set of files (nested fileset attribute).
+     */
+    public void addFileset(FileSet set) {
+        filesets.add(set);
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ant/Groovy.java b/groovy-core/src/main/org/codehaus/groovy/ant/Groovy.java
new file mode 100644
index 0000000..f8f9b8e
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ant/Groovy.java
@@ -0,0 +1,404 @@
+/*
+ $Id$
+
+ Copyright 2005 (C) Jeremy Rayner. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.ant;
+
+import groovy.lang.Binding;
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyShell;
+import groovy.lang.Script;
+import groovy.util.AntBuilder;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.lang.reflect.Field;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.tools.ErrorReporter;
+
+/**
+ * Executes a series of Groovy statements.
+ *
+ * <p>Statements can
+ * either be read in from a text file using the <i>src</i> attribute or from
+ * between the enclosing groovy tags.</p>
+ */
+public class Groovy extends Task {
+    /**
+     * files to load
+     */
+    private Vector filesets = new Vector();
+
+    /**
+     * input file
+     */
+    private File srcFile = null;
+
+    /**
+     * input command
+     */
+    private String command = "";
+
+    /**
+     * Results Output file.
+     */
+    private File output = null;
+
+    /**
+     * Append to an existing file or overwrite it?
+     */
+    private boolean append = false;
+
+    private Path classpath;
+
+    /**
+     * Compiler configuration.
+     *
+     * Used to specify the debug output to print stacktraces in case something fails.
+     * TODO: Could probably be reused to specify the encoding of the files to load or other properties.
+     */
+    private CompilerConfiguration configuration = new CompilerConfiguration();
+
+    /**
+     * Enable compiler to report stack trace information if a problem occurs
+     * during compilation.
+     * @param stacktrace
+     */
+    public void setStacktrace(boolean stacktrace) {
+        configuration.setDebug(stacktrace);
+    }
+
+
+    /**
+     * Set the name of the file to be run. The folder of the file is automatically added to the classpath.
+     * Required unless statements are enclosed in the build file
+     */
+    public void setSrc(final File srcFile) {
+        this.srcFile = srcFile;
+    }
+
+    /**
+     * Set an inline command to execute.
+     * NB: Properties are not expanded in this text.
+     */
+    public void addText(String txt) {
+        log("addText('"+txt+"')", Project.MSG_VERBOSE);
+        this.command += txt;
+    }
+
+    /**
+     * Adds a set of files (nested fileset attribute).
+     */
+    public void addFileset(FileSet set) {
+        filesets.addElement(set);
+    }
+
+    /**
+     * Set the output file;
+     * optional, defaults to the Ant log.
+     */
+    public void setOutput(File output) {
+        this.output = output;
+    }
+
+    /**
+     * whether output should be appended to or overwrite
+     * an existing file.  Defaults to false.
+     *
+     * @since Ant 1.5
+     */
+    public void setAppend(boolean append) {
+        this.append = append;
+    }
+
+
+    /**
+     * Sets the classpath for loading.
+     * @param classpath The classpath to set
+     */
+    public void setClasspath(final Path classpath) {
+        this.classpath = classpath;
+    }
+
+    /**
+     * Returns a new path element that can be configured.
+     * Gets called for instance by Ant when it encounters a nested <classpath> element. 
+     */
+    public Path createClasspath() {
+        if (this.classpath == null) {
+            this.classpath = new Path(getProject());
+        }
+        return this.classpath.createPath();
+    }
+
+    /**
+     * Set the classpath for loading
+     * using the classpath reference.
+     */
+    public void setClasspathRef(final Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * Gets the classpath.
+     * @return Returns a Path
+     */
+    public Path getClasspath() {
+        return classpath;
+    }
+
+    /**
+     * Load the file and then execute it
+     */
+    public void execute() throws BuildException {
+        log("execute()", Project.MSG_VERBOSE);
+
+        command = command.trim();
+
+        if (srcFile == null && command.length() == 0
+            && filesets.isEmpty()) {
+            throw new BuildException("Source file does not exist!", getLocation());
+        }
+
+        if (srcFile != null && !srcFile.exists()) {
+            throw new BuildException("Source file does not exist!", getLocation());
+        }
+
+        // deal with the filesets
+        for (int i = 0; i < filesets.size(); i++) {
+            FileSet fs = (FileSet) filesets.elementAt(i);
+            DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+            File srcDir = fs.getDir(getProject());
+
+            String[] srcFiles = ds.getIncludedFiles();
+        }
+
+        try {
+            PrintStream out = System.out;
+            try {
+                if (output != null) {
+                    log("Opening PrintStream to output file " + output,
+                        Project.MSG_VERBOSE);
+                    out = new PrintStream(
+                              new BufferedOutputStream(
+                                  new FileOutputStream(output
+                                                       .getAbsolutePath(),
+                                                       append)));
+                }
+
+                // if there are no groovy statements between the enclosing Groovy tags
+                // then read groovy statements in from a text file using the src attribute
+                if (command == null || command.trim().length() == 0) {
+                	createClasspath().add(new Path(getProject(), srcFile.getParentFile().getCanonicalPath()));
+                    command = getText(new BufferedReader(new FileReader(srcFile)));
+                }
+
+
+                if (command != null) {
+                    execGroovy(command,out);
+                } else {
+                    throw new BuildException("Source file does not exist!", getLocation());
+                }
+
+            } finally {
+                if (out != null && out != System.out) {
+                    out.close();
+                }
+            }
+        } catch (IOException e) {
+            throw new BuildException(e, getLocation());
+        }
+
+        log("statements executed successfully", Project.MSG_VERBOSE);
+    }
+
+
+    private static String getText(BufferedReader reader) throws IOException {
+        StringBuffer answer = new StringBuffer();
+        // reading the content of the file within a char buffer allow to keep the correct line endings
+        char[] charBuffer = new char[4096];
+        int nbCharRead = 0;
+        while ((nbCharRead = reader.read(charBuffer)) != -1) {
+            // appends buffer
+            answer.append(charBuffer, 0, nbCharRead);
+        }
+        reader.close();
+        return answer.toString();
+    }
+
+
+    /**
+     * read in lines and execute them
+     */
+    protected void runStatements(Reader reader, PrintStream out)
+        throws IOException {
+        log("runStatements()", Project.MSG_VERBOSE);
+
+        StringBuffer txt = new StringBuffer();
+        String line = "";
+
+        BufferedReader in = new BufferedReader(reader);
+
+        while ((line = in.readLine()) != null) {
+            line = getProject().replaceProperties(line);
+
+            if (line.indexOf("--") >= 0) {
+                txt.append("\n");
+            }
+        }
+        // Catch any statements not followed by ;
+        if (!txt.equals("")) {
+            execGroovy(txt.toString(), out);
+        }
+    }
+
+
+    /**
+     * Exec the statement.
+     */
+    protected void execGroovy(final String txt, final PrintStream out) {
+        log("execGroovy()", Project.MSG_VERBOSE);
+
+        // Check and ignore empty statements
+        if ("".equals(txt.trim())) {
+            return;
+        }
+
+        log("Groovy: " + txt, Project.MSG_VERBOSE);
+
+        //log(getClasspath().toString(),Project.MSG_VERBOSE);
+        Object mavenPom = null;
+        final Project project = getProject();
+        final ClassLoader baseClassLoader;
+        // treat the case Ant is run through Maven, and
+        if ("org.apache.commons.grant.GrantProject".equals(project.getClass().getName())) {
+            try {
+               final Object propsHandler = project.getClass().getMethod("getPropsHandler", new Class[0]).invoke(project, new Object[0]);
+               final Field contextField = propsHandler.getClass().getDeclaredField("context");
+               contextField.setAccessible(true);
+               final Object context = contextField.get(propsHandler);
+               mavenPom = InvokerHelper.invokeMethod(context, "getProject", new Object[0]);
+            }
+            catch (Exception e) {
+                throw new BuildException("Impossible to retrieve Maven's Ant project: " + e.getMessage(), getLocation());
+            }
+            // let ASM lookup "root" classloader
+            Thread.currentThread().setContextClassLoader(GroovyShell.class.getClassLoader());
+            // load groovy into "root.maven" classloader instead of "root" so that
+            // groovy script can access Maven classes
+            baseClassLoader = mavenPom.getClass().getClassLoader();
+        } else {
+            baseClassLoader = GroovyShell.class.getClassLoader();
+        }
+
+        final GroovyClassLoader classLoader = new GroovyClassLoader(baseClassLoader);
+        addClassPathes(classLoader);
+        
+        final GroovyShell groovy = new GroovyShell(classLoader, new Binding(), configuration);
+        try {
+            final Script script = groovy.parse(txt);
+            script.setProperty("ant", new AntBuilder(project, getOwningTarget()));
+            script.setProperty("project", project);
+            script.setProperty("properties", new AntProjectPropertiesDelegate(project));
+            script.setProperty("target", getOwningTarget());
+            script.setProperty("task", this);
+            if (mavenPom != null) {
+                script.setProperty("pom", mavenPom);
+            }
+            script.run();
+        } catch (CompilationFailedException e) {
+            StringWriter writer = new StringWriter();
+            new ErrorReporter( e, false ).write( new PrintWriter(writer) );
+            String message = writer.toString();
+            throw new BuildException("Script Failed: "+ message, getLocation());
+        }
+    }
+
+
+	/**
+	 * Adds the class pathes (if any)
+	 * @param classLoader the classloader to configure
+	 */
+	protected void addClassPathes(final GroovyClassLoader classLoader)
+	{
+		if (classpath != null)
+		{
+			for (int i = 0; i < classpath.list().length; i++)
+			{
+	            classLoader.addClasspath(classpath.list()[i]);
+			}
+		}
+	}
+
+    /**
+     * print any results in the statement.
+     */
+    protected void printResults(PrintStream out) {
+        log("printResults()", Project.MSG_VERBOSE);
+        StringBuffer line = new StringBuffer();
+        out.println(line);
+        line = new StringBuffer();
+        out.println();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ant/Groovyc.java b/groovy-core/src/main/org/codehaus/groovy/ant/Groovyc.java
new file mode 100644
index 0000000..da38095
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ant/Groovyc.java
@@ -0,0 +1,517 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ant;
+
+import groovy.lang.GroovyClassLoader;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.charset.Charset;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.listener.AnsiColorLogger;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.GlobPatternMapper;
+import org.apache.tools.ant.util.SourceFileScanner;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.tools.ErrorReporter;
+
+
+/**
+ * Compiles Groovy source files. This task can take the following
+ * arguments:
+ * <ul>
+ * <li>sourcedir
+ * <li>destdir
+ * <li>classpath
+ * <li>stacktrace
+ * </ul>
+ * Of these arguments, the <b>sourcedir</b> and <b>destdir</b> are required.
+ * <p>
+ * When this task executes, it will recursively scan the sourcedir and
+ * destdir looking for Groovy source files to compile. This task makes its
+ * compile decision based on timestamp.
+ * 
+ * Based heavily on the Javac implementation in Ant
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Hein Meling
+ * @version $Revision$ 
+ */
+public class Groovyc extends MatchingTask {
+
+    private CompilerConfiguration configuration = new CompilerConfiguration();
+    private Path src;
+    private File destDir;
+    private Path compileClasspath;
+    private Path compileSourcepath;
+    private String encoding;
+
+    protected boolean failOnError = true;
+    protected boolean listFiles = false;
+    protected File[] compileList = new File[0];
+
+    public static void main(String[] args) {
+        String dest = ".";
+        String src = ".";
+        boolean listFiles = false;
+        if (args.length > 0) {
+            dest = args[0];
+        }
+        if (args.length > 1) {
+            src = args[1];
+        }
+        if (args.length > 2) {
+            String flag = args[2];
+            if (flag.equalsIgnoreCase("true")) {
+                listFiles = true;
+            }
+        }
+
+        Project project = new Project();
+        project.addBuildListener(new AnsiColorLogger());
+
+        Groovyc compiler = new Groovyc();
+        compiler.setProject(project);
+        compiler.setSrcdir(new Path(project, src));
+        compiler.setDestdir(project.resolveFile(dest));
+        compiler.setListfiles(listFiles);
+        compiler.execute();
+    }
+
+    public Groovyc() {
+    }
+
+    /**
+     * Adds a path for source compilation.
+     *
+     * @return a nested src element.
+     */
+    public Path createSrc() {
+        if (src == null) {
+            src = new Path(getProject());
+        }
+        return src.createPath();
+    }
+
+    /**
+     * Recreate src.
+     *
+     * @return a nested src element.
+     */
+    protected Path recreateSrc() {
+        src = null;
+        return createSrc();
+    }
+
+    /**
+     * Set the source directories to find the source Java files.
+     * @param srcDir the source directories as a path
+     */
+    public void setSrcdir(Path srcDir) {
+        if (src == null) {
+            src = srcDir;
+        }
+        else {
+            src.append(srcDir);
+        }
+    }
+
+    /**
+     * Gets the source dirs to find the source java files.
+     * @return the source directorys as a path
+     */
+    public Path getSrcdir() {
+        return src;
+    }
+
+    /**
+     * Set the destination directory into which the Java source
+     * files should be compiled.
+     * @param destDir the destination director
+     */
+    public void setDestdir(File destDir) {
+        this.destDir = destDir;
+    }
+
+    /**
+     * Enable verbose compiling which will display which files
+     * are being compiled
+     * @param verbose
+     */
+    public void setVerbose(boolean verbose) {
+        configuration.setVerbose( verbose );
+    }
+
+    /**
+     * Enable compiler to report stack trace information if a problem occurs
+     * during compilation.
+     * @param stacktrace
+     */
+    public void setStacktrace(boolean stacktrace) {
+        configuration.setDebug(stacktrace);
+    }
+
+    /**
+     * Gets the destination directory into which the java source files
+     * should be compiled.
+     * @return the destination directory
+     */
+    public File getDestdir() {
+        return destDir;
+    }
+
+    /**
+     * Set the sourcepath to be used for this compilation.
+     * @param sourcepath the source path
+     */
+    public void setSourcepath(Path sourcepath) {
+        if (compileSourcepath == null) {
+            compileSourcepath = sourcepath;
+        }
+        else {
+            compileSourcepath.append(sourcepath);
+        }
+    }
+
+    /**
+     * Gets the sourcepath to be used for this compilation.
+     * @return the source path
+     */
+    public Path getSourcepath() {
+        return compileSourcepath;
+    }
+
+    /**
+     * Adds a path to sourcepath.
+     * @return a sourcepath to be configured
+     */
+    public Path createSourcepath() {
+        if (compileSourcepath == null) {
+            compileSourcepath = new Path(getProject());
+        }
+        return compileSourcepath.createPath();
+    }
+
+    /**
+     * Adds a reference to a source path defined elsewhere.
+     * @param r a reference to a source path
+     */
+    public void setSourcepathRef(Reference r) {
+        createSourcepath().setRefid(r);
+    }
+
+    /**
+     * Set the classpath to be used for this compilation.
+     *
+     * @param classpath an Ant Path object containing the compilation classpath.
+     */
+    public void setClasspath(Path classpath) {
+        if (compileClasspath == null) {
+            compileClasspath = classpath;
+        }
+        else {
+            compileClasspath.append(classpath);
+        }
+    }
+
+    /**
+     * Gets the classpath to be used for this compilation.
+     * @return the class path
+     */
+    public Path getClasspath() {
+        return compileClasspath;
+    }
+
+    /**
+     * Adds a path to the classpath.
+     * @return a class path to be configured
+     */
+    public Path createClasspath() {
+        if (compileClasspath == null) {
+            compileClasspath = new Path(getProject());
+        }
+        return compileClasspath.createPath();
+    }
+
+    /**
+     * Adds a reference to a classpath defined elsewhere.
+     * @param r a reference to a classpath
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    public String createEncoding() {
+        if (encoding == null) {
+            encoding = System.getProperty("file.encoding");
+        }
+        return encoding;
+    }
+
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * If true, list the source files being handed off to the compiler.
+     * @param list if true list the source files
+     */
+    public void setListfiles(boolean list) {
+        listFiles = list;
+    }
+
+    /**
+     * Get the listfiles flag.
+     * @return the listfiles flag
+     */
+    public boolean getListfiles() {
+        return listFiles;
+    }
+
+    /**
+     * Indicates whether the build will continue
+     * even if there are compilation errors; defaults to true.
+     * @param fail if true halt the build on failure
+     */
+    public void setFailonerror(boolean fail) {
+        failOnError = fail;
+    }
+
+    /**
+     * @ant.attribute ignore="true"
+     * @param proceed inverse of failoferror
+     */
+    public void setProceed(boolean proceed) {
+        failOnError = !proceed;
+    }
+
+    /**
+     * Gets the failonerror flag.
+     * @return the failonerror flag
+     */
+    public boolean getFailonerror() {
+        return failOnError;
+    }
+
+    /**
+     * Executes the task.
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+        checkParameters();
+        resetFileLists();
+
+        // scan source directories and dest directory to build up
+        // compile lists
+        String[] list = src.list();
+        for (int i = 0; i < list.length; i++) {
+            File srcDir = getProject().resolveFile(list[i]);
+            if (!srcDir.exists()) {
+                throw new BuildException("srcdir \"" + srcDir.getPath() + "\" does not exist!", getLocation());
+            }
+
+            DirectoryScanner ds = this.getDirectoryScanner(srcDir);
+            String[] files = ds.getIncludedFiles();
+
+            scanDir(srcDir, destDir != null ? destDir : srcDir, files);
+        }
+
+        compile();
+    }
+
+    /**
+     * Clear the list of files to be compiled and copied..
+     */
+    protected void resetFileLists() {
+        compileList = new File[0];
+    }
+
+    /**
+     * Scans the directory looking for source files to be compiled.
+     * The results are returned in the class variable compileList
+     *
+     * @param srcDir   The source directory
+     * @param destDir  The destination directory
+     * @param files    An array of filenames
+     */
+    protected void scanDir(File srcDir, File destDir, String[] files) {
+        GlobPatternMapper m = new GlobPatternMapper();
+        m.setFrom("*.groovy");
+        m.setTo("*.class");
+        SourceFileScanner sfs = new SourceFileScanner(this);
+        File[] newFiles = sfs.restrictAsFiles(files, srcDir, destDir, m);
+
+        if (newFiles.length > 0) {
+            File[] newCompileList = new File[compileList.length + newFiles.length];
+            System.arraycopy(compileList, 0, newCompileList, 0, compileList.length);
+            System.arraycopy(newFiles, 0, newCompileList, compileList.length, newFiles.length);
+            compileList = newCompileList;
+        }
+    }
+
+    /**
+     * Gets the list of files to be compiled.
+     * @return the list of files as an array
+     */
+    public File[] getFileList() {
+        return compileList;
+    }
+
+    protected void checkParameters() throws BuildException {
+        if (src == null) {
+            throw new BuildException("srcdir attribute must be set!", getLocation());
+        }
+        if (src.size() == 0) {
+            throw new BuildException("srcdir attribute must be set!", getLocation());
+        }
+
+        if (destDir != null && !destDir.isDirectory()) {
+            throw new BuildException(
+                "destination directory \"" + destDir + "\" does not exist " + "or is not a directory",
+                getLocation());
+        }
+
+        if (encoding != null && !Charset.isSupported(encoding)) {
+            throw new BuildException("encoding \"\" not supported");
+        }
+    }
+
+    protected void compile() {
+
+        if (compileList.length > 0) {
+            log(
+                "Compiling "
+                    + compileList.length
+                    + " source file"
+                    + (compileList.length == 1 ? "" : "s")
+                    + (destDir != null ? " to " + destDir : ""));
+
+            if (listFiles) {
+                for (int i = 0; i < compileList.length; i++) {
+                    String filename = compileList[i].getAbsolutePath();
+
+                    // TODO this logging does not seem to appear in the maven build??
+                    // COMMENT Hein: This is not ant's problem;
+                    // fix it in maven instead if you really need this from maven!
+                    log(filename);
+//                    System.out.println("compiling: " + filename);
+                }
+            }
+
+            try {
+                Path classpath = getClasspath();
+                if (classpath != null) {
+                    configuration.setClasspath(classpath.toString());
+                }
+                configuration.setTargetDirectory(destDir);
+
+                if (encoding != null) {
+                    configuration.setSourceEncoding(encoding);
+                }
+
+                CompilationUnit unit = new CompilationUnit(configuration, null, buildClassLoaderFor());
+                unit.addSources(compileList);
+                unit.compile();
+            }
+            catch (Exception e) {
+
+                StringWriter writer = new StringWriter();
+                new ErrorReporter( e, false ).write( new PrintWriter(writer) );
+                String message = writer.toString();
+
+                if (failOnError) {
+                    throw new BuildException(message, e, getLocation());
+                }
+                else {
+                    log(message, Project.MSG_ERR);
+                }
+
+            }
+        }
+    }
+
+    private GroovyClassLoader buildClassLoaderFor() {
+        ClassLoader parent = this.getClass().getClassLoader();
+        if (parent instanceof AntClassLoader) {
+            AntClassLoader antLoader = (AntClassLoader) parent;
+            String[] pathElm = antLoader.getClasspath().split(File.pathSeparator);
+            List classpath = configuration.getClasspath();
+            /*
+             * Iterate over the classpath provided to groovyc, and add any missing path
+             * entries to the AntClassLoader.  This is a workaround, since for some reason
+             * 'directory' classpath entries were not added to the AntClassLoader' classpath. 
+             */
+            for (Iterator iter = classpath.iterator(); iter.hasNext();) {
+                String cpEntry = (String) iter.next();
+                boolean found = false;
+                for (int i = 0; i < pathElm.length; i++) {
+                    if (cpEntry.equals(pathElm[i])) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (!found)
+                    antLoader.addPathElement(cpEntry);
+            }
+        }
+        return new GroovyClassLoader(parent, configuration);
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ant/RootLoaderRef.java b/groovy-core/src/main/org/codehaus/groovy/ant/RootLoaderRef.java
new file mode 100644
index 0000000..af18da5
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ant/RootLoaderRef.java
@@ -0,0 +1,158 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) Jochen Theodorou. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+ 
+package org.codehaus.groovy.ant;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.codehaus.groovy.tools.LoaderConfiguration;
+import org.codehaus.groovy.tools.RootLoader;
+
+ 
+/**
+ * Sets the RootLoader as reference.
+ * Reexecution of this task will set a new instance of RootLoader for
+ * the reference. 
+ *
+ * arguments:
+ * <ul>
+ * <li>ref</li>
+ * <li>classpath</li>
+ * </ul>
+ * 
+ * all arguments are requiered. 
+ *
+ * As ant requieres an AntClassLoader as reference, this will create a RootLoader
+ * and set an AntClassLoader as child and stored in the reference. The AntClassLoader
+ * instance will not have a classpath nor will it have access to the classpath somehow,
+ * all loading is done by the RootLoader parent. To avoid problems with loading classes 
+ * multiple times and using them at the same time, this task will filter out the ant jars
+ * and the commons-logging jars. This only works if the ant jars are starting with "ant-" and
+ * the logging jar starts with "commons-logging-".
+ * 
+ * This was needed because if ant wants to access a task argument that uses for example a Path
+ * it look for a matching method which includes a matching class. But two classes of the same name
+ * with different classloaders are different, so ant would not be able to find the method.
+ *
+ * @see org.codehaus.groovy.tools.RootLoader
+ * @author Jochen Theodorou
+ * @version $Revision$ 
+ */
+public class RootLoaderRef extends MatchingTask {
+    private String name;
+    private Path taskClasspath;
+    
+    /**
+     * sets the name of the reference which should store the Loader
+     */
+    public void setRef(String n){
+        name = n;
+    }
+    
+    public void execute() throws BuildException {
+        if (taskClasspath==null || taskClasspath.size()==0) {
+            throw new BuildException("no classpath given");
+        }
+        Project project = getProject();
+        AntClassLoader loader = new AntClassLoader(makeRoot(),true);
+        project.addReference(name,loader);
+    }
+    
+    private RootLoader makeRoot() {
+        String[] list = taskClasspath.list();
+        LoaderConfiguration lc = new LoaderConfiguration();
+        for (int i=0; i<list.length; i++) {
+            if (list[i].matches(".*ant-[^/]*jar$")) {
+                continue;
+            }
+            if (list[i].matches(".*commons-logging-[^/]*jar$")) {
+                continue;
+            }
+            if (list[i].matches(".*xerces-[^/]*jar$")) {
+                continue;
+            }
+            lc.addFile(list[i]);
+        }
+        return new RootLoader(lc);
+    }
+    
+    /**
+     * Set the classpath to be used for this compilation.
+     *
+     * @param classpath an Ant Path object containing the compilation classpath.
+     */
+    public void setClasspath(Path classpath) {
+        if (taskClasspath == null) {
+            taskClasspath = classpath;
+        }
+        else {
+            taskClasspath.append(classpath);
+        }
+    }
+    
+    /**
+     * Adds a reference to a classpath defined elsewhere.
+     * @param r a reference to a classpath
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+    
+    /**
+     * Adds a path to the classpath.
+     * @return a class path to be configured
+     */
+    public Path createClasspath() {
+        if (taskClasspath == null) {
+            taskClasspath = new Path(getProject());
+        }
+        return taskClasspath.createPath();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ant/VerifyClass.java b/groovy-core/src/main/org/codehaus/groovy/ant/VerifyClass.java
new file mode 100644
index 0000000..9a65eee
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ant/VerifyClass.java
@@ -0,0 +1,182 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ant;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.util.CheckClassAdapter;
+import org.objectweb.asm.util.TraceMethodVisitor;
+import org.objectweb.asm.tree.AbstractInsnNode ;
+import org.objectweb.asm.tree.ClassNode ;
+import org.objectweb.asm.tree.MethodNode ;
+import org.objectweb.asm.tree.analysis.Analyzer ;
+import org.objectweb.asm.tree.analysis.Frame ;
+import org.objectweb.asm.tree.analysis.SimpleVerifier ;
+
+/**
+ * Verify Class files. This task can take the following
+ * arguments:
+ * <ul>
+ * <li>dir
+ * </ul>
+ * When this task executes, it will recursively scan the dir and 
+ * look for class files to verify.  
+ */
+public class VerifyClass extends MatchingTask {
+    private String topDir=null;
+    private boolean verbose = false;
+    
+    public VerifyClass() {}
+
+    public void execute() throws BuildException {
+        if (topDir==null) throw new BuildException("no dir attribute is set");
+        File top = new File(topDir);
+        if (!top.exists()) throw new BuildException("the directory "+top+" does not exist");
+        log ("top dir is "+top);
+        int fails = execute(top);
+        if (fails==0) {
+            log ("no bytecode problems found");
+        } else {
+            log ("found "+fails+" failing classes");
+        }
+    }
+    
+    public void setDir(String dir) throws BuildException {
+        topDir = dir;
+    }
+    
+    public void setVerbose(boolean v) {
+        verbose = v;
+    }
+    
+    private int execute(File dir) {
+        int fails = 0;
+        File[] files = dir.listFiles();
+        for (int i = 0; i < files.length; i++) {
+            File f =files[i];
+            if (f.isDirectory()) {
+                fails += execute(f);
+            } else if (f.getName().endsWith(".class")) {
+                try {
+                    boolean ok = readClass(f.getCanonicalPath());
+                    if (!ok) fails++;
+                } catch (IOException ioe) {
+                    log(ioe.getMessage());
+                    throw new BuildException(ioe);
+                } 
+            }
+        }
+        return fails;
+    }
+    
+    private boolean readClass(String clazz) throws IOException {
+        ClassReader cr = new ClassReader(new FileInputStream(clazz));
+        ClassNode ca = new ClassNode ( ) 
+          {
+            public void visitEnd () {
+              //accept(cv);
+            }
+          } ;
+        cr.accept(new CheckClassAdapter(ca), true);
+        boolean failed=false;
+        
+        List methods = ca.methods;
+        for (int i = 0; i < methods.size(); ++i) {
+          MethodNode method = (MethodNode)methods.get(i);
+          if (method.instructions.size() > 0) {
+            Analyzer a = new Analyzer(new SimpleVerifier());
+            try {
+              a.analyze(ca.name, method);
+              continue;
+            } catch (Exception e) {
+              e.printStackTrace();
+            }
+            final Frame[] frames = a.getFrames();
+
+            if (!failed) {
+                failed=true;
+                log("verifying of class "+clazz+" failed");
+            }
+            if (verbose) log(method.name + method.desc);
+            TraceMethodVisitor cv = new TraceMethodVisitor(null) {
+              public void visitMaxs (int maxStack, int maxLocals) {
+                StringBuffer buffer = new StringBuffer();
+                for (int i = 0; i < text.size(); ++i) {
+                  String s = frames[i] == null ? "null" : frames[i].toString();
+                  while (s.length() < maxStack+maxLocals+1) {
+                    s += " ";
+                  }
+                  buffer.append(Integer.toString(i + 100000).substring(1));
+                  buffer.append(" ");
+                  buffer.append(s);
+                  buffer.append(" : ");
+                  buffer.append(text.get(i));
+                }
+                if (verbose) log(buffer.toString());
+              }
+            };
+            for (int j = 0; j < method.instructions.size(); ++j) {
+              Object insn = method.instructions.get(j);
+              if (insn instanceof AbstractInsnNode) {
+                ((AbstractInsnNode)insn).accept(cv);
+              } else {
+                cv.visitLabel((Label)insn);
+              }
+            }
+            cv.visitMaxs(method.maxStack, method.maxLocals);
+          }
+        }
+        return !failed;
+    }
+    
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ant/package.html b/groovy-core/src/main/org/codehaus/groovy/ant/package.html
new file mode 100644
index 0000000..aa78a68
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ant/package.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <title>package org.codehaus.groovy.ant.*</title>
+  </head>
+  <body>
+    <p>
+      Ant tasks for working with Groovy - such as groovyc for compiling Groovy source code to
+      Java bytecode
+    </p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlib.xml b/groovy-core/src/main/org/codehaus/groovy/antlib.xml
new file mode 100644
index 0000000..3e34e84
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlib.xml
@@ -0,0 +1,4 @@
+<antlib>
+    <taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc"/>
+    <taskdef name="groovy"  classname="org.codehaus.groovy.ant.Groovy"/>
+</antlib>
\ No newline at end of file
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/ASTParserException.java b/groovy-core/src/main/org/codehaus/groovy/antlr/ASTParserException.java
new file mode 100644
index 0000000..b3be44f
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/ASTParserException.java
@@ -0,0 +1,44 @@
+/**
+ *
+ * Copyright 2004 James Strachan
+ *
+ * Licensed 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.antlr;
+
+import antlr.collections.AST;
+import org.codehaus.groovy.syntax.ParserException;
+
+/**
+ * Thrown when trying to parse the AST
+ *
+ * @version $Revision$
+ */
+public class ASTParserException extends ParserException {
+    private AST ast;
+
+    public ASTParserException(ASTRuntimeException e) {
+        super(e.getMessage(), e, e.getLine(), e.getColumn());
+        this.ast = e.getAst();
+    }
+
+    public ASTParserException(String message, ASTRuntimeException e) {
+        super(message, e, e.getLine(), e.getColumn());
+        this.ast = e.getAst();
+    }
+
+    public AST getAst() {
+        return ast;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/ASTRuntimeException.java b/groovy-core/src/main/org/codehaus/groovy/antlr/ASTRuntimeException.java
new file mode 100644
index 0000000..01470bd
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/ASTRuntimeException.java
@@ -0,0 +1,54 @@
+/**
+ *
+ * Copyright 2004 James Strachan
+ *
+ * Licensed 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.antlr;
+
+import antlr.collections.AST;
+
+/**
+ * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
+ * @version $Revision$
+ */
+public class ASTRuntimeException extends RuntimeException {
+    private AST ast;
+
+    public ASTRuntimeException(AST ast, String message) {
+        super(message + description(ast));
+        this.ast = ast;
+    }
+
+    public ASTRuntimeException(AST ast, String message, Throwable throwable) {
+        super(message + description(ast), throwable);
+    }
+
+    protected static String description(AST node) {
+        return (node != null) ? " at line: " + node.getLine() + " column: " + node.getColumn() : "";
+    }
+
+    public AST getAst() {
+        return ast;
+    }
+
+    public int getLine() {
+        return ast != null ? ast.getLine() : -1;
+    }
+
+    public int getColumn() {
+        return ast != null ? ast.getColumn() : -1;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/AntlrASTProcessSnippets.java b/groovy-core/src/main/org/codehaus/groovy/antlr/AntlrASTProcessSnippets.java
new file mode 100644
index 0000000..ad221fa
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/AntlrASTProcessSnippets.java
@@ -0,0 +1,102 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr;
+
+/**
+ * Process to decorate antlr AST with ending line/col info, and if
+ * possible the snipppet of source from the start/end line/col for each node.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+import antlr.collections.AST;
+import java.util.*;
+
+public class AntlrASTProcessSnippets implements AntlrASTProcessor{
+    private SourceBuffer sourceBuffer;
+
+    public AntlrASTProcessSnippets(SourceBuffer sourceBuffer) {
+        this.sourceBuffer = sourceBuffer;
+    }
+
+    /**
+     * decorate antlr AST with ending line/col info, and if
+     * possible the snipppet of source from the start/end line/col for each node.
+     * @param t the AST to decorate
+     * @return the decorated AST
+     */
+    public AST process(AST t) {
+        // first visit
+        List l = new ArrayList();
+        t = traverse((GroovySourceAST)t,l,null);
+
+        //System.out.println("l:" + l);
+        // second visit
+        Iterator itr = l.iterator();
+        if (itr.hasNext()) { itr.next(); /* discard first */ }
+        t = traverse((GroovySourceAST)t,null,itr);
+        return t;
+    }
+
+    /**
+     * traverse an AST node
+     * @param t the AST node to traverse
+     * @param l A list to add line/col info to
+     * @param itr An iterator over a list of line/col
+     * @return A decorated AST node
+     */
+    private AST traverse(GroovySourceAST t,List l,Iterator itr) {
+        if (t == null) { return t; }
+
+        // first visit of node
+        if (l != null) {
+            l.add(new LineColumn(t.getLine(),t.getColumn()));
+        }
+
+        // second vist of node
+        if (itr != null && itr.hasNext()) {
+            LineColumn lc = (LineColumn)itr.next();
+            if (t.getLineLast() == 0) {
+                int nextLine = lc.getLine();
+                int nextColumn = lc.getColumn();
+                if (nextLine < t.getLine() || (nextLine == t.getLine() && nextColumn < t.getColumn())) {
+                    nextLine = t.getLine();
+                    nextColumn = t.getColumn();
+                }
+                t.setLineLast(nextLine);
+                t.setColumnLast(nextColumn);
+                // This is a good point to call t.setSnippet(),
+                // but it bulks up the AST too much for production code.
+            }
+        }
+
+        GroovySourceAST child = (GroovySourceAST)t.getFirstChild();
+        if (child != null) {
+            traverse(child,l,itr);
+        }
+
+        GroovySourceAST sibling = (GroovySourceAST)t.getNextSibling();
+        if (sibling != null) {
+            traverse(sibling,l,itr);
+        }
+
+        return t;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/AntlrASTProcessor.java b/groovy-core/src/main/org/codehaus/groovy/antlr/AntlrASTProcessor.java
new file mode 100644
index 0000000..3f010b1
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/AntlrASTProcessor.java
@@ -0,0 +1,36 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr;
+
+import antlr.collections.AST;
+
+/**
+ * An interface for processing antlr AST objects
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+public interface AntlrASTProcessor {
+    /**
+     * performs some processing on the supplied AST node.
+     * @param t the AST node to process.
+     * @return possibly returns the AST modified or null, depends on the implementation.
+     */
+    AST process(AST t);
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/AntlrParserPlugin.java b/groovy-core/src/main/org/codehaus/groovy/antlr/AntlrParserPlugin.java
new file mode 100644
index 0000000..77d3302
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/AntlrParserPlugin.java
@@ -0,0 +1,2298 @@
+/**
+ *
+ * Copyright 2004 James Strachan
+ *
+ * Licensed 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.antlr;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+import antlr.TokenStreamRecognitionException;
+import antlr.collections.AST;
+import com.thoughtworks.xstream.XStream;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.antlr.parser.GroovyLexer;
+import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+import org.codehaus.groovy.antlr.treewalker.*;
+import org.codehaus.groovy.ast.*;
+import org.codehaus.groovy.ast.expr.*;
+import org.codehaus.groovy.ast.stmt.*;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.ParserPlugin;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.syntax.*;
+import org.objectweb.asm.Opcodes;
+
+import java.io.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A parser plugin which adapts the JSR Antlr Parser to the Groovy runtime
+ *
+ * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
+ * @version $Revision$
+ */
+public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, GroovyTokenTypes {
+
+    private AST ast;
+    private ClassNode classNode;
+    private String[] tokenNames;
+
+
+    public Reduction parseCST(final SourceUnit sourceUnit, Reader reader) throws CompilationFailedException {
+        ast = null;
+
+        setController(sourceUnit);
+
+        SourceBuffer sourceBuffer = new SourceBuffer();
+        UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(reader,sourceBuffer);
+        GroovyLexer lexer = new GroovyLexer(unicodeReader);
+        unicodeReader.setLexer(lexer);
+        GroovyRecognizer parser = GroovyRecognizer.make(lexer);
+        parser.setSourceBuffer(sourceBuffer);
+        tokenNames = parser.getTokenNames();
+        parser.setFilename(sourceUnit.getName());
+
+        // start parsing at the compilationUnit rule
+        try {
+            parser.compilationUnit();
+        }
+        catch (TokenStreamRecognitionException tsre) {
+            RecognitionException e = tsre.recog;
+            SyntaxException se = new SyntaxException(e.getMessage(),e,e.getLine(),e.getColumn());
+            se.setFatal(true);
+            sourceUnit.addError(se);
+        }
+        catch (RecognitionException e) {
+            SyntaxException se = new SyntaxException(e.getMessage(),e,e.getLine(),e.getColumn());
+            se.setFatal(true);
+            sourceUnit.addError(se);
+        }
+        catch (TokenStreamException e) {
+            sourceUnit.addException(e);
+        }
+
+        ast = parser.getAST();
+
+        AntlrASTProcessor snippets = new AntlrASTProcessSnippets(sourceBuffer);
+        ast = snippets.process(ast);
+        
+        AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+            	outputASTInVariousFormsIfNeeded(sourceUnit);
+                return null;
+            }
+        });
+        
+        return null; //new Reduction(Tpken.EOF);
+    }
+
+    public SourceSummary getSummary() {
+        SummaryCollector summaryCollector = new SummaryCollector();
+        AntlrASTProcessor treewalker = new PreOrderTraversal(summaryCollector);
+        treewalker.process(ast);
+        return summaryCollector.getSourceSummary();
+    }
+
+    private void outputASTInVariousFormsIfNeeded(SourceUnit sourceUnit) {
+        // straight xstream output of AST
+        if ("xml".equals(System.getProperty("antlr.ast"))) {
+            saveAsXML(sourceUnit.getName(), ast);
+        }
+
+        // 'pretty printer' output of AST
+        if ("groovy".equals(System.getProperty("antlr.ast"))) {
+            try {
+                PrintStream out = new PrintStream(new FileOutputStream(sourceUnit.getName() + ".pretty.groovy"));
+                Visitor visitor = new SourcePrinter(out,tokenNames);
+                AntlrASTProcessor treewalker = new SourceCodeTraversal(visitor);
+                treewalker.process(ast);
+            } catch (FileNotFoundException e) {
+                System.out.println("Cannot create " + sourceUnit.getName() + ".pretty.groovy");
+            }
+        }
+
+        // output AST in format suitable for opening in http://freemind.sourceforge.net
+        // which is a really nice way of seeing the AST, folding nodes etc
+        if ("mindmap".equals(System.getProperty("antlr.ast"))) {
+            try {
+                PrintStream out = new PrintStream(new FileOutputStream(sourceUnit.getName() + ".mm"));
+                Visitor visitor = new MindMapPrinter(out,tokenNames);
+                AntlrASTProcessor treewalker = new PreOrderTraversal(visitor);
+                treewalker.process(ast);
+            } catch (FileNotFoundException e) {
+                System.out.println("Cannot create " + sourceUnit.getName() + ".mm");
+            }
+        }
+
+        // html output of AST
+        if ("html".equals(System.getProperty("antlr.ast"))) {
+            try {
+                PrintStream out = new PrintStream(new FileOutputStream(sourceUnit.getName() + ".html"));
+                List v = new ArrayList();
+                v.add(new NodeAsHTMLPrinter(out,tokenNames));
+                v.add(new SourcePrinter(out,tokenNames));
+                Visitor visitors = new CompositeVisitor(v);
+                AntlrASTProcessor treewalker = new SourceCodeTraversal(visitors);
+                treewalker.process(ast);
+            } catch (FileNotFoundException e) {
+                System.out.println("Cannot create " + sourceUnit.getName() + ".html");
+            }
+        }
+
+
+    }
+
+    private void saveAsXML(String name, AST ast) {
+        XStream xstream = new XStream();
+        try {
+            xstream.toXML(ast, new FileWriter(name + ".antlr.xml"));
+            System.out.println("Written AST to " + name + ".antlr.xml");
+        }
+        catch (Exception e) {
+            System.out.println("Couldn't write to " + name + ".antlr.xml");
+            e.printStackTrace();
+        }
+    }
+
+    public ModuleNode buildAST(SourceUnit sourceUnit, ClassLoader classLoader, Reduction cst) throws ParserException {
+        setClassLoader(classLoader);
+        makeModule();
+        try {
+            convertGroovy(ast);
+        }
+        catch (ASTRuntimeException e) {
+            throw new ASTParserException(e.getMessage() + ". File: " + sourceUnit.getName(), e);
+        }
+        return output;
+    }
+
+    /**
+     * Converts the Antlr AST to the Groovy AST
+     */
+    protected void convertGroovy(AST node) {
+        while (node != null) {
+            int type = node.getType();
+            switch (type) {
+                case PACKAGE_DEF:
+                    packageDef(node);
+                    break;
+
+                case IMPORT:
+                    importDef(node);
+                    break;
+
+                case CLASS_DEF:
+                    classDef(node);
+                    break;
+
+                case INTERFACE_DEF:
+                    interfaceDef(node);
+                    break;
+
+                case METHOD_DEF:
+                    methodDef(node);
+                    break;
+
+                default:
+                    {
+                        Statement statement = statement(node);
+                        output.addStatement(statement);
+                    }
+            }
+            node = node.getNextSibling();
+        }
+    }
+
+    // Top level control structures
+    //-------------------------------------------------------------------------
+
+    protected void packageDef(AST packageDef) {
+        AST node = packageDef.getFirstChild();
+        if (isType(ANNOTATIONS, node)) {
+            node = node.getNextSibling();
+        }
+        String name = qualifiedName(node);
+        setPackageName(name);
+    }
+    
+    protected void importDef(AST importNode) {
+        // TODO handle static imports
+
+        AST node = importNode.getFirstChild();
+
+        String alias = null;
+        if (isType(LITERAL_as, node)) {
+            //import is like "import Foo as Bar"
+            node = node.getFirstChild();
+            AST aliasNode = node.getNextSibling();
+            alias = identifier(aliasNode);
+        }
+
+        if (node.getNumberOfChildren()==0) {
+            // import is like  "import Foo"
+            String name = identifier(node);
+            ClassNode type = ClassHelper.make(name);
+            configureAST(type,importNode);
+            importClass(type,name,alias);
+            return;
+        }
+
+        AST packageNode = node.getFirstChild();
+        String packageName = qualifiedName(packageNode);
+        AST nameNode = packageNode.getNextSibling();
+        if (isType(STAR, nameNode)) {
+            // import is like "import foo.*"
+            importPackageWithStar(packageName);
+            if (alias!=null) throw new GroovyBugError(
+                    "imports like 'import foo.* as Bar' are not "+
+                    "supported and should be caught by the grammar");
+        } else {
+            // import is like "import foo.Bar"
+            String name = identifier(nameNode);
+            ClassNode type = ClassHelper.make(packageName+"."+name);
+            configureAST(type,importNode);
+            importClass(type,name,alias);
+        }
+    }
+
+    protected void interfaceDef(AST classDef) {
+        List annotations = new ArrayList();
+        AST node = classDef.getFirstChild();
+        int modifiers = Opcodes.ACC_PUBLIC;
+        if (isType(MODIFIERS, node)) {
+            modifiers = modifiers(node, annotations, modifiers);
+            node = node.getNextSibling();
+        }
+        modifiers |= Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE;
+
+        String name = identifier(node);
+        node = node.getNextSibling();
+        ClassNode superClass = ClassHelper.OBJECT_TYPE;
+
+        ClassNode[] interfaces = {};
+        if (isType(EXTENDS_CLAUSE, node)) {
+            interfaces = interfaces(node);
+            node = node.getNextSibling();
+        }
+
+        addNewClassName(name);
+        classNode = new ClassNode(dot(getPackageName(), name), modifiers, superClass, interfaces, null);
+        classNode.addAnnotations(annotations);
+        configureAST(classNode, classDef);
+
+        assertNodeType(OBJBLOCK, node);
+        objectBlock(node);
+        output.addClass(classNode);
+        classNode = null;
+    }
+
+    protected void classDef(AST classDef) {
+        List annotations = new ArrayList();
+        AST node = classDef.getFirstChild();
+        int modifiers = Opcodes.ACC_PUBLIC;
+        if (isType(MODIFIERS, node)) {
+            modifiers = modifiers(node, annotations, modifiers);
+            node = node.getNextSibling();
+        }
+
+        String name = identifier(node);
+        node = node.getNextSibling();
+
+        ClassNode superClass = null;
+        if (isType(EXTENDS_CLAUSE, node)) {
+            superClass = makeType(node);
+            node = node.getNextSibling();
+        }
+
+        ClassNode[] interfaces = {};
+        if (isType(IMPLEMENTS_CLAUSE, node)) {
+            interfaces = interfaces(node);
+            node = node.getNextSibling();
+        }
+
+        // TODO read mixins
+        MixinNode[] mixins = {};
+
+        addNewClassName(name);
+        classNode = new ClassNode(dot(getPackageName(), name), modifiers, superClass, interfaces, mixins);
+        classNode.addAnnotations(annotations);
+        configureAST(classNode, classDef);
+
+        assertNodeType(OBJBLOCK, node);
+        objectBlock(node);
+        output.addClass(classNode);
+        classNode = null;
+    }
+
+    protected void objectBlock(AST objectBlock) {
+        for (AST node = objectBlock.getFirstChild(); node != null; node = node.getNextSibling()) {
+            int type = node.getType();
+            switch (type) {
+                case OBJBLOCK:
+                    objectBlock(node);
+                    break;
+
+                case METHOD_DEF:
+                    methodDef(node);
+                    break;
+
+                case CTOR_IDENT:
+                    constructorDef(node);
+                    break;
+
+                case VARIABLE_DEF:
+                    fieldDef(node);
+                    break;
+
+                case STATIC_INIT:
+                    staticInit(node);
+                    break;
+                    
+                case INSTANCE_INIT:
+                    objectInit(node);
+                    break;
+                    
+                default:
+                    unknownAST(node);
+            }
+        }
+    }
+    
+    protected void throwsList(AST node,List list) {
+    	String clazz = identifier(node);
+    	ClassNode exception = ClassHelper.make(clazz);
+    	list.add(exception);
+    	AST next = node.getNextSibling();
+    	if (next!=null) throwsList(next, list);
+    	next = node.getFirstChild();
+    	if (next!=null) throwsList(next, list);
+    }
+
+    protected void methodDef(AST methodDef) {
+        List annotations = new ArrayList();
+        AST node = methodDef.getFirstChild();
+        int modifiers = Opcodes.ACC_PUBLIC;
+        if (isType(MODIFIERS, node)) {
+            modifiers = modifiers(node, annotations, modifiers);
+            node = node.getNextSibling();
+        }
+
+        if (classNode!=null && (classNode.getModifiers() & Opcodes.ACC_INTERFACE) >0) {
+            modifiers |= Opcodes.ACC_ABSTRACT;
+        }
+
+        ClassNode returnType = null;
+        if (isType(TYPE, node)) {
+            returnType = makeType(node);
+            node = node.getNextSibling();
+        }
+
+        String name = identifier(node);
+        if (classNode != null) {
+            if (classNode.getNameWithoutPackage().equals(name)) {
+                throw new ASTRuntimeException(methodDef, "Invalid constructor format. Try remove the 'def' expression?");
+            }
+        }
+        node = node.getNextSibling();
+
+        assertNodeType(PARAMETERS, node);
+        Parameter[] parameters = parameters(node);
+        if (parameters==null) parameters = Parameter.EMPTY_ARRAY;
+        node = node.getNextSibling();
+        
+        ClassNode[] exceptions=new ClassNode[0];
+        if (isType(LITERAL_throws, node)) {
+        	AST throwsNode = node.getFirstChild();
+        	List exceptionList = new ArrayList();
+        	throwsList(throwsNode, exceptionList);
+        	exceptions = (ClassNode[]) exceptionList.toArray(exceptions);
+        	node = node.getNextSibling();
+        }
+
+        Statement code = null;
+        if ((modifiers & Opcodes.ACC_ABSTRACT) == 0) {
+            if (node==null) {
+                throw new ASTRuntimeException(methodDef, "You defined a method without body. Try adding a body, or declare it abstract.");
+            }
+            assertNodeType(SLIST, node);
+            code = statementList(node);
+        }
+
+        MethodNode methodNode = new MethodNode(name, modifiers, returnType, parameters, exceptions, code);
+        methodNode.addAnnotations(annotations);
+        configureAST(methodNode, methodDef);
+        if (classNode != null) {
+            classNode.addMethod(methodNode);
+        }
+        else {
+            output.addMethod(methodNode);
+        }
+    }
+    
+    protected void staticInit(AST staticInit) {        
+        BlockStatement code = (BlockStatement) statementList(staticInit);
+        classNode.addStaticInitializerStatements(code.getStatements(),false);
+    }
+    
+    protected void objectInit(AST init) {        
+        BlockStatement code = (BlockStatement) statementList(init);
+        classNode.addObjectInitializerStatements(code);
+    }
+    
+    protected void constructorDef(AST constructorDef) {
+        List annotations = new ArrayList();
+        AST node = constructorDef.getFirstChild();
+        int modifiers = Opcodes.ACC_PUBLIC;
+        if (isType(MODIFIERS, node)) {
+            modifiers = modifiers(node, annotations, modifiers);
+            node = node.getNextSibling();
+        }
+
+        assertNodeType(PARAMETERS, node);
+        Parameter[] parameters = parameters(node);
+        if (parameters == null) parameters = Parameter.EMPTY_ARRAY;
+        node = node.getNextSibling();
+
+        ClassNode[] exceptions=new ClassNode[0];
+        if (isType(LITERAL_throws, node)) {
+        	AST throwsNode = node.getFirstChild();
+        	List exceptionList = new ArrayList();
+        	throwsList(throwsNode, exceptionList);
+        	exceptions = (ClassNode[]) exceptionList.toArray(exceptions);
+        	node = node.getNextSibling();
+        }
+        
+        assertNodeType(SLIST, node);
+        Statement code = statementList(node);
+
+        ConstructorNode constructorNode = classNode.addConstructor(modifiers, parameters, exceptions, code);
+        constructorNode.addAnnotations(annotations);
+        configureAST(constructorNode, constructorDef);
+    }
+
+    protected void fieldDef(AST fieldDef) {
+        List annotations = new ArrayList();
+        AST node = fieldDef.getFirstChild();
+
+        int modifiers = 0;
+        if (isType(MODIFIERS, node)) {
+            modifiers = modifiers(node, annotations, modifiers);
+            node = node.getNextSibling();
+        }
+        
+        if (classNode.isInterface()) {
+        	modifiers |= Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
+        	if ( (modifiers & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) == 0) {
+        		modifiers |= Opcodes.ACC_PUBLIC;
+        	}
+        }
+
+        ClassNode type = null;
+        if (isType(TYPE, node)) {
+            type = makeType(node);
+            node = node.getNextSibling();
+        }
+
+        String name = identifier(node);
+        node = node.getNextSibling();
+
+        Expression initialValue = null;
+        if (node != null) {
+            assertNodeType(ASSIGN, node);
+            initialValue = expression(node);
+        }
+
+        if (initialValue == null && type != null) {
+            if (type==ClassHelper.int_TYPE) {
+                initialValue = new ConstantExpression(new Integer(0));
+            }
+            else if (type==ClassHelper.long_TYPE) {
+                initialValue = new ConstantExpression(new Long(0L));
+            }
+            else if (type==ClassHelper.double_TYPE) {
+                initialValue = new ConstantExpression(new Double(0.0));
+            }
+            else if (type==ClassHelper.float_TYPE) {
+                initialValue = new ConstantExpression(new Float(0.0F));
+            }
+            else if (type==ClassHelper.boolean_TYPE) {
+                initialValue = ConstantExpression.FALSE;
+            }
+            else if (type==ClassHelper.short_TYPE) {
+                initialValue = new ConstantExpression(new Short((short) 0));
+            }
+            else if (type==ClassHelper.byte_TYPE) {
+                initialValue = new ConstantExpression(new Byte((byte) 0));
+            }
+            else if (type==ClassHelper.char_TYPE) {
+                initialValue = new ConstantExpression(new Character((char) 0));
+            }
+        }
+
+
+        FieldNode fieldNode = new FieldNode(name, modifiers, type, classNode, initialValue);
+        fieldNode.addAnnotations(annotations);
+        configureAST(fieldNode, fieldDef);
+
+        if (!hasVisibility(modifiers)) {
+            // lets set the modifiers on the field
+            int fieldModifiers = 0;
+            int flags = Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT | Opcodes.ACC_VOLATILE | Opcodes.ACC_FINAL;
+
+            if (!hasVisibility(modifiers)) {
+                modifiers |= Opcodes.ACC_PUBLIC;
+                fieldModifiers |= Opcodes.ACC_PRIVATE;
+            }
+
+            // lets pass along any other modifiers we need
+            fieldModifiers |= (modifiers & flags);
+            fieldNode.setModifiers(fieldModifiers);
+            
+            PropertyNode propertyNode = new PropertyNode(fieldNode, modifiers, null, null);
+            configureAST(propertyNode, fieldDef);
+            classNode.addProperty(propertyNode);
+        }
+        else {
+            fieldNode.setModifiers(modifiers);
+            classNode.addField(fieldNode);
+        }
+    }
+
+    protected ClassNode[] interfaces(AST node) {
+        List interfaceList = new ArrayList();
+        for (AST implementNode = node.getFirstChild(); implementNode != null; implementNode = implementNode.getNextSibling()) {
+        	interfaceList.add(ClassHelper.make(qualifiedName(implementNode)));
+        }
+        ClassNode[] interfaces = {};
+        if (!interfaceList.isEmpty()) {
+            interfaces = new ClassNode[interfaceList.size()];
+            interfaceList.toArray(interfaces);
+
+        }
+        return interfaces;
+    }
+
+    protected Parameter[] parameters(AST parametersNode) {
+        AST node = parametersNode.getFirstChild();
+        if (node == null) {
+        	if (isType(IMPLICIT_PARAMETERS, parametersNode)) return Parameter.EMPTY_ARRAY;
+            return null;
+        }
+        else {
+            List parameters = new ArrayList();
+            do {
+                parameters.add(parameter(node));
+                node = node.getNextSibling();
+            }
+            while (node != null);
+            Parameter[] answer = new Parameter[parameters.size()];
+            parameters.toArray(answer);
+            return answer;
+        }
+    }
+
+    protected Parameter parameter(AST paramNode) {
+        List annotations = new ArrayList();
+        AST node = paramNode.getFirstChild();
+
+        int modifiers = 0;
+        if (isType(MODIFIERS, node)) {
+            modifiers = modifiers(node, annotations, modifiers);
+            node = node.getNextSibling();
+        }
+
+        ClassNode type = ClassHelper.DYNAMIC_TYPE;
+        if (isType(TYPE, node)) {
+            type = makeType(node);
+            node = node.getNextSibling();
+        }
+
+        String name = identifier(node);
+        node = node.getNextSibling();
+        VariableExpression leftExpression = new VariableExpression(name, type);
+        configureAST(leftExpression, paramNode);
+
+        Parameter parameter = null;
+        if (node != null) {
+            assertNodeType(ASSIGN, node);
+            Expression rightExpression = expression(node.getFirstChild());
+            parameter = new Parameter(type, name, rightExpression);
+        }
+        else
+            parameter = new Parameter(type, name);
+
+        // TODO
+        //configureAST(parameter,paramNode);
+        //parameter.addAnnotations(annotations);
+        return parameter;
+    }
+
+    protected int modifiers(AST modifierNode, List annotations, int defaultModifiers) {
+        assertNodeType(MODIFIERS, modifierNode);
+
+        boolean access = false;
+        int answer = 0;
+
+        for (AST node = modifierNode.getFirstChild(); node != null; node = node.getNextSibling()) {
+            int type = node.getType();
+            switch (type) {
+                // annotations
+                case ANNOTATION:
+                    annotations.add(annotation(node));
+                    break;
+
+
+                    // core access scope modifiers
+                case LITERAL_private:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_PRIVATE);
+                    access = setAccessTrue(node, access);
+                    break;
+
+                case LITERAL_protected:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_PROTECTED);
+                    access = setAccessTrue(node, access);
+                    break;
+
+                case LITERAL_public:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_PUBLIC);
+                    access = setAccessTrue(node, access);
+                    break;
+
+                    // other modifiers
+                case ABSTRACT:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_ABSTRACT);
+                    break;
+
+                case FINAL:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_FINAL);
+                    break;
+
+                case LITERAL_native:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_NATIVE);
+                    break;
+
+                case LITERAL_static:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_STATIC);
+                    break;
+
+                case STRICTFP:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_STRICT);
+                    break;
+
+                case LITERAL_synchronized:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_SYNCHRONIZED);
+                    break;
+
+                case LITERAL_transient:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_TRANSIENT);
+                    break;
+
+                case LITERAL_volatile:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_VOLATILE);
+                    break;
+
+                default:
+                    unknownAST(node);
+            }
+        }
+        if (!access) {
+            answer |= defaultModifiers;
+        }
+        return answer;
+    }
+
+    protected boolean setAccessTrue(AST node, boolean access) {
+        if (!access) {
+            return true;
+        }
+        else {
+            throw new ASTRuntimeException(node, "Cannot specify modifier: " + node.getText() + " when access scope has already been defined");
+        }
+    }
+
+    protected int setModifierBit(AST node, int answer, int bit) {
+        if ((answer & bit) != 0) {
+            throw new ASTRuntimeException(node, "Cannot repeat modifier: " + node.getText());
+        }
+        return answer | bit;
+    }
+
+    protected AnnotationNode annotation(AST annotationNode) {
+        AST node = annotationNode.getFirstChild();
+        String name = identifier(node);
+        AnnotationNode annotatedNode = new AnnotationNode(ClassHelper.make(name));
+        configureAST(annotatedNode, node);
+        while (true) {
+            node = node.getNextSibling();
+            if (isType(ANNOTATION_MEMBER_VALUE_PAIR, node)) {
+                AST memberNode = node.getFirstChild();
+                String param = identifier(memberNode);
+                Expression expression = expression(memberNode.getNextSibling());
+                annotatedNode.addMember(param, expression);
+            }
+            else {
+                break;
+            }
+        }
+        return annotatedNode;
+    }
+
+
+
+    // Statements
+    //-------------------------------------------------------------------------
+
+    protected Statement statement(AST node) {
+        Statement statement = null;
+        int type = node.getType();
+        switch (type) {
+            case SLIST:
+            case LITERAL_finally:
+                statement = statementList(node);
+                break;
+
+            case METHOD_CALL:
+                statement = methodCall(node);
+                break;
+
+            case VARIABLE_DEF:
+                statement = variableDef(node);
+                break;
+
+
+            case LABELED_STAT:
+                statement = labelledStatement(node);
+                break;
+
+            case LITERAL_assert:
+                statement = assertStatement(node);
+                break;
+
+            case LITERAL_break:
+                statement = breakStatement(node);
+                break;
+
+            case LITERAL_continue:
+                statement = continueStatement(node);
+                break;
+
+            case LITERAL_if:
+                statement = ifStatement(node);
+                break;
+
+            case LITERAL_for:
+                statement = forStatement(node);
+                break;
+
+            case LITERAL_return:
+                statement = returnStatement(node);
+                break;
+
+            case LITERAL_synchronized:
+                statement = synchronizedStatement(node);
+                break;
+
+            case LITERAL_switch:
+                statement = switchStatement(node);
+                break;
+
+            case LITERAL_with:
+                statement = withStatement(node);
+                break;
+
+            case LITERAL_try:
+                statement = tryStatement(node);
+                break;
+
+            case LITERAL_throw:
+                statement = throwStatement(node);
+                break;
+
+            case LITERAL_while:
+                statement = whileStatement(node);
+                break;
+
+            default:
+                statement = new ExpressionStatement(expression(node));
+        }
+        if (statement != null) {
+            configureAST(statement, node);
+        }
+        return statement;
+    }
+
+    protected Statement statementList(AST code) {
+        return statementListNoChild(code.getFirstChild());
+    }
+
+    protected Statement statementListNoChild(AST node) {
+        BlockStatement block = new BlockStatement();
+        // no need to configureAST(block,node); as node is probably null
+        for (; node != null; node = node.getNextSibling()) {
+            block.addStatement(statement(node));
+        }
+        return block;
+    }
+
+    protected Statement assertStatement(AST assertNode) {
+        AST node = assertNode.getFirstChild();
+        BooleanExpression booleanExpression = booleanExpression(node);
+        Expression messageExpression = null;
+
+        node = node.getNextSibling();
+        if (node != null) {
+            messageExpression = expression(node);
+        }
+        else {
+            messageExpression = ConstantExpression.NULL;
+        }
+        AssertStatement assertStatement = new AssertStatement(booleanExpression, messageExpression);
+        configureAST(assertStatement, assertNode);
+        return assertStatement;
+    }
+
+    protected Statement breakStatement(AST node) {
+        BreakStatement breakStatement = new BreakStatement(label(node));
+        configureAST(breakStatement, node);
+        return breakStatement;
+    }
+
+    protected Statement continueStatement(AST node) {
+        ContinueStatement continueStatement = new ContinueStatement(label(node));
+        configureAST(continueStatement, node);
+        return continueStatement;
+    }
+
+    protected Statement forStatement(AST forNode) {
+        assertNotLegacyFor(forNode);
+        AST inNode = forNode.getFirstChild();
+        AST variableNode = inNode.getFirstChild();
+        AST collectionNode = variableNode.getNextSibling();
+
+        ClassNode type = ClassHelper.OBJECT_TYPE;
+        if (isType(VARIABLE_DEF, variableNode)) {
+            AST typeNode = variableNode.getFirstChild();
+            assertNodeType(TYPE, typeNode);
+
+            type = type(typeNode);
+            variableNode = typeNode.getNextSibling();
+        }
+        String variable = identifier(variableNode);
+
+        Expression collectionExpression = expression(collectionNode);
+        Statement block = statement(inNode.getNextSibling());
+        Parameter forParameter = new Parameter(type,variable);
+
+        ForStatement forStatement = new ForStatement(forParameter, collectionExpression, block);
+        configureAST(forStatement, forNode);
+        return forStatement;
+    }
+
+    private void assertNotLegacyFor(AST forNode) {
+        AST childNode = forNode.getFirstChild();
+        boolean legacy = false;
+        while (childNode != null) {
+            int type = childNode.getType();
+            if (type == FOR_INIT || type == FOR_CONDITION || type == FOR_ITERATOR) {
+                legacy = true;
+                break;
+            }
+            childNode = childNode.getNextSibling();
+        }
+        if (legacy) {
+            throw new ASTRuntimeException(forNode, "For statement contains unexpected tokens. Possible attempt to use unsupported Java-style for loop.");
+        }
+    }
+
+    protected Statement ifStatement(AST ifNode) {
+        AST node = ifNode.getFirstChild();
+        assertNodeType(EXPR, node);
+        BooleanExpression booleanExpression = booleanExpression(node);
+
+        node = node.getNextSibling();
+        Statement ifBlock = statement(node);
+
+        Statement elseBlock = EmptyStatement.INSTANCE;
+        node = node.getNextSibling();
+        if (node != null) {
+            elseBlock = statement(node);
+        }
+        IfStatement ifStatement = new IfStatement(booleanExpression, ifBlock, elseBlock);
+        configureAST(ifStatement, ifNode);
+        return ifStatement;
+    }
+
+    protected Statement labelledStatement(AST labelNode) {
+        AST node = labelNode.getFirstChild();
+        String label = identifier(node);
+        Statement statement = statement(node.getNextSibling());
+        statement.setStatementLabel(label);
+        return statement;
+    }
+
+    protected Statement methodCall(AST code) {
+        Expression expression = methodCallExpression(code);
+        ExpressionStatement expressionStatement = new ExpressionStatement(expression);
+        configureAST(expressionStatement, code);
+        return expressionStatement;
+    }
+
+    protected Statement variableDef(AST variableDef) {
+        AST node = variableDef.getFirstChild();
+        ClassNode type = null;
+        if (isType(MODIFIERS, node)) {
+            node = node.getNextSibling();
+        }
+        if (isType(TYPE, node)) {
+            type = makeType(node);
+            node = node.getNextSibling();
+        }
+
+        String name = identifier(node);
+        node = node.getNextSibling();
+
+        VariableExpression leftExpression = new VariableExpression(name, type);
+        configureAST(leftExpression, variableDef);
+
+        Expression rightExpression = ConstantExpression.NULL;
+        if (node != null) {
+            assertNodeType(ASSIGN, node);
+
+            rightExpression = expression(node.getFirstChild());
+        }
+        Token token = makeToken(Types.ASSIGN, variableDef);
+
+        // TODO should we have a variable declaration statement?
+        DeclarationExpression expression = new DeclarationExpression(leftExpression, token, rightExpression);
+        configureAST(expression, variableDef);
+        ExpressionStatement expressionStatement = new ExpressionStatement(expression);
+        configureAST(expressionStatement, variableDef);
+        return expressionStatement;
+    }
+
+    protected Statement returnStatement(AST node) {
+        AST exprNode = node.getFirstChild();
+
+        // This will pick up incorrect sibling node if 'node' is a plain 'return'
+		//
+		//if (exprNode == null) {
+        //    exprNode = node.getNextSibling();
+        //}
+        if (exprNode != null) {
+            Expression expression = expression(exprNode);
+            if (expression instanceof ConstantExpression) {
+                ConstantExpression constantExpr = (ConstantExpression) expression;
+                if (constantExpr.getValue() == null) {
+                    return ReturnStatement.RETURN_NULL_OR_VOID;
+                }
+            }
+            ReturnStatement returnStatement = new ReturnStatement(expression);
+            configureAST(returnStatement, node);
+            return returnStatement;
+        }
+        else {
+            return ReturnStatement.RETURN_NULL_OR_VOID;
+        }
+    }
+
+    protected Statement switchStatement(AST switchNode) {
+        AST node = switchNode.getFirstChild();
+        Expression expression = expression(node);
+        Statement defaultStatement = EmptyStatement.INSTANCE;
+
+        List list = new ArrayList();
+        for (node = node.getNextSibling(); isType(CASE_GROUP, node); node = node.getNextSibling()) {
+            AST child = node.getFirstChild();
+            if (isType(LITERAL_case, child)) {
+                list.add(caseStatement(child));
+            } else {
+                defaultStatement = statement(child.getNextSibling());
+            }
+        }
+        if (node != null) {
+            unknownAST(node);
+        }
+        SwitchStatement switchStatement = new SwitchStatement(expression, list, defaultStatement);
+        configureAST(switchStatement, switchNode);
+        return switchStatement;
+    }
+
+    protected CaseStatement caseStatement(AST node) {
+        List expressions = new ArrayList();
+        Statement statement = EmptyStatement.INSTANCE;
+        AST nextSibling = node;
+        do {
+            Expression expression = expression(nextSibling.getFirstChild());
+            expressions.add(expression);
+            nextSibling = nextSibling.getNextSibling();
+        } while (isType(LITERAL_case, nextSibling));
+        if (!isType(LITERAL_default, nextSibling) && nextSibling != null) {
+             statement = statement(nextSibling);
+        }
+        CaseStatement answer;
+        if (expressions.size() == 1) {
+            // single case uses original code for effiiency
+            answer = new CaseStatement((Expression) expressions.get(0), statement);
+        } else {
+            // multiple cases in casegroup are grouped as an expression
+            // doesn't seem to mix well with certain case expressions, e.g. regex
+            ListExpression listExpression = new ListExpression(expressions);
+            answer = new CaseStatement(listExpression, statement);
+        }
+        configureAST(answer, node);
+        return answer;
+    }
+
+    protected Statement synchronizedStatement(AST syncNode) {
+        AST node = syncNode.getFirstChild();
+        Expression expression = expression(node);
+        Statement code = statement(node.getNextSibling());
+        SynchronizedStatement synchronizedStatement = new SynchronizedStatement(expression, code);
+        configureAST(synchronizedStatement, syncNode);
+        return synchronizedStatement;
+    }
+
+    protected Statement throwStatement(AST node) {
+        AST expressionNode = node.getFirstChild();
+        if (expressionNode == null) {
+            expressionNode = node.getNextSibling();
+        }
+        if (expressionNode == null) {
+            throw new ASTRuntimeException(node, "No expression available");
+        }
+        ThrowStatement throwStatement = new ThrowStatement(expression(expressionNode));
+        configureAST(throwStatement, node);
+        return throwStatement;
+    }
+
+    protected Statement tryStatement(AST tryStatementNode) {
+        AST tryNode = tryStatementNode.getFirstChild();
+        Statement tryStatement = statement(tryNode);
+        Statement finallyStatement = EmptyStatement.INSTANCE;
+        AST node = tryNode.getNextSibling();
+
+        // lets do the catch nodes
+        List catches = new ArrayList();
+        for (; node != null && isType(LITERAL_catch, node); node = node.getNextSibling()) {
+            catches.add(catchStatement(node));
+        }
+
+        if (isType(LITERAL_finally, node)) {
+            finallyStatement = statement(node);
+            node = node.getNextSibling();
+        }
+
+        TryCatchStatement tryCatchStatement = new TryCatchStatement(tryStatement, finallyStatement);
+        configureAST(tryCatchStatement, tryStatementNode);
+        for (Iterator iter = catches.iterator(); iter.hasNext();) {
+            CatchStatement statement = (CatchStatement) iter.next();
+            tryCatchStatement.addCatch(statement);
+        }
+        return tryCatchStatement;
+    }
+
+    protected CatchStatement catchStatement(AST catchNode) {
+        AST node = catchNode.getFirstChild();
+        Parameter parameter = parameter(node);
+        ClassNode exceptionType = parameter.getType();
+        String variable = parameter.getName();
+        node = node.getNextSibling();
+        Statement code = statement(node);
+        Parameter catchParameter = new Parameter(exceptionType,variable);
+        CatchStatement answer = new CatchStatement(catchParameter, code);
+        configureAST(answer, catchNode);
+        return answer;
+    }
+
+    protected Statement whileStatement(AST whileNode) {
+        AST node = whileNode.getFirstChild();
+        assertNodeType(EXPR, node);
+        BooleanExpression booleanExpression = booleanExpression(node);
+
+        node = node.getNextSibling();
+        Statement block = statement(node);
+        WhileStatement whileStatement = new WhileStatement(booleanExpression, block);
+        configureAST(whileStatement, whileNode);
+        return whileStatement;
+    }
+
+    protected Statement withStatement(AST node) {
+        notImplementedYet(node);
+        return null; /** TODO */
+    }
+
+
+
+    // Expressions
+    //-------------------------------------------------------------------------
+
+    protected Expression expression(AST node) {
+        return expression(node,false);
+    }
+    
+    protected Expression expression(AST node, boolean convertToConstant) {
+        Expression expression = expressionSwitch(node);
+        if (convertToConstant) {
+            // a method name can never be a VariableExprssion, so it must converted
+            // to a ConstantExpression then. This is needed as the expression
+            // method doesn't know we want a ConstantExpression instead of a
+            // VariableExpression
+            if ( expression != VariableExpression.THIS_EXPRESSION &&
+                 expression != VariableExpression.SUPER_EXPRESSION &&
+                 expression instanceof VariableExpression) 
+            {
+                VariableExpression ve = (VariableExpression) expression;
+                expression = new ConstantExpression(ve.getName());
+            }
+        }
+        configureAST(expression, node);
+        return expression;       
+    }
+
+    protected Expression expressionSwitch(AST node) {
+        int type = node.getType();
+        switch (type) {
+            case EXPR:
+                return expression(node.getFirstChild());
+
+            case ELIST:
+                return expressionList(node);
+
+            case SLIST:
+                return blockExpression(node);
+
+            case CLOSABLE_BLOCK:
+                return closureExpression(node);
+
+            case SUPER_CTOR_CALL:
+                return specialConstructorCallExpression(node,ClassNode.SUPER);
+
+            case METHOD_CALL:
+                return methodCallExpression(node);
+
+            case LITERAL_new:
+                return constructorCallExpression(node.getFirstChild());
+
+            case CTOR_CALL:
+                return specialConstructorCallExpression(node,ClassNode.THIS);
+
+            case QUESTION:
+                return ternaryExpression(node);
+
+            case OPTIONAL_DOT:
+            case SPREAD_DOT:
+            case DOT:
+                return dotExpression(node);
+
+            case IDENT:
+            case LITERAL_boolean:
+            case LITERAL_byte:
+            case LITERAL_char:
+            case LITERAL_double:
+            case LITERAL_float:
+            case LITERAL_int:
+            case LITERAL_long:
+            case LITERAL_short:
+            case LITERAL_void:
+                return variableExpression(node);
+
+            case LIST_CONSTRUCTOR:
+                return listExpression(node);
+
+            case MAP_CONSTRUCTOR:
+                return mapExpression(node);
+
+            case LABELED_ARG:
+                return mapEntryExpression(node);
+
+            case SPREAD_ARG:
+                return spreadExpression(node);
+
+            case SPREAD_MAP_ARG:
+                return spreadMapExpression(node);
+
+            // commented out of groovy.g due to non determinisms
+            //case MEMBER_POINTER_DEFAULT:
+            //    return defaultMethodPointerExpression(node);
+
+            case MEMBER_POINTER:
+                return methodPointerExpression(node);
+
+            case INDEX_OP:
+                return indexExpression(node);
+
+            case LITERAL_instanceof:
+                return instanceofExpression(node);
+
+            case LITERAL_as:
+                return asExpression(node);
+
+            case TYPECAST:
+                return castExpression(node);
+
+                // literals
+
+            case LITERAL_true:
+                return ConstantExpression.TRUE;
+
+            case LITERAL_false:
+                return ConstantExpression.FALSE;
+
+            case LITERAL_null:
+                return ConstantExpression.NULL;
+
+            case STRING_LITERAL:
+                ConstantExpression constantExpression = new ConstantExpression(node.getText());
+                configureAST(constantExpression, node);
+                return constantExpression;
+
+            case STRING_CONSTRUCTOR:
+                return gstring(node);
+
+            case NUM_DOUBLE:
+            case NUM_FLOAT:
+            case NUM_BIG_DECIMAL:
+                return decimalExpression(node);
+
+            case NUM_BIG_INT:
+            case NUM_INT:
+            case NUM_LONG:
+                return integerExpression(node);
+
+            case LITERAL_this:
+                return VariableExpression.THIS_EXPRESSION;
+
+            case LITERAL_super:
+                return VariableExpression.SUPER_EXPRESSION;
+
+
+                // Unary expressions
+            case LNOT:
+                NotExpression notExpression = new NotExpression(expression(node.getFirstChild()));
+                configureAST(notExpression, node);
+                return notExpression;
+
+            case UNARY_MINUS:
+                return negateExpression(node);
+
+            case BNOT:
+                BitwiseNegExpression bitwiseNegExpression = new BitwiseNegExpression(expression(node.getFirstChild()));
+                configureAST(bitwiseNegExpression, node);
+                return bitwiseNegExpression;
+
+            case UNARY_PLUS:
+                return expression(node.getFirstChild());
+
+
+                // Prefix expressions
+            case INC:
+                return prefixExpression(node, Types.PLUS_PLUS);
+
+            case DEC:
+                return prefixExpression(node, Types.MINUS_MINUS);
+
+                // Postfix expressions
+            case POST_INC:
+                return postfixExpression(node, Types.PLUS_PLUS);
+
+            case POST_DEC:
+                return postfixExpression(node, Types.MINUS_MINUS);
+
+
+                // Binary expressions
+
+            case ASSIGN:
+                return binaryExpression(Types.ASSIGN, node);
+
+            case EQUAL:
+                return binaryExpression(Types.COMPARE_EQUAL, node);
+
+            case NOT_EQUAL:
+                return binaryExpression(Types.COMPARE_NOT_EQUAL, node);
+
+            case COMPARE_TO:
+                return binaryExpression(Types.COMPARE_TO, node);
+
+            case LE:
+                return binaryExpression(Types.COMPARE_LESS_THAN_EQUAL, node);
+
+            case LT:
+                return binaryExpression(Types.COMPARE_LESS_THAN, node);
+
+            case GT:
+                return binaryExpression(Types.COMPARE_GREATER_THAN, node);
+
+            case GE:
+                return binaryExpression(Types.COMPARE_GREATER_THAN_EQUAL, node);
+
+                /**
+                 * TODO treble equal?
+                 return binaryExpression(Types.COMPARE_IDENTICAL, node);
+
+                 case ???:
+                 return binaryExpression(Types.LOGICAL_AND_EQUAL, node);
+
+                 case ???:
+                 return binaryExpression(Types.LOGICAL_OR_EQUAL, node);
+
+                 */
+
+            case LAND:
+                return binaryExpression(Types.LOGICAL_AND, node);
+
+            case LOR:
+                return binaryExpression(Types.LOGICAL_OR, node);
+
+            case BAND:
+                return binaryExpression(Types.BITWISE_AND, node);
+
+            case BAND_ASSIGN:
+                return binaryExpression(Types.BITWISE_AND_EQUAL, node);
+
+            case BOR:
+                return binaryExpression(Types.BITWISE_OR, node);
+
+            case BOR_ASSIGN:
+                return binaryExpression(Types.BITWISE_OR_EQUAL, node);
+
+            case BXOR:
+                return binaryExpression(Types.BITWISE_XOR, node);
+
+            case BXOR_ASSIGN:
+                return binaryExpression(Types.BITWISE_XOR_EQUAL, node);
+
+
+            case PLUS:
+                return binaryExpression(Types.PLUS, node);
+
+            case PLUS_ASSIGN:
+                return binaryExpression(Types.PLUS_EQUAL, node);
+
+
+            case MINUS:
+                return binaryExpression(Types.MINUS, node);
+
+            case MINUS_ASSIGN:
+                return binaryExpression(Types.MINUS_EQUAL, node);
+
+
+            case STAR:
+                return binaryExpression(Types.MULTIPLY, node);
+
+            case STAR_ASSIGN:
+                return binaryExpression(Types.MULTIPLY_EQUAL, node);
+
+
+            case STAR_STAR:
+                return binaryExpression(Types.POWER, node);
+
+            case STAR_STAR_ASSIGN:
+                return binaryExpression(Types.POWER_EQUAL, node);
+
+
+            case DIV:
+                return binaryExpression(Types.DIVIDE, node);
+
+            case DIV_ASSIGN:
+                return binaryExpression(Types.DIVIDE_EQUAL, node);
+
+
+            case MOD:
+                return binaryExpression(Types.MOD, node);
+
+            case MOD_ASSIGN:
+                return binaryExpression(Types.MOD_EQUAL, node);
+
+            case SL:
+                return binaryExpression(Types.LEFT_SHIFT, node);
+
+            case SL_ASSIGN:
+                return binaryExpression(Types.LEFT_SHIFT_EQUAL, node);
+
+            case SR:
+                return binaryExpression(Types.RIGHT_SHIFT, node);
+
+            case SR_ASSIGN:
+                return binaryExpression(Types.RIGHT_SHIFT_EQUAL, node);
+
+            case BSR:
+                return binaryExpression(Types.RIGHT_SHIFT_UNSIGNED, node);
+
+            case BSR_ASSIGN:
+                return binaryExpression(Types.RIGHT_SHIFT_UNSIGNED_EQUAL, node);
+
+                // Regex
+            case REGEX_FIND:
+                return binaryExpression(Types.FIND_REGEX, node);
+
+            case REGEX_MATCH:
+                return binaryExpression(Types.MATCH_REGEX, node);
+
+
+                // Ranges
+            case RANGE_INCLUSIVE:
+                return rangeExpression(node, true);
+
+            case RANGE_EXCLUSIVE:
+                return rangeExpression(node, false);
+
+            case DYNAMIC_MEMBER:
+                return dynamicMemberExpression(node);
+                
+            case LITERAL_in:
+                return binaryExpression(Types.KEYWORD_IN,node);
+                
+            default:
+                unknownAST(node);
+        }
+        return null;
+    }
+
+    protected Expression dynamicMemberExpression(AST dynamicMemberNode) {
+        AST node = dynamicMemberNode.getFirstChild();
+        return expression(node);
+    }
+
+    protected Expression ternaryExpression(AST ternaryNode) {
+        AST node = ternaryNode.getFirstChild();
+        BooleanExpression booleanExpression = booleanExpression(node);
+        node = node.getNextSibling();
+        Expression left = expression(node);
+        Expression right = expression(node.getNextSibling());
+        TernaryExpression ternaryExpression = new TernaryExpression(booleanExpression, left, right);
+        configureAST(ternaryExpression, ternaryNode);
+        return ternaryExpression;
+    }
+
+    protected Expression variableExpression(AST node) {
+        String text = node.getText();
+
+        // TODO we might wanna only try to resolve the name if we are
+        // on the left hand side of an expression or before a dot?
+        VariableExpression variableExpression = new VariableExpression(text);
+        configureAST(variableExpression, node);
+        return variableExpression;
+    }
+
+    protected Expression rangeExpression(AST rangeNode, boolean inclusive) {
+        AST node = rangeNode.getFirstChild();
+        Expression left = expression(node);
+        Expression right = expression(node.getNextSibling());
+        RangeExpression rangeExpression = new RangeExpression(left, right, inclusive);
+        configureAST(rangeExpression, rangeNode);
+        return rangeExpression;
+    }
+
+    protected Expression spreadExpression(AST node) {
+        AST exprNode = node.getFirstChild();
+        AST listNode = exprNode.getFirstChild();
+        Expression right = expression(listNode);
+        SpreadExpression spreadExpression = new SpreadExpression(right);
+        configureAST(spreadExpression, node);
+        return spreadExpression;
+    }
+
+    protected Expression spreadMapExpression(AST node) {
+        AST exprNode = node.getFirstChild();
+        Expression expr = expression(exprNode);
+        SpreadMapExpression spreadMapExpression = new SpreadMapExpression(expr);
+        configureAST(spreadMapExpression, node);
+        return spreadMapExpression;
+    }
+
+    protected Expression methodPointerExpression(AST node) {
+        AST exprNode = node.getFirstChild();
+        String methodName = identifier(exprNode.getNextSibling());
+        Expression expression = expression(exprNode);
+        MethodPointerExpression methodPointerExpression = new MethodPointerExpression(expression, methodName);
+        configureAST(methodPointerExpression, node);
+        return methodPointerExpression;
+    }
+
+/*  commented out due to groovy.g non-determinisms
+  protected Expression defaultMethodPointerExpression(AST node) {
+        AST exprNode = node.getFirstChild();
+        String methodName = exprNode.toString();
+        MethodPointerExpression methodPointerExpression = new MethodPointerExpression(null, methodName);
+        configureAST(methodPointerExpression, node);
+        return methodPointerExpression;
+    }
+*/
+
+    protected Expression listExpression(AST listNode) {
+        List expressions = new ArrayList();
+        AST elist = listNode.getFirstChild();
+        assertNodeType(ELIST, elist);
+
+        for (AST node = elist.getFirstChild(); node != null; node = node.getNextSibling()) {
+            // check for stray labeled arguments:
+            switch (node.getType()) {
+            case LABELED_ARG:       assertNodeType(COMMA, node);       break;  // helpful error?
+            case SPREAD_MAP_ARG:    assertNodeType(SPREAD_ARG, node);  break;  // helpful error
+            }
+            expressions.add(expression(node));
+        }
+        ListExpression listExpression = new ListExpression(expressions);
+        configureAST(listExpression, listNode);
+        return listExpression;
+    }
+
+    /**
+     * Typically only used for map constructors I think?
+     */
+    protected Expression mapExpression(AST mapNode) {
+        List expressions = new ArrayList();
+        AST elist = mapNode.getFirstChild();
+        if (elist != null) {  // totally empty in the case of [:]
+            assertNodeType(ELIST, elist);
+            for (AST node = elist.getFirstChild(); node != null; node = node.getNextSibling()) {
+                switch (node.getType()) {
+                case LABELED_ARG:
+                case SPREAD_MAP_ARG:
+                    break;  // legal cases
+                case SPREAD_ARG:
+                    assertNodeType(SPREAD_MAP_ARG, node);  break;  // helpful error
+                default:
+                    assertNodeType(LABELED_ARG, node);  break;  // helpful error
+                }
+                expressions.add(mapEntryExpression(node));
+            }
+        }
+        MapExpression mapExpression = new MapExpression(expressions);
+        configureAST(mapExpression, mapNode);
+        return mapExpression;
+    }
+
+    protected MapEntryExpression mapEntryExpression(AST node) {
+        if (node.getType() == SPREAD_MAP_ARG) {
+            AST rightNode = node.getFirstChild();
+            Expression keyExpression = spreadMapExpression(node);
+            Expression rightExpression = expression(rightNode);
+            MapEntryExpression mapEntryExpression = new MapEntryExpression(keyExpression, rightExpression);
+            configureAST(mapEntryExpression, node);
+            return mapEntryExpression;
+        }
+        else {
+            AST keyNode = node.getFirstChild();
+            Expression keyExpression = expression(keyNode);
+            AST valueNode = keyNode.getNextSibling();
+            Expression valueExpression = expression(valueNode);
+            MapEntryExpression mapEntryExpression = new MapEntryExpression(keyExpression, valueExpression);
+            configureAST(mapEntryExpression, node);
+            return mapEntryExpression;
+        }
+    }
+
+
+    protected Expression instanceofExpression(AST node) {
+        AST leftNode = node.getFirstChild();
+        Expression leftExpression = expression(leftNode);
+
+        AST rightNode = leftNode.getNextSibling();
+        ClassNode type = buildName(rightNode);
+        assertTypeNotNull(type, rightNode);
+
+        Expression rightExpression = new ClassExpression(type);
+        configureAST(rightExpression, rightNode);
+        BinaryExpression binaryExpression = new BinaryExpression(leftExpression, makeToken(Types.KEYWORD_INSTANCEOF, node), rightExpression);
+        configureAST(binaryExpression, node);
+        return binaryExpression;
+    }
+
+    protected void assertTypeNotNull(ClassNode type, AST rightNode) {
+        if (type == null) {
+            throw new ASTRuntimeException(rightNode, "No type available for: " + qualifiedName(rightNode));
+        }
+    }
+
+    protected Expression asExpression(AST node) {
+        AST leftNode = node.getFirstChild();
+        Expression leftExpression = expression(leftNode);
+
+        AST rightNode = leftNode.getNextSibling();
+        ClassNode type = buildName(rightNode);
+
+        return CastExpression.asExpression(type, leftExpression);
+    }
+
+    protected Expression castExpression(AST castNode) {
+        AST node = castNode.getFirstChild();
+        ClassNode type = buildName(node);
+        assertTypeNotNull(type, node);
+
+        AST expressionNode = node.getNextSibling();
+        Expression expression = expression(expressionNode);
+
+        CastExpression castExpression = new CastExpression(type, expression);
+        configureAST(castExpression, castNode);
+        return castExpression;
+    }
+
+
+    protected Expression indexExpression(AST indexNode) {
+        AST leftNode = indexNode.getFirstChild();
+        Expression leftExpression = expression(leftNode);
+
+        AST rightNode = leftNode.getNextSibling();
+        Expression rightExpression = expression(rightNode);
+
+        BinaryExpression binaryExpression = new BinaryExpression(leftExpression, makeToken(Types.LEFT_SQUARE_BRACKET, indexNode), rightExpression);
+        configureAST(binaryExpression, indexNode);
+        return binaryExpression;
+    }
+
+    protected Expression binaryExpression(int type, AST node) {
+        Token token = makeToken(type, node);
+
+        AST leftNode = node.getFirstChild();
+        Expression leftExpression = expression(leftNode);
+
+        AST rightNode = leftNode.getNextSibling();
+        if (rightNode == null) {
+            return leftExpression;
+        }
+
+        if (Types.ofType(type, Types.ASSIGNMENT_OPERATOR)) {
+            if (leftExpression instanceof VariableExpression || leftExpression.getClass() == PropertyExpression.class
+                                                             || leftExpression instanceof FieldExpression
+                                                             || leftExpression instanceof AttributeExpression
+                                                             || leftExpression instanceof DeclarationExpression) {
+                // Do nothing.
+            }
+            else if (leftExpression instanceof ConstantExpression) {
+                throw new ASTRuntimeException(node, "\n[" + ((ConstantExpression) leftExpression).getValue() + "] is a constant expression, but it should be a variable expression");
+            }
+            else if (leftExpression instanceof BinaryExpression) {
+                Expression leftexp = ((BinaryExpression) leftExpression).getLeftExpression();
+                int lefttype = ((BinaryExpression) leftExpression).getOperation().getType();
+                if (!Types.ofType(lefttype, Types.ASSIGNMENT_OPERATOR) && lefttype != Types.LEFT_SQUARE_BRACKET) {
+                    throw new ASTRuntimeException(node, "\n" + ((BinaryExpression) leftExpression).getText() + " is a binary expression, but it should be a variable expression");
+                }
+            }
+            else if (leftExpression instanceof GStringExpression) {
+                throw new ASTRuntimeException(node, "\n\"" + ((GStringExpression) leftExpression).getText() + "\" is a GString expression, but it should be a variable expression");
+            }
+            else if (leftExpression instanceof MethodCallExpression) {
+                throw new ASTRuntimeException(node, "\n\"" + ((MethodCallExpression) leftExpression).getText() + "\" is a method call expression, but it should be a variable expression");
+            }
+            else if (leftExpression instanceof MapExpression) {
+                throw new ASTRuntimeException(node, "\n'" + ((MapExpression) leftExpression).getText() + "' is a map expression, but it should be a variable expression");
+            }
+            else {
+                throw new ASTRuntimeException(node, "\n" + leftExpression.getClass() + ", with its value '" + leftExpression.getText() + "', is a bad expression as the LSH of an assignment operator");
+            }
+        }
+        /*if (rightNode == null) {
+            throw new NullPointerException("No rightNode associated with binary expression");
+        }*/
+        Expression rightExpression = expression(rightNode);
+        BinaryExpression binaryExpression = new BinaryExpression(leftExpression, token, rightExpression);
+        configureAST(binaryExpression, node);
+        return binaryExpression;
+    }
+
+    protected Expression prefixExpression(AST node, int token) {
+        Expression expression = expression(node.getFirstChild());
+        PrefixExpression prefixExpression = new PrefixExpression(makeToken(token, node), expression);
+        configureAST(prefixExpression, node);
+        return prefixExpression;
+    }
+
+    protected Expression postfixExpression(AST node, int token) {
+        Expression expression = expression(node.getFirstChild());
+        PostfixExpression postfixExpression = new PostfixExpression(expression, makeToken(token, node));
+        configureAST(postfixExpression, node);
+        return postfixExpression;
+    }
+
+    protected BooleanExpression booleanExpression(AST node) {
+        BooleanExpression booleanExpression = new BooleanExpression(expression(node));
+        configureAST(booleanExpression, node);
+        return booleanExpression;
+    }
+
+    protected Expression dotExpression(AST node) {
+        // lets decide if this is a propery invocation or a method call
+        AST leftNode = node.getFirstChild();
+        if (leftNode != null) {
+            AST identifierNode = leftNode.getNextSibling();
+            if (identifierNode != null) {
+                Expression leftExpression = expression(leftNode);
+                if (isType(SELECT_SLOT, identifierNode)) {
+                    Expression field = expression(identifierNode.getFirstChild(),true);
+                    AttributeExpression attributeExpression = new AttributeExpression(leftExpression, field, node.getType() != DOT);
+                    if (node.getType() == SPREAD_DOT) {
+                        attributeExpression.setSpreadSafe(true);
+                    }
+                    configureAST(attributeExpression, node);
+                    return attributeExpression;
+                }
+                Expression property = expression(identifierNode,true);
+                
+                PropertyExpression propertyExpression = new PropertyExpression(leftExpression, property, node.getType() != DOT);
+                if (node.getType() == SPREAD_DOT) {
+                    propertyExpression.setSpreadSafe(true);
+                } 
+                configureAST(propertyExpression, node);
+                return propertyExpression;
+            }
+        }
+        return methodCallExpression(node);
+    }
+    
+    protected Expression specialConstructorCallExpression(AST methodCallNode, ClassNode special) {
+        AST node = methodCallNode.getFirstChild();
+        Expression arguments = arguments(node);
+        
+        ConstructorCallExpression expression = new ConstructorCallExpression(special, arguments);
+        configureAST(expression, methodCallNode);
+        return expression;
+    }
+
+    private int getTypeInParenthesis(AST node) {
+        if (! isType(EXPR,node) ) node = node.getFirstChild();
+        while (node!=null &&isType(EXPR,node) && node.getNextSibling()==null) {
+            node = node.getFirstChild();
+        }
+        if (node==null) return -1;
+        return node.getType();
+    }
+
+    protected Expression methodCallExpression(AST methodCallNode) {
+        AST node = methodCallNode.getFirstChild();
+        /* // Bad idea, since foo(1)(2) is valid Groovy for foo(1).call(2).
+        if (isType(METHOD_CALL, node)) {
+            // sometimes method calls get wrapped in method calls for some wierd reason
+            return methodCallExpression(node);
+        }
+        */
+
+        Expression objectExpression;
+        AST selector;
+        AST elist = node.getNextSibling();
+        
+        boolean implicitThis = false;
+        boolean safe = isType(OPTIONAL_DOT, node);
+        boolean spreadSafe = isType(SPREAD_DOT, node);
+        if (isType(DOT, node) || safe || spreadSafe) {
+            AST objectNode = node.getFirstChild();
+            objectExpression = expression(objectNode);
+            selector = objectNode.getNextSibling();
+        } else {
+            implicitThis = true;
+            objectExpression = VariableExpression.THIS_EXPRESSION;
+            selector = node;
+        } 
+
+        Expression name = null;
+        if (isType(LITERAL_super, selector)) {
+            implicitThis = true;
+            name = new ConstantExpression("super");
+            if (objectExpression == VariableExpression.THIS_EXPRESSION) {
+                objectExpression = VariableExpression.SUPER_EXPRESSION;
+            }
+        } else if (isPrimitiveTypeLiteral(selector)) {
+            throw new ASTRuntimeException(selector, "Primitive type literal: " + selector.getText()
+                    + " cannot be used as a method name");
+        } else if (isType(SELECT_SLOT, selector)) {
+            Expression field = expression(selector.getFirstChild(),true);
+            AttributeExpression attributeExpression = new AttributeExpression(objectExpression, field, node.getType() != DOT);
+            configureAST(attributeExpression, node);
+            Expression arguments = arguments(elist);
+            MethodCallExpression expression = new MethodCallExpression(attributeExpression, "call", arguments);
+            configureAST(expression, methodCallNode);
+            return expression;
+        } else if  
+               (isType(DYNAMIC_MEMBER, selector) || isType(IDENT,selector) || 
+                isType(STRING_CONSTRUCTOR,selector) || isType (STRING_LITERAL,selector)) 
+        { 
+            name = expression(selector,true);
+        } else {
+            implicitThis = false;
+            name = new ConstantExpression("call");
+            objectExpression = expression(selector,true);
+        } 
+
+        Expression arguments = arguments(elist);
+        MethodCallExpression expression = new MethodCallExpression(objectExpression, name, arguments);
+        expression.setSafe(safe);
+        expression.setSpreadSafe(spreadSafe);
+        expression.setImplicitThis(implicitThis);
+        Expression ret = expression;
+        //FIXME: do we really want this() to create a new object regardless
+        // the position.. for example not as first statement in a constructor
+        // this=first statement in contructor is handled by specialConstructorCallExpression
+        // we may have to add a check and remove this part of the code
+        if (implicitThis && "this".equals(expression.getMethodAsString())) {
+            ret = new ConstructorCallExpression(this.classNode, arguments);
+        }
+        configureAST(ret, methodCallNode);
+        return ret;
+    }
+    
+    protected Expression constructorCallExpression(AST node) {
+        AST constructorCallNode = node;
+        ClassNode type = buildName(constructorCallNode);
+
+        if (isType(CTOR_CALL, node) || isType(LITERAL_new, node)) {
+            node = node.getFirstChild();
+        }
+
+        AST elist = node.getNextSibling();
+
+        if (elist == null && isType(ELIST, node)) {
+            elist = node;
+            if ("(".equals(type.getName())) {
+                type = classNode;
+            }
+        }
+
+        if (isType(ARRAY_DECLARATOR, elist)) {
+            AST expressionNode = elist.getFirstChild();
+            if (expressionNode == null) {
+                throw new ASTRuntimeException(elist, "No expression for the array constructor call");
+            }
+            List size = arraySizeExpression(expressionNode);
+            ArrayExpression arrayExpression = new ArrayExpression(type, null, size);
+            configureAST(arrayExpression, constructorCallNode);
+            return arrayExpression;
+        }
+        Expression arguments = arguments(elist);
+        ConstructorCallExpression expression = new ConstructorCallExpression(type, arguments);
+        configureAST(expression, constructorCallNode);
+        return expression;
+    }
+    
+    protected List arraySizeExpression(AST node) {
+        List list;
+        Expression size = null;
+    	if (isType(ARRAY_DECLARATOR,node)) {
+    		AST right = node.getNextSibling();
+        	if (right!=null) {
+        		size = expression(right);
+        	} else {
+        		size = ConstantExpression.EMTPY_EXPRESSION;
+        	}
+        	list = arraySizeExpression(node.getFirstChild());
+        } else {
+        	size = expression(node);
+        	list = new ArrayList();
+        }
+    	list.add(size);
+    	return list;
+    }
+
+    protected Expression arguments(AST elist) {
+        List expressionList = new ArrayList();
+        // FIXME: all labeled arguments should follow any unlabeled arguments
+        boolean namedArguments = false;
+        for (AST node = elist; node != null; node = node.getNextSibling()) {
+            if (isType(ELIST, node)) {
+                for (AST child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
+                    namedArguments |= addArgumentExpression(child, expressionList);
+                }
+            }
+            else {
+                namedArguments |= addArgumentExpression(node, expressionList);
+            }
+        }
+        if (namedArguments) {
+            if (!expressionList.isEmpty()) {
+                // lets remove any non-MapEntryExpression instances
+                // such as if the last expression is a ClosureExpression
+                // so lets wrap the named method calls in a Map expression
+                List argumentList = new ArrayList();
+                for (Iterator iter = expressionList.iterator(); iter.hasNext();) {
+                    Expression expression = (Expression) iter.next();
+                    if (!(expression instanceof MapEntryExpression)) {
+                        argumentList.add(expression);
+                    }
+                }
+                if (!argumentList.isEmpty()) {
+                    expressionList.removeAll(argumentList);
+                    MapExpression mapExpression = new MapExpression(expressionList);
+                    configureAST(mapExpression, elist);
+                    argumentList.add(0, mapExpression);
+                    ArgumentListExpression argumentListExpression = new ArgumentListExpression(argumentList);
+                    configureAST(argumentListExpression, elist);
+                    return argumentListExpression;
+                }
+            }
+            NamedArgumentListExpression namedArgumentListExpression = new NamedArgumentListExpression(expressionList);
+            configureAST(namedArgumentListExpression, elist);
+            return namedArgumentListExpression;
+        }
+        else {
+            ArgumentListExpression argumentListExpression = new ArgumentListExpression(expressionList);
+            configureAST(argumentListExpression, elist);
+            return argumentListExpression;
+        }
+    }
+
+    protected boolean addArgumentExpression(AST node, List expressionList) {
+        if (node.getType() == SPREAD_MAP_ARG) {
+            AST rightNode = node.getFirstChild();
+            Expression keyExpression = spreadMapExpression(node);
+            Expression rightExpression = expression(rightNode);
+            MapEntryExpression mapEntryExpression = new MapEntryExpression(keyExpression, rightExpression);
+            expressionList.add(mapEntryExpression);
+            return true;
+        }
+        else {
+            Expression expression = expression(node);
+            expressionList.add(expression);
+            return expression instanceof MapEntryExpression;
+        }
+    }
+
+    protected Expression expressionList(AST node) {
+        List expressionList = new ArrayList();
+        for (AST child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
+            expressionList.add(expression(child));
+        }
+        if (expressionList.size() == 1) {
+            return (Expression) expressionList.get(0);
+        }
+        else {
+            ListExpression listExpression = new ListExpression(expressionList);
+            configureAST(listExpression, node);
+            return listExpression;
+        }
+    }
+
+    protected ClosureExpression closureExpression(AST node) {
+        AST paramNode = node.getFirstChild();
+        Parameter[] parameters = null;
+        AST codeNode = paramNode;
+        if (isType(PARAMETERS, paramNode) || isType(IMPLICIT_PARAMETERS, paramNode)) {
+            parameters = parameters(paramNode);
+            codeNode = paramNode.getNextSibling();
+        }
+        Statement code = statementListNoChild(codeNode);
+        ClosureExpression closureExpression = new ClosureExpression(parameters, code);
+        configureAST(closureExpression, node);
+        return closureExpression;
+    }
+
+    protected Expression blockExpression(AST node) {
+        AST codeNode = node.getFirstChild();
+        if (codeNode == null)  return ConstantExpression.NULL;
+        if (codeNode.getType() == EXPR && codeNode.getNextSibling() == null) {
+            // Simplify common case of {expr} to expr.
+            return expression(codeNode);
+        }
+        Parameter[] parameters = Parameter.EMPTY_ARRAY;
+        Statement code = statementListNoChild(codeNode);
+        ClosureExpression closureExpression = new ClosureExpression(parameters, code);
+        configureAST(closureExpression, node);
+        // Call it immediately.
+        String callName = "call";
+        Expression noArguments = new ArgumentListExpression();
+        MethodCallExpression call = new MethodCallExpression(closureExpression, callName, noArguments);
+        configureAST(call, node);
+        return call;
+    }
+
+    protected Expression negateExpression(AST negateExpr) {
+        AST node = negateExpr.getFirstChild();
+
+        // if we are a number literal then lets just parse it
+        // as the negation operator on MIN_INT causes rounding to a long
+        String text = node.getText();
+        switch (node.getType()) {
+            case NUM_DOUBLE:
+            case NUM_FLOAT:
+            case NUM_BIG_DECIMAL:
+                ConstantExpression constantExpression = new ConstantExpression(Numbers.parseDecimal("-" + text));
+                configureAST(constantExpression, negateExpr);
+                return constantExpression;
+
+            case NUM_BIG_INT:
+            case NUM_INT:
+            case NUM_LONG:
+                ConstantExpression constantLongExpression = new ConstantExpression(Numbers.parseInteger("-" + text));
+                configureAST(constantLongExpression, negateExpr);
+                return constantLongExpression;
+
+            default:
+                NegationExpression negationExpression = new NegationExpression(expression(node));
+                configureAST(negationExpression, negateExpr);
+                return negationExpression;
+        }
+    }
+
+    protected ConstantExpression decimalExpression(AST node) {
+        String text = node.getText();
+        ConstantExpression constantExpression = new ConstantExpression(Numbers.parseDecimal(text));
+        configureAST(constantExpression, node);
+        return constantExpression;
+    }
+
+    protected ConstantExpression integerExpression(AST node) {
+        String text = node.getText();
+        ConstantExpression constantExpression = new ConstantExpression(Numbers.parseInteger(text));
+        configureAST(constantExpression, node);
+        return constantExpression;
+    }
+
+    protected Expression gstring(AST gstringNode) {
+        List strings = new ArrayList();
+        List values = new ArrayList();
+
+        StringBuffer buffer = new StringBuffer();
+
+        boolean isPrevString = false;
+
+        for (AST node = gstringNode.getFirstChild(); node != null; node = node.getNextSibling()) {
+            int type = node.getType();
+            String text = null;
+            switch (type) {
+
+                case STRING_LITERAL:
+                    if (isPrevString)  assertNodeType(IDENT, node);  // parser bug
+                    isPrevString = true;
+                    text = node.getText();
+                    ConstantExpression constantExpression = new ConstantExpression(text);
+                    configureAST(constantExpression, node);
+                    strings.add(constantExpression);
+                    buffer.append(text);
+                    break;
+
+                default:
+                    {
+                        if (!isPrevString)  assertNodeType(IDENT, node);  // parser bug
+                        isPrevString = false;
+                        Expression expression = expression(node);
+                        values.add(expression);
+                        buffer.append("$");
+                        buffer.append(expression.getText());
+                    }
+                    break;
+            }
+        }
+        GStringExpression gStringExpression = new GStringExpression(buffer.toString(), strings, values);
+        configureAST(gStringExpression, gstringNode);
+        return gStringExpression;
+    }
+
+    protected ClassNode type(AST typeNode) {
+        // TODO intern types?
+        // TODO configureAST(...)
+        return buildName(typeNode.getFirstChild());
+    }
+
+    public static String qualifiedName(AST qualifiedNameNode) {
+        if (isType(IDENT, qualifiedNameNode)) {
+            return qualifiedNameNode.getText();
+        }
+        if (isType(DOT, qualifiedNameNode)) {
+            AST node = qualifiedNameNode.getFirstChild();
+            StringBuffer buffer = new StringBuffer();
+            boolean first = true;
+
+            for (; node != null; node = node.getNextSibling()) {
+                if (first) {
+                    first = false;
+                }
+                else {
+                    buffer.append(".");
+                }
+                buffer.append(qualifiedName(node));
+            }
+            return buffer.toString();
+        }
+        else {
+            return qualifiedNameNode.getText();
+        }
+    }
+
+    protected ClassNode makeType(AST typeNode) {
+        ClassNode answer = ClassHelper.DYNAMIC_TYPE;
+        AST node = typeNode.getFirstChild();
+        if (node != null) {
+            if (isType(INDEX_OP, node) || isType(ARRAY_DECLARATOR, node)) {
+                return makeType(node).makeArray();
+             }
+            return ClassHelper.make(qualifiedName(node));
+        }
+        return answer;
+    }
+
+    /**
+     * Performs a name resolution to see if the given name is a type from imports,
+     * aliases or newly created classes
+     */
+    /*protected String resolveTypeName(String name, boolean safe) {
+        if (name == null) {
+            return null;
+        }
+        return resolveNewClassOrName(name, safe);
+    }*/
+
+    /**
+     * Extracts an identifier from the Antlr AST and then performs a name resolution
+     * to see if the given name is a type from imports, aliases or newly created classes
+     */
+    protected ClassNode buildName(AST node) {
+        if (isType(TYPE, node)) {
+            node = node.getFirstChild();
+        }
+        ClassNode answer = null;
+        if (isType(DOT, node) || isType(OPTIONAL_DOT, node)) {
+            answer = ClassHelper.make(qualifiedName(node));
+        }
+        else if (isPrimitiveTypeLiteral(node)) {
+            answer = ClassHelper.make(node.getText());
+        }
+        else if (isType(INDEX_OP, node) || isType(ARRAY_DECLARATOR, node)) {
+            AST child = node.getFirstChild();
+            return buildName(child).makeArray();
+        }
+        else {
+            String identifier = node.getText();
+            answer = ClassHelper.make(identifier);
+        }
+        AST nextSibling = node.getNextSibling();
+        if (isType(INDEX_OP, nextSibling) || isType(ARRAY_DECLARATOR, node)) {
+            return answer.makeArray();
+        }
+        else {
+            return answer;
+        }
+    }
+
+    protected boolean isPrimitiveTypeLiteral(AST node) {
+        int type = node.getType();
+        switch (type) {
+            case LITERAL_boolean:
+            case LITERAL_byte:
+            case LITERAL_char:
+            case LITERAL_double:
+            case LITERAL_float:
+            case LITERAL_int:
+            case LITERAL_long:
+            case LITERAL_short:
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Extracts an identifier from the Antlr AST
+     */
+    protected String identifier(AST node) {
+        assertNodeType(IDENT, node);
+        return node.getText();
+    }
+
+    protected String label(AST labelNode) {
+        AST node = labelNode.getFirstChild();
+        if (node == null) {
+            return null;
+        }
+        return identifier(node);
+    }
+
+
+
+    // Helper methods
+    //-------------------------------------------------------------------------
+
+
+    /**
+     * Returns true if the modifiers flags contain a visibility modifier
+     */
+    protected boolean hasVisibility(int modifiers) {
+        return (modifiers & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC)) != 0;
+    }
+
+    protected void configureAST(ASTNode node, AST ast) {
+        if (ast==null) throw new ASTRuntimeException(ast, "PARSER BUG: Tried to configure "+node.getClass().getName()+" with null Node");
+        node.setColumnNumber(ast.getColumn());
+        node.setLineNumber(ast.getLine());
+        if (ast instanceof GroovySourceAST) {
+            node.setLastColumnNumber(((GroovySourceAST)ast).getColumnLast());
+            node.setLastLineNumber(((GroovySourceAST)ast).getLineLast());
+        }
+
+        // TODO we could one day store the Antlr AST on the Groovy AST
+        // node.setCSTNode(ast);
+    }
+
+    protected static Token makeToken(int typeCode, AST node) {
+        return Token.newSymbol(typeCode, node.getLine(), node.getColumn());
+    }
+
+    protected String getFirstChildText(AST node) {
+        AST child = node.getFirstChild();
+        return child != null ? child.getText() : null;
+    }
+
+
+    public static boolean isType(int typeCode, AST node) {
+        return node != null && node.getType() == typeCode;
+    }
+
+    private String getTokenName(int token) {
+        if (tokenNames==null) return ""+token;
+        return tokenNames[token];
+    }
+    
+    private String getTokenName(AST node) {
+        if (node==null) return "null";
+        return getTokenName(node.getType());
+    }
+
+    protected void assertNodeType(int type, AST node) {
+        if (node == null) {
+            throw new ASTRuntimeException(node, "No child node available in AST when expecting type: " + getTokenName(type));
+        }
+        if (node.getType() != type) {            
+            throw new ASTRuntimeException(node, "Unexpected node type: " + getTokenName(node) + " found when expecting type: " + getTokenName(type));
+        }
+    }
+
+    protected void notImplementedYet(AST node) {
+        throw new ASTRuntimeException(node, "AST node not implemented yet for type: " + getTokenName(node));
+    }
+
+    protected void unknownAST(AST node) {
+        if (node.getType() == CLASS_DEF) {
+            throw new ASTRuntimeException(node,
+                    "Class definition not expected here. Possible attempt to use inner class. " +
+                            "Inner classes not supported, perhaps try using a closure instead.");
+        }
+        throw new ASTRuntimeException(node, "Unknown type: " + getTokenName(node));
+    }
+
+    protected void dumpTree(AST ast) {
+        for (AST node = ast.getFirstChild(); node != null; node = node.getNextSibling()) {
+            dump(node);
+        }
+    }
+
+    protected void dump(AST node) {
+        System.out.println("Type: " + getTokenName(node) + " text: " + node.getText());
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/AntlrParserPluginFactory.java b/groovy-core/src/main/org/codehaus/groovy/antlr/AntlrParserPluginFactory.java
new file mode 100644
index 0000000..1362c33
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/AntlrParserPluginFactory.java
@@ -0,0 +1,34 @@
+/**
+ *
+ * Copyright 2004 James Strachan
+ *
+ * Licensed 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.antlr;
+
+import org.codehaus.groovy.control.ParserPlugin;
+import org.codehaus.groovy.control.ParserPluginFactory;
+import org.codehaus.groovy.control.CompilerConfiguration;
+
+/**
+ * @version $Revision$
+ */
+public class AntlrParserPluginFactory extends ParserPluginFactory {
+
+    public ParserPlugin createParserPlugin() {
+        // TODO remove this hack after JSR-1 release
+        CompilerConfiguration.setJsrGroovy(true);
+        return new AntlrParserPlugin();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/AntlrSourceSummary.java b/groovy-core/src/main/org/codehaus/groovy/antlr/AntlrSourceSummary.java
new file mode 100644
index 0000000..940e186
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/AntlrSourceSummary.java
@@ -0,0 +1,73 @@
+/*
+ $Id$
+
+ Copyright 2005 (C) Jeremy Rayner. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.antlr;
+
+import org.codehaus.groovy.syntax.SourceSummary;
+import org.codehaus.groovy.syntax.ClassSource;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Provides a summary of a SourceUnit (could contain 0 or more classes)
+ *
+ * @author Jeremy Rayner
+ */
+public class AntlrSourceSummary implements SourceSummary {
+    private List publicClassSources;
+
+    public AntlrSourceSummary() {
+        this.publicClassSources = new ArrayList();
+    }
+
+    public void addPublic(ClassSource classSource) {
+        publicClassSources.add(classSource);
+    }
+
+    public List getPublicClassSources() {
+        return publicClassSources;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/GroovySourceAST.java b/groovy-core/src/main/org/codehaus/groovy/antlr/GroovySourceAST.java
new file mode 100644
index 0000000..21a4933
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/GroovySourceAST.java
@@ -0,0 +1,138 @@
+package org.codehaus.groovy.antlr;
+
+import antlr.collections.AST;
+import antlr.*;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * We have an AST subclass so we can track source information.
+ * Very odd that ANTLR doesn't do this by default.
+ *
+ * @author Mike Spille
+ * @author Jeremy Rayner <groovy@ross-rayner.com>
+ */
+public class GroovySourceAST extends CommonAST implements Comparable {
+    private int line;
+    private int col;
+    private int lineLast;
+    private int colLast;
+    private String snippet;
+
+    public GroovySourceAST() {
+    }
+
+    public GroovySourceAST(Token t) {
+        super(t);
+    }
+
+    public void initialize(AST ast) {
+        super.initialize(ast);
+        line = ast.getLine();
+        col = ast.getColumn();
+    }
+
+    public void initialize(Token t) {
+        super.initialize(t);
+        line = t.getLine();
+        col = t.getColumn();
+    }
+
+    public void setLast(Token last) {
+        lineLast = last.getLine();
+        colLast = last.getColumn();
+    }
+
+    public int getLineLast() {
+        return lineLast;
+    }
+
+    public void setLineLast(int lineLast) {
+        this.lineLast = lineLast;
+    }
+
+    public int getColumnLast() {
+        return colLast;
+    }
+
+    public void setColumnLast(int colLast) {
+        this.colLast = colLast;
+    }
+
+    public void setLine(int line) {
+        this.line = line;
+    }
+
+    public int getLine() {
+        return (line);
+    }
+
+    public void setColumn(int column) {
+        this.col = column;
+    }
+
+    public int getColumn() {
+        return (col);
+    }
+
+    public void setSnippet(String snippet) {
+        this.snippet = snippet;
+    }
+
+    public String getSnippet() {
+        return snippet;
+    }
+
+    public int compareTo(Object object) {
+        if (object == null) {
+            return 0;
+        }
+        if (!(object instanceof AST)) {
+            return 0;
+        }
+        AST that = (AST) object;
+
+        // todo - possibly check for line/col with values of 0 or less...
+
+        if (this.getLine() < that.getLine()) {
+            return -1;
+        }
+        if (this.getLine() > that.getLine()) {
+            return 1;
+        }
+
+        if (this.getColumn() < that.getColumn()) {
+            return -1;
+        }
+        if (this.getColumn() > that.getColumn()) {
+            return 1;
+        }
+
+        return 0;
+    }
+
+    public GroovySourceAST childAt(int position) {
+        List list = new ArrayList();
+        AST child = this.getFirstChild();
+        while (child != null) {
+            list.add(child);
+            child = child.getNextSibling();
+        }
+        try {
+            return (GroovySourceAST)list.get(position);
+        } catch (IndexOutOfBoundsException e) {
+            return null;
+        }
+    }
+
+    public GroovySourceAST childOfType(int type) {
+        AST child = this.getFirstChild();
+        while (child != null) {
+            if (child.getType() == type) { return (GroovySourceAST)child; }
+            child = child.getNextSibling();
+        }
+        return null;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/LexerFrame.java b/groovy-core/src/main/org/codehaus/groovy/antlr/LexerFrame.java
new file mode 100644
index 0000000..cc9a586
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/LexerFrame.java
@@ -0,0 +1,189 @@
+package org.codehaus.groovy.antlr;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.Hashtable;
+
+import javax.swing.*;
+import javax.swing.border.Border;
+import javax.swing.text.BadLocationException;
+import org.codehaus.groovy.antlr.parser.*;
+
+import antlr.*;
+
+/**
+ * @author Santhosh Kumar T
+ * @version 1.0
+ */
+
+public class LexerFrame extends JFrame implements ActionListener{
+    JSplitPane jSplitPane1 = new JSplitPane();
+    JScrollPane jScrollPane1 = new JScrollPane();
+    JScrollPane jScrollPane2 = new JScrollPane();
+    JTextPane tokenPane = new HScrollableTextPane();
+    JButton jbutton = new JButton("open");
+    JPanel mainPanel = new JPanel(new BorderLayout());
+    JTextArea scriptPane = new JTextArea();
+    Border border1;
+    Border border2;
+
+    Class lexerClass;
+
+    public LexerFrame(Class lexerClass, Class tokenTypesClass){
+        super("Token Steam Viewer");
+        this.lexerClass = lexerClass;
+        try{
+            jbInit();
+            setSize(500, 500);
+            listTokens(tokenTypesClass);
+
+            final JPopupMenu popup = new JPopupMenu();
+            popup.add(loadFileAction);
+
+            jbutton.setSize(30,30);
+            jbutton.addMouseListener(new MouseAdapter(){
+                public void mouseReleased(MouseEvent e) {
+                    //if(e.isPopupTrigger())
+                        popup.show(scriptPane, e.getX(), e.getY());
+                }
+            });
+            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        } catch(Exception e){
+            e.printStackTrace();
+        }
+    }
+
+    Hashtable tokens = new Hashtable();
+
+    private void listTokens(Class tokenTypes) throws Exception{
+        Field field[] = tokenTypes.getDeclaredFields();
+        for(int i = 0; i<field.length; i++)
+            tokens.put(field[i].get(null), field[i].getName());
+    }
+
+    public void actionPerformed(ActionEvent ae){
+        Token token = (Token) ((JComponent) ae.getSource()).getClientProperty("token");
+        if(token.getType()==Token.EOF_TYPE){
+            scriptPane.select(0, 0);
+            return;
+        }
+        try{
+            int start = scriptPane.getLineStartOffset(token.getLine()-1)+token.getColumn()-1;
+            scriptPane.select(start, start+token.getText().length());
+            scriptPane.requestFocus();
+        } catch(BadLocationException ex){
+        }
+    }
+
+    private Action loadFileAction = new AbstractAction("Open File..."){
+        public void actionPerformed(ActionEvent ae){
+            JFileChooser jfc = new JFileChooser();
+            int response = jfc.showOpenDialog(LexerFrame.this);
+            if(response!=JFileChooser.APPROVE_OPTION)
+                return;
+            try{
+                scanScript(jfc.getSelectedFile());
+            } catch(Exception ex){
+                ex.printStackTrace();
+            }
+        }
+    };
+
+    private void scanScript(File file) throws Exception{
+        scriptPane.read(new FileReader(file), null);
+
+        // create lexer
+        Constructor constructor = lexerClass.getConstructor(new Class[]{InputStream.class});
+        CharScanner lexer = (CharScanner) constructor.newInstance(new Object[]{new FileInputStream(file)});
+
+        tokenPane.setEditable(true);
+        tokenPane.setText("");
+
+        int line = 1;
+        ButtonGroup bg = new ButtonGroup();
+        Token token = null;
+
+        while(true){
+            token = lexer.nextToken();
+            JToggleButton tokenButton = new JToggleButton((String) tokens.get(new Integer(token.getType())));
+            bg.add(tokenButton);
+            tokenButton.addActionListener(this);
+            tokenButton.setToolTipText(token.getText());
+            tokenButton.putClientProperty("token", token);
+            tokenButton.setMargin(new Insets(0, 1, 0, 1));
+            tokenButton.setFocusPainted(false);
+            if(token.getLine()>line){
+                tokenPane.getDocument().insertString(tokenPane.getDocument().getLength(), "\n", null);
+                line = token.getLine();
+            }
+            insertComponent(tokenButton);
+            if(token.getType()==Token.EOF_TYPE)
+                break;
+        }
+
+        tokenPane.setEditable(false);
+        tokenPane.setCaretPosition(0);
+    }
+
+    private void insertComponent(JComponent comp){
+        try{
+            tokenPane.getDocument().insertString(tokenPane.getDocument().getLength(), " ", null);
+        } catch(BadLocationException ex1){
+        }
+        try{
+            tokenPane.setCaretPosition(tokenPane.getDocument().getLength()-1);
+        } catch(Exception ex){
+            tokenPane.setCaretPosition(0);
+        }
+        tokenPane.insertComponent(comp);
+    }
+
+    private void jbInit() throws Exception{
+        border1 = BorderFactory.createEmptyBorder();
+        border2 = BorderFactory.createEmptyBorder();
+        jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT);
+        tokenPane.setEditable(false);
+        tokenPane.setText("");
+        scriptPane.setFont(new java.awt.Font("DialogInput", 0, 12));
+        scriptPane.setEditable(false);
+        scriptPane.setMargin(new Insets(5, 5, 5, 5));
+        scriptPane.setText("");
+        jScrollPane1.setBorder(border1);
+        jScrollPane2.setBorder(border1);
+        jSplitPane1.setMinimumSize(new Dimension(800,600));
+        mainPanel.add(jSplitPane1, BorderLayout.CENTER);
+        mainPanel.add(jbutton,BorderLayout.NORTH);
+        this.getContentPane().add(mainPanel);
+        jSplitPane1.add(jScrollPane1, JSplitPane.LEFT);
+        jScrollPane1.getViewport().add(tokenPane, null);
+        jSplitPane1.add(jScrollPane2, JSplitPane.RIGHT);
+        jScrollPane2.getViewport().add(scriptPane, null);
+
+        jScrollPane1.setColumnHeaderView(new JLabel(" Token Stream:"));
+        jScrollPane2.setColumnHeaderView(new JLabel(" Input Script:"));
+        jSplitPane1.setResizeWeight(0.5);
+    }
+
+    public static void main(String[] args) throws Exception{
+        try{
+            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+        } catch(Exception ignore){
+        }
+        new LexerFrame(GroovyLexer.class, GroovyTokenTypes.class).setVisible(true);
+    }
+}
+
+
+class HScrollableTextPane extends JTextPane{
+    public boolean getScrollableTracksViewportWidth(){
+        return(getSize().width<getParent().getSize().width);
+    }
+
+    public void setSize(Dimension d){
+        if(d.width<getParent().getSize().width){
+            d.width = getParent().getSize().width;
+        }
+        super.setSize(d);
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/LineColumn.java b/groovy-core/src/main/org/codehaus/groovy/antlr/LineColumn.java
new file mode 100644
index 0000000..f48563f
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/LineColumn.java
@@ -0,0 +1,66 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr;
+
+/**
+ * An object representing a line and column position
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+public class LineColumn {
+    private int line;
+    private int column;
+
+    public LineColumn(int line, int column) {
+        this.line = line;
+        this.column = column;
+    }
+
+    public int getLine() {
+        return line;
+    }
+
+    public int getColumn() {
+        return column;
+    }
+
+    public boolean equals(Object that) {
+        if (this == that) return true;
+        if (that == null || getClass() != that.getClass()) return false;
+
+        final LineColumn lineColumn = (LineColumn) that;
+
+        if (column != lineColumn.column) return false;
+        if (line != lineColumn.line) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result;
+        result = line;
+        result = 29 * result + column;
+        return result;
+    }
+
+    public String toString() {
+        return "[" + line + "," + column + "]";
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/Main.java b/groovy-core/src/main/org/codehaus/groovy/antlr/Main.java
new file mode 100644
index 0000000..04e2d88
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/Main.java
@@ -0,0 +1,177 @@
+package org.codehaus.groovy.antlr;
+
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.io.FileReader;
+
+import org.codehaus.groovy.antlr.parser.GroovyLexer;
+import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
+
+import antlr.ASTFactory;
+import antlr.CommonAST;
+import antlr.Token;
+import antlr.collections.AST;
+import antlr.debug.misc.ASTFrame;
+
+class Main {
+
+    static boolean whitespaceIncluded = false;
+
+	static boolean showTree = false;
+    //static boolean xml = false;
+	static boolean verbose = false;
+    public static void main(String[] args) {
+		// Use a try/catch block for parser exceptions
+		try {
+			// if we have at least one command-line argument
+			if (args.length > 0 ) {
+				System.err.println("Parsing...");
+
+				// for each directory/file specified on the command line
+				for(int i=0; i< args.length;i++) {
+					if ( args[i].equals("-showtree") ) {
+						showTree = true;
+					}
+                    //else if ( args[i].equals("-xml") ) {
+                    //    xml = true;
+                    //}
+					else if ( args[i].equals("-verbose") ) {
+						verbose = true;
+					}
+					else if ( args[i].equals("-trace") ) {
+						GroovyRecognizer.tracing = true;
+						GroovyLexer.tracing = true;
+					}
+					else if ( args[i].equals("-traceParser") ) {
+						GroovyRecognizer.tracing = true;
+					}
+					else if ( args[i].equals("-traceLexer") ) {
+						GroovyLexer.tracing = true;
+					}
+                                        else if ( args[i].equals("-whitespaceIncluded") ) {
+                                            whitespaceIncluded = true;
+                                        }
+                                        else {
+						doFile(new File(args[i])); // parse it
+					}
+				} }
+			else
+				System.err.println("Usage: java -jar groovyc.jar [-showtree] [-verbose] [-trace{,Lexer,Parser}]"+
+                                   "<directory or file name>");
+		}
+		catch(Exception e) {
+			System.err.println("exception: "+e);
+			e.printStackTrace(System.err);   // so we can get stack trace
+		}
+	}
+
+
+	// This method decides what action to take based on the type of
+	//   file we are looking at
+	public static void doFile(File f)
+							  throws Exception {
+		// If this is a directory, walk each file/dir in that directory
+		if (f.isDirectory()) {
+			String files[] = f.list();
+			for(int i=0; i < files.length; i++)
+				doFile(new File(f, files[i]));
+		}
+
+		// otherwise, if this is a groovy file, parse it!
+		else if (f.getName().endsWith(".groovy")) {
+			System.err.println(" --- "+f.getAbsolutePath());
+			// parseFile(f.getName(), new FileInputStream(f));
+            SourceBuffer sourceBuffer = new SourceBuffer();
+            UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(new FileReader(f),sourceBuffer);
+            GroovyLexer lexer = new GroovyLexer(unicodeReader);
+            unicodeReader.setLexer(lexer);
+			parseFile(f.getName(),lexer,sourceBuffer);
+		}
+	}
+
+	// Here's where we do the real work...
+	public static void parseFile(String f, GroovyLexer l, SourceBuffer sourceBuffer)
+								 throws Exception {
+		try {
+			// Create a parser that reads from the scanner
+			GroovyRecognizer parser = GroovyRecognizer.make(l);
+            parser.setSourceBuffer(sourceBuffer);
+			parser.setFilename(f);
+                        
+                        if (whitespaceIncluded) {
+                            GroovyLexer lexer = parser.getLexer();
+                            lexer.setWhitespaceIncluded(true);
+                            while (true) {
+                                Token t = lexer.nextToken();
+                                System.out.println(t);
+                                if (t == null || t.getType() == Token.EOF_TYPE)  break;
+                            }
+                            return;
+                        }
+
+			// start parsing at the compilationUnit rule
+			parser.compilationUnit();
+			
+			System.out.println("parseFile "+f+" => "+parser.getAST());
+
+			// do something with the tree
+			doTreeAction(f, parser.getAST(), parser.getTokenNames());
+		}
+		catch (Exception e) {
+			System.err.println("parser exception: "+e);
+			e.printStackTrace();   // so we can get stack trace		
+		}
+	}
+	
+	public static void doTreeAction(String f, AST t, String[] tokenNames) {
+		if ( t==null ) return;
+		if ( showTree ) {
+			CommonAST.setVerboseStringConversion(true, tokenNames);
+			ASTFactory factory = new ASTFactory();
+			AST r = factory.create(0,"AST ROOT");
+			r.setFirstChild(t);
+			final ASTFrame frame = new ASTFrame("Groovy AST", r);
+			frame.setVisible(true);
+			frame.addWindowListener(
+				new WindowAdapter() {
+                   public void windowClosing (WindowEvent e) {
+                       frame.setVisible(false); // hide the Frame
+                       frame.dispose();
+                       System.exit(0);
+                   }
+		        }
+			);
+			if (verbose)  System.out.println(t.toStringList());
+		}
+        /*if ( xml ) {
+			((CommonAST)t).setVerboseStringConversion(true, tokenNames);
+			ASTFactory factory = new ASTFactory();
+			AST r = factory.create(0,"AST ROOT");
+			r.setFirstChild(t);
+            XStream xstream = new XStream();
+            xstream.alias("ast", CommonAST.class);
+			try {
+                xstream.toXML(r,new FileWriter(f + ".xml"));
+                System.out.println("Written AST to " + f + ".xml");
+            } catch (Exception e) {
+                System.out.println("couldn't write to " + f + ".xml");
+                e.printStackTrace();
+            }
+			//if (verbose)  System.out.println(t.toStringList());
+		}*/
+	/*@todo
+		GroovyTreeParser tparse = new GroovyTreeParser();
+		try {
+			tparse.compilationUnit(t);
+			if (verbose)  System.out.println("successful walk of result AST for "+f);
+		}
+		catch (RecognitionException e) {
+			System.err.println(e.getMessage());
+			e.printStackTrace();
+		}
+	@todo*/
+
+	}
+}
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/SourceBuffer.java b/groovy-core/src/main/org/codehaus/groovy/antlr/SourceBuffer.java
new file mode 100644
index 0000000..34fdd50
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/SourceBuffer.java
@@ -0,0 +1,110 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * A simple buffer that provides line/col access to chunks of source code
+ * held within itself.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+public class SourceBuffer {
+    private List lines;
+    private StringBuffer current;
+
+    public SourceBuffer() {
+        lines = new ArrayList();
+        //lines.add(new StringBuffer()); // dummy row for position [0] in the List
+
+        current = new StringBuffer();
+        lines.add(current);
+    }
+
+    /**
+     * Obtains a snippet of the source code within the bounds specified
+     * @param start (inclusive line/ inclusive column)
+     * @param end (inclusive line / exclusive column)
+     * @return specified snippet of source code as a String, or null if no source available
+     */
+    public String getSnippet(LineColumn start, LineColumn end) {
+        // preconditions
+        if (start == null || end == null) { return null; } // no text to return
+        if (start.equals(end)) { return null; } // no text to return
+        if (lines.size() == 1 && current.length() == 0) { return null; } // buffer hasn't been filled yet
+
+        // working variables
+        int startLine = start.getLine();
+        int startColumn = start.getColumn();
+        int endLine = end.getLine();
+        int endColumn = end.getColumn();
+
+        // reset any out of bounds requests
+        if (startLine < 1) { startLine = 1;}
+        if (endLine < 1) { endLine = 1;}
+        if (startColumn < 1) { startColumn = 1;}
+        if (endColumn < 1) { endColumn = 1;}
+        if (startLine > lines.size()) { startLine = lines.size(); }
+        if (endLine > lines.size()) { endLine = lines.size(); }
+
+        // obtain the snippet from the buffer within specified bounds
+        StringBuffer snippet = new StringBuffer();
+        for (int i = startLine - 1; i < endLine;i++) {
+            String line = ((StringBuffer)lines.get(i)).toString();
+            if (startLine == endLine) {
+                // reset any out of bounds requests (again)
+                if (startColumn > line.length()) { startColumn = line.length();}
+                if (startColumn < 1) { startColumn = 1;}
+                if (endColumn > line.length()) { endColumn = line.length() + 1;}
+                if (endColumn < 1) { endColumn = 1;}
+
+                line = line.substring(startColumn - 1, endColumn - 1);
+            } else {
+                if (i == startLine - 1) {
+                    if (startColumn - 1 < line.length()) {
+                        line = line.substring(startColumn - 1);
+                    }
+                }
+                if (i == endLine - 1) {
+                    if (endColumn - 1 < line.length()) {
+                        line = line.substring(0,endColumn - 1);
+                    }
+                }
+            }
+            snippet.append(line);
+        }
+        return snippet.toString();
+    }
+
+    /**
+     * Writes the specified character into the buffer
+     * @param c
+     */
+    public void write(int c) {
+        if (c != -1) {
+            current.append((char)c);
+        }
+        if (c == '\n') {
+            current = new StringBuffer();
+            lines.add(current);
+        }
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/UnicodeEscapingReader.java b/groovy-core/src/main/org/codehaus/groovy/antlr/UnicodeEscapingReader.java
new file mode 100644
index 0000000..96f50a8
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/UnicodeEscapingReader.java
@@ -0,0 +1,151 @@
+/**
+ * Copyright 2005 Alan Green
+ *
+ * Licensed 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.antlr;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import antlr.CharScanner;
+
+/**
+ * Translates GLS-defined unicode escapes into characters. Throws an exception
+ * in the event of an invalid unicode escape being detected.
+ *
+ * <p>No attempt has been made to optimise this class for speed or
+ * space.</p>
+ *
+ * @version $Revision$
+ */
+public class UnicodeEscapingReader extends Reader {
+
+    private Reader reader;
+    private CharScanner lexer;
+    private boolean hasNextChar = false;
+    private int nextChar;
+    private SourceBuffer sourceBuffer;
+
+    /**
+     * Constructor.
+     * @param reader The reader that this reader will filter over.
+     */
+    public UnicodeEscapingReader(Reader reader,SourceBuffer sourceBuffer) {
+        this.reader = reader;
+        this.sourceBuffer = sourceBuffer;
+    }
+
+    /**
+     * Sets the lexer that is using this reader. Must be called before the
+     * lexer is used.
+     */
+    public void setLexer(CharScanner lexer) {
+        this.lexer = lexer;
+    }
+
+    /**
+     * Reads characters from the underlying reader.
+     * @see java.io.Reader#read(char[],int,int)
+     */
+    public int read(char cbuf[], int off, int len) throws IOException {
+        int c = 0;
+        int count = 0;
+        while (count < len && (c = read())!= -1) {
+            cbuf[off + count] = (char) c;
+            count++;
+        }
+        return (count == 0 && c == -1) ? -1 : count;
+    }
+
+    /**
+     * Gets the next character from the underlying reader,
+     * translating escapes as required.
+     * @see java.io.Reader#close()
+     */
+    public int read() throws IOException {
+        if (hasNextChar) {
+            hasNextChar = false;
+            write(nextChar);
+            return nextChar;
+        }
+
+        int c = reader.read();
+        if (c != '\\') {
+            write(c);
+            return c;
+        }
+
+        // Have one backslash, continue if next char is 'u'
+        c = reader.read();
+        if (c != 'u') {
+            hasNextChar = true;
+            nextChar = c;
+            write('\\');
+            return '\\';
+        }
+
+        // Swallow multiple 'u's
+        do {
+            c = reader.read();
+        } while (c == 'u');
+
+        // Get first hex digit
+        checkHexDigit(c);
+        StringBuffer charNum = new StringBuffer();
+        charNum.append((char) c);
+
+        // Must now be three more hex digits
+        for (int i = 0; i < 3; i++) {
+            c = reader.read();
+            checkHexDigit(c);
+            charNum.append((char) c);
+        }
+        int rv = Integer.parseInt(charNum.toString(), 16);
+        write(rv);
+        return rv;
+    }
+    private void write(int c) {
+        if (sourceBuffer != null) {sourceBuffer.write(c);}
+    }
+    /**
+     * Checks that the given character is indeed a hex digit.
+     */
+    private void checkHexDigit(int c) throws IOException {
+        if (c >= '0' && c <= '9') {
+            return;
+        }
+        if (c >= 'a' && c <= 'f') {
+            return;
+        }
+        if (c >= 'A' && c <= 'F') {
+            return;
+        }
+        // Causes the invalid escape to be skipped
+        hasNextChar = true;
+        nextChar = c;
+        throw new IOException("Did not find four digit hex character code."
+                + " line: " + lexer.getLine() + " col:" + lexer.getColumn());
+    }
+
+    /**
+     * Closes this reader by calling close on the underlying reader.
+     * @see java.io.Reader#close()
+     */
+    public void close() throws IOException {
+        reader.close();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/groovy.g b/groovy-core/src/main/org/codehaus/groovy/antlr/groovy.g
new file mode 100644
index 0000000..46eb37f
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/groovy.g
@@ -0,0 +1,3684 @@
+// Note: Please don't use physical tabs.  Logical tabs for indent are width 4.
+header {
+package org.codehaus.groovy.antlr.parser;
+import org.codehaus.groovy.antlr.*;
+import java.util.*;
+import java.io.InputStream;
+import java.io.Reader;
+import antlr.InputBuffer;
+import antlr.LexerSharedInputState;
+}
+ 
+/** JSR-241 Groovy Recognizer
+ *
+ * Run 'java Main [-showtree] directory-full-of-groovy-files'
+ *
+ * [The -showtree option pops up a Swing frame that shows
+ *  the AST constructed from the parser.]
+ *
+ * Contributing authors:
+ *              John Mitchell           johnm@non.net
+ *              Terence Parr            parrt@magelang.com
+ *              John Lilley             jlilley@empathy.com
+ *              Scott Stanchfield       thetick@magelang.com
+ *              Markus Mohnen           mohnen@informatik.rwth-aachen.de
+ *              Peter Williams          pete.williams@sun.com
+ *              Allan Jacobs            Allan.Jacobs@eng.sun.com
+ *              Steve Messick           messick@redhills.com
+ *              James Strachan          jstrachan@protique.com
+ *              John Pybus              john@pybus.org
+ *              John Rose               rose00@mac.com
+ *              Jeremy Rayner           groovy@ross-rayner.com
+ *
+ * Version 1.00 December 9, 1997 -- initial release
+ * Version 1.01 December 10, 1997
+ *              fixed bug in octal def (0..7 not 0..8)
+ * Version 1.10 August 1998 (parrt)
+ *              added tree construction
+ *              fixed definition of WS,comments for mac,pc,unix newlines
+ *              added unary plus
+ * Version 1.11 (Nov 20, 1998)
+ *              Added "shutup" option to turn off last ambig warning.
+ *              Fixed inner class def to allow named class defs as statements
+ *              synchronized requires compound not simple statement
+ *              add [] after builtInType DOT class in primaryExpression
+ *              "const" is reserved but not valid..removed from modifiers
+ * Version 1.12 (Feb 2, 1999)
+ *              Changed LITERAL_xxx to xxx in tree grammar.
+ *              Updated java.g to use tokens {...} now for 2.6.0 (new feature).
+ *
+ * Version 1.13 (Apr 23, 1999)
+ *              Didn't have (stat)? for else clause in tree parser.
+ *              Didn't gen ASTs for interface extends.  Updated tree parser too.
+ *              Updated to 2.6.0.
+ * Version 1.14 (Jun 20, 1999)
+ *              Allowed final/abstract on local classes.
+ *              Removed local interfaces from methods
+ *              Put instanceof precedence where it belongs...in relationalExpr
+ *                      It also had expr not type as arg; fixed it.
+ *              Missing ! on SEMI in classBlock
+ *              fixed: (expr) + "string" was parsed incorrectly (+ as unary plus).
+ *              fixed: didn't like Object[].class in parser or tree parser
+ * Version 1.15 (Jun 26, 1999)
+ *              Screwed up rule with instanceof in it. :(  Fixed.
+ *              Tree parser didn't like (expr).something; fixed.
+ *              Allowed multiple inheritance in tree grammar. oops.
+ * Version 1.16 (August 22, 1999)
+ *              Extending an interface built a wacky tree: had extra EXTENDS.
+ *              Tree grammar didn't allow multiple superinterfaces.
+ *              Tree grammar didn't allow empty var initializer: {}
+ * Version 1.17 (October 12, 1999)
+ *              ESC lexer rule allowed 399 max not 377 max.
+ *              java.tree.g didn't handle the expression of synchronized
+ *              statements.
+ * Version 1.18 (August 12, 2001)
+ *              Terence updated to Java 2 Version 1.3 by
+ *              observing/combining work of Allan Jacobs and Steve
+ *              Messick.  Handles 1.3 src.  Summary:
+ *              o  primary didn't include boolean.class kind of thing
+ *              o  constructor calls parsed explicitly now:
+ *                 see explicitConstructorInvocation
+ *              o  add strictfp modifier
+ *              o  missing objBlock after new expression in tree grammar
+ *              o  merged local class definition alternatives, moved after declaration
+ *              o  fixed problem with ClassName.super.field
+ *              o  reordered some alternatives to make things more efficient
+ *              o  long and double constants were not differentiated from int/float
+ *              o  whitespace rule was inefficient: matched only one char
+ *              o  add an examples directory with some nasty 1.3 cases
+ *              o  made Main.java use buffered IO and a Reader for Unicode support
+ *              o  supports UNICODE?
+ *                 Using Unicode charVocabulay makes code file big, but only
+ *                 in the bitsets at the end. I need to make ANTLR generate
+ *                 unicode bitsets more efficiently.
+ * Version 1.19 (April 25, 2002)
+ *              Terence added in nice fixes by John Pybus concerning floating
+ *              constants and problems with super() calls.  John did a nice
+ *              reorg of the primary/postfix expression stuff to read better
+ *              and makes f.g.super() parse properly (it was METHOD_CALL not
+ *              a SUPER_CTOR_CALL).  Also:
+ *
+ *              o  "finally" clause was a root...made it a child of "try"
+ *              o  Added stuff for asserts too for Java 1.4, but *commented out*
+ *                 as it is not backward compatible.
+ *
+ * Version 1.20 (October 27, 2002)
+ *
+ *        Terence ended up reorging John Pybus' stuff to
+ *        remove some nondeterminisms and some syntactic predicates.
+ *        Note that the grammar is stricter now; e.g., this(...) must
+ *      be the first statement.
+ *
+ *        Trinary ?: operator wasn't working as array name:
+ *                (isBig ? bigDigits : digits)[i];
+ *
+ *        Checked parser/tree parser on source for
+ *                Resin-2.0.5, jive-2.1.1, jdk 1.3.1, Lucene, antlr 2.7.2a4,
+ *              and the 110k-line jGuru server source.
+ *
+ * Version 1.21 (October 17, 2003)
+ *  Fixed lots of problems including:
+ *  Ray Waldin: add typeDefinition to interfaceBlock in java.tree.g
+ *  He found a problem/fix with floating point that start with 0
+ *  Ray also fixed problem that (int.class) was not recognized.
+ *  Thorsten van Ellen noticed that \n are allowed incorrectly in strings.
+ *  TJP fixed CHAR_LITERAL analogously.
+ *
+ * Version 1.21.2 (March, 2003)
+ *        Changes by Matt Quail to support generics (as per JDK1.5/JSR14)
+ *        Notes:
+ *        o We only allow the "extends" keyword and not the "implements"
+ *              keyword, since thats what JSR14 seems to imply.
+ *        o Thanks to Monty Zukowski for his help on the antlr-interest
+ *              mail list.
+ *        o Thanks to Alan Eliasen for testing the grammar over his
+ *              Fink source base
+ *
+ * Version 1.22 (July, 2004)
+ *        Changes by Michael Studman to support Java 1.5 language extensions
+ *        Notes:
+ *        o Added support for annotations types
+ *        o Finished off Matt Quail's generics enhancements to support bound type arguments
+ *        o Added support for new for statement syntax
+ *        o Added support for static import syntax
+ *        o Added support for enum types
+ *        o Tested against JDK 1.5 source base and source base of jdigraph project
+ *        o Thanks to Matt Quail for doing the hard part by doing most of the generics work
+ *
+ * Version 1.22.1 (July 28, 2004)
+ *        Bug/omission fixes for Java 1.5 language support
+ *        o Fixed tree structure bug with classOrInterface - thanks to Pieter Vangorpto for
+ *              spotting this
+ *        o Fixed bug where incorrect handling of SR and BSR tokens would cause type
+ *              parameters to be recognised as type arguments.
+ *        o Enabled type parameters on constructors, annotations on enum constants
+ *              and package definitions
+ *        o Fixed problems when parsing if ((char.class.equals(c))) {} - solution by Matt Quail at Cenqua
+ *
+ * Version 1.22.2 (July 28, 2004)
+ *        Slight refactoring of Java 1.5 language support
+ *        o Refactored for/"foreach" productions so that original literal "for" literal
+ *          is still used but the for sub-clauses vary by token type
+ *        o Fixed bug where type parameter was not included in generic constructor's branch of AST
+ *
+ * Version 1.22.3 (August 26, 2004)
+ *        Bug fixes as identified by Michael Stahl; clean up of tabs/spaces
+ *        and other refactorings
+ *        o Fixed typeParameters omission in identPrimary and newStatement
+ *        o Replaced GT reconcilliation code with simple semantic predicate
+ *        o Adapted enum/assert keyword checking support from Michael Stahl's java15 grammar
+ *        o Refactored typeDefinition production and field productions to reduce duplication
+ *
+ * Version 1.22.4 (October 21, 2004)
+ *    Small bux fixes
+ *    o Added typeArguments to explicitConstructorInvocation, e.g. new <String>MyParameterised()
+ *    o Added typeArguments to postfixExpression productions for anonymous inner class super
+ *      constructor invocation, e.g. new Outer().<String>super()
+ *    o Fixed bug in array declarations identified by Geoff Roy
+ *
+ * Version 1.22.4.g.1
+ *    o I have taken java.g for Java1.5 from Michael Studman (1.22.4)
+ *      and have applied the groovy.diff from java.g (1.22) by John Rose
+ *      back onto the new root (1.22.4) - Jeremy Rayner (Jan 2005)
+ *    o for a map of the task see... 
+ *      http://groovy.javanicus.com/java-g.png
+ *
+ * This grammar is in the PUBLIC DOMAIN
+ */
+
+class GroovyRecognizer extends Parser;
+options {
+    k = 3;                            // three token lookahead
+    exportVocab=Groovy;               // Call its vocabulary "Groovy"
+    codeGenMakeSwitchThreshold = 2;   // Some optimizations
+    codeGenBitsetTestThreshold = 3;
+    defaultErrorHandler = false;      // Don't generate parser error handlers
+    buildAST = true;
+//  ASTLabelType = "GroovyAST";
+}
+
+tokens {
+    BLOCK; MODIFIERS; OBJBLOCK; SLIST; METHOD_DEF; VARIABLE_DEF;
+    INSTANCE_INIT; STATIC_INIT; TYPE; CLASS_DEF; INTERFACE_DEF;
+    PACKAGE_DEF; ARRAY_DECLARATOR; EXTENDS_CLAUSE; IMPLEMENTS_CLAUSE;
+    PARAMETERS; PARAMETER_DEF; LABELED_STAT; TYPECAST; INDEX_OP;
+    POST_INC; POST_DEC; METHOD_CALL; EXPR;
+    IMPORT; UNARY_MINUS; UNARY_PLUS; CASE_GROUP; ELIST; FOR_INIT; FOR_CONDITION;
+    FOR_ITERATOR; EMPTY_STAT; FINAL="final"; ABSTRACT="abstract";
+    UNUSED_GOTO="goto"; UNUSED_CONST="const"; UNUSED_DO="do";
+    STRICTFP="strictfp"; SUPER_CTOR_CALL; CTOR_CALL; CTOR_IDENT; VARIABLE_PARAMETER_DEF;
+    STRING_CONSTRUCTOR; STRING_CTOR_MIDDLE;
+    CLOSABLE_BLOCK; IMPLICIT_PARAMETERS;
+    SELECT_SLOT; DYNAMIC_MEMBER;
+    LABELED_ARG; SPREAD_ARG; SPREAD_MAP_ARG; SCOPE_ESCAPE;
+    LIST_CONSTRUCTOR; MAP_CONSTRUCTOR;
+    FOR_IN_ITERABLE;
+    STATIC_IMPORT; ENUM_DEF; ENUM_CONSTANT_DEF; FOR_EACH_CLAUSE; ANNOTATION_DEF; ANNOTATIONS;
+    ANNOTATION; ANNOTATION_MEMBER_VALUE_PAIR; ANNOTATION_FIELD_DEF; ANNOTATION_ARRAY_INIT;
+    TYPE_ARGUMENTS; TYPE_ARGUMENT; TYPE_PARAMETERS; TYPE_PARAMETER; WILDCARD_TYPE;
+    TYPE_UPPER_BOUNDS; TYPE_LOWER_BOUNDS;
+}
+
+{
+        /** This factory is the correct way to wire together a Groovy parser and lexer. */
+    public static GroovyRecognizer make(GroovyLexer lexer) {
+        GroovyRecognizer parser = new GroovyRecognizer(lexer.plumb());
+        // TODO: set up a common error-handling control block, to avoid excessive tangle between these guys
+        parser.lexer = lexer;
+        lexer.parser = parser;
+        parser.setASTNodeClass("org.codehaus.groovy.antlr.GroovySourceAST");
+        parser.warningList = new ArrayList();
+        return parser;
+    }
+    // Create a scanner that reads from the input stream passed to us...
+    public static GroovyRecognizer make(InputStream in) { return make(new GroovyLexer(in)); }
+    public static GroovyRecognizer make(Reader in) { return make(new GroovyLexer(in)); }
+    public static GroovyRecognizer make(InputBuffer in) { return make(new GroovyLexer(in)); }
+    public static GroovyRecognizer make(LexerSharedInputState in) { return make(new GroovyLexer(in)); }
+    
+    private static GroovySourceAST dummyVariableToforceClassLoaderToFindASTClass = new GroovySourceAST();
+
+    List warningList;
+    public List getWarningList() { return warningList; }
+    
+    GroovyLexer lexer;
+    public GroovyLexer getLexer() { return lexer; }
+    public void setFilename(String f) { super.setFilename(f); lexer.setFilename(f); }
+    private SourceBuffer sourceBuffer;
+    public void setSourceBuffer(SourceBuffer sourceBuffer) {
+        this.sourceBuffer = sourceBuffer;
+    }
+
+    /** Create an AST node with the token type and text passed in, but
+     *  with the same background information as another supplied Token (e.g. line numbers)
+     * to be used in place of antlr tree construction syntax,
+     * i.e. #[TOKEN,"text"]  becomes  create(TOKEN,"text",anotherToken)
+     *
+     * todo - change antlr.ASTFactory to do this instead...
+     */
+    public AST create(int type, String txt, Token first, Token last) {
+        AST t = astFactory.create(type,txt);
+        if ( t != null && first != null) {
+            // first copy details from first token
+            t.initialize(first);
+            // then ensure that type and txt are specific to this new node
+            t.initialize(type,txt);
+        }
+
+        if ((t instanceof GroovySourceAST) && last != null) {
+            GroovySourceAST node = (GroovySourceAST)t;
+            node.setLast(last);
+            // This is a good point to call node.setSnippet(),
+            // but it bulks up the AST too much for production code.
+        }
+        return t;
+    }
+
+
+    // stuff to adjust ANTLR's tracing machinery
+    public static boolean tracing = false;  // only effective if antlr.Tool is run with -traceParser
+    public void traceIn(String rname) throws TokenStreamException {
+        if (!GroovyRecognizer.tracing)  return;
+        super.traceIn(rname);
+    }
+    public void traceOut(String rname) throws TokenStreamException {
+        if (!GroovyRecognizer.tracing)  return;
+        if (returnAST != null)  rname += returnAST.toStringList();
+        super.traceOut(rname);
+    }
+        
+    // Error handling.  This is a funnel through which parser errors go, when the parser can suggest a solution.
+    public void requireFailed(String problem, String solution) throws SemanticException {
+        // TODO: Needs more work.
+        Token lt = null;
+        try { lt = LT(1); }
+        catch (TokenStreamException ee) { }
+        if (lt == null)  lt = Token.badToken;
+        throw new SemanticException(problem + ";\n   solution: " + solution,
+                                    getFilename(), lt.getLine(), lt.getColumn());
+    }
+
+    public void addWarning(String warning, String solution) {
+        Token lt = null;
+        try { lt = LT(1); }
+        catch (TokenStreamException ee) { }
+        if (lt == null)  lt = Token.badToken;
+
+        Map row = new HashMap();
+        row.put("warning" ,warning);
+        row.put("solution",solution);
+        row.put("filename",getFilename());
+        row.put("line"    ,new Integer(lt.getLine()));
+        row.put("column"  ,new Integer(lt.getColumn()));
+        // System.out.println(row);
+        warningList.add(row);
+    }
+
+    // Convenience method for checking of expected error syndromes.
+    private void require(boolean z, String problem, String solution) throws SemanticException {
+        if (!z)  requireFailed(problem, solution);
+    }
+
+
+    // Query a name token to see if it begins with a capital letter.
+    // This is used to tell the difference (w/o symbol table access) between {String x} and {println x}.
+    private boolean isUpperCase(Token x) {
+        if (x == null || x.getType() != IDENT)  return false;  // cannot happen?
+        String xtext = x.getText();
+        return (xtext.length() > 0 && Character.isUpperCase(xtext.charAt(0)));
+    }
+
+    private AST currentClass = null;  // current enclosing class (for constructor recognition)
+    // Query a name token to see if it is identical with the current class name.
+    // This is used to distinguish constructors from other methods.
+    private boolean isConstructorIdent(Token x) {
+        if (currentClass == null)  return false;
+        if (currentClass.getType() != IDENT)  return false;  // cannot happen?
+        String cname = currentClass.getText();
+
+        if (x == null || x.getType() != IDENT)  return false;  // cannot happen?
+        return cname.equals(x.getText());
+    }
+
+    // Scratch variable for last 'sep' token.
+    // Written by the 'sep' rule, read only by immediate callers of 'sep'.
+    // (Not entirely clean, but better than a million xx=sep occurrences.)
+    private int sepToken = EOF;
+
+    // Scratch variable for last argument list; tells whether there was a label.
+    // Written by 'argList' rule, read only by immediate callers of 'argList'.
+    private boolean argListHasLabels = false;
+
+    // Scratch variable, holds most recently completed pathExpression.
+    // Read only by immediate callers of 'pathExpression' and 'expression'.
+    private AST lastPathExpression = null;
+
+    // Inherited attribute pushed into most expression rules.
+    // If not zero, it means that the left context of the expression
+    // being parsed is a statement boundary or an initializer sign '='.
+    // Only such expressions are allowed to reach across newlines
+    // to pull in an LCURLY and appended block.
+    private final int LC_STMT = 1, LC_INIT = 2;
+
+    /**
+     * Counts the number of LT seen in the typeArguments production.
+     * It is used in semantic predicates to ensure we have seen
+     * enough closing '>' characters; which actually may have been
+     * either GT, SR or BSR tokens.
+     */
+    private int ltCounter = 0;
+    
+    /* This symbol is used to work around a known ANTLR limitation.
+     * In a loop with syntactic predicate, ANTLR needs help knowing
+     * that the loop exit is a second alternative.
+     * Example usage:  ( (LCURLY)=> block | {ANTLR_LOOP_EXIT}? )*
+     * Probably should be an ANTLR RFE.
+     */
+    ////// Original comment in Java grammar:
+    // Unfortunately a syntactic predicate can only select one of
+    // multiple alternatives on the same level, not break out of
+    // an enclosing loop, which is why this ugly hack (a fake
+    // empty alternative with always-false semantic predicate)
+    // is necessary.
+    private static final boolean ANTLR_LOOP_EXIT = false;
+}
+
+// Compilation Unit: In Groovy, this is a single file or script. This is the start
+// rule for this parser
+compilationUnit
+    :
+        // The very first characters of the file may be "#!".  If so, ignore the first line.
+        (SH_COMMENT!)?
+
+        // we can have comments at the top of a file
+        nls!
+
+        // A compilation unit starts with an optional package definition
+        (   (annotationsOpt "package")=> packageDefinition
+        |   (statement[EOF])?
+        )
+
+        // The main part of the script is a sequence of any number of statements.
+        // Semicolons and/or significant newlines serve as separators.
+        ( sep! (statement[sepToken])? )*
+        EOF!
+    ;
+
+/** A Groovy script or simple expression.  Can be anything legal inside {...}. */
+snippetUnit
+    :   nls! blockBody[EOF]
+    ;
+
+
+// Package statement: optional annotations followed by "package" then the package identifier.
+packageDefinition
+        //TODO? options {defaultErrorHandler = true;} // let ANTLR handle errors
+    :   annotationsOpt p:"package"^ {#p.setType(PACKAGE_DEF);} identifier
+    ;
+
+
+// Import statement: import followed by a package or class name
+importStatement
+        //TODO? options {defaultErrorHandler = true;}
+        { boolean isStatic = false; }
+    :   i:"import"^ {#i.setType(IMPORT);} ( "static"! {#i.setType(STATIC_IMPORT);} )? identifierStar
+    ;
+
+// TODO REMOVE
+// A type definition is either a class, interface, enum or annotation with possible additional semis.
+//typeDefinition
+//      options {defaultErrorHandler = true;}
+//      :       m:modifiers!
+//              typeDefinitionInternal[#m]
+//      |       SEMI!
+//      ;
+
+// Added this production, even though 'typeDefinition' seems to be obsolete,
+// as this is referenced by many other parts of the grammar.
+// Protected type definitions production for reuse in other productions
+protected typeDefinitionInternal[AST mods]
+    :   cd:classDefinition[#mods]       // inner class
+        {#typeDefinitionInternal = #cd;}
+    |   id:interfaceDefinition[#mods]   // inner interface
+        {#typeDefinitionInternal = #id;}
+    |   ed:enumDefinition[#mods]        // inner enum
+        {#typeDefinitionInternal = #ed;}
+    |   ad:annotationDefinition[#mods]  // inner annotation
+        {#typeDefinitionInternal = #ad;}
+    ;
+
+/** A declaration is the creation of a reference or primitive-type variable,
+ *  or (if arguments are present) of a method.
+ *  Generically, this is called a 'variable' definition, even in the case of a class field or method.
+ *  It may start with the modifiers and/or a declaration keyword "def".
+ *  It may also start with the modifiers and a capitalized type name.
+ *  <p>
+ *  AST effect: Create a separate Type/Var tree for each var in the var list.
+ *  Must be guarded, as in (declarationStart) => declaration.
+ */
+declaration!
+    :
+        // method/variable using a 'def' or a modifier; type is optional
+        m:modifiers
+        (t:typeSpec[false])?
+        v:variableDefinitions[#m, #t]
+        {#declaration = #v;}
+    |
+        // method/variable using a type only
+        t2:typeSpec[false]
+        v2:variableDefinitions[null,#t2]
+        {#declaration = #v2;}
+    ;
+
+
+// *TODO* We must also audit the various occurrences of warning
+// suppressions like "options { greedy = true; }".
+
+/** A declaration with one declarator and no initialization, like a parameterDeclaration.
+ *  Used to parse loops like <code>for (int x in y)</code> (up to the <code>in</code> keyword).
+ */
+singleDeclarationNoInit!
+    :
+        // method/variable using a 'def' or a modifier; type is optional
+        m:modifiers
+        (t:typeSpec[false])?
+        v:singleVariable[#m, #t]
+        {#singleDeclarationNoInit = #v;}
+    |
+        // method/variable using a type only
+        t2:typeSpec[false]
+        v2:singleVariable[null,#t2]
+        {#singleDeclarationNoInit = #v2;}
+    ;
+
+/** A declaration with one declarator and optional initialization, like a parameterDeclaration.
+ *  Used to parse declarations used for both binding and effect, in places like argument
+ *  lists and <code>while</code> statements.
+ */
+singleDeclaration
+    :   sd:singleDeclarationNoInit!
+        { #singleDeclaration = #sd; }
+        (varInitializer)?
+    ;
+
+/** Used only as a lookahead predicate, before diving in and parsing a declaration.
+ *  A declaration can be unambiguously introduced with "def", an annotation or a modifier token like "final".
+ *  It may also be introduced by a simple identifier whose first character is an uppercase letter,
+ *  as in {String x}.  A declaration can also be introduced with a built in type like 'int' or 'void'.
+ *  Brackets (array and generic) are allowed, as in {List[] x} or {int[][] y}.
+ *  Anything else is parsed as a statement of some sort (expression or command).
+ *  <p>
+ *  (In the absence of explicit method-call parens, we assume a capitalized name is a type name.
+ *  Yes, this is a little hacky.  Alternatives are to complicate the declaration or command
+ *  syntaxes, or to have the parser query the symbol table.  Parse-time queries are evil.
+ *  And we want both {String x} and {println x}.  So we need a syntactic razor-edge to slip
+ *  between 'println' and 'String'.)
+ *  
+ *   *TODO* The declarationStart production needs to be strengthened to recognize
+ *  things like {List<String> foo}.
+ *  Right now it only knows how to skip square brackets after the type, not
+ *  angle brackets.
+ *  This probably turns out to be tricky because of >> vs. > >. If so,
+ *  just put a TODO comment in.
+ */
+declarationStart!
+    :   "def"
+    |   modifier
+    |   AT IDENT  // IDENT != "interface"
+    |   (   upperCaseIdent
+        |   builtInType
+        |   qualifiedTypeName
+        ) (LBRACK balancedTokens RBRACK)* IDENT
+    ;
+
+/** Not yet used - but we could use something like this to look for fully qualified type names 
+ */
+qualifiedTypeName!
+				 :
+				 			 IDENT (DOT IDENT)* DOT upperCaseIdent
+				 ;
+	
+/** Used to look ahead for a constructor 
+ */
+constructorStart!
+    :
+        modifiersOpt! id:IDENT! {isConstructorIdent(id)}? nls! LPAREN! //...
+    ;
+
+
+/** Used only as a lookahead predicate for nested type declarations. */
+
+/*TODO* The lookahead in typeDeclarationStart needs to skip annotations, not
+just stop at '@', because variable and method declarations can also be
+annotated.
+> typeDeclarationStart!
+>     :   (modifier!)* ("class" | "interface" | "enum" | AT )
+S.B. something like
+>     :   (modifier! | annotationTokens!)* ("class" | "interface" |
+> "enum" )
+(And maybe @interface, if Java 5 allows nested annotation types? Don't
+know offhand.)
+Where annotationTokens can be a quick paren-skipper, as in other
+places: '@' ident '(' balancedTokens ')'.
+*/
+
+typeDeclarationStart!
+    :   modifiersOpt! ("class" | "interface" | "enum" | AT "interface")
+    ;
+    
+/** An IDENT token whose spelling is required to start with an uppercase letter.
+ *  In the case of a simple statement {UpperID name} the identifier is taken to be a type name, not a command name.
+ */
+upperCaseIdent
+    :   {isUpperCase(LT(1))}?
+        IDENT
+    ;
+
+// A type specification is a type name with possible brackets afterwards
+// (which would make it an array type).
+// Set addImagNode true for types inside expressions, not declarations.
+typeSpec[boolean addImagNode]
+    :    classTypeSpec[addImagNode]
+    |    builtInTypeSpec[addImagNode]
+    ;
+
+// also check that 'classOrInterfaceType[false]' is a suitable substitution for 'identifier'
+
+// A class type specification is a class type with either:
+// - possible brackets afterwards
+//   (which would make it an array type).
+// - generic type arguments after
+classTypeSpec[boolean addImagNode]  {Token first = LT(1);}
+    :   ct:classOrInterfaceType[false]!
+        declaratorBrackets[#ct]
+        {
+            if ( addImagNode ) {
+                #classTypeSpec = #(create(TYPE,"TYPE",first,LT(1)), #classTypeSpec);
+            }
+        }
+    ;
+
+// A non-built in type name, with possible type parameters
+classOrInterfaceType[boolean addImagNode]  {Token first = LT(1);}
+    :   IDENT^ (typeArguments)?
+        (   options{greedy=true;}: // match as many as possible
+            DOT^
+            IDENT (typeArguments)?
+        )*
+        {
+            if ( addImagNode ) {
+                #classOrInterfaceType = #(create(TYPE,"TYPE",first,LT(1)), #classOrInterfaceType);
+            }
+        }
+    ;
+
+// A specialised form of typeSpec where built in types must be arrays
+typeArgumentSpec
+    :   classTypeSpec[true]
+    |   builtInTypeArraySpec[true]
+    ;
+
+// A generic type argument is a class type, a possibly bounded wildcard type or a built-in type array
+typeArgument  {Token first = LT(1);}
+    :   (   typeArgumentSpec
+        |   wildcardType
+        )
+        {#typeArgument = #(create(TYPE_ARGUMENT,"TYPE_ARGUMENT",first,LT(1)), #typeArgument);}
+    ;
+
+// Wildcard type indicating all types (with possible constraint)
+wildcardType
+    :   q:QUESTION^ {#q.setType(WILDCARD_TYPE);}
+        (("extends" | "super")=> typeArgumentBounds)?
+    ;
+
+// Type arguments to a class or interface type
+typeArguments
+{Token first = LT(1);
+int currentLtLevel = 0;}
+    :
+        {currentLtLevel = ltCounter;}
+        LT! {ltCounter++;} nls!
+        typeArgument
+        (   options{greedy=true;}: // match as many as possible
+            {inputState.guessing !=0 || ltCounter == currentLtLevel + 1}?
+            COMMA! nls! typeArgument
+        )*
+        nls!
+        (   // turn warning off since Antlr generates the right code,
+            // plus we have our semantic predicate below
+            options{generateAmbigWarnings=false;}:
+            typeArgumentsOrParametersEnd
+        )?
+
+        // make sure we have gobbled up enough '>' characters
+        // if we are at the "top level" of nested typeArgument productions
+        {(currentLtLevel != 0) || ltCounter == currentLtLevel}?
+
+        {#typeArguments = #(create(TYPE_ARGUMENTS, "TYPE_ARGUMENTS",first,LT(1)), #typeArguments);}
+    ;
+
+// this gobbles up *some* amount of '>' characters, and counts how many
+// it gobbled.
+protected typeArgumentsOrParametersEnd
+    :   GT! {ltCounter-=1;} nls!
+    |   SR! {ltCounter-=2;} nls!
+    |   BSR! {ltCounter-=3;} nls!
+    ;
+
+// Restriction on wildcard types based on super class or derrived class
+typeArgumentBounds
+    {Token first = LT(1);boolean isUpperBounds = false;}
+    :
+        ( "extends"! {isUpperBounds=true;} | "super"! ) nls! classOrInterfaceType[false] nls!
+        {
+            if (isUpperBounds)
+            {
+                #typeArgumentBounds = #(create(TYPE_UPPER_BOUNDS,"TYPE_UPPER_BOUNDS",first,LT(1)), #typeArgumentBounds);
+            }
+            else
+            {
+                #typeArgumentBounds = #(create(TYPE_LOWER_BOUNDS,"TYPE_LOWER_BOUNDS",first,LT(1)), #typeArgumentBounds);
+            }
+        }
+    ;
+
+// A builtin type array specification is a builtin type with brackets afterwards
+builtInTypeArraySpec[boolean addImagNode]  {Token first = LT(1);}
+    :   bt:builtInType!
+        (   (LBRACK)=>   // require at least one []
+            declaratorBrackets[#bt] 
+        |   {require(false,
+                          "primitive type parameters not allowed here",
+                           "use the corresponding wrapper type, such as Integer for int"
+                           );}
+        )
+        {
+            if ( addImagNode ) {
+                #builtInTypeArraySpec = #(create(TYPE,"TYPE",first,LT(1)), #builtInTypeArraySpec);
+            }
+        }
+    ;
+
+// A builtin type specification is a builtin type with possible brackets
+// afterwards (which would make it an array type).
+builtInTypeSpec[boolean addImagNode]  {Token first = LT(1);}
+    :   bt:builtInType!
+        declaratorBrackets[#bt]
+        {
+            if ( addImagNode ) {
+                #builtInTypeSpec = #(create(TYPE,"TYPE",first,LT(1)), #builtInTypeSpec);
+            }
+        }
+    ;
+
+// A type name. which is either a (possibly qualified and parameterized)
+// class name or a primitive (builtin) type
+type
+    :   classOrInterfaceType[false]
+    |   builtInType
+    ;
+
+// The primitive types.
+builtInType
+    :   "void"
+    |   "boolean"
+    |   "byte"
+    |   "char"
+    |   "short"
+    |   "int"
+    |   "float"
+    |   "long"
+    |   "double"
+    |   "any"
+    ;
+
+// A (possibly-qualified) java identifier. We start with the first IDENT
+// and expand its name by adding dots and following IDENTS
+identifier
+    :   IDENT
+        (   options { greedy = true; } :
+            DOT^ nls! IDENT )*
+    ;
+
+identifierStar
+    :   IDENT
+        (   options { greedy = true; } :
+            DOT^  nls! IDENT )*
+        (   DOT^  nls! STAR
+        |   "as"^ nls! IDENT
+        )?
+    ;
+
+modifiersInternal
+        { int seenDef = 0; }
+    :
+        (
+            // Without this hush, there is a warning that @IDENT and @interface
+            // can follow modifiersInternal.  But how is @IDENT possible after
+            // modifiersInternal?  And how is @interface possible inside modifiersInternal?
+            // Is there an antlr bug?
+            options{generateAmbigWarnings=false;}:
+
+            // 'def' is an empty modifier, for disambiguating declarations
+            {seenDef++ == 0}?       // do not allow multiple "def" tokens
+            "def"! nls!
+        |
+            // Note: Duplication of modifiers is detected when walking the AST.
+            modifier nls!
+        |
+            {LA(1)==AT && !LT(2).getText().equals("interface")}?
+            annotation nls!
+        )+
+    ;
+
+/** A list of one or more modifier, annotation, or "def". */
+modifiers  {Token first = LT(1);}
+    :   modifiersInternal
+        {#modifiers = #(create(MODIFIERS, "MODIFIERS",first,LT(1)), #modifiers);}
+    ;
+
+/** A list of zero or more modifiers, annotations, or "def". */
+modifiersOpt  {Token first = LT(1);}
+    :   (
+            // See comment above on hushing warnings.
+            options{generateAmbigWarnings=false;}:
+
+            modifiersInternal
+        )?
+        {#modifiersOpt = #(create(MODIFIERS, "MODIFIERS",first,LT(1)), #modifiersOpt);}
+    ;
+
+// modifiers for Java classes, interfaces, class/instance vars and methods
+modifier
+    :   "private"
+    |   "public"
+    |   "protected"
+    |   "static"
+    |   "transient"
+    |   "final"
+    |   "abstract"
+    |   "native"
+    |   "threadsafe"
+    |   "synchronized"
+    |   "volatile"
+    |   "strictfp"
+    ;
+
+annotation!  {Token first = LT(1);}
+    :   AT! i:identifier ( LPAREN! ( args:annotationArguments )? RPAREN! )?
+        {#annotation = #(create(ANNOTATION,"ANNOTATION",first,LT(1)), i, args);}
+    ;
+
+annotationsOpt  {Token first = LT(1);}
+    :   (annotation nls!)*
+        {#annotationsOpt = #(create(ANNOTATIONS, "ANNOTATIONS", first, LT(1)), #annotationsOpt);}
+;
+
+annotationArguments
+    :   annotationMemberValueInitializer | anntotationMemberValuePairs
+    ;
+
+anntotationMemberValuePairs
+    :   annotationMemberValuePair ( COMMA! nls! annotationMemberValuePair )*
+    ;
+
+annotationMemberValuePair!  {Token first = LT(1);}
+    :   i:IDENT ASSIGN! nls! v:annotationMemberValueInitializer
+            {#annotationMemberValuePair = #(create(ANNOTATION_MEMBER_VALUE_PAIR,"ANNOTATION_MEMBER_VALUE_PAIR",first,LT(1)), i, v);}
+    ;
+
+annotationMemberValueInitializer
+    :   conditionalExpression[0] | annotation
+    ;
+
+/*OBS*
+// This is an initializer used to set up an annotation member array.
+annotationMemberArrayInitializer
+    :   lc:LCURLY^ {#lc.setType(ANNOTATION_ARRAY_INIT);}
+        (   annotationMemberArrayValueInitializer
+            (
+                // CONFLICT: does a COMMA after an initializer start a new
+                // initializer or start the option ',' at end?
+                // ANTLR generates proper code by matching
+                // the comma as soon as possible.
+                options {
+                        warnWhenFollowAmbig = false;
+                }
+            :
+                COMMA! nls! annotationMemberArrayValueInitializer
+            )*
+            (COMMA! nls!)?
+        )?
+        RCURLY!
+    ;
+*OBS*/
+
+// The two things that can initialize an annotation array element are a conditional expression
+// and an annotation (nested annotation array initialisers are not valid)
+annotationMemberArrayValueInitializer
+    :   conditionalExpression[0]
+    |   annotation nls!
+    ;
+
+superClassClause!
+    {Token first = LT(1);}
+    :
+        ( "extends" nls! c:classOrInterfaceType[false] nls! )?
+        {#superClassClause = #(create(EXTENDS_CLAUSE,"EXTENDS_CLAUSE",first,LT(1)),c);}
+    ;
+
+// Definition of a Java class
+classDefinition![AST modifiers]
+{Token first = LT(1);AST prevCurrentClass = currentClass; }
+    :   "class" IDENT nls!
+       { currentClass = #IDENT; }
+        // it _might_ have type paramaters
+        (tp:typeParameters)?
+        // it _might_ have a superclass...
+        sc:superClassClause
+        // it might implement some interfaces...
+        ic:implementsClause
+        // now parse the body of the class
+        cb:classBlock
+        {#classDefinition = #(create(CLASS_DEF,"CLASS_DEF",first,LT(1)),
+                                                            modifiers,IDENT,tp,sc,ic,cb);}
+        { currentClass = prevCurrentClass; }
+    ;
+
+//TODO - where has superClassClause! production gone???
+
+// Definition of a Java Interface
+interfaceDefinition![AST modifiers]  {Token first = LT(1);}
+    :   "interface" IDENT nls!
+        // it _might_ have type paramaters
+        (tp:typeParameters)?
+        // it might extend some other interfaces
+        ie:interfaceExtends
+        // now parse the body of the interface (looks like a class...)
+        ib:interfaceBlock
+        {#interfaceDefinition = #(create(INTERFACE_DEF,"INTERFACE_DEF",first,LT(1)),
+                                  modifiers,IDENT,tp,ie,ib);}
+    ;
+
+enumDefinition![AST modifiers]  {Token first = LT(1);}
+    :   "enum" IDENT
+        // it might implement some interfaces...
+        ic:implementsClause
+        // now parse the body of the enum
+        eb:enumBlock
+        {#enumDefinition = #(create(ENUM_DEF,"ENUM_DEF",first,LT(1)),
+                             modifiers,IDENT,ic,eb);}
+    ;
+
+annotationDefinition![AST modifiers]  {Token first = LT(1);}
+    :   AT "interface" IDENT
+        // now parse the body of the annotation
+        ab:annotationBlock
+        {#annotationDefinition = #(create(ANNOTATION_DEF,"ANNOTATION_DEF",first,LT(1)),
+                                   modifiers,IDENT,ab);}
+    ;
+
+typeParameters
+{Token first = LT(1);int currentLtLevel = 0;}
+    :
+        {currentLtLevel = ltCounter;}
+        LT! {ltCounter++;} nls!
+        typeParameter (COMMA! nls! typeParameter)*
+        nls!
+        (typeArgumentsOrParametersEnd)?
+
+        // make sure we have gobbled up enough '>' characters
+        // if we are at the "top level" of nested typeArgument productions
+        {(currentLtLevel != 0) || ltCounter == currentLtLevel}?
+
+        {#typeParameters = #(create(TYPE_PARAMETERS, "TYPE_PARAMETERS",first,LT(1)), #typeParameters);}
+    ;
+
+typeParameter  {Token first = LT(1);}
+    :
+        // I'm pretty sure Antlr generates the right thing here:
+        (id:IDENT) ( options{generateAmbigWarnings=false;}: typeParameterBounds )?
+        {#typeParameter = #(create(TYPE_PARAMETER,"TYPE_PARAMETER",first,LT(1)), #typeParameter);}
+    ;
+
+typeParameterBounds  {Token first = LT(1);}
+    :
+        "extends"! nls! classOrInterfaceType[false]
+        (BAND! nls! classOrInterfaceType[false])*
+        {#typeParameterBounds = #(create(TYPE_UPPER_BOUNDS,"TYPE_UPPER_BOUNDS",first,LT(1)), #typeParameterBounds);}
+    ;
+
+// This is the body of a class. You can have classFields and extra semicolons.
+classBlock  {Token first = LT(1);}
+    :   LCURLY!
+        ( classField )? ( sep! ( classField )? )*
+        RCURLY!
+        {#classBlock = #(create(OBJBLOCK, "OBJBLOCK",first,LT(1)), #classBlock);}
+    ;
+
+// This is the body of an interface. You can have interfaceField and extra semicolons.
+interfaceBlock  {Token first = LT(1);}
+    :   LCURLY!
+        ( interfaceField )? ( sep! ( interfaceField )? )*
+        RCURLY!
+        {#interfaceBlock = #(create(OBJBLOCK, "OBJBLOCK",first,LT(1)), #interfaceBlock);}
+    ;
+
+// This is the body of an annotation. You can have annotation fields and extra semicolons,
+// That's about it (until you see what an annoation field is...)
+annotationBlock  {Token first = LT(1);}
+    :   LCURLY!
+        ( annotationField )? ( sep! ( annotationField )? )*
+        RCURLY!
+        {#annotationBlock = #(create(OBJBLOCK, "OBJBLOCK",first,LT(1)), #annotationBlock);}
+    ;
+
+// This is the body of an enum. You can have zero or more enum constants
+// followed by any number of fields like a regular class
+enumBlock  {Token first = LT(1);}
+    :   LCURLY!
+        (
+            // Need a syntactic predicate, since enumConstants
+            // can start with foo() as well as classField.
+            // (It's a true ambiguity, visible in the specification.
+            // To resolve in practice, use "def" before a real method.)
+            (enumConstantsStart)=> enumConstants
+        |   (classField)?
+        )
+        ( sep! (classField)? )*
+        RCURLY!
+        {#enumBlock = #(create(OBJBLOCK, "OBJBLOCK",first,LT(1)), #enumBlock);}
+    ;
+
+/** Guard for enumConstants.  */
+enumConstantsStart
+    :   enumConstant (COMMA | SEMI | NLS | RCURLY)
+    ;
+
+/** Comma-separated list of one or more enum constant definitions.  */
+enumConstants
+    :
+        enumConstant
+        ( options{greedy=true;}: COMMA! nls! enumConstant )*
+        ( COMMA! nls! )?            // trailing extra comma is OK
+    ;
+
+// An annotation field
+annotationField!  {Token first = LT(1);}
+    :   mods:modifiersOpt!
+        (   td:typeDefinitionInternal[#mods]
+            {#annotationField = #td;}
+        |   t:typeSpec[false]               // annotation field
+            (
+                // Need a syntactic predicate, since variableDefinitions
+                // can start with foo() also.  Since method defs are not legal
+                // in this context, there's no harm done.
+                (IDENT LPAREN)=>
+                i:IDENT              // the name of the field
+                LPAREN! RPAREN!
+
+                /*OBS* rt:declaratorBrackets[#t] *OBS*/
+
+                ( "default" nls! amvi:annotationMemberValueInitializer )?
+
+                {#annotationField =
+                        #(create(ANNOTATION_FIELD_DEF,"ANNOTATION_FIELD_DEF",first,LT(1)),
+                                 mods,
+                                 #(create(TYPE,"TYPE",first,LT(1)),t),
+                                 i,amvi
+                                 );}
+            |   v:variableDefinitions[#mods,#t]    // variable
+                {#annotationField = #v;}
+            )
+        )
+    ;
+
+//An enum constant may have optional parameters and may have a
+//a class body
+enumConstant!  {Token first = LT(1);}
+    :   an:annotationsOpt // Note:  Cannot start with "def" or another modifier.
+        i:IDENT
+        (   LPAREN!
+            a:argList
+            RPAREN!
+        )?
+        ( b:enumConstantBlock )?
+        {#enumConstant = #(create(ENUM_CONSTANT_DEF, "ENUM_CONSTANT_DEF",first,LT(1)), an, i, a, b);}
+    ;
+
+//The class-like body of an enum constant
+enumConstantBlock  {Token first = LT(1);}
+    :   LCURLY!
+        (enumConstantField)? ( sep! (enumConstantField)? )*
+        RCURLY!
+        {#enumConstantBlock = #(create(OBJBLOCK, "OBJBLOCK",first,LT(1)), #enumConstantBlock);}
+    ;
+
+//An enum constant field is just like a class field but without
+//the posibility of a constructor definition or a static initializer
+
+// TODO - maybe allow 'declaration' production within this production, 
+// but how to disallow constructors and static initializers...
+enumConstantField!  {Token first = LT(1);}
+    :   mods:modifiersOpt!
+        (   td:typeDefinitionInternal[#mods]
+            {#enumConstantField = #td;}
+        |   // A generic method has the typeParameters before the return type.
+            // This is not allowed for variable definitions, but this production
+            // allows it, a semantic check could be used if you wanted.
+            (tp:typeParameters)? t:typeSpec[false]          // method or variable declaration(s)
+            (
+                // Need a syntactic predicate, since variableDefinitions
+                // can start with foo() also.  Since method defs are not legal
+                // in this context, there's no harm done.
+                (IDENT LPAREN)=>
+
+                IDENT                                     // the name of the method
+
+                // parse the formal parameter declarations.
+                LPAREN! param:parameterDeclarationList RPAREN!
+
+                /*OBS* rt:declaratorBrackets[#t] *OBS*/
+
+                // get the list of exceptions that this method is
+                // declared to throw
+                ((nls "throws") => tc:throwsClause)?
+
+                ( s2:compoundStatement )?
+                // TODO - verify that 't' is useful/correct here, used to be 'rt'
+                {#enumConstantField = #(create(METHOD_DEF,"METHOD_DEF",first,LT(1)),
+                                         mods,
+                                         tp,
+                                         #(create(TYPE,"TYPE",first,LT(1)),t),
+                                         IDENT,
+                                         param,
+                                         tc,
+                                         s2);}
+
+            |   v:variableDefinitions[#mods,#t]
+                {#enumConstantField = #v;}
+            )
+        )
+
+        // "{ ... }" instance initializer
+    |   s4:compoundStatement
+        {#enumConstantField = #(create(INSTANCE_INIT,"INSTANCE_INIT",first,LT(1)), s4);}
+    ;
+
+// An interface can extend several other interfaces...
+interfaceExtends  {Token first = LT(1);}
+    :   (
+            e:"extends"! nls!
+            classOrInterfaceType[false] ( COMMA! nls! classOrInterfaceType[false] )* nls!
+        )?
+        {#interfaceExtends = #(create(EXTENDS_CLAUSE,"EXTENDS_CLAUSE",first,LT(1)),
+                               #interfaceExtends);}
+    ;
+
+// A class can implement several interfaces...
+implementsClause  {Token first = LT(1);}
+    :   (
+            i:"implements"! nls!
+            classOrInterfaceType[false] ( COMMA! nls! classOrInterfaceType[false] )* nls!
+        )?
+        {#implementsClause = #(create(IMPLEMENTS_CLAUSE,"IMPLEMENTS_CLAUSE",first,LT(1)),
+                               #implementsClause);}
+    ;
+
+// Now the various things that can be defined inside a class
+classField!  {Token first = LT(1);}
+    :   // method, constructor, or variable declaration
+        (constructorStart)=>
+        mc:modifiersOpt! ctor:constructorDefinition[#mc]
+        {#classField = #ctor;}
+    |
+        (declarationStart)=>
+        d:declaration
+        {#classField = #d;}
+    |
+        //TODO - unify typeDeclaration and typeDefinitionInternal names
+        // type declaration
+        (typeDeclarationStart)=>
+        mods:modifiersOpt!
+        (   td:typeDefinitionInternal[#mods]
+                {#classField = #td;}
+        )
+
+    // "static { ... }" class initializer
+    |   "static" s3:compoundStatement
+        {#classField = #(create(STATIC_INIT,"STATIC_INIT",first,LT(1)), s3);}
+
+    // "{ ... }" instance initializer
+    |   s4:compoundStatement
+        {#classField = #(create(INSTANCE_INIT,"INSTANCE_INIT",first,LT(1)), s4);}
+    ;
+
+// Now the various things that can be defined inside a interface
+interfaceField!
+    :   // method, constructor, or variable declaration
+        (declarationStart)=>
+        d:declaration
+        {#interfaceField = #d;}
+    |
+        //TODO - unify typeDeclaration and typeDefinitionInternal names
+        // type declaration
+        (typeDeclarationStart)=>
+        mods:modifiersOpt
+
+        (   td:typeDefinitionInternal[#mods]
+            {#interfaceField = #td;}
+        )
+    ;
+
+constructorBody
+    :   lc:LCURLY^ nls!         {#lc.setType(SLIST);}
+        (   (explicitConstructorInvocation) =>   // Java compatibility hack
+                explicitConstructorInvocation (sep! blockBody[sepToken])?
+            |   blockBody[EOF]
+        )
+        RCURLY!
+;
+
+
+/** Catch obvious constructor calls, but not the expr.super(...) calls */
+explicitConstructorInvocation
+    :   (typeArguments)?
+        (   "this"! lp1:LPAREN^ argList RPAREN!
+            {#lp1.setType(CTOR_CALL);}
+        |   "super"! lp2:LPAREN^ argList RPAREN!
+            {#lp2.setType(SUPER_CTOR_CALL);}
+        )
+    ;
+
+/** The tail of a declaration.
+  * Either v1, v2, ... (with possible initializers) or else m(args){body}.
+  * The two arguments are the modifier list (if any) and the declaration head (if any).
+  * The declaration head is the variable type, or (for a method) the return type.
+  * If it is missing, then the variable type is taken from its initializer (if there is one).
+  * Otherwise, the variable type defaults to 'any'.
+  * DECIDE:  Method return types default to the type of the method body, as an expression.
+  */
+variableDefinitions[AST mods, AST t]  {Token first = LT(1);}
+    :   variableDeclarator[getASTFactory().dupTree(mods),
+                           getASTFactory().dupTree(t)]
+        (   COMMA! nls!
+            variableDeclarator[getASTFactory().dupTree(mods),
+                               getASTFactory().dupTree(t)]
+        )*
+    |
+        // The parser allows a method definition anywhere a variable definition is accepted.
+
+        (   id:IDENT
+        |   qid:STRING_LITERAL          {#qid.setType(IDENT);}  // use for operator defintions, etc.
+        )
+
+        // parse the formal parameter declarations.
+        LPAREN! param:parameterDeclarationList! RPAREN!
+
+        /*OBS*rt:declaratorBrackets[#t]*/
+
+        // get the list of exceptions that this method is
+        // declared to throw
+        ((nls "throws") =>  tc:throwsClause!  )? 
+
+        // the method body is an open block
+        // but, it may have an optional constructor call (for constructors only)
+        // this constructor clause is only used for constructors using 'def'
+        // which look like method declarations
+        // since the block is optional and nls is part of sep we have to be sure
+        // a newline is followed by a block or ignore the nls too
+        ((nls! LCURLY) =>  (nlsWarn! mb:openBlock!))?
+
+        {   if (#qid != null)  #id = #qid;
+            #variableDefinitions =
+                    #(create(METHOD_DEF,"METHOD_DEF",first,LT(1)),
+                      mods, #(create(TYPE,"TYPE",first,LT(1)),t), id, param, tc, mb);
+        }
+    ;
+
+/** I've split out constructors separately; we could maybe integrate back into variableDefinitions 
+ *  later on if we maybe simplified 'def' to be a type declaration?
+ */
+constructorDefinition[AST mods]  {Token first = LT(1);}
+    :
+        id:IDENT
+
+        // parse the formal parameter declarations.
+        LPAREN! param:parameterDeclarationList! RPAREN!
+
+        /*OBS*rt:declaratorBrackets[#t]*/
+
+        // get the list of exceptions that this method is
+        // declared to throw
+        ((nls "throws") => tc:throwsClause!  )? nlsWarn!
+        // the method body is an open block
+        // but, it may have an optional constructor call (for constructors only)
+
+        // TODO assert that the id matches the class
+        { isConstructorIdent(id); }
+
+        cb:constructorBody!
+        {   #constructorDefinition =  #(create(CTOR_IDENT,"CTOR_IDENT",first,LT(1)),  mods, param, tc, cb);
+        }
+     ;
+
+/** Declaration of a variable. This can be a class/instance variable,
+ *  or a local variable in a method
+ *  It can also include possible initialization.
+ */
+variableDeclarator![AST mods, AST t]  {Token first = LT(1);}
+    :
+        id:variableName
+        /*OBS*d:declaratorBrackets[t]*/
+        (v:varInitializer)?
+        {#variableDeclarator = #(create(VARIABLE_DEF,"VARIABLE_DEF",first,LT(1)), mods, #(create(TYPE,"TYPE",first,LT(1)),t), id, v);}
+    ;
+
+/** Used in cases where a declaration cannot have commas, or ends with the "in" operator instead of '='. */
+singleVariable![AST mods, AST t]  {Token first = LT(1);}
+    :
+        id:variableName
+        {#singleVariable = #(create(VARIABLE_DEF,"VARIABLE_DEF",first,LT(1)), mods, #(create(TYPE,"TYPE",first,LT(1)),t), id);}
+    ;
+
+variableName
+    :   IDENT
+    ;
+
+/** After some type names, where zero or more empty bracket pairs are allowed.
+ *  We use ARRAY_DECLARATOR to represent this.
+ *  TODO:  Is there some more Groovy way to view this in terms of the indexed property syntax?
+ */
+declaratorBrackets[AST typ]
+    :   {#declaratorBrackets=typ;}
+        (
+            // A following list constructor might conflict with index brackets; prefer the declarator.
+            options {greedy=true;} :
+            lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!
+        )*
+    ;
+
+/** An assignment operator '=' followed by an expression.  (Never empty.) */
+varInitializer
+    :   ASSIGN^ nls! expression[LC_INIT]
+        // In {T x = y}, the left-context of y is that of an initializer.
+    ;
+
+/*OBS*
+// This is an initializer used to set up an array.
+arrayInitializer
+    :   lc:LCURLY^ {#lc.setType(ARRAY_INIT);}
+        (   initializer
+            (
+                // CONFLICT: does a COMMA after an initializer start a new
+                // initializer or start the option ',' at end?
+                // ANTLR generates proper code by matching
+                // the comma as soon as possible.
+                options {
+                        warnWhenFollowAmbig = false;
+                }
+            :
+                COMMA! initializer
+            )*
+            (COMMA!)?
+        )?
+        RCURLY!
+    ;
+*OBS*/
+
+/*OBS*  // Use [...] for initializing all sorts of sequences, including arrays.
+// The two "things" that can initialize an array element are an expression
+// and another (nested) array initializer.
+initializer
+    :   expression
+    |   arrayInitializer
+    ;
+*OBS*/
+
+/*OBS???
+// This is the header of a method. It includes the name and parameters
+// for the method.
+// This also watches for a list of exception classes in a "throws" clause.
+ctorHead
+    :   IDENT // the name of the method
+
+        // parse the formal parameter declarations.
+        LPAREN! parameterDeclarationList RPAREN!
+
+        // get the list of exceptions that this method is declared to throw
+        (throwsClause)?
+    ;
+*OBS*/
+
+// This is a list of exception classes that the method is declared to throw
+throwsClause
+    :   nls! "throws"^ nls! identifier ( COMMA! nls! identifier )* 
+    ;
+
+/** A list of zero or more formal parameters.
+ *  If a parameter is variable length (e.g. String... myArg) it should be
+ *  to the right of any other parameters of the same kind.
+ *  General form:  (req, ..., opt, ..., [rest], key, ..., [restKeys], [block]
+ *  This must be sorted out after parsing, since the various declaration forms
+ *  are impossible to tell apart without backtracking.
+ */
+parameterDeclarationList  {Token first = LT(1);}
+    :
+        (
+            parameterDeclaration
+            (   COMMA! nls!
+                parameterDeclaration
+            )*
+        )?
+        {#parameterDeclarationList = #(create(PARAMETERS,"PARAMETERS",first,LT(1)),
+                                       #parameterDeclarationList);}
+    ;
+
+/** A formal parameter for a method or closure. */
+parameterDeclaration!
+        { Token first = LT(1);boolean spreadParam = false; }
+    :
+        pm:parameterModifiersOpt
+        (   options {greedy=true;} :
+            t:typeSpec[false]
+        )?
+
+        // TODO:  What do formal parameters for keyword arguments look like?
+
+        // TODO:  Should this be SPREAD_ARG instead?
+        ( TRIPLE_DOT! { spreadParam = true; } )?
+
+        id:IDENT
+
+        // allow an optional default value expression
+        (exp:varInitializer)?
+
+        /*OBS*pd:declaratorBrackets[#t]*/
+        {
+            if (spreadParam) {
+                #parameterDeclaration = #(create(VARIABLE_PARAMETER_DEF,"VARIABLE_PARAMETER_DEF",first,LT(1)),
+                      pm, #(create(TYPE,"TYPE",first,LT(1)),t), id, exp);
+            } else {
+                #parameterDeclaration = #(create(PARAMETER_DEF,"PARAMETER_DEF",first,LT(1)),
+                      pm, #(create(TYPE,"TYPE",first,LT(1)),t), id, exp);
+            }
+        }
+    ;
+
+/*OBS*
+variableLengthParameterDeclaration!  {Token first = LT(1);}
+    :   pm:parameterModifier t:typeSpec[false] TRIPLE_DOT! id:IDENT
+
+        /*OBS* pd:declaratorBrackets[#t]* /
+        {#variableLengthParameterDeclaration = #(create(VARIABLE_PARAMETER_DEF,"VARIABLE_PARAMETER_DEF",first,LT(1)),
+                                                                                            pm, #(create(TYPE,"TYPE",first,LT(1)),t), id);}
+    ;
+*OBS*/
+
+parameterModifiersOpt
+        { Token first = LT(1);int seenDef = 0; }
+        //final and/or def can appear amongst annotations in any order
+    :   (   {seenDef++ == 0}?       // do not allow multiple "def" tokens
+            "def"!  nls!            // redundant, but allowed for symmetry
+        |   "final" nls!
+        |   annotation nls!
+        )*
+        {#parameterModifiersOpt = #(create(MODIFIERS,"MODIFIERS",first,LT(1)), #parameterModifiersOpt);}
+    ;
+
+/** Closure parameters are exactly like method parameters,
+ *  except that they are not enclosed in parentheses, but rather
+ *  are prepended to the front of a block, just after the brace.
+ *  They are separated from the closure body by a CLOSABLE_BLOCK_OP token '->'.
+ */
+// With '|' there would be restrictions on bitwise-or expressions.
+closableBlockParamsOpt[boolean addImplicit]
+    :   (parameterDeclarationList nls CLOSABLE_BLOCK_OP)=>
+        parameterDeclarationList nls! CLOSABLE_BLOCK_OP! nls!
+    |   {addImplicit}?
+        implicitParameters
+    |
+        /* else do not parse any parameters at all */
+    ;
+
+/** Lookahead to check whether a block begins with explicit closure arguments. */
+closableBlockParamsStart!
+    :
+        parameterDeclarationList nls CLOSABLE_BLOCK_OP
+    ;
+
+/** Simple names, as in {x|...}, are completely equivalent to {(def x)|...}.  Build the right AST. */
+closableBlockParam!  {Token first = LT(1);}
+    :   id:IDENT!
+        {#closableBlockParam = #(create(PARAMETER_DEF,"PARAMETER_DEF",first,LT(1)),
+                               #(create(MODIFIERS,"MODIFIERS",first,LT(1))), #(create(TYPE,"TYPE",first,LT(1))),
+                               id);}
+    ;
+
+// Compound statement. This is used in many contexts:
+// Inside a class definition prefixed with "static":
+// it is a class initializer
+// Inside a class definition without "static":
+// it is an instance initializer
+// As the body of a method
+// As a completely indepdent braced block of code inside a method
+// it starts a new scope for variable definitions
+// In Groovy, this is called an "open block".  It cannot have closure arguments.
+
+compoundStatement
+    :   openBlock
+    ;
+
+/** An open block is not allowed to have closure arguments. */
+openBlock
+    :   lc:LCURLY^ nls!     {#lc.setType(SLIST);}
+        // AST type of SLIST means "never gonna be a closure"
+        blockBody[EOF]
+        RCURLY!
+    ;
+
+/** A block body is a parade of zero or more statements or expressions. */
+blockBody[int prevToken]
+    :   
+        (statement[prevToken])? (sep! (statement[sepToken])?)*
+    ;
+
+/** A block which is known to be a closure, even if it has no apparent arguments.
+ *  A block inside an expression or after a method call is always assumed to be a closure.
+ *  Only labeled, unparameterized blocks which occur directly as substatements are kept open.
+ */
+closableBlock
+    :   lc:LCURLY^ nls!     {#lc.setType(CLOSABLE_BLOCK);}
+        closableBlockParamsOpt[true]
+        blockBody[EOF]
+        RCURLY!
+    ;
+
+/** A block known to be a closure, but which omits its arguments, is given this placeholder.
+ *  A subsequent pass is responsible for deciding if there is an implicit 'it' parameter,
+ *  or if the parameter list should be empty.
+ */
+implicitParameters  {Token first = LT(1);}
+    :   {   #implicitParameters = #(create(IMPLICIT_PARAMETERS,"IMPLICIT_PARAMETERS",first,LT(1)));  }
+    ;
+
+/** A sub-block of a block can be either open or closable.
+ *  It is closable if and only if there are explicit closure arguments.
+ *  Compare this to a block which is appended to a method call,
+ *  which is given closure arguments, even if they are not explicit in the code.
+ */
+openOrClosableBlock
+    :   lc:LCURLY^ nls!
+        cp:closableBlockParamsOpt[false]
+        {   if (#cp == null)    #lc.setType(SLIST);
+            else                #lc.setType(CLOSABLE_BLOCK);
+        }
+        blockBody[EOF]
+        RCURLY!
+    ;
+
+/** A statement is an element of a block.
+ *  Typical statements are declarations (which are scoped to the block)
+ *  and expressions.
+ */
+statement[int prevToken]
+    // prevToken is NLS if previous statement is separated only by a newline
+
+    // declarations are ambiguous with "ID DOT" relative to expression
+    // statements. Must backtrack to be sure. Could use a semantic
+    // predicate to test symbol table to see what the type was coming
+    // up, but that's pretty hard without a symbol table ;)
+    :   (declarationStart)=>
+        declaration
+
+    // Attach a label to the front of a statement
+    // This block is executed for effect, unless it has an explicit closure argument.
+    |
+        (IDENT COLON)=>
+        pfx:statementLabelPrefix!
+        {#statement = #pfx;}  // nest it all under the label prefix
+        (   (LCURLY) => openOrClosableBlock
+        |   statement[COLON]
+        )
+
+    // An expression statement. This could be a method call,
+    // assignment statement, or any other expression evaluated for
+    // side-effects.
+    // The prevToken is used to check for dumb expressions like +1.
+    |    expressionStatement[prevToken]
+
+    // class definition
+    |    m:modifiersOpt! typeDefinitionInternal[#m]
+
+    // If-else statement
+    |   "if"^ LPAREN! assignmentLessExpression RPAREN! nlsWarn! compatibleBodyStatement
+        (
+            // CONFLICT: the old "dangling-else" problem...
+            //           ANTLR generates proper code matching
+            //                       as soon as possible.  Hush warning.
+            options {
+                    warnWhenFollowAmbig = false;
+            }
+        :   // lookahead to check if we're entering an 'else' clause
+            ( (sep!)? "else"! )=>
+            (sep!)?  // allow SEMI here for compatibility with Java
+            "else"! nlsWarn! compatibleBodyStatement
+        )?
+
+    // For statement
+    |   forStatement
+
+    // While statement
+    |   "while"^ LPAREN! strictContextExpression RPAREN! nlsWarn! compatibleBodyStatement
+
+    /*OBS* no do-while statement in Groovy (too ambiguous)
+    // do-while statement
+    |   "do"^ statement "while"! LPAREN! strictContextExpression RPAREN! SEMI!
+    *OBS*/
+    // With statement
+    // (This is the Groovy scope-shift mechanism, used for builders.)
+    |   "with"^ LPAREN! strictContextExpression RPAREN! nlsWarn! compoundStatement
+
+    // Splice statement, meaningful only inside a "with" expression.
+    // PROPOSED, DECIDE.  Prevents the namespace pollution of a "text" method or some such.
+    |   sp:STAR^ nls!                       {#sp.setType(SPREAD_ARG);}
+        expressionStatement[EOF]
+    // Example:  with(htmlbuilder) { head{} body{ *"some text" } }
+    // Equivalent to:  { htmlbuilder.head{} htmlbuilder.body{ (htmlbuilder as Collection).add("some text") } }
+
+    // Import statement.  Can be used in any scope.  Has "import x as y" also.
+    |   importStatement
+
+    // switch/case statement
+    |   "switch"^ LPAREN! strictContextExpression RPAREN! nlsWarn! LCURLY! nls!
+        ( casesGroup )*
+        RCURLY!
+
+    // exception try-catch block
+    |   tryBlock
+
+    // synchronize a statement
+    |   "synchronized"^ LPAREN! strictContextExpression RPAREN! nlsWarn! compoundStatement
+
+
+    /*OBS*
+    // empty statement
+    |   s:SEMI {#s.setType(EMPTY_STAT);}
+    *OBS*/
+
+    |   branchStatement
+    ;
+
+forStatement
+    :   f:"for"^
+        LPAREN!
+        (   (forInit SEMI)=>traditionalForClause
+            // *OBS*
+            // There's no need at all for squeezing in the new Java 5 "for"
+            // syntax, since Groovy's is a suitable alternative.
+            // |   (parameterDeclaration COLON)=> forEachClause
+            // *OBS*
+        |   // the coast is clear; it's a modern Groovy for statement
+            forInClause
+        )
+        RPAREN! nlsWarn!
+        compatibleBodyStatement                                  // statement to loop over
+    ;
+
+traditionalForClause
+    :
+        forInit SEMI!   // initializer
+        forCond SEMI!   // condition test
+        forIter         // updater
+    ;
+
+/*OBS*
+forEachClause  {Token first = LT(1);}
+    :
+        p:parameterDeclaration COLON! expression
+        {#forEachClause = #(create(FOR_EACH_CLAUSE,"FOR_EACH_CLAUSE",first,LT(1)), #forEachClause);}
+    ;
+*OBS*/
+
+forInClause
+    :   (   (declarationStart)=>
+            decl:singleDeclarationNoInit
+        |   IDENT
+        )
+        (
+            i:"in"^         {#i.setType(FOR_IN_ITERABLE);}
+            shiftExpression[0]
+        |
+            { addWarning(
+              "A colon at this point is legal Java but not recommended in Groovy.",
+              "Use the 'in' keyword."
+              );
+            require(#decl != null,
+                "Java-style for-each statement requires a type declaration."
+                ,
+                "Use the 'in' keyword, as for (x in y) {...}"
+                );
+            }
+            c:COLON^         {#c.setType(FOR_IN_ITERABLE);}
+            expression[0]
+        )
+    ;
+
+/** In Java, "if", "while", and "for" statements can take random, non-braced statements as their bodies.
+ *  Support this practice, even though it isn't very Groovy.
+ */
+compatibleBodyStatement
+    :   (LCURLY)=>
+        compoundStatement
+    |
+        statement[EOF]
+    ;
+
+/** In Groovy, return, break, continue, throw, and assert can be used in a parenthesized expression context.
+ *  Example:  println (x || (return));  println assert x, "won't print a false value!"
+ *  If an optional expression is missing, its value is void (this coerces to null when a value is required).
+ */
+branchStatement
+    :
+    // Return an expression
+        "return"^
+        ( expression[0] )?
+
+    // break:  get out of a loop, or switch, or method call
+    // continue:  do next iteration of a loop, or leave a closure
+    |   ("break"^ | "continue"^)
+        (
+            (IDENT COLON)=>
+            statementLabelPrefix
+        )?
+        ( expression[0] )?
+
+    // throw an exception
+    |   "throw"^ expression[0]
+
+
+    // TODO - decide on definitive 'assert' statement in groovy (1.4 and|or groovy)
+    // asserts
+    // 1.4+ ...
+    //      |   "assert"^ expression[0] ( COLON! expression[0] )?
+
+    // groovy assertion...
+    |   "assert"^ assignmentLessExpression
+        (   options {greedy=true;} :
+            (   COMMA!  // TODO:  gratuitous change caused failures
+            |   COLON!  // standard Java syntax, but looks funny in Groovy
+            )
+            expression[0]
+        )?
+    ;
+
+/** A labeled statement, consisting of a vanilla identifier followed by a colon. */
+// Note:  Always use this lookahead, to keep antlr from panicking: (IDENT COLON)=>
+statementLabelPrefix
+    :   IDENT c:COLON^ {#c.setType(LABELED_STAT);} nls!
+    ;
+
+/** An expression statement can be any general expression.
+ *  <p>
+ *  An expression statement can also be a <em>command</em>,
+ *  which is a simple method call in which the outermost parentheses are omitted.
+ *  <p>
+ *  Certain "suspicious" looking forms are flagged for the user to disambiguate.
+ */
+// DECIDE: A later semantic pass can flag dumb expressions that dot occur in
+//         positions where their value is not used, e.g., <code>{1+1;println}</code>
+expressionStatement[int prevToken]
+        {Token first = LT(1);boolean isPathExpr = false;  }
+    : 
+        (   (suspiciousExpressionStatementStart)=>
+            checkSuspiciousExpressionStatement[prevToken]
+        )?
+        // Checks are now out of the way; here's the real rule:
+        head:expression[LC_STMT]
+        {   isPathExpr = (#head == lastPathExpression);  }
+        (
+            // A path expression (e.g., System.out.print) can take arguments.
+            {isPathExpr}?
+            cmd:commandArguments[#head]!
+            {#expressionStatement = #cmd;}
+        )?
+        {#expressionStatement = #(create(EXPR,"EXPR",first,LT(1)),#expressionStatement);}
+    ;
+        
+/**
+ *  If two statements are separated by newline (not SEMI), the second had
+ *  better not look like the latter half of an expression.  If it does, issue a warning.
+ *  <p>
+ *  Also, if the expression starts with a closure, it needs to
+ *  have an explicit parameter list, in order to avoid the appearance of a
+ *  compound statement.  This is a hard error.
+ *  <p>
+ *  These rules are different from Java's "dumb expression" restriction.
+ *  Unlike Java, Groovy blocks can end with arbitrary (even dumb) expressions,
+ *  as a consequence of optional 'return' and 'continue' tokens.
+ * <p>
+ *  To make the programmer's intention clear, a leading closure must have an
+ *  explicit parameter list, and must not follow a previous statement separated
+ *  only by newlines.
+ */
+checkSuspiciousExpressionStatement[int prevToken]
+    :
+        (~LCURLY | LCURLY closableBlockParamsStart)=>  //FIXME too much lookahead
+        // Either not a block, or a block with an explicit closure parameter list.
+        (   {prevToken == NLS}?
+            {   addWarning(
+                "Expression statement looks like it may continue a previous statement.",
+                "Either remove previous newline, or add an explicit semicolon ';'.");
+            }
+        )?
+    |
+        // Else we have a block without any visible closure parameters.
+        {prevToken == NLS}?
+        // if prevToken is NLS, we have double trouble; issue a double warning
+        // Example:  obj.foo \n {println x}
+        // Might be appended block:  obj.foo {println x}
+        // Might be closure expression:  obj.foo ; {x->println x}
+        // Might be open block:  obj.foo ; L:{println x}
+        {   require(false,
+            "Closure expression looks like it may be an isolated open block, "+
+            "or it may continue a previous statement."
+            ,
+            "Add an explicit parameter list, as in {it -> ...}, or label it as L:{...}, "+
+            "and also either remove previous newline, or add an explicit semicolon ';'."
+            );
+        }
+    |
+        {prevToken != NLS}?
+        // If prevToken is SEMI or something else, issue a single warning:
+        // Example:  obj.foo ; {println x}
+        // Might be closure expression:  obj.foo ; {x->println x}
+        // Might be open block:  obj.foo ; L:{println x}
+        {   require(false,
+            "Closure expression looks like it may be an isolated open block.",
+            "Add an explicit parameter list, as in {it -> ...}, or label it as L:{...}.");
+        }
+    ;
+
+/** Lookahead for suspicious statement warnings and errors. */
+suspiciousExpressionStatementStart
+    :
+        (   (PLUS | MINUS)
+        |   (LBRACK | LPAREN | LCURLY)
+        )
+        // TODO:  Expand this set?
+    ;
+
+// Support for switch/case:
+casesGroup  {Token first = LT(1);}
+    :   (   // CONFLICT: to which case group do the statements bind?
+            // ANTLR generates proper code: it groups the
+            // many "case"/"default" labels together then
+            // follows them with the statements
+            options {
+                greedy = true;
+            }
+            :
+            aCase
+        )+
+        caseSList
+        {#casesGroup = #(create(CASE_GROUP, "CASE_GROUP",first,LT(1)), #casesGroup);}
+    ;
+
+aCase
+    :   ("case"^ expression[0] | "default") COLON! nls!
+    ;
+
+caseSList  {Token first = LT(1);}
+    :   statement[COLON] (sep! (statement[sepToken])?)*
+        {#caseSList = #(create(SLIST,"SLIST",first,LT(1)),#caseSList);}
+    ;
+
+// The initializer for a for loop
+forInit  {Token first = LT(1);}
+    :   // if it looks like a declaration, it is
+        (declarationStart)=> declaration
+    |   // else it's a comma-separated list of expressions
+        (controlExpressionList)?
+        {#forInit = #(create(FOR_INIT,"FOR_INIT",first,LT(1)),#forInit);}
+    ;
+
+forCond  {Token first = LT(1);}
+    :   (strictContextExpression)?
+        {#forCond = #(create(FOR_CONDITION,"FOR_CONDITION",first,LT(1)),#forCond);}
+    ;
+
+forIter  {Token first = LT(1);}
+    :   (controlExpressionList)?
+        {#forIter = #(create(FOR_ITERATOR,"FOR_ITERATOR",first,LT(1)),#forIter);}
+    ;
+
+// an exception handler try/catch block
+tryBlock
+    :   "try"^ nlsWarn! compoundStatement
+            ( options {greedy=true;} :  nls! handler)*
+            ( options {greedy=true;} :  nls! finallyClause)?
+    ;
+
+finallyClause
+    :   "finally"^ nlsWarn! compoundStatement
+    ;
+
+// an exception handler
+handler
+    :   "catch"^ LPAREN! parameterDeclaration RPAREN! nlsWarn! compoundStatement
+    ;
+
+/** A member name (x.y) or element name (x[y]) can serve as a command name,
+ *  which may be followed by a list of arguments.
+ *  Unlike parenthesized arguments, these must be plain expressions,
+ *  without labels or spread operators.
+ */
+commandArguments[AST head]  {Token first = LT(1);}
+    :
+        expression[0] ( COMMA! nls! expression[0] )*
+        // println 2+2 //OK
+        // println(2+2) //OK
+        // println (2)+2 //BAD
+        // println((2)+2) //OK
+        // (println(2)+2) //OK
+        // compare (2), 2 //BAD
+        // compare( (2), 2 ) //OK
+        // foo.bar baz{bat}, bang{boz} //OK?!
+        {
+            AST elist = #(create(ELIST,"ELIST",first,LT(1)), #commandArguments);
+            AST headid = getASTFactory().dup(#head);
+            headid.setType(METHOD_CALL);
+            headid.setText("<command>");
+            #commandArguments = #(headid, head, elist);
+        }
+    ;
+
+// expressions
+// Note that most of these expressions follow the pattern
+//   thisLevelExpression :
+//         nextHigherPrecedenceExpression
+//                 (OPERATOR nextHigherPrecedenceExpression)*
+// which is a standard recursive definition for a parsing an expression.
+// The operators in java have the following precedences:
+//      lowest  (15)  = **= *= /= %= += -= <<= >>= >>>= &= ^= |=
+//                      (14)  ?:
+//                      (13)  ||
+//                      (12)  &&
+//                      (11)  |
+//                      (10)  ^
+//                      ( 9)  &
+//                      ( 8)  == != <=>
+//                      ( 7)  < <= > >= instanceof as
+//                      ( 6)  << >> .. ...
+//                      ( 5)  +(binary) -(binary)
+//                      ( 4)  * / %
+//                      ( 3)  ++(pre/post) --(pre/post) +(unary) -(unary)
+//                      ( 2)  **(power)
+//                      ( 1)  ~  ! $ (type)
+//                            . ?. *. (dot -- identifier qualification)
+//                            []   () (method call)  {} (closableBlock)  [] (list/map)
+//                            new  () (explicit parenthesis)
+//                            $x (scope escape)
+//
+// the last two are not usually on a precedence chart; I put them in
+// to point out that new has a higher precedence than '.', so you
+// can validy use
+//       new Frame().show()
+//
+// Note that the above precedence levels map to the rules below...
+// Once you have a precedence chart, writing the appropriate rules as below
+//   is usually very straightfoward
+
+
+// the mother of all expressions
+// This nonterminal is not used for expression statements, which have a more restricted syntax
+// due to possible ambiguities with other kinds of statements.  This nonterminal is used only
+// in contexts where we know we have an expression.  It allows general Java-type expressions.
+expression[int lc_stmt]
+    :   assignmentExpression[lc_stmt]
+    ;
+
+// This is a list of expressions.
+// Used for backward compatibility, in a few places where
+// comma-separated lists of Java expression statements and declarations are required.
+controlExpressionList  {Token first = LT(1);}
+    :   strictContextExpression (COMMA! nls! strictContextExpression)*
+        {#controlExpressionList = #(create(ELIST,"ELIST",first,LT(1)), controlExpressionList);}
+    ;
+
+/** A "path expression" is a name or other primary, possibly qualified by various
+ *  forms of dot, and/or followed by various kinds of brackets.
+ *  It can be used for value or assigned to, or else further qualified, indexed, or called.
+ *  It is called a "path" because it looks like a linear path through a data structure.
+ *  Examples:  x.y, x?.y, x*.y, x.@y; x[], x[y], x[y,z]; x(), x(y), x(y,z); x{s}; a.b[n].c(x).d{s}
+ *  (Compare to a C lvalue, or LeftHandSide in the JLS section 15.26.)
+ *  General expressions are built up from path expressions, using operators like '+' and '='.
+ */
+pathExpression[int lc_stmt]
+        { AST prefix = null; }
+    :	
+        pre:primaryExpression!
+        { prefix = #pre; }
+
+        (
+            options {
+                // \n{foo} could match here or could begin a new statement
+                // We do want to match here. Turn off warning.
+                greedy=true;
+                // This turns the ambiguity warning of the second alternative
+                // off. See below. (The "ANTLR_LOOP_EXIT" predicate makes it non-issue)
+                //@@ warnWhenFollowAmbig=false;
+            }
+            // Parsing of this chain is greedy.  For example, a pathExpression may be a command name
+            // followed by a command argument, but that command argument cannot begin with an LPAREN,
+            // since a parenthesized expression is greedily attached to the pathExpression as a method argument.
+            // The lookahead is also necessary to reach across newline in foo \n {bar}.
+            // (Apparently antlr's basic approximate LL(k) lookahead is too weak for this.)
+        :   (pathElementStart)=>
+            nls!
+            pe:pathElement[prefix]!
+            { prefix = #pe; }
+        |
+            {lc_stmt == LC_STMT || lc_stmt == LC_INIT}?
+            (nls LCURLY)=>
+            nlsWarn!
+            apb:appendedBlock[prefix]!
+            { prefix = #apb; }
+        )*
+
+        {
+            #pathExpression = prefix;
+            lastPathExpression = #pathExpression;
+        }
+    ;
+
+pathElement[AST prefix]
+        // The primary can then be followed by a chain of .id, (a), [a], and {...}
+    :
+        {   #pathElement = prefix;  }
+        (   // Spread operator:  x*.y  ===  x?.collect{it.y}
+            SPREAD_DOT^
+        |   // Optional-null operator:  x?.y  === (x==null)?null:x.y
+            OPTIONAL_DOT^
+        |   // Member pointer operator: foo.&y == foo.metaClass.getMethodPointer(foo, "y")
+            MEMBER_POINTER^
+        |   // The all-powerful dot.
+            (nls! DOT^)
+        ) nls!
+        (typeArguments)?   // TODO: Java 5 type argument application via prefix x.<Integer>y
+        namePart
+    |
+        mca:methodCallArgs[prefix]!
+        {   #pathElement = #mca;  }
+    |
+        // Can always append a block, as foo{bar}
+        apb:appendedBlock[prefix]!
+        {   #pathElement = #apb;  }
+    |
+        // Element selection is always an option, too.
+        // In Groovy, the stuff between brackets is a general argument list,
+        // since the bracket operator is transformed into a method call.
+        ipa:indexPropertyArgs[prefix]!
+        {   #pathElement = #ipa;  }
+
+/*NYI*
+    |   DOT^ nls! "this"
+
+    |   DOT^ nls! "super"
+        (   // (new Outer()).super()  (create enclosing instance)
+            lp3:LPAREN^ argList RPAREN!
+            {#lp3.setType(SUPER_CTOR_CALL);}
+        |   DOT^ IDENT
+            (   lps:LPAREN^ {#lps.setType(METHOD_CALL);}
+                argList
+                RPAREN!
+            )?
+        )
+    |   DOT^ nls! newExpression
+*NYI*/
+    ;
+
+pathElementStart!
+    :   (nls! DOT)
+    |   SPREAD_DOT
+    |   OPTIONAL_DOT
+//todo - nondeterminisms    |   MEMBER_POINTER_DEFAULT
+    |   MEMBER_POINTER
+    |   LBRACK
+    |   LPAREN
+    |   LCURLY
+    ;
+
+/** This is the grammar for what can follow a dot:  x.a, x.@a, x.&a, x.'a', etc.
+ *  Note: <code>typeArguments</code> is handled by the caller of <code>namePart</code>.
+ */
+namePart  {Token first = LT(1);}
+    :
+        (   ats:AT^     {#ats.setType(SELECT_SLOT);}  )?
+        // foo.@bar selects the field (or attribute), not property
+
+        (   IDENT
+        |   sl:STRING_LITERAL {#sl.setType(IDENT);}
+            // foo.'bar' is in all ways same as foo.bar, except that bar can have an arbitrary spelling
+        |   dynamicMemberName
+        |
+            openBlock
+            // PROPOSAL, DECIDE:  Is this inline form of the 'with' statement useful?
+            // Definition:  a.{foo} === {with(a) {foo}}
+            // May cover some path expression use-cases previously handled by dynamic scoping (closure delegates).
+
+                                                                    // lets allow common keywords as property names
+        |   keywordPropertyNames
+
+/* lets allow some common keywords for properties like 'in', 'class', 'def' etc
+ * TODO: Reinstate this logic if we change or remove keywordPropertyNames.
+ * See also LITERAL_in logic in the lexer.
+        // Recover with a good diagnostic from a common error:
+        |   "in"  // poster child; the lexer makes all keywords after dot look like "in"
+            {   String kwd = LT(1).getText();
+                require(false,
+                    "illegal keyword after dot in x."+kwd,
+                    "put the keyword in quotes, as in x.'"+kwd+"'");
+                // This helps the user recover from ruined Java identifiers, as in System.'in'.
+                // DECIDE: Shall we just define foo.in to DTRT automagically, or do we want the syntax check?
+            }
+*/                        
+        )
+
+        // (No, x.&@y is not needed; just say x.&y as Slot or some such.)
+    ;
+
+/** Allowed keywords after dot (as a member name) and before colon (as a label).
+ *  TODO: What's the rationale for these?
+ */
+keywordPropertyNames
+    :   (   "class" | "in" | "as" | "def"
+        |   "if" | "else" | "for" | "while" | "do" | "switch" | "try" | "catch" | "finally"
+        |   builtInType
+        )
+        { #keywordPropertyNames.setType(IDENT); }
+    ;
+                                                
+/** If a dot is followed by a parenthesized or quoted expression, the member is computed dynamically,
+ *  and the member selection is done only at runtime.  This forces a statically unchecked member access.
+ */
+dynamicMemberName  {Token first = LT(1);}
+    :   (   parenthesizedExpression
+        |   stringConstructorExpression
+        )
+        { #dynamicMemberName = #(create(DYNAMIC_MEMBER, "DYNAMIC_MEMBER",first,LT(1)), #dynamicMemberName); }
+    ;
+
+/** An expression may be followed by one or both of (...) and {...}.
+ *  Note: If either is (...) or {...} present, it is a method call.
+ *  The {...} is appended to the argument list, and matches a formal of type Closure.
+ *  If there is no method member, a property (or field) is used instead, and must itself be callable.
+ *  <p>
+ *  If the methodCallArgs are absent, it is a property reference.
+ *  If there is no property, it is treated as a field reference, but never a method reference.
+ *  <p>
+ *  Arguments in the (...) can be labeled, and the appended block can be labeled also.
+ *  If there is a mix of unlabeled and labeled arguments,
+ *  all the labeled arguments must follow the unlabeled arguments,
+ *  except that the closure (labeled or not) is always a separate final argument.
+ *  Labeled arguments are collected up and passed as a single argument to a formal of type Map.
+ *  <p>
+ *  Therefore, f(x,y, a:p, b:q) {s} is equivalent in all ways to f(x,y, [a:p,b:q], {s}).
+ *  Spread arguments of sequence type count as unlabeled arguments,
+ *  while spread arguments of map type count as labeled arguments.
+ *  (This distinction must sometimes be checked dynamically.)
+ *
+ *  A plain unlabeled argument is allowed to match a trailing Map or Closure argument:
+ *  f(x, a:p) {s}  ===  f(*[ x, [a:p], {s} ])
+ */
+// AST is [METHOD_CALL, callee, ELIST? CLOSABLE_BLOCK?].
+// Note that callee is often of the form x.y but not always.
+// If the callee is not of the form x.y, then an implicit .call is needed.
+methodCallArgs[AST callee]
+    :
+        {#methodCallArgs = callee;}
+        lp:LPAREN^ {#lp.setType(METHOD_CALL);}
+        argList
+        RPAREN!
+    ;
+
+/** An appended block follows any expression.
+ *  If the expression is not a method call, it is given an empty argument list.
+ */
+appendedBlock[AST callee]
+    :
+        {
+            // If the callee is itself a call, flatten the AST.
+            if (callee != null && callee.getType() == METHOD_CALL) {
+                #appendedBlock = callee;
+            } else {
+                AST lbrace = getASTFactory().create(LT(1));
+                lbrace.setType(METHOD_CALL);
+                if (callee != null)  lbrace.addChild(callee);
+                #appendedBlock = lbrace;
+            }
+        }
+        /*  FIXME DECIDE: should appended blocks accept labels?
+        (   (IDENT COLON nls LCURLY)=>
+            IDENT c:COLON^ {#c.setType(LABELED_ARG);} nls!
+        )? */
+        closableBlock
+    ;
+
+/** An expression may be followed by [...].
+ *  Unlike Java, these brackets may contain a general argument list,
+ *  which is passed to the array element operator, which can make of it what it wants.
+ *  The brackets may also be empty, as in T[].  This is how Groovy names array types.
+ *  <p>Returned AST is [INDEX_OP, indexee, ELIST].
+ */
+indexPropertyArgs[AST indexee]
+    :
+        {#indexPropertyArgs = indexee;}
+        lb:LBRACK^ {#lb.setType(INDEX_OP);}
+        argList
+        RBRACK!
+    ;
+
+// assignment expression (level 15)
+assignmentExpression[int lc_stmt]
+    :   conditionalExpression[lc_stmt]
+        (
+            (   ASSIGN^
+            |   PLUS_ASSIGN^
+            |   MINUS_ASSIGN^
+            |   STAR_ASSIGN^
+            |   DIV_ASSIGN^
+            |   MOD_ASSIGN^
+            |   SR_ASSIGN^
+            |   BSR_ASSIGN^
+            |   SL_ASSIGN^
+            |   BAND_ASSIGN^
+            |   BXOR_ASSIGN^
+            |   BOR_ASSIGN^
+            |   STAR_STAR_ASSIGN^
+            //|   USEROP_13^  //DECIDE: This is how user-define ops would show up.
+            )
+            nls!
+            assignmentExpression[lc_stmt == LC_STMT? LC_INIT: 0]
+            // If left-context of {x = y} is a statement boundary,
+            // define the left-context of y as an initializer.
+        )?
+    ;
+
+// conditional test (level 14)
+conditionalExpression[int lc_stmt]
+    :   logicalOrExpression[lc_stmt]
+        ( QUESTION^ nls! assignmentExpression[0] COLON! nls! conditionalExpression[0] )?
+    ;
+
+
+// logical or (||)  (level 13)
+logicalOrExpression[int lc_stmt]
+    :   logicalAndExpression[lc_stmt] (LOR^ nls! logicalAndExpression[0])*
+    ;
+
+
+// logical and (&&)  (level 12)
+logicalAndExpression[int lc_stmt]
+    :   inclusiveOrExpression[lc_stmt] (LAND^ nls! inclusiveOrExpression[0])*
+    ;
+
+// bitwise or non-short-circuiting or (|)  (level 11)
+inclusiveOrExpression[int lc_stmt]
+    :   exclusiveOrExpression[lc_stmt] (BOR^ nls! exclusiveOrExpression[0])*
+    ;
+
+
+// exclusive or (^)  (level 10)
+exclusiveOrExpression[int lc_stmt]
+    :   andExpression[lc_stmt] (BXOR^ nls! andExpression[0])*
+    ;
+
+
+// bitwise or non-short-circuiting and (&)  (level 9)
+andExpression[int lc_stmt]
+    :   regexExpression[lc_stmt] (BAND^ nls! regexExpression[0])*
+    ;
+
+// regex find and match (=~ and ==~) (level 8.5)
+// jez: moved =~ closer to precedence of == etc, as...
+// 'if (foo =~ "a.c")' is very close in intent to 'if (foo == "abc")'
+regexExpression[int lc_stmt]
+    :   equalityExpression[lc_stmt] ((REGEX_FIND^ | REGEX_MATCH^) nls! equalityExpression[0])*
+    ;
+
+// equality/inequality (==/!=) (level 8)
+equalityExpression[int lc_stmt]
+    :   relationalExpression[lc_stmt] ((NOT_EQUAL^ | EQUAL^ | COMPARE_TO^) nls! relationalExpression[0])*
+    ;
+
+// boolean relational expressions (level 7)
+relationalExpression[int lc_stmt]
+    :   shiftExpression[lc_stmt]
+        (   (   (   LT^
+                |   GT^
+                |   LE^
+                |   GE^
+                |   "in"^
+                )
+                nls!
+                shiftExpression[0]
+            )?
+        |   "instanceof"^ nls! typeSpec[true]
+        |   "as"^         nls! typeSpec[true] //TODO: Rework to allow type expression?
+        )
+    ;
+
+
+
+// bit shift expressions (level 6)
+shiftExpression[int lc_stmt]
+    :   additiveExpression[lc_stmt]
+        (
+            ((SL^ | SR^ | BSR^)
+            |   RANGE_INCLUSIVE^
+            |   RANGE_EXCLUSIVE^
+            )
+            nls!
+            additiveExpression[0]
+        )*
+    ;
+
+
+// binary addition/subtraction (level 5)
+additiveExpression[int lc_stmt]
+    :   multiplicativeExpression[lc_stmt]
+        (
+            options {greedy=true;} :
+            // Be greedy here, to favor {x+y} instead of {print +value}
+            (PLUS^ | MINUS^) nls!
+            multiplicativeExpression[0]
+        )*
+    ;
+
+
+// multiplication/division/modulo (level 4)
+multiplicativeExpression[int lc_stmt]
+    :    ( INC^ nls!  powerExpressionNotPlusMinus[0] ((STAR^ | DIV^ | MOD^ )  nls!  powerExpression[0])* )
+    |    ( DEC^ nls!  powerExpressionNotPlusMinus[0] ((STAR^ | DIV^ | MOD^ )  nls!  powerExpression[0])* )
+    |    ( MINUS^ {#MINUS.setType(UNARY_MINUS);} nls!   powerExpressionNotPlusMinus[0] ((STAR^ | DIV^ | MOD^ )  nls!  powerExpression[0])* )
+    |    ( PLUS^ {#PLUS.setType(UNARY_PLUS);} nls!   powerExpressionNotPlusMinus[0] ((STAR^ | DIV^ | MOD^ )  nls!  powerExpression[0])* )
+    |    (  powerExpressionNotPlusMinus[lc_stmt] ((STAR^ | DIV^ | MOD^ )  nls!  powerExpression[0])* )
+    ;
+    
+// math power operator (**) (level 3)
+powerExpression[int lc_stmt]
+    :   unaryExpression[lc_stmt] (STAR_STAR^ nls! unaryExpression[0])*
+    ;
+    
+// math power operator (**) (level 3) 
+// (without ++(prefix)/--(prefix)/+(unary)/-(unary))
+// The different rules are needed to avoid ambigous selection
+// of alternatives. 
+powerExpressionNotPlusMinus[int lc_stmt]
+    :   unaryExpressionNotPlusMinus[lc_stmt] (STAR_STAR^ nls! unaryExpression[0])*
+    ;
+
+// ++(prefix)/--(prefix)/+(unary)/-(unary) (level 2)
+unaryExpression[int lc_stmt]
+    :   INC^ nls! unaryExpression[0]
+    |   DEC^ nls! unaryExpression[0]
+    |   MINUS^   {#MINUS.setType(UNARY_MINUS);}   nls! unaryExpression[0] 
+    |   PLUS^    {#PLUS.setType(UNARY_PLUS);}     nls! unaryExpression[0] 
+    |   unaryExpressionNotPlusMinus[lc_stmt]
+    ;
+
+// ~(BNOT)/!(LNOT)/(type casting) (level 1)
+unaryExpressionNotPlusMinus[int lc_stmt]
+    :   //BAND^    {#BAND.setType(MEMBER_POINTER_DEFAULT);}   nls!  namePart
+    //|
+        BNOT^ nls! unaryExpression[0]
+    |   LNOT^ nls! unaryExpression[0]
+    |   (   // subrule allows option to shut off warnings
+            options {
+                    // "(int" ambig with postfixExpr due to lack of sequence
+                    // info in linear approximate LL(k). It's ok. Shut up.
+                    generateAmbigWarnings=false;
+            }
+        :   // If typecast is built in type, must be numeric operand
+            // Have to backtrack to see if operator follows
+            // FIXME: DECIDE: This syntax is wormy.  Can we deprecate or remove?
+            (LPAREN builtInTypeSpec[true] RPAREN unaryExpression[0])=>
+            lpb:LPAREN^ {#lpb.setType(TYPECAST);} builtInTypeSpec[true] RPAREN!
+            unaryExpression[0]
+
+            // Have to backtrack to see if operator follows. If no operator
+            // follows, it's a typecast. No semantic checking needed to parse.
+            // if it _looks_ like a cast, it _is_ a cast; else it's a "(expr)"
+            // FIXME: DECIDE: This syntax is wormy.  Can we deprecate or remove?
+            // TODO:  Rework this mess for Groovy.
+        |   (LPAREN classTypeSpec[true] RPAREN unaryExpressionNotPlusMinus[0])=>
+            lp:LPAREN^ {#lp.setType(TYPECAST);} classTypeSpec[true] RPAREN!
+            unaryExpressionNotPlusMinus[0]
+
+        |   postfixExpression[lc_stmt]
+        )
+    ;
+
+// qualified names, array expressions, method invocation, post inc/dec
+postfixExpression[int lc_stmt]
+    :
+        pathExpression[lc_stmt]
+        (
+            options {greedy=true;} :
+            // possibly add on a post-increment or post-decrement.
+            // allows INC/DEC on too much, but semantics can check
+            in:INC^ {#in.setType(POST_INC);}
+        |   de:DEC^ {#de.setType(POST_DEC);}
+        )?
+    ;
+    
+// TODO:  Move pathExpression to this point in the file.
+
+// the basic element of an expression
+primaryExpression
+    :   IDENT
+        /*OBS*  //keywords can follow dot in Groovy; no need for this special case
+        ( options {greedy=true;} : DOT^ "class" )?
+        *OBS*/
+    |   constant
+    |   newExpression
+    |   "this"
+    |   "super"
+    |   parenthesizedExpression             // (general stuff...)
+    |   closableBlockConstructorExpression
+    |   listOrMapConstructorExpression
+    |   stringConstructorExpression         // "foo $bar baz"; presented as multiple tokens
+    |   scopeEscapeExpression               // $x
+    |   builtInType
+    /*OBS*  //class names work fine as expressions
+            // look for int.class and int[].class
+    |   bt:builtInType!
+        declaratorBrackets[bt]
+        DOT^ nls! "class"
+    *OBS*/
+    ;
+
+// Note:  This is guaranteed to be an EXPR AST.
+// That is, parentheses are preserved, in case the walker cares about them.
+// They are significant sometimes, as in (f(x)){y} vs. f(x){y}.
+parenthesizedExpression
+    :   LPAREN! strictContextExpression RPAREN!
+    ;
+
+scopeEscapeExpression
+    :   DOLLAR^  {#DOLLAR.setType(SCOPE_ESCAPE);} (IDENT | scopeEscapeExpression)
+        // PROPOSE: The SCOPE_ESCAPE operator pops its operand out of the scope of a "with" block.
+        // If not within a "with" block, it pops the operand out of the static global scope,
+        // into whatever dynamic (unchecked) global scope is available when the script is run,
+        // regardless of package and imports.
+        // Example of SCOPE_ESCAPE:  def x=1; with ([x:2,y:-1]) { def y=3; println [$x, x, y] }  =>  "[1, 2, 3]"
+    ;
+
+/** Things that can show up as expressions, but only in strict
+ *  contexts like inside parentheses, argument lists, and list constructors.
+ */
+strictContextExpression  {Token first = LT(1);}
+    :
+        (   (declarationStart)=>
+            singleDeclaration  // used for both binding and value, as: while (String xx = nextln()) { println xx }
+        |   expression[0]
+        |   branchStatement // useful to embed inside expressions (cf. C++ throw)
+        |   annotation      // creates an annotation value
+        )
+        // For the sake of the AST walker, mark nodes like this very clearly.
+        {#strictContextExpression = #(create(EXPR,"EXPR",first,LT(1)),#strictContextExpression);}
+    ;
+    
+assignmentLessExpression  {Token first = LT(1);}
+    :
+        (   conditionalExpression[0]
+        )
+        // For the sake of the AST walker, mark nodes like this very clearly.
+        {#assignmentLessExpression = #(create(EXPR,"EXPR",first,LT(1)),#assignmentLessExpression);}
+    ;
+
+
+closableBlockConstructorExpression
+    :   closableBlock
+    ;
+
+// Groovy syntax for "$x $y" or /$x $y/.
+stringConstructorExpression  {Token first = LT(1);}
+    :   cs:STRING_CTOR_START
+        { #cs.setType(STRING_LITERAL); }
+
+        stringConstructorValuePart
+
+        (   cm:STRING_CTOR_MIDDLE
+            { #cm.setType(STRING_LITERAL); }
+            stringConstructorValuePart
+        )*
+
+        ce:STRING_CTOR_END
+        { #ce.setType(STRING_LITERAL);
+          #stringConstructorExpression =
+            #(create(STRING_CONSTRUCTOR,"STRING_CONSTRUCTOR",first,LT(1)), stringConstructorExpression);
+        }
+    ;
+
+stringConstructorValuePart
+    :
+    (
+        // PROPOSE: allow spread markers on string constructor arguments
+        sp:STAR^                        {#sp.setType(SPREAD_ARG);}
+    )?
+    (   identifier
+    |   openOrClosableBlock
+    )
+    ;
+
+/**
+ * A list constructor is a argument list enclosed in square brackets, without labels.
+ * Any argument can be decorated with a spread operator (*x), but not a label (a:x).
+ * Examples:  [], [1], [1,2], [1,*l1,2], [*l1,*l2].
+ * (The l1, l2 must be a sequence or null.)
+ * <p>
+ * A map constructor is an argument list enclosed in square brackets, with labels everywhere,
+ * except on spread arguments, which stand for whole maps spliced in.
+ * A colon alone between the brackets also forces the expression to be an empty map constructor.
+ * Examples: [:], [a:1], [a:1,b:2], [a:1,*:m1,b:2], [*:m1,*:m2]
+ * (The m1, m2 must be a map or null.)
+ * Values associated with identical keys overwrite from left to right:
+ * [a:1,a:2]  ===  [a:2]
+ * <p>
+ * Some malformed constructor expressions are not detected in the parser, but in a post-pass.
+ * Bad examples: [1,b:2], [a:1,2], [:1].
+ * (Note that method call arguments, by contrast, can be a mix of keyworded and non-keyworded arguments.)
+ */
+// The parser allows a mix of labeled and unlabeled arguments, but there must be a semantic check that
+// the arguments are all labeled (or SPREAD_MAP_ARG) or all unlabeled (and not SPREAD_MAP_ARG).
+listOrMapConstructorExpression
+        { boolean hasLabels = false; }
+    :   lcon:LBRACK^
+        argList                 { hasLabels |= argListHasLabels;  }  // any argument label implies a map
+        RBRACK!
+        { #lcon.setType(hasLabels ? MAP_CONSTRUCTOR : LIST_CONSTRUCTOR); }
+    |
+        /* Special case:  [:] is an empty map constructor. */
+        emcon:LBRACK^ COLON! RBRACK!   {#emcon.setType(MAP_CONSTRUCTOR);}
+    ;
+
+/*OBS*
+/** Match a, a.b.c refs, a.b.c(...) refs, a.b.c[], a.b.c[].class,
+ *  and a.b.c.class refs. Also this(...) and super(...). Match
+ *  this or super.
+ */
+/*OBS*
+identPrimary
+    :   (ta1:typeArguments!)?
+        IDENT
+        // Syntax for method invocation with type arguments is
+        // <String>foo("blah")
+        (
+            options {
+                // .ident could match here or in postfixExpression.
+                // We do want to match here. Turn off warning.
+                greedy=true;
+                // This turns the ambiguity warning of the second alternative
+                // off. See below. (The "ANTLR_LOOP_EXIT" predicate makes it non-issue)
+                warnWhenFollowAmbig=false;
+            }
+            // we have a new nondeterminism because of
+            // typeArguments... only a syntactic predicate will help...
+            // The problem is that this loop here conflicts with
+            // DOT typeArguments "super" in postfixExpression (k=2)
+            // A proper solution would require a lot of refactoring...
+        :   (DOT (typeArguments)? IDENT) =>
+            DOT^ (ta2:typeArguments!)? IDENT
+        |   {ANTLR_LOOP_EXIT}?  //(see documentation above)
+        )*
+        (
+            options {
+                // ARRAY_DECLARATOR here conflicts with INDEX_OP in
+                // postfixExpression on LBRACK RBRACK.
+                // We want to match [] here, so greedy. This overcomes
+                // limitation of linear approximate lookahead.
+                greedy=true;
+            }
+        :   (   lp:LPAREN^ {#lp.setType(METHOD_CALL);}
+                // if the input is valid, only the last IDENT may
+                // have preceding typeArguments... rather hacky, this is...
+                {if (#ta2 != null) astFactory.addASTChild(currentAST, #ta2);}
+                {if (#ta2 == null) astFactory.addASTChild(currentAST, #ta1);}
+                argList RPAREN!
+            )
+        |   (    options {greedy=true;} :
+                lbc:LBRACK^ {#lbc.setType(ARRAY_DECLARATOR);} RBRACK!
+            )+
+        )?
+    ;
+*OBS*/
+
+/** object instantiation.
+ *  Trees are built as illustrated by the following input/tree pairs:
+ *
+ *  new T()
+ *
+ *  new
+ *   |
+ *   T --  ELIST
+ *                 |
+ *                arg1 -- arg2 -- .. -- argn
+ *
+ *  new int[]
+ *
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR
+ *
+ *  new int[] {1,2}
+ *
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR -- ARRAY_INIT
+ *                                                                |
+ *                                                              EXPR -- EXPR
+ *                                                                |   |
+ *                                                                1       2
+ *
+ *  new int[3]
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR
+ *                              |
+ *                        EXPR
+ *                              |
+ *                              3
+ *
+ *  new int[1][2]
+ *
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR
+ *                         |
+ *               ARRAY_DECLARATOR -- EXPR
+ *                         |                  |
+ *                       EXPR                    1
+ *                         |
+ *                         2
+ *
+ */
+newExpression
+    :   "new"^ nls! (typeArguments)? type
+        (   nls!
+            mca:methodCallArgs[null]!
+
+            (
+                options { greedy=true; }:
+                apb1:appendedBlock[#mca]!
+                { #mca = #apb1; }
+            )?
+
+            {#newExpression.addChild(#mca.getFirstChild());}
+
+        //|  
+        //from blackrag: new Object.f{} matches this part here
+        //and that shouldn't happen unless we decide to support
+        //this kind of Object initialization        
+            //apb:appendedBlock[null]!
+            // FIXME:  This node gets dropped, somehow.
+
+            //{#newExpression.addChild(#apb.getFirstChild());}
+
+            //TODO - NYI* (anonymousInnerClassBlock)? *NYI
+
+            //java 1.1
+            // Note: This will allow bad constructs like
+            //      new int[4][][3] {exp,exp}.
+            //      There needs to be a semantic check here...
+            // to make sure:
+            //   a) [ expr ] and [ ] are not mixed
+            //   b) [ expr ] and an init are not used together
+        |   newArrayDeclarator //(arrayInitializer)?
+            // Groovy does not support Java syntax for initialized new arrays.
+            // Use sequence constructors instead.
+
+        )
+        // DECIDE:  Keep 'new x()' syntax?
+    ;
+
+/*NYI*
+anonymousInnerClassBlock
+    :   classBlock
+    ;
+*NYI*/
+
+argList
+    {Token first = LT(1); boolean hl = false, hl2; }
+    :   (
+            hl=argument
+            (
+                options { greedy=true; }:
+                COMMA! hl2=argument             { hl |= hl2; }
+                // Note:  nls not needed, since we are inside parens,
+                // and those insignificant newlines are suppressed by the lexer.
+            )*
+            {#argList = #(create(ELIST,"ELIST",first,LT(1)), argList);}
+        |   /*nothing*/
+            {#argList = create(ELIST,"ELIST",first,LT(1));}
+        )
+
+        // DECIDE: Allow an extra trailing comma, for easy editing of long lists.
+        // This applies uniformly to [x,y,] and (x,y,).  It is inspired by Java's a[] = {x,y,}.
+        (   COMMA!  )?
+        { argListHasLabels = hl; }  // return the value
+    ;
+
+/** A single argument in (...) or [...].  Corresponds to to a method or closure parameter.
+ *  May be labeled.  May be modified by the spread operator '*' ('*:' for keywords).
+ */
+argument
+returns [boolean hasLabel = false]
+    :
+        // Optional argument label.
+        // Usage:  Specifies a map key, or a keyworded argument.
+        (   (argumentLabelStart) =>
+            argumentLabel c:COLON^          {#c.setType(LABELED_ARG);}
+
+            {   hasLabel = true;  }  // signal to caller the presence of a label
+
+        |   // Spread operator:  f(*[a,b,c])  ===  f(a,b,c);  f(1,*null,2)  ===  f(1,2).
+            sp:STAR^                        {#sp.setType(SPREAD_ARG);}
+            // spread maps are marked, as f(*:m) for f(a:x, b:y) if m==[a:x, b:y]
+            (
+                COLON!                      {#sp.setType(SPREAD_MAP_ARG);}
+                { hasLabel = true; }  // signal to caller the presence of a label
+            )?
+        )?
+
+        strictContextExpression
+        {
+            require(LA(1) != COLON,
+                "illegal colon after argument expression",
+                "a complex label expression before a colon must be parenthesized");
+        }
+    ;
+
+/** A label for an argument is of the form a:b, 'a':b, "a":b, (a):b, etc..
+ *      The labels in (a:b), ('a':b), and ("a":b) are in all ways equivalent,
+ *      except that the quotes allow more spellings.
+ *  Equivalent dynamically computed labels are (('a'):b) and ("${'a'}":b)
+ *  but not ((a):b) or "$a":b, since the latter cases evaluate (a) as a normal identifier.
+ *      Bottom line:  If you want a truly variable label, use parens and say ((a):b).
+ */
+argumentLabel
+    :   (IDENT) =>
+        id:IDENT                  {#id.setType(STRING_LITERAL);}  // identifiers are self-quoting in this context
+    |   (keywordPropertyNames) =>
+        kw:keywordPropertyNames   {#kw.setType(STRING_LITERAL);}  // identifiers are self-quoting in this context
+    |   primaryExpression                                         // dynamic expression
+    ;
+
+/** For lookahead only.  Fast approximate parse of an argumentLabel followed by a colon. */
+argumentLabelStart!
+        // allow number and string literals as labels for maps
+    :   (
+            IDENT | keywordPropertyNames
+        |   constantNumber | STRING_LITERAL
+        |   (LPAREN | STRING_CTOR_START)=> balancedBrackets
+        )
+        COLON
+    ;
+
+newArrayDeclarator
+    :   (
+            // CONFLICT:
+            // newExpression is a primaryExpression which can be
+            // followed by an array index reference. This is ok,
+            // as the generated code will stay in this loop as
+            // long as it sees an LBRACK (proper behavior)
+            options {
+                warnWhenFollowAmbig = false;
+            }
+        :
+            lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);}
+                (expression[0])?
+            RBRACK!
+        )+
+    ;
+
+/** Numeric, string, regexp, boolean, or null constant. */
+constant
+    :   constantNumber
+    |   STRING_LITERAL
+    |   "true"
+    |   "false"
+    |   "null"
+    ;
+
+/** Numeric constant. */
+constantNumber
+    :   NUM_INT
+    |   NUM_FLOAT
+    |   NUM_LONG
+    |   NUM_DOUBLE
+    |   NUM_BIG_INT
+    |   NUM_BIG_DECIMAL
+    ;
+
+/** Fast lookahead across balanced brackets of all sorts. */
+balancedBrackets!
+    :   LPAREN balancedTokens RPAREN
+    |   LBRACK balancedTokens RBRACK
+    |   LCURLY balancedTokens RCURLY
+    |   STRING_CTOR_START balancedTokens STRING_CTOR_END
+    ;
+
+balancedTokens!
+    :   (   balancedBrackets
+        |   ~(LPAREN|LBRACK|LCURLY | STRING_CTOR_START
+             |RPAREN|RBRACK|RCURLY | STRING_CTOR_END)
+        )*
+    ;
+
+/** A statement separator is either a semicolon or a significant newline. 
+ *  Any number of additional (insignificant) newlines may accompany it.
+ */
+//  (All the '!' signs simply suppress the default AST building.)
+//  Returns the type of the separator in this.sepToken, in case it matters.
+sep!
+    :   SEMI!
+        (options { greedy=true; }: NLS!)*
+        { sepToken = SEMI; }
+    |   NLS!                // this newline is significant!
+        { sepToken = NLS; }
+        (
+            options { greedy=true; }:
+            SEMI!           // this superfluous semicolon is gobbled
+            (options { greedy=true; }: NLS!)*
+            { sepToken = SEMI; }
+        )*
+    ;
+
+/** Zero or more insignificant newlines, all gobbled up and thrown away. */
+nls!
+    :
+        (options { greedy=true; }: NLS!)?
+        // Note:  Use '?' rather than '*', relying on the fact that the lexer collapses
+        // adjacent NLS tokens, always.  This lets the parser use its LL(3) lookahead
+        // to "see through" sequences of newlines.  If there were a '*' here, the lookahead
+        // would be weaker, since the parser would have to be prepared for long sequences
+        // of NLS tokens.
+    ;
+
+/** Zero or more insignificant newlines, all gobbled up and thrown away,
+ *  but a warning message is left for the user, if there was a newline.
+ */
+nlsWarn!
+    :
+        (   (NLS)=>
+            { addWarning(
+              "A newline at this point does not follow the Groovy Coding Conventions.",
+              "Keep this statement on one line, or use curly braces to break across multiple lines."
+            ); }
+        )?
+        nls!
+    ;
+
+
+//----------------------------------------------------------------------------
+// The Groovy scanner
+//----------------------------------------------------------------------------
+class GroovyLexer extends Lexer;
+
+options {
+    exportVocab=Groovy;             // call the vocabulary "Groovy"
+    testLiterals=false;             // don't automatically test for literals
+    k=4;                                    // four characters of lookahead
+    charVocabulary='\u0003'..'\uFFFF';
+    // without inlining some bitset tests, couldn't do unicode;
+    // I need to make ANTLR generate smaller bitsets; see
+    // bottom of GroovyLexer.java
+    codeGenBitsetTestThreshold=20;
+}
+
+{
+    /** flag for enabling the "assert" keyword */
+    private boolean assertEnabled = true;
+    /** flag for enabling the "enum" keyword */
+    private boolean enumEnabled = true;
+    /** flag for including whitespace tokens (for IDE preparsing) */
+    private boolean whitespaceIncluded = false;
+
+    /** Enable the "assert" keyword */
+    public void enableAssert(boolean shouldEnable) { assertEnabled = shouldEnable; }
+    /** Query the "assert" keyword state */
+    public boolean isAssertEnabled() { return assertEnabled; }
+    /** Enable the "enum" keyword */
+    public void enableEnum(boolean shouldEnable) { enumEnabled = shouldEnable; }
+    /** Query the "enum" keyword state */
+    public boolean isEnumEnabled() { return enumEnabled; }
+
+    /** Include whitespace tokens.  Note that this breaks the parser.   */
+    public void setWhitespaceIncluded(boolean z) { whitespaceIncluded = z; }
+    /** Are whitespace tokens included? */
+    public boolean isWhitespaceIncluded() { return whitespaceIncluded; }
+
+    {
+        // Initialization actions performed on construction.
+        setTabSize(1);  // get rid of special tab interpretation, for IDEs and general clarity
+    }
+
+    /** Bumped when inside '[x]' or '(x)', reset inside '{x}'.  See ONE_NL.  */
+    protected int parenLevel = 0;
+    protected int suppressNewline = 0;  // be really mean to newlines inside strings
+    protected static final int SCS_TYPE = 3, SCS_VAL = 4, SCS_LIT = 8, SCS_LIMIT = 16;
+    protected static final int SCS_SQ_TYPE = 0, SCS_TQ_TYPE = 1, SCS_RE_TYPE = 2;
+    protected int stringCtorState = 0;  // hack string and regexp constructor boundaries
+    /** Push parenLevel here and reset whenever inside '{x}'. */
+    protected ArrayList parenLevelStack = new ArrayList();
+    protected int lastSigTokenType = EOF;  // last returned non-whitespace token
+
+    protected void pushParenLevel() {
+        parenLevelStack.add(new Integer(parenLevel*SCS_LIMIT + stringCtorState));
+        parenLevel = 0;
+        stringCtorState = 0;
+    }
+    protected void popParenLevel() {
+        int npl = parenLevelStack.size();
+        if (npl == 0)  return;
+        int i = ((Integer) parenLevelStack.remove(--npl)).intValue();
+        parenLevel      = i / SCS_LIMIT;
+        stringCtorState = i % SCS_LIMIT;
+    }
+
+    protected void restartStringCtor(boolean expectLiteral) {
+        if (stringCtorState != 0) {
+            stringCtorState = (expectLiteral? SCS_LIT: SCS_VAL) + (stringCtorState & SCS_TYPE);
+        }
+    }
+    
+    protected boolean allowRegexpLiteral() {
+        return !isExpressionEndingToken(lastSigTokenType);
+    }
+
+    /** Return true for an operator or punctuation which can end an expression.
+     *  Return true for keywords, identifiers, and literals.
+     *  Return true for tokens which can end expressions (right brackets, ++, --).
+     *  Return false for EOF and all other operator and punctuation tokens.
+     *  Used to suppress the recognition of /foo/ as opposed to the simple division operator '/'.
+     */
+    // Cf. 'constant' and 'balancedBrackets' rules in the grammar.)
+    protected static boolean isExpressionEndingToken(int ttype) {
+        switch (ttype) {
+        case INC:               // x++ / y
+        case DEC:               // x-- / y
+        case RPAREN:            // (x) / y
+        case RBRACK:            // f[x] / y
+        case RCURLY:            // f{x} / y
+        case STRING_LITERAL:    // "x" / y
+        case STRING_CTOR_END:   // "$x" / y
+        case NUM_INT:           // 0 / y
+        case NUM_FLOAT:         // 0f / y
+        case NUM_LONG:          // 0l / y
+        case NUM_DOUBLE:        // 0.0 / y
+        case NUM_BIG_INT:       // 0g / y
+        case NUM_BIG_DECIMAL:   // 0.0g / y
+        case IDENT:             // x / y
+        // and a bunch of keywords (all of them; no sense picking and choosing):
+        case LITERAL_any:
+        case LITERAL_as:
+        case LITERAL_assert:
+        case LITERAL_boolean:
+        case LITERAL_break:
+        case LITERAL_byte:
+        case LITERAL_case:
+        case LITERAL_catch:
+        case LITERAL_char:
+        case LITERAL_class:
+        case LITERAL_continue:
+        case LITERAL_def:
+        case LITERAL_default:
+        case LITERAL_double:
+        case LITERAL_else:
+        case LITERAL_enum:
+        case LITERAL_extends:
+        case LITERAL_false:
+        case LITERAL_finally:
+        case LITERAL_float:
+        case LITERAL_for:
+        case LITERAL_if:
+        case LITERAL_implements:
+        case LITERAL_import:
+        case LITERAL_in:
+        case LITERAL_instanceof:
+        case LITERAL_int:
+        case LITERAL_interface:
+        case LITERAL_long:
+        case LITERAL_native:
+        case LITERAL_new:
+        case LITERAL_null:
+        case LITERAL_package:
+        case LITERAL_private:
+        case LITERAL_protected:
+        case LITERAL_public:
+        case LITERAL_return:
+        case LITERAL_short:
+        case LITERAL_static:
+        case LITERAL_super:
+        case LITERAL_switch:
+        case LITERAL_synchronized:
+        case LITERAL_this:
+        case LITERAL_threadsafe:
+        case LITERAL_throw:
+        case LITERAL_throws:
+        case LITERAL_transient:
+        case LITERAL_true:
+        case LITERAL_try:
+        case LITERAL_void:
+        case LITERAL_volatile:
+        case LITERAL_while:
+        case LITERAL_with:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    protected void newlineCheck(boolean check) throws RecognitionException {
+        if (check && suppressNewline > 0) {
+            require(suppressNewline == 0,
+                "end of line reached within a simple string 'x' or \"x\" or /x/",
+                "for multi-line literals, use triple quotes '''x''' or \"\"\"x\"\"\"");
+            suppressNewline = 0;  // shut down any flood of errors
+        }
+        newline();
+    }
+    
+    protected boolean atValidDollarEscape() throws CharStreamException {
+        // '$' (('*')? ('{' | LETTER)) =>
+        int k = 1;
+        char lc = LA(k++);
+        if (lc != '$')  return false;
+        lc = LA(k++);
+        if (lc == '*')  lc = LA(k++);
+        return (lc == '{' || (lc != '$' && Character.isJavaIdentifierStart(lc)));
+    }
+
+    /** This is a bit of plumbing which resumes collection of string constructor bodies,
+     *  after an embedded expression has been parsed.
+     *  Usage:  new GroovyRecognizer(new GroovyLexer(in).plumb()).
+     */
+    public TokenStream plumb() {
+        return new TokenStream() {
+            public Token nextToken() throws TokenStreamException {
+                if (stringCtorState >= SCS_LIT) {
+                    // This goo is modeled upon the ANTLR code for nextToken:
+                    int quoteType = (stringCtorState & SCS_TYPE);
+                    stringCtorState = 0;  // get out of this mode, now
+                    resetText();
+                    try {
+                        switch (quoteType) {
+                        case SCS_SQ_TYPE:
+                            mSTRING_CTOR_END(true, /*fromStart:*/false, false); break;
+                        case SCS_TQ_TYPE:
+                            mSTRING_CTOR_END(true, /*fromStart:*/false, true); break;
+                        case SCS_RE_TYPE:
+                            mREGEXP_CTOR_END(true, /*fromStart:*/false); break;
+                        default:  throw new AssertionError(false);
+                        }
+                        lastSigTokenType = _returnToken.getType();
+                        return _returnToken;
+                    } catch (RecognitionException e) {
+                        throw new TokenStreamRecognitionException(e);
+                    } catch (CharStreamException cse) {
+                        if ( cse instanceof CharStreamIOException ) {
+                            throw new TokenStreamIOException(((CharStreamIOException)cse).io);
+                        }
+                        else {
+                            throw new TokenStreamException(cse.getMessage());
+                        }
+                    }
+                }
+                Token token = GroovyLexer.this.nextToken();
+                int lasttype = token.getType();
+                if (whitespaceIncluded) {
+                    switch (lasttype) {  // filter out insignificant types
+                    case WS:
+                    case ONE_NL:
+                    case SL_COMMENT:
+                    case ML_COMMENT:
+                        lasttype = lastSigTokenType;  // back up!
+                    }
+                }
+                lastSigTokenType = lasttype;
+                return token;
+            }
+        };
+    }
+
+        // stuff to adjust ANTLR's tracing machinery
+    public static boolean tracing = false;  // only effective if antlr.Tool is run with -traceLexer
+    public void traceIn(String rname) throws CharStreamException {
+        if (!GroovyLexer.tracing)  return;
+        super.traceIn(rname);
+    }
+    public void traceOut(String rname) throws CharStreamException {
+        if (!GroovyLexer.tracing)  return;
+        if (_returnToken != null)  rname += tokenStringOf(_returnToken);
+        super.traceOut(rname);
+    }
+    private static java.util.HashMap ttypes;
+    private static String tokenStringOf(Token t) {
+        if (ttypes == null) {
+            java.util.HashMap map = new java.util.HashMap();
+            java.lang.reflect.Field[] fields = GroovyTokenTypes.class.getDeclaredFields();
+            for (int i = 0; i < fields.length; i++) {
+                if (fields[i].getType() != int.class)  continue;
+                try {
+                    map.put(fields[i].get(null), fields[i].getName());
+                } catch (IllegalAccessException ee) {
+                }
+            }
+            ttypes = map;
+        }
+        Integer tt = new Integer(t.getType());
+        Object ttn = ttypes.get(tt);
+        if (ttn == null)  ttn = "<"+tt+">";
+        return "["+ttn+",\""+t.getText()+"\"]";
+    }
+
+    protected GroovyRecognizer parser;  // little-used link; TODO: get rid of
+    private void require(boolean z, String problem, String solution) throws SemanticException {
+        // TODO: Direct to a common error handler, rather than through the parser.
+        if (!z)  parser.requireFailed(problem, solution);
+    }    
+}
+
+// TODO:  Borneo-style ops.
+
+// OPERATORS
+QUESTION          options {paraphrase="'?'";}           :   '?'             ;
+LPAREN            options {paraphrase="'('";}           :   '('             {++parenLevel;};
+RPAREN            options {paraphrase="')'";}           :   ')'             {--parenLevel;};
+LBRACK            options {paraphrase="'['";}           :   '['             {++parenLevel;};
+RBRACK            options {paraphrase="']'";}           :   ']'             {--parenLevel;};
+LCURLY            options {paraphrase="'{'";}           :   '{'             {pushParenLevel();};
+RCURLY            options {paraphrase="'}'";}           :   '}'             {popParenLevel(); if(stringCtorState!=0) restartStringCtor(true);};
+COLON             options {paraphrase="':'";}           :   ':'             ;
+COMMA             options {paraphrase="','";}           :   ','             ;
+DOT               options {paraphrase="'.'";}           :   '.'             ;
+ASSIGN            options {paraphrase="'='";}           :   '='             ;
+COMPARE_TO        options {paraphrase="'<=>'";}         :   "<=>"           ;
+EQUAL             options {paraphrase="'=='";}          :   "=="            ;
+LNOT              options {paraphrase="'!'";}           :   '!'             ;
+BNOT              options {paraphrase="'~'";}           :   '~'             ;
+NOT_EQUAL         options {paraphrase="'!='";}          :   "!="            ;
+protected  //switched from combined rule
+DIV               options {paraphrase="'/'";}           :   '/'             ;
+protected  //switched from combined rule
+DIV_ASSIGN        options {paraphrase="'/='";}          :   "/="            ;
+PLUS              options {paraphrase="'+'";}           :   '+'             ;
+PLUS_ASSIGN       options {paraphrase="'+='";}          :   "+="            ;
+INC               options {paraphrase="'++'";}          :   "++"            ;
+MINUS             options {paraphrase="'-'";}           :   '-'             ;
+MINUS_ASSIGN      options {paraphrase="'-='";}          :   "-="            ;
+DEC               options {paraphrase="'--'";}          :   "--"            ;
+STAR              options {paraphrase="'*'";}           :   '*'             ;
+STAR_ASSIGN       options {paraphrase="'*='";}          :   "*="            ;
+MOD               options {paraphrase="'%'";}           :   '%'             ;
+MOD_ASSIGN        options {paraphrase="'%='";}          :   "%="            ;
+SR                options {paraphrase="'>>'";}          :   ">>"            ;
+SR_ASSIGN         options {paraphrase="'>>='";}         :   ">>="           ;
+BSR               options {paraphrase="'>>>'";}         :   ">>>"           ;
+BSR_ASSIGN        options {paraphrase="'>>>='";}        :   ">>>="          ;
+GE                options {paraphrase="'>='";}          :   ">="            ;
+GT                options {paraphrase="'>'";}           :   ">"             ;
+SL                options {paraphrase="'<<'";}          :   "<<"            ;
+SL_ASSIGN         options {paraphrase="'<<='";}         :   "<<="           ;
+LE                options {paraphrase="'<='";}          :   "<="            ;
+LT                options {paraphrase="'<'";}           :   '<'             ;
+BXOR              options {paraphrase="'^'";}           :   '^'             ;
+BXOR_ASSIGN       options {paraphrase="'^='";}          :   "^="            ;
+BOR               options {paraphrase="'|'";}           :   '|'             ;
+BOR_ASSIGN        options {paraphrase="'|='";}          :   "|="            ;
+LOR               options {paraphrase="'||'";}          :   "||"            ;
+BAND              options {paraphrase="'&'";}           :   '&'             ;
+BAND_ASSIGN       options {paraphrase="'&='";}          :   "&="            ;
+LAND              options {paraphrase="'&&'";}          :   "&&"            ;
+SEMI              options {paraphrase="';'";}           :   ';'             ;
+DOLLAR            options {paraphrase="'$'";}           :   '$'             ;
+RANGE_INCLUSIVE   options {paraphrase="'..'";}          :   ".."            ;
+RANGE_EXCLUSIVE   options {paraphrase="'..<'";}         :   "..<"           ;
+TRIPLE_DOT        options {paraphrase="'...'";}         :   "..."           ;
+SPREAD_DOT        options {paraphrase="'*.'";}          :   "*."            ;
+OPTIONAL_DOT      options {paraphrase="'?.'";}          :   "?."            ;
+MEMBER_POINTER    options {paraphrase="'.&'";}          :   ".&"            ;
+REGEX_FIND        options {paraphrase="'=~'";}          :   "=~"            ;
+REGEX_MATCH       options {paraphrase="'==~'";}         :   "==~"           ;
+STAR_STAR         options {paraphrase="'**'";}          :   "**"            ;
+STAR_STAR_ASSIGN  options {paraphrase="'**='";}         :   "**="           ;
+CLOSABLE_BLOCK_OP options {paraphrase="'->'";}          :   "->"            ;
+
+// Whitespace -- ignored
+WS
+options {
+    paraphrase="whitespace";
+}
+    :
+        (
+            options { greedy=true; }:
+            ' '
+        |   '\t'
+        |   '\f'
+        |   '\\' ONE_NL[false]
+        )+
+        { if (!whitespaceIncluded)  _ttype = Token.SKIP; }
+    ;
+
+protected
+ONE_NL![boolean check]
+options {
+    paraphrase="a newline";
+}
+ :   // handle newlines, which are significant in Groovy
+        (   options {generateAmbigWarnings=false;}
+        :   "\r\n"  // Evil DOS
+        |   '\r'    // Macintosh
+        |   '\n'    // Unix (the right way)
+        )
+        {
+            // update current line number for error reporting
+            newlineCheck(check);
+        }
+    ;
+        
+// Group any number of newlines (with comments and whitespace) into a single token.
+// This reduces the amount of parser lookahead required to parse around newlines.
+// It is an invariant that the parser never sees NLS tokens back-to-back.
+NLS
+options {
+    paraphrase="some newlines, whitespace or comments";
+}
+    :   ONE_NL[true]
+        (   {!whitespaceIncluded}?
+            (ONE_NL[true] | WS | SL_COMMENT | ML_COMMENT)+
+            // (gobble, gobble)*
+        )?
+        // Inside (...) and [...] but not {...}, ignore newlines.
+        {   if (whitespaceIncluded) {
+                // keep the token as-is
+            } else if (parenLevel != 0) {
+                // when directly inside parens, all newlines are ignored here
+                $setType(Token.SKIP);
+            } else {
+                // inside {...}, newlines must be explicitly matched as 'nls!'
+                $setText("<newline>");
+            }
+        }
+    ;
+
+// Single-line comments
+SL_COMMENT
+options {
+    paraphrase="a single line comment";
+}
+    :   "//"
+        (
+            options {  greedy = true;  }:
+            // '\uffff' means the EOF character.
+            // This will fix the issue GROOVY-766 (infinite loop).
+            ~('\n'|'\r'|'\uffff')
+        )*
+        { if (!whitespaceIncluded)  $setType(Token.SKIP); }
+        //This might be significant, so don't swallow it inside the comment:
+        //ONE_NL
+    ;
+
+// Script-header comments
+SH_COMMENT
+options {
+    paraphrase="a script header";
+}
+    :   {getLine() == 1 && getColumn() == 1}?  "#!"
+        (
+            options {  greedy = true;  }:
+            // '\uffff' means the EOF character.
+            // This will fix the issue GROOVY-766 (infinite loop).
+            ~('\n'|'\r'|'\uffff')
+        )*
+        { if (!whitespaceIncluded)  $setType(Token.SKIP); }
+        //ONE_NL  //Never a significant newline, but might as well separate it.
+    ;
+
+// multiple-line comments
+ML_COMMENT
+options {
+    paraphrase="a comment";
+}
+    :   "/*"
+        (   /*  '\r' '\n' can be matched in one alternative or by matching
+                '\r' in one iteration and '\n' in another. I am trying to
+                handle any flavor of newline that comes in, but the language
+                that allows both "\r\n" and "\r" and "\n" to all be valid
+                newline is ambiguous. Consequently, the resulting grammar
+                must be ambiguous. I'm shutting this warning off.
+             */
+            options {
+                    generateAmbigWarnings=false;
+            }
+        :
+            ( '*' ~'/' ) => '*'
+        |   ONE_NL[true]
+        |   ~('*'|'\n'|'\r'|'\uffff')
+        )*
+        "*/"
+        { if (!whitespaceIncluded)  $setType(Token.SKIP); }
+    ;
+
+
+// string literals
+STRING_LITERAL
+options {
+    paraphrase="a string literal";
+}
+        {int tt=0;}
+    :   ("'''") =>  //...shut off ambiguity warning
+        "'''"!
+        (   STRING_CH | ESC | '"' | '$' | STRING_NL[true]
+        |   ('\'' (~'\'' | '\'' ~'\'')) => '\''  // allow 1 or 2 close quotes
+        )*
+        "'''"!
+    |   '\''!
+                                {++suppressNewline;}
+        (   STRING_CH | ESC | '"' | '$'  )*
+                                {--suppressNewline;}
+        '\''!
+    |   ("\"\"\"") =>  //...shut off ambiguity warning
+        "\"\"\""!
+        tt=STRING_CTOR_END[true, /*tripleQuote:*/ true]
+        {$setType(tt);}
+    |   '"'!
+                                {++suppressNewline;}
+        tt=STRING_CTOR_END[true, /*tripleQuote:*/ false]
+        {$setType(tt);}
+    ;
+
+protected
+STRING_CTOR_END[boolean fromStart, boolean tripleQuote]
+returns [int tt=STRING_CTOR_END]
+options {
+    paraphrase="a string literal end";
+}
+        { boolean dollarOK = false; }
+    :
+        (
+            options {  greedy = true;  }:
+            STRING_CH | ESC | '\'' | STRING_NL[tripleQuote]
+        |   ('"' (~'"' | '"' ~'"'))=> {tripleQuote}? '"'  // allow 1 or 2 close quotes
+        )*
+        (   (   { !tripleQuote }? "\""!
+            |   {  tripleQuote }? "\"\"\""!
+            )
+            {
+                if (fromStart)      tt = STRING_LITERAL;  // plain string literal!
+                if (!tripleQuote)   {--suppressNewline;}
+                // done with string constructor!
+                //assert(stringCtorState == 0);
+            }
+        |   {dollarOK = atValidDollarEscape();}
+            '$'!
+            {
+                require(dollarOK,
+                    "illegal string body character after dollar sign",
+                    "either escape a literal dollar sign \"\\$5\" or bracket the value expression \"${5}\"");
+                // Yes, it's a string constructor, and we've got a value part.
+                tt = (fromStart ? STRING_CTOR_START : STRING_CTOR_MIDDLE);
+                stringCtorState = SCS_VAL + (tripleQuote? SCS_TQ_TYPE: SCS_SQ_TYPE);
+            }
+        )
+        {   $setType(tt);  }
+    ;
+
+protected
+STRING_CH
+options {
+    paraphrase="a string character";
+}
+    :   ~('"'|'\''|'\\'|'$'|'\n'|'\r'|'\uffff')
+    ;
+
+REGEXP_LITERAL
+options {
+    paraphrase="a regular expression literal";
+}
+        {int tt=0;}
+    :   {allowRegexpLiteral()}?
+        '/'!
+        {++suppressNewline;}
+        //Do this, but require it to be non-trivial:  REGEXP_CTOR_END[true]
+        // There must be at least one symbol or $ escape, lest the regexp collapse to '//'.
+        // (This should be simpler, but I don't know how to do it w/o ANTLR warnings vs. '//' comments.)
+        (
+            REGEXP_SYMBOL
+            tt=REGEXP_CTOR_END[true]
+        |   {!atValidDollarEscape()}? '$'
+            tt=REGEXP_CTOR_END[true]
+        |   '$'!
+            {
+                // Yes, it's a regexp constructor, and we've got a value part.
+                tt = STRING_CTOR_START;
+                stringCtorState = SCS_VAL + SCS_RE_TYPE;
+            }
+        )
+        {$setType(tt);}
+
+    |   DIV                 {$setType(DIV);}
+    |   DIV_ASSIGN          {$setType(DIV_ASSIGN);}
+    ;
+
+protected
+REGEXP_CTOR_END[boolean fromStart]
+returns [int tt=STRING_CTOR_END]
+options {
+    paraphrase="a regular expression literal end";
+}
+    :
+        (
+            options {  greedy = true;  }:
+            REGEXP_SYMBOL
+        |
+            {!atValidDollarEscape()}? '$'
+        )*
+        (   '/'!
+            {
+                if (fromStart)      tt = STRING_LITERAL;  // plain regexp literal!
+                {--suppressNewline;}
+                // done with regexp constructor!
+                //assert(stringCtorState == 0);
+            }
+        |   '$'!
+            {
+                // Yes, it's a regexp constructor, and we've got a value part.
+                tt = (fromStart ? STRING_CTOR_START : STRING_CTOR_MIDDLE);
+                stringCtorState = SCS_VAL + SCS_RE_TYPE;
+            }
+        )
+        {   $setType(tt);  }
+    ;
+
+protected
+REGEXP_SYMBOL
+options {
+    paraphrase="a regular expression character";
+}
+    :
+        (
+            ~('*'|'/'|'$'|'\\'|'\n'|'\r'|'\uffff')
+        |   '\\' ~('\n'|'\r')   // most backslashes are passed through unchanged
+        |!  '\\' ONE_NL[false]         { $setText('\n'); }     // always normalize to newline
+        )
+        ('*')*      // stars handled specially to avoid ambig. on /**/
+    ;
+
+// escape sequence -- note that this is protected; it can only be called
+// from another lexer rule -- it will not ever directly return a token to
+// the parser
+// There are various ambiguities hushed in this rule. The optional
+// '0'...'9' digit matches should be matched here rather than letting
+// them go back to STRING_LITERAL to be matched. ANTLR does the
+// right thing by matching immediately; hence, it's ok to shut off
+// the FOLLOW ambig warnings.
+protected
+ESC
+options {
+    paraphrase="an escape sequence";
+}
+    :   '\\'!
+        (   'n'     {$setText("\n");}
+        |   'r'     {$setText("\r");}
+        |   't'     {$setText("\t");}
+        |   'b'     {$setText("\b");}
+        |   'f'     {$setText("\f");}
+        |   '"'
+        |   '\''
+        |   '\\'
+        |   '$'     //escape Groovy $ operator uniformly also
+        |   ('u')+ {$setText("");}
+            HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
+            {char ch = (char)Integer.parseInt($getText,16); $setText(ch);}
+        |   '0'..'3'
+            (
+                options {
+                    warnWhenFollowAmbig = false;
+                }
+            :   '0'..'7'
+                (
+                    options {
+                        warnWhenFollowAmbig = false;
+                    }
+                :   '0'..'7'
+                )?
+            )?
+            {char ch = (char)Integer.parseInt($getText,8); $setText(ch);}
+        |   '4'..'7'
+            (
+                options {
+                    warnWhenFollowAmbig = false;
+                }
+            :   '0'..'7'
+            )?
+            {char ch = (char)Integer.parseInt($getText,8); $setText(ch);}
+        )
+    |!  '\\' ONE_NL[false]
+    //|!  ONE_NL[true]          { $setText('\n'); }             // always normalize to newline
+    ;
+
+protected 
+STRING_NL[boolean allowNewline]
+options {
+    paraphrase="a newline inside a string";
+}
+    :  {if (!allowNewline) throw new MismatchedCharException('\n', '\n', true, this); } 
+       ONE_NL[false] { $setText('\n'); }
+    ;
+
+
+// hexadecimal digit (again, note it's protected!)
+protected
+HEX_DIGIT
+options {
+    paraphrase="a hexadecimal digit";
+}
+    :   ('0'..'9'|'A'..'F'|'a'..'f')
+    ;
+
+
+// a dummy rule to force vocabulary to be all characters (except special
+// ones that ANTLR uses internally (0 to 2)
+protected
+VOCAB
+options {
+    paraphrase="a character";
+}
+    :   '\3'..'\377'
+    ;
+
+
+// an identifier. Note that testLiterals is set to true! This means
+// that after we match the rule, we look in the literals table to see
+// if it's a literal or really an identifer
+IDENT
+options {
+    paraphrase="an identifier";
+}
+    //options {testLiterals=true;}  // Actually, this is done manually in the actions below.
+    :   LETTER(LETTER|DIGIT)*
+        {
+            if (stringCtorState != 0) {
+                if (LA(1) == '.' && LA(2) != '$' &&
+                        Character.isJavaIdentifierStart(LA(2))) {
+                    // pick up another name component before going literal again:
+                    restartStringCtor(false);
+                } else {
+                    // go back to the string
+                    restartStringCtor(true);
+                }
+            }
+            int ttype = testLiteralsTable(IDENT);
+        /* The grammar allows a few keywords to follow dot.
+         * TODO: Reinstate this logic if we change or remove keywordPropertyNames.
+            if (ttype != IDENT && lastSigTokenType == DOT) {
+                // A few keywords can follow a dot:
+                switch (ttype) {
+                case LITERAL_this: case LITERAL_super: case LITERAL_class:
+                    break;
+                default:
+                    ttype = LITERAL_in;  // the poster child for bad dotted names
+                }
+            }
+        */
+            $setType(ttype);
+
+            // check if "assert" keyword is enabled
+            if (assertEnabled && "assert".equals($getText)) {
+                $setType(LITERAL_assert); // set token type for the rule in the parser
+            }
+            // check if "enum" keyword is enabled
+            if (enumEnabled && "enum".equals($getText)) {
+                $setType(LITERAL_enum); // set token type for the rule in the parser
+            }
+        }
+    ;
+
+protected
+LETTER
+options {
+    paraphrase="a letter";
+}
+    :   'a'..'z'|'A'..'Z'|'\u00C0'..'\u00D6'|'\u00D8'..'\u00F6'|'\u00F8'..'\u00FF'|'\u0100'..'\uFFFE'|'_'
+    // TODO:  Recognize all the Java identifier starts here (except '$').
+    ;
+
+protected
+DIGIT
+options {
+    paraphrase="a digit";
+}
+    :   '0'..'9'
+    // TODO:  Recognize all the Java identifier parts here (except '$').
+    ;
+
+// a numeric literal
+NUM_INT
+options {
+    paraphrase="a numeric literal";
+}
+    {boolean isDecimal=false; Token t=null;}
+    :
+/*OBS*
+        '.' {_ttype = DOT;}
+        (
+            (('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
+            {
+                if (t != null && t.getText().toUpperCase().indexOf('F')>=0) {
+                    _ttype = NUM_FLOAT;
+                }
+                else {
+                    _ttype = NUM_DOUBLE; // assume double
+                }
+            })
+        |
+            // JDK 1.5 token for variable length arguments
+            (".." {_ttype = TRIPLE_DOT;})
+        )?
+    |
+*OBS*/
+        // TODO:  This complex pattern seems wrong.  Verify or fix.
+        (   '0' {isDecimal = true;} // special case for just '0'
+            (   ('x'|'X')
+                {isDecimal = false;}
+                (                                                                                   // hex
+                    // the 'e'|'E' and float suffix stuff look
+                    // like hex digits, hence the (...)+ doesn't
+                    // know when to stop: ambig. ANTLR resolves
+                    // it correctly by matching immediately. It
+                    // is therefor ok to hush warning.
+                    options {
+                        warnWhenFollowAmbig=false;
+                    }
+                :   HEX_DIGIT
+                )+
+
+            |   //float or double with leading zero
+                (('0'..'9')+ ('.'('0'..'9')|EXPONENT|FLOAT_SUFFIX)) => ('0'..'9')+
+
+            |   ('0'..'7')+                                                                     // octal
+                {isDecimal = false;}
+            )?
+        |   ('1'..'9') ('0'..'9')*  {isDecimal=true;}               // non-zero decimal
+        )
+        (   ('l'|'L') { _ttype = NUM_LONG; }
+        |   ('i'|'I') { _ttype = NUM_INT; }
+        |   BIG_SUFFIX { _ttype = NUM_BIG_INT; }
+
+        // only check to see if it's a float if looks like decimal so far
+        |
+            (~'.' | '.' ('0'..'9')) =>
+            {isDecimal}?
+            (   '.' ('0'..'9')+ (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;} | g2:BIG_SUFFIX {t=g2;})?
+            |   EXPONENT (f3:FLOAT_SUFFIX {t=f3;} | g3:BIG_SUFFIX {t=g3;})?
+            |   f4:FLOAT_SUFFIX {t=f4;}
+            )
+            {
+                String txt = (t == null ? "" : t.getText().toUpperCase());
+                if (txt.indexOf('F') >= 0) {
+                    _ttype = NUM_FLOAT;
+                } else if (txt.indexOf('G') >= 0) {
+                    _ttype = NUM_BIG_DECIMAL;
+                } else {
+                    _ttype = NUM_DOUBLE; // assume double
+                }
+            }
+        )?
+    ;
+
+// JDK 1.5 token for annotations and their declarations
+// also a groovy operator for actual field access e.g. 'telson.@age' 
+AT
+options {
+    paraphrase="'@'";
+}
+    :   '@'
+    ;
+
+// a couple protected methods to assist in matching floating point numbers
+protected
+EXPONENT
+options {
+    paraphrase="an exponent";
+}
+    :   ('e'|'E') ('+'|'-')? ('0'..'9')+
+    ;
+
+
+protected
+FLOAT_SUFFIX
+options {
+    paraphrase="a float or double suffix";
+}
+    :   'f'|'F'|'d'|'D'
+    ;
+
+protected
+BIG_SUFFIX
+options {
+    paraphrase="a big decimal suffix";
+}
+    :   'g'|'G'
+    ;
+
+// Note: Please don't use physical tabs.  Logical tabs for indent are width 4.
+// Here's a little hint for you, Emacs:
+// Local Variables:
+// tab-width: 4
+// mode: antlr-mode
+// indent-tabs-mode: nil
+// End:
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/java/Groovifier.java b/groovy-core/src/main/org/codehaus/groovy/antlr/java/Groovifier.java
new file mode 100644
index 0000000..e0aec10
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/java/Groovifier.java
@@ -0,0 +1,34 @@
+package org.codehaus.groovy.antlr.java;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+import org.codehaus.groovy.antlr.treewalker.VisitorAdapter;
+
+public class Groovifier extends VisitorAdapter implements GroovyTokenTypes {
+    private String[] tokenNames;
+    
+	public Groovifier(String[] tokenNames) {
+		this.tokenNames = tokenNames;
+	}
+	
+    public void visitDefault(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            // only want to do this once per node...
+
+        	// remove 'public' when implied already
+        	if (t.getType() == LITERAL_public) {
+        		t.setType(EXPR);
+        	}
+/*        	if (t.getType() == MODIFIERS) {
+       			GroovySourceAST publicNode = t.childOfType(LITERAL_public);
+       			if (t.getNumberOfChildren() > 1 && publicNode != null) {
+       				// has more than one modifier, and one of them is public
+       				
+       				// delete 'public' node
+       				publicNode.setType(EXPR); // near enough the same as delete for now...
+       			}
+        	}*/
+        	// ----        	
+        }
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/java/Java2GroovyConverter.java b/groovy-core/src/main/org/codehaus/groovy/antlr/java/Java2GroovyConverter.java
new file mode 100644
index 0000000..e2d5152
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/java/Java2GroovyConverter.java
@@ -0,0 +1,209 @@
+package org.codehaus.groovy.antlr.java;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+import org.codehaus.groovy.antlr.treewalker.VisitorAdapter;
+
+public class Java2GroovyConverter extends VisitorAdapter{
+    private String[] tokenNames;
+    private int[] typeMapping;
+    
+	public Java2GroovyConverter(String[] tokenNames) {
+		this.tokenNames = tokenNames;
+		typeMapping = new int[400]; // magic number, much greater than current number of java tokens
+		typeMapping[JavaTokenTypes.ABSTRACT] = GroovyTokenTypes.ABSTRACT;
+		
+		typeMapping[JavaTokenTypes.EOF] = GroovyTokenTypes.EOF;
+		typeMapping[JavaTokenTypes.NULL_TREE_LOOKAHEAD] = GroovyTokenTypes.NULL_TREE_LOOKAHEAD;
+		typeMapping[JavaTokenTypes.BLOCK] = GroovyTokenTypes.BLOCK;
+		typeMapping[JavaTokenTypes.MODIFIERS] = GroovyTokenTypes.MODIFIERS;
+		typeMapping[JavaTokenTypes.OBJBLOCK] = GroovyTokenTypes.OBJBLOCK;
+		typeMapping[JavaTokenTypes.SLIST] = GroovyTokenTypes.SLIST;
+		typeMapping[JavaTokenTypes.METHOD_DEF] = GroovyTokenTypes.METHOD_DEF;
+		typeMapping[JavaTokenTypes.VARIABLE_DEF] = GroovyTokenTypes.VARIABLE_DEF;
+		typeMapping[JavaTokenTypes.INSTANCE_INIT] = GroovyTokenTypes.INSTANCE_INIT;
+		typeMapping[JavaTokenTypes.STATIC_INIT] = GroovyTokenTypes.STATIC_INIT;
+		typeMapping[JavaTokenTypes.TYPE] = GroovyTokenTypes.TYPE;
+		typeMapping[JavaTokenTypes.CLASS_DEF] = GroovyTokenTypes.CLASS_DEF;
+		typeMapping[JavaTokenTypes.INTERFACE_DEF] = GroovyTokenTypes.INTERFACE_DEF;
+		typeMapping[JavaTokenTypes.PACKAGE_DEF] = GroovyTokenTypes.PACKAGE_DEF;
+		typeMapping[JavaTokenTypes.ARRAY_DECLARATOR] = GroovyTokenTypes.ARRAY_DECLARATOR;
+		typeMapping[JavaTokenTypes.EXTENDS_CLAUSE] = GroovyTokenTypes.EXTENDS_CLAUSE;
+		typeMapping[JavaTokenTypes.IMPLEMENTS_CLAUSE] = GroovyTokenTypes.IMPLEMENTS_CLAUSE;
+		typeMapping[JavaTokenTypes.PARAMETERS] = GroovyTokenTypes.PARAMETERS;
+		typeMapping[JavaTokenTypes.PARAMETER_DEF] = GroovyTokenTypes.PARAMETER_DEF;
+		typeMapping[JavaTokenTypes.LABELED_STAT] = GroovyTokenTypes.LABELED_STAT;
+		typeMapping[JavaTokenTypes.TYPECAST] = GroovyTokenTypes.TYPECAST;
+		typeMapping[JavaTokenTypes.INDEX_OP] = GroovyTokenTypes.INDEX_OP;
+		typeMapping[JavaTokenTypes.POST_INC] = GroovyTokenTypes.POST_INC;
+		typeMapping[JavaTokenTypes.POST_DEC] = GroovyTokenTypes.POST_DEC;
+		typeMapping[JavaTokenTypes.METHOD_CALL] = GroovyTokenTypes.METHOD_CALL;
+		typeMapping[JavaTokenTypes.EXPR] = GroovyTokenTypes.EXPR;
+//		typeMapping[JavaTokenTypes.ARRAY_INIT] = GroovyTokenTypes.ARRAY_INIT;
+		typeMapping[JavaTokenTypes.IMPORT] = GroovyTokenTypes.IMPORT;
+		typeMapping[JavaTokenTypes.UNARY_MINUS] = GroovyTokenTypes.UNARY_MINUS;
+		typeMapping[JavaTokenTypes.UNARY_PLUS] = GroovyTokenTypes.UNARY_PLUS;
+		typeMapping[JavaTokenTypes.CASE_GROUP] = GroovyTokenTypes.CASE_GROUP;
+		typeMapping[JavaTokenTypes.ELIST] = GroovyTokenTypes.ELIST;
+		typeMapping[JavaTokenTypes.FOR_INIT] = GroovyTokenTypes.FOR_INIT;
+		typeMapping[JavaTokenTypes.FOR_CONDITION] = GroovyTokenTypes.FOR_CONDITION;
+		typeMapping[JavaTokenTypes.FOR_ITERATOR] = GroovyTokenTypes.FOR_ITERATOR;
+		typeMapping[JavaTokenTypes.EMPTY_STAT] = GroovyTokenTypes.EMPTY_STAT;
+		typeMapping[JavaTokenTypes.FINAL] = GroovyTokenTypes.FINAL;
+		typeMapping[JavaTokenTypes.ABSTRACT] = GroovyTokenTypes.ABSTRACT;
+		typeMapping[JavaTokenTypes.STRICTFP] = GroovyTokenTypes.STRICTFP;
+		typeMapping[JavaTokenTypes.SUPER_CTOR_CALL] = GroovyTokenTypes.SUPER_CTOR_CALL;
+		typeMapping[JavaTokenTypes.CTOR_CALL] = GroovyTokenTypes.CTOR_CALL;
+		typeMapping[JavaTokenTypes.VARIABLE_PARAMETER_DEF] = GroovyTokenTypes.VARIABLE_PARAMETER_DEF;
+		typeMapping[JavaTokenTypes.STATIC_IMPORT] = GroovyTokenTypes.STATIC_IMPORT;
+		typeMapping[JavaTokenTypes.ENUM_DEF] = GroovyTokenTypes.ENUM_DEF;
+		typeMapping[JavaTokenTypes.ENUM_CONSTANT_DEF] = GroovyTokenTypes.ENUM_CONSTANT_DEF;
+		typeMapping[JavaTokenTypes.FOR_EACH_CLAUSE] = GroovyTokenTypes.FOR_EACH_CLAUSE;
+		typeMapping[JavaTokenTypes.ANNOTATION_DEF] = GroovyTokenTypes.ANNOTATION_DEF;
+		typeMapping[JavaTokenTypes.ANNOTATIONS] = GroovyTokenTypes.ANNOTATIONS;
+		typeMapping[JavaTokenTypes.ANNOTATION] = GroovyTokenTypes.ANNOTATION;
+		typeMapping[JavaTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR] = GroovyTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR;
+		typeMapping[JavaTokenTypes.ANNOTATION_FIELD_DEF] = GroovyTokenTypes.ANNOTATION_FIELD_DEF;
+		typeMapping[JavaTokenTypes.ANNOTATION_ARRAY_INIT] = GroovyTokenTypes.ANNOTATION_ARRAY_INIT;
+		typeMapping[JavaTokenTypes.TYPE_ARGUMENTS] = GroovyTokenTypes.TYPE_ARGUMENTS;
+		typeMapping[JavaTokenTypes.TYPE_ARGUMENT] = GroovyTokenTypes.TYPE_ARGUMENT;
+		typeMapping[JavaTokenTypes.TYPE_PARAMETERS] = GroovyTokenTypes.TYPE_PARAMETERS;
+		typeMapping[JavaTokenTypes.TYPE_PARAMETER] = GroovyTokenTypes.TYPE_PARAMETER;
+		typeMapping[JavaTokenTypes.WILDCARD_TYPE] = GroovyTokenTypes.WILDCARD_TYPE;
+		typeMapping[JavaTokenTypes.TYPE_UPPER_BOUNDS] = GroovyTokenTypes.TYPE_UPPER_BOUNDS;
+		typeMapping[JavaTokenTypes.TYPE_LOWER_BOUNDS] = GroovyTokenTypes.TYPE_LOWER_BOUNDS;
+		typeMapping[JavaTokenTypes.LITERAL_package] = GroovyTokenTypes.LITERAL_package;
+		typeMapping[JavaTokenTypes.SEMI] = GroovyTokenTypes.SEMI;
+		typeMapping[JavaTokenTypes.LITERAL_import] = GroovyTokenTypes.LITERAL_import;
+		typeMapping[JavaTokenTypes.LITERAL_static] = GroovyTokenTypes.LITERAL_static;
+		typeMapping[JavaTokenTypes.LBRACK] = GroovyTokenTypes.LBRACK;
+		typeMapping[JavaTokenTypes.RBRACK] = GroovyTokenTypes.RBRACK;
+		typeMapping[JavaTokenTypes.IDENT] = GroovyTokenTypes.IDENT;
+		typeMapping[JavaTokenTypes.DOT] = GroovyTokenTypes.DOT;
+		typeMapping[JavaTokenTypes.QUESTION] = GroovyTokenTypes.QUESTION;
+		typeMapping[JavaTokenTypes.LITERAL_extends] = GroovyTokenTypes.LITERAL_extends;
+		typeMapping[JavaTokenTypes.LITERAL_super] = GroovyTokenTypes.LITERAL_super;
+		typeMapping[JavaTokenTypes.LT] = GroovyTokenTypes.LT;
+		typeMapping[JavaTokenTypes.COMMA] = GroovyTokenTypes.COMMA;
+		typeMapping[JavaTokenTypes.GT] = GroovyTokenTypes.GT;
+		typeMapping[JavaTokenTypes.SR] = GroovyTokenTypes.SR;
+		typeMapping[JavaTokenTypes.BSR] = GroovyTokenTypes.BSR;
+		typeMapping[JavaTokenTypes.LITERAL_void] = GroovyTokenTypes.LITERAL_void;
+		typeMapping[JavaTokenTypes.LITERAL_boolean] = GroovyTokenTypes.LITERAL_boolean;
+		typeMapping[JavaTokenTypes.LITERAL_byte] = GroovyTokenTypes.LITERAL_byte;
+		typeMapping[JavaTokenTypes.LITERAL_char] = GroovyTokenTypes.LITERAL_char;
+		typeMapping[JavaTokenTypes.LITERAL_short] = GroovyTokenTypes.LITERAL_short;
+		typeMapping[JavaTokenTypes.LITERAL_int] = GroovyTokenTypes.LITERAL_int;
+		typeMapping[JavaTokenTypes.LITERAL_float] = GroovyTokenTypes.LITERAL_float;
+		typeMapping[JavaTokenTypes.LITERAL_long] = GroovyTokenTypes.LITERAL_long;
+		typeMapping[JavaTokenTypes.LITERAL_double] = GroovyTokenTypes.LITERAL_double;
+		typeMapping[JavaTokenTypes.STAR] = GroovyTokenTypes.STAR;
+		typeMapping[JavaTokenTypes.LITERAL_private] = GroovyTokenTypes.LITERAL_private;
+		typeMapping[JavaTokenTypes.LITERAL_public] = GroovyTokenTypes.LITERAL_public;
+		typeMapping[JavaTokenTypes.LITERAL_protected] = GroovyTokenTypes.LITERAL_protected;
+		typeMapping[JavaTokenTypes.LITERAL_transient] = GroovyTokenTypes.LITERAL_transient;
+		typeMapping[JavaTokenTypes.LITERAL_native] = GroovyTokenTypes.LITERAL_native;
+		typeMapping[JavaTokenTypes.LITERAL_threadsafe] = GroovyTokenTypes.LITERAL_threadsafe;
+		typeMapping[JavaTokenTypes.LITERAL_synchronized] = GroovyTokenTypes.LITERAL_synchronized;
+		typeMapping[JavaTokenTypes.LITERAL_volatile] = GroovyTokenTypes.LITERAL_volatile;
+		typeMapping[JavaTokenTypes.AT] = GroovyTokenTypes.AT;
+		typeMapping[JavaTokenTypes.LPAREN] = GroovyTokenTypes.LPAREN;
+		typeMapping[JavaTokenTypes.RPAREN] = GroovyTokenTypes.RPAREN;
+		typeMapping[JavaTokenTypes.ASSIGN] = GroovyTokenTypes.ASSIGN;
+		typeMapping[JavaTokenTypes.LCURLY] = GroovyTokenTypes.LCURLY;
+		typeMapping[JavaTokenTypes.RCURLY] = GroovyTokenTypes.RCURLY;
+		typeMapping[JavaTokenTypes.LITERAL_class] = GroovyTokenTypes.LITERAL_class;
+		typeMapping[JavaTokenTypes.LITERAL_interface] = GroovyTokenTypes.LITERAL_interface;
+		typeMapping[JavaTokenTypes.LITERAL_enum] = GroovyTokenTypes.LITERAL_enum;
+		typeMapping[JavaTokenTypes.BAND] = GroovyTokenTypes.BAND;
+		typeMapping[JavaTokenTypes.LITERAL_default] = GroovyTokenTypes.LITERAL_default;
+		typeMapping[JavaTokenTypes.LITERAL_implements] = GroovyTokenTypes.LITERAL_implements;
+		typeMapping[JavaTokenTypes.LITERAL_this] = GroovyTokenTypes.LITERAL_this;
+		typeMapping[JavaTokenTypes.LITERAL_throws] = GroovyTokenTypes.LITERAL_throws;
+		typeMapping[JavaTokenTypes.TRIPLE_DOT] = GroovyTokenTypes.TRIPLE_DOT;
+		typeMapping[JavaTokenTypes.COLON] = GroovyTokenTypes.COLON;
+		typeMapping[JavaTokenTypes.LITERAL_if] = GroovyTokenTypes.LITERAL_if;
+		typeMapping[JavaTokenTypes.LITERAL_else] = GroovyTokenTypes.LITERAL_else;
+		typeMapping[JavaTokenTypes.LITERAL_while] = GroovyTokenTypes.LITERAL_while;
+		typeMapping[JavaTokenTypes.LITERAL_break] = GroovyTokenTypes.LITERAL_break;
+		typeMapping[JavaTokenTypes.LITERAL_continue] = GroovyTokenTypes.LITERAL_continue;
+		typeMapping[JavaTokenTypes.LITERAL_return] = GroovyTokenTypes.LITERAL_return;
+		typeMapping[JavaTokenTypes.LITERAL_switch] = GroovyTokenTypes.LITERAL_switch;
+		typeMapping[JavaTokenTypes.LITERAL_throw] = GroovyTokenTypes.LITERAL_throw;
+		typeMapping[JavaTokenTypes.LITERAL_assert] = GroovyTokenTypes.LITERAL_assert;
+		typeMapping[JavaTokenTypes.LITERAL_for] = GroovyTokenTypes.LITERAL_for;
+		typeMapping[JavaTokenTypes.LITERAL_case] = GroovyTokenTypes.LITERAL_case;
+		typeMapping[JavaTokenTypes.LITERAL_try] = GroovyTokenTypes.LITERAL_try;
+		typeMapping[JavaTokenTypes.LITERAL_finally] = GroovyTokenTypes.LITERAL_finally;
+		typeMapping[JavaTokenTypes.LITERAL_catch] = GroovyTokenTypes.LITERAL_catch;
+		typeMapping[JavaTokenTypes.PLUS_ASSIGN] = GroovyTokenTypes.PLUS_ASSIGN;
+		typeMapping[JavaTokenTypes.MINUS_ASSIGN] = GroovyTokenTypes.MINUS_ASSIGN;
+		typeMapping[JavaTokenTypes.STAR_ASSIGN] = GroovyTokenTypes.STAR_ASSIGN;
+		typeMapping[JavaTokenTypes.DIV_ASSIGN] = GroovyTokenTypes.DIV_ASSIGN;
+		typeMapping[JavaTokenTypes.MOD_ASSIGN] = GroovyTokenTypes.MOD_ASSIGN;
+		typeMapping[JavaTokenTypes.SR_ASSIGN] = GroovyTokenTypes.SR_ASSIGN;
+		typeMapping[JavaTokenTypes.BSR_ASSIGN] = GroovyTokenTypes.BSR_ASSIGN;
+		typeMapping[JavaTokenTypes.SL_ASSIGN] = GroovyTokenTypes.SL_ASSIGN;
+		typeMapping[JavaTokenTypes.BAND_ASSIGN] = GroovyTokenTypes.BAND_ASSIGN;
+		typeMapping[JavaTokenTypes.BXOR_ASSIGN] = GroovyTokenTypes.BXOR_ASSIGN;
+		typeMapping[JavaTokenTypes.BOR_ASSIGN] = GroovyTokenTypes.BOR_ASSIGN;
+		typeMapping[JavaTokenTypes.LOR] = GroovyTokenTypes.LOR;
+		typeMapping[JavaTokenTypes.LAND] = GroovyTokenTypes.LAND;
+		typeMapping[JavaTokenTypes.BOR] = GroovyTokenTypes.BOR;
+		typeMapping[JavaTokenTypes.BXOR] = GroovyTokenTypes.BXOR;
+		typeMapping[JavaTokenTypes.NOT_EQUAL] = GroovyTokenTypes.NOT_EQUAL;
+		typeMapping[JavaTokenTypes.EQUAL] = GroovyTokenTypes.EQUAL;
+		typeMapping[JavaTokenTypes.LE] = GroovyTokenTypes.LE;
+		typeMapping[JavaTokenTypes.GE] = GroovyTokenTypes.GE;
+		typeMapping[JavaTokenTypes.LITERAL_instanceof] = GroovyTokenTypes.LITERAL_instanceof;
+		typeMapping[JavaTokenTypes.SL] = GroovyTokenTypes.SL;
+		typeMapping[JavaTokenTypes.PLUS] = GroovyTokenTypes.PLUS;
+		typeMapping[JavaTokenTypes.MINUS] = GroovyTokenTypes.MINUS;
+		typeMapping[JavaTokenTypes.DIV] = GroovyTokenTypes.DIV;
+		typeMapping[JavaTokenTypes.MOD] = GroovyTokenTypes.MOD;
+		typeMapping[JavaTokenTypes.INC] = GroovyTokenTypes.INC;
+		typeMapping[JavaTokenTypes.DEC] = GroovyTokenTypes.DEC;
+		typeMapping[JavaTokenTypes.BNOT] = GroovyTokenTypes.BNOT;
+		typeMapping[JavaTokenTypes.LNOT] = GroovyTokenTypes.LNOT;
+		typeMapping[JavaTokenTypes.LITERAL_true] = GroovyTokenTypes.LITERAL_true;
+		typeMapping[JavaTokenTypes.LITERAL_false] = GroovyTokenTypes.LITERAL_false;
+		typeMapping[JavaTokenTypes.LITERAL_null] = GroovyTokenTypes.LITERAL_null;
+		typeMapping[JavaTokenTypes.LITERAL_new] = GroovyTokenTypes.LITERAL_new;
+		typeMapping[JavaTokenTypes.NUM_INT] = GroovyTokenTypes.NUM_INT;
+		typeMapping[JavaTokenTypes.STRING_LITERAL] = GroovyTokenTypes.STRING_LITERAL;
+		typeMapping[JavaTokenTypes.NUM_FLOAT] = GroovyTokenTypes.NUM_FLOAT;
+		typeMapping[JavaTokenTypes.NUM_LONG] = GroovyTokenTypes.NUM_LONG;
+		typeMapping[JavaTokenTypes.NUM_DOUBLE] = GroovyTokenTypes.NUM_DOUBLE;
+		typeMapping[JavaTokenTypes.WS] = GroovyTokenTypes.WS;
+		typeMapping[JavaTokenTypes.SL_COMMENT] = GroovyTokenTypes.SL_COMMENT;
+		typeMapping[JavaTokenTypes.ML_COMMENT] = GroovyTokenTypes.ML_COMMENT;
+		typeMapping[JavaTokenTypes.ESC] = GroovyTokenTypes.ESC;
+		typeMapping[JavaTokenTypes.HEX_DIGIT] = GroovyTokenTypes.HEX_DIGIT;
+		typeMapping[JavaTokenTypes.VOCAB] = GroovyTokenTypes.VOCAB;
+		typeMapping[JavaTokenTypes.EXPONENT] = GroovyTokenTypes.EXPONENT;
+		typeMapping[JavaTokenTypes.FLOAT_SUFFIX] = GroovyTokenTypes.FLOAT_SUFFIX;
+	}
+	
+    public void visitDefault(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            // only want to do this once per node...
+        	t.setType(typeMapping[t.getType()]);
+           	// ----
+
+        	// need to remove double quotes in string literals
+        	// as groovy AST doesn't expect to have them
+        	if (t.getType() == GroovyTokenTypes.STRING_LITERAL) {
+        		String text = t.getText();
+        		if (isDoubleQuoted(text)) {
+        			t.setText(text.substring(1, text.length() - 1)); // chop off the double quotes at start and end
+        		}
+        	}
+        }
+    }
+
+	private boolean isDoubleQuoted(String text) {
+		return text != null && text.length() > 2 
+				&& text.charAt(0) == '"' 
+				&& text.charAt(text.length() - 1) == '"';
+	}
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/java/Java2GroovyMain.java b/groovy-core/src/main/org/codehaus/groovy/antlr/java/Java2GroovyMain.java
new file mode 100644
index 0000000..858e9fb
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/java/Java2GroovyMain.java
@@ -0,0 +1,191 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr.java;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.PrintStream;
+import java.io.StringReader;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.PosixParser;
+import org.codehaus.groovy.antlr.AntlrASTProcessor;
+import org.codehaus.groovy.antlr.SourceBuffer;
+import org.codehaus.groovy.antlr.UnicodeEscapingReader;
+import org.codehaus.groovy.antlr.java.Java2GroovyConverter;
+import org.codehaus.groovy.antlr.java.JavaLexer;
+import org.codehaus.groovy.antlr.java.JavaRecognizer;
+import org.codehaus.groovy.antlr.parser.GroovyLexer;
+import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
+import org.codehaus.groovy.antlr.treewalker.*;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+
+import antlr.collections.AST;
+
+public class Java2GroovyMain {
+
+	public static void main(String[] args) {
+		try{
+			Options options = new Options();
+			PosixParser cliParser = new PosixParser();
+			CommandLine cli = cliParser.parse(options, args);
+            String[] filenames = cli.getArgs();
+            if( filenames.length == 0 ) {
+            	System.err.println("Needs at least one filename");
+            }
+            List filenameList = Arrays.asList(filenames);
+            Iterator i = filenameList.iterator();
+            while (i.hasNext()) {
+            	String filename = (String) i.next();
+            	File f = new File(filename);
+            	String text = DefaultGroovyMethods.getText(f);
+            	System.out.println(convert(text, true, true));
+            }
+		} catch (Throwable t) {
+			t.printStackTrace();
+		}
+	}
+
+	public static String convert(String input) throws Exception{
+		return convert(input, false, false);
+	}
+	
+	public static String convert(String input,boolean withHeader, boolean withNewLines) throws Exception{
+        JavaRecognizer parser = getJavaParser(input);
+        String[] tokenNames = parser.getTokenNames();
+        parser.compilationUnit();
+        AST ast = parser.getAST();
+        // modify the Java AST into a Groovy AST
+        modifyJavaASTintoGroovyAST(tokenNames, ast);
+        String[] groovyTokenNames = getGroovyTokenNames(input);
+        // groovify the fat Java-Like Groovy AST
+        groovifyFatJavaLikeGroovyAST(ast, groovyTokenNames);
+
+        // now output        
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Visitor visitor = new SourcePrinter(new PrintStream(baos),groovyTokenNames, withNewLines);
+        AntlrASTProcessor traverser = new SourceCodeTraversal(visitor);
+
+        traverser.process(ast);
+        
+        String header = "";
+        if (withHeader) {
+	        header = "/*\n" +
+	        				"  Automatically Converted from Java Source \n" +
+	        				"  \n" +
+	        				"  by java2groovy v0.0.1   Copyright Jeremy Rayner 2007\n" +
+	        				"  \n" +
+	        				"  !! NOT FIT FOR ANY PURPOSE !! \n" +
+	        				"  'java2groovy' cannot be used to convert one working program into another" +
+	        				"  */\n\n";
+        }
+        return header + new String(baos.toByteArray());
+    }
+
+	/**
+	 * @param ast
+	 * @param groovyTokenNames
+	 */
+	private static void groovifyFatJavaLikeGroovyAST(AST ast, String[] groovyTokenNames) {
+		Visitor groovifier = new Groovifier(groovyTokenNames);
+        AntlrASTProcessor groovifierTraverser = new PreOrderTraversal(groovifier);
+        groovifierTraverser.process(ast);
+	}
+
+	/**
+	 * @param tokenNames
+	 * @param ast
+	 */
+	private static void modifyJavaASTintoGroovyAST(String[] tokenNames, AST ast) {
+		Visitor java2groovyConverter = new Java2GroovyConverter(tokenNames);
+        AntlrASTProcessor java2groovyTraverser = new PreOrderTraversal(java2groovyConverter);
+        java2groovyTraverser.process(ast);
+	}
+
+	/**
+	 * @param input
+	 * @return
+	 */
+	private static JavaRecognizer getJavaParser(String input) {
+		JavaRecognizer parser = null;
+        SourceBuffer sourceBuffer = new SourceBuffer();
+        UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(new StringReader(input),sourceBuffer);
+        JavaLexer lexer = new JavaLexer(unicodeReader);
+        unicodeReader.setLexer(lexer);
+        parser = JavaRecognizer.make(lexer);
+        parser.setSourceBuffer(sourceBuffer);
+		return parser;
+	}
+
+	public static String mindmap(String input) throws Exception{
+        JavaRecognizer parser = getJavaParser(input);
+        String[] tokenNames = parser.getTokenNames();
+        parser.compilationUnit();
+        AST ast = parser.getAST();
+        // modify the Java AST into a Groovy AST
+        modifyJavaASTintoGroovyAST(tokenNames, ast);
+        String[] groovyTokenNames = getGroovyTokenNames(input);
+        // groovify the fat Java-Like Groovy AST
+        groovifyFatJavaLikeGroovyAST(ast, groovyTokenNames);
+
+        // now output        
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Visitor visitor = new MindMapPrinter(new PrintStream(baos),groovyTokenNames);
+        AntlrASTProcessor traverser = new SourceCodeTraversal(visitor);
+
+        traverser.process(ast);
+        
+        return new String(baos.toByteArray());
+    }
+
+	public static String nodePrinter(String input) throws Exception{
+        JavaRecognizer parser = getJavaParser(input);
+        String[] tokenNames = parser.getTokenNames();
+        parser.compilationUnit();
+        AST ast = parser.getAST();
+        // modify the Java AST into a Groovy AST
+        modifyJavaASTintoGroovyAST(tokenNames, ast);
+        String[] groovyTokenNames = getGroovyTokenNames(input);
+        // groovify the fat Java-Like Groovy AST
+        groovifyFatJavaLikeGroovyAST(ast, groovyTokenNames);
+
+        // now output        
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Visitor visitor = new NodePrinter(new PrintStream(baos),groovyTokenNames);
+        AntlrASTProcessor traverser = new SourceCodeTraversal(visitor);
+
+        traverser.process(ast);
+        
+        return new String(baos.toByteArray());
+    }
+
+	private static String[] getGroovyTokenNames(String input) {
+        GroovyRecognizer groovyParser = null;
+        SourceBuffer groovySourceBuffer = new SourceBuffer();
+        UnicodeEscapingReader groovyUnicodeReader = new UnicodeEscapingReader(new StringReader(input),groovySourceBuffer);
+        GroovyLexer groovyLexer = new GroovyLexer(groovyUnicodeReader);
+        groovyUnicodeReader.setLexer(groovyLexer);
+        groovyParser = GroovyRecognizer.make(groovyLexer);
+        return groovyParser.getTokenNames();
+	}
+	
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/java/JavaLexer.java b/groovy-core/src/main/org/codehaus/groovy/antlr/java/JavaLexer.java
new file mode 100644
index 0000000..b81f489
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/java/JavaLexer.java
@@ -0,0 +1,2126 @@
+// $ANTLR 2.7.2: "java.g" -> "JavaLexer.java"$
+
+package org.codehaus.groovy.antlr.java;
+import org.codehaus.groovy.antlr.*;
+import org.codehaus.groovy.antlr.parser.*;
+import java.util.*;
+import java.io.InputStream;
+import java.io.Reader;
+import antlr.InputBuffer;
+import antlr.LexerSharedInputState;
+
+import java.io.InputStream;
+import antlr.TokenStreamException;
+import antlr.TokenStreamIOException;
+import antlr.TokenStreamRecognitionException;
+import antlr.CharStreamException;
+import antlr.CharStreamIOException;
+import antlr.ANTLRException;
+import java.io.Reader;
+import java.util.Hashtable;
+import antlr.CharScanner;
+import antlr.InputBuffer;
+import antlr.ByteBuffer;
+import antlr.CharBuffer;
+import antlr.Token;
+import antlr.CommonToken;
+import antlr.RecognitionException;
+import antlr.NoViableAltForCharException;
+import antlr.MismatchedCharException;
+import antlr.TokenStream;
+import antlr.ANTLRHashString;
+import antlr.LexerSharedInputState;
+import antlr.collections.impl.BitSet;
+import antlr.SemanticException;
+
+public class JavaLexer extends antlr.CharScanner implements JavaTokenTypes, TokenStream
+ {
+
+    protected static final int SCS_TYPE = 3, SCS_VAL = 4, SCS_LIT = 8, SCS_LIMIT = 16;
+    protected static final int SCS_SQ_TYPE = 0, SCS_TQ_TYPE = 1, SCS_RE_TYPE = 2;
+    protected int stringCtorState = 0;  // hack string and regexp constructor boundaries
+    protected int lastSigTokenType = EOF;  // last returned non-whitespace token
+
+    /** flag for enabling the "assert" keyword */
+	private boolean assertEnabled = true;
+	/** flag for enabling the "enum" keyword */
+	private boolean enumEnabled = true;
+    /** flag for including whitespace tokens (for IDE preparsing) */
+    private boolean whitespaceIncluded = false;
+
+	/** Enable the "assert" keyword */
+	public void enableAssert(boolean shouldEnable) { assertEnabled = shouldEnable; }
+	/** Query the "assert" keyword state */
+	public boolean isAssertEnabled() { return assertEnabled; }
+	/** Enable the "enum" keyword */
+	public void enableEnum(boolean shouldEnable) { enumEnabled = shouldEnable; }
+	/** Query the "enum" keyword state */
+	public boolean isEnumEnabled() { return enumEnabled; }
+
+    /** This is a bit of plumbing which resumes collection of string constructor bodies,
+     *  after an embedded expression has been parsed.
+     *  Usage:  new JavaRecognizer(new JavaLexer(in).plumb()).
+     */
+    public TokenStream plumb() {
+        return new TokenStream() {
+            public Token nextToken() throws TokenStreamException {
+                if (stringCtorState >= SCS_LIT) {
+                    // This goo is modeled upon the ANTLR code for nextToken:
+                    int quoteType = (stringCtorState & SCS_TYPE);
+                    stringCtorState = 0;  // get out of this mode, now
+                    resetText();
+/*                    try {
+                        switch (quoteType) {
+                        case SCS_SQ_TYPE:
+//todo: suitable replacement???     mSTRING_CTOR_END(true, false, false); 
+                        	break;
+                        case SCS_TQ_TYPE:
+//                            mSTRING_CTOR_END(true, false, true); 
+                        	break;
+                        case SCS_RE_TYPE:
+//                            mREGEXP_CTOR_END(true, false); 
+                        	break;
+                        default:  throw new AssertionError(false);
+                        }
+                        lastSigTokenType = _returnToken.getType();
+                        return _returnToken;
+                    }*//* catch (RecognitionException e) {
+                        throw new TokenStreamRecognitionException(e);
+                    }*/ /*catch (CharStreamException cse) {
+                        if ( cse instanceof CharStreamIOException ) {
+                            throw new TokenStreamIOException(((CharStreamIOException)cse).io);
+                        }
+                        else {
+                            throw new TokenStreamException(cse.getMessage());
+                        }
+                    }*/
+                }
+                Token token = JavaLexer.this.nextToken();
+                int lasttype = token.getType();
+                if (whitespaceIncluded) {
+                    switch (lasttype) {  // filter out insignificant types
+                    case WS:
+                    case SL_COMMENT:
+                    case ML_COMMENT:
+                        lasttype = lastSigTokenType;  // back up!
+                    }
+                }
+                lastSigTokenType = lasttype;
+                return token;
+            }
+        };
+    }
+    
+    protected JavaRecognizer parser;  // little-used link; TODO: get rid of
+public JavaLexer(InputStream in) {
+	this(new ByteBuffer(in));
+}
+public JavaLexer(Reader in) {
+	this(new CharBuffer(in));
+}
+public JavaLexer(InputBuffer ib) {
+	this(new LexerSharedInputState(ib));
+}
+public JavaLexer(LexerSharedInputState state) {
+	super(state);
+	caseSensitiveLiterals = true;
+	setCaseSensitive(true);
+	literals = new Hashtable();
+	literals.put(new ANTLRHashString("byte", this), new Integer(79));
+	literals.put(new ANTLRHashString("public", this), new Integer(88));
+	literals.put(new ANTLRHashString("case", this), new Integer(121));
+	literals.put(new ANTLRHashString("short", this), new Integer(81));
+	literals.put(new ANTLRHashString("break", this), new Integer(114));
+	literals.put(new ANTLRHashString("while", this), new Integer(113));
+	literals.put(new ANTLRHashString("new", this), new Integer(157));
+	literals.put(new ANTLRHashString("instanceof", this), new Integer(144));
+	literals.put(new ANTLRHashString("implements", this), new Integer(106));
+	literals.put(new ANTLRHashString("synchronized", this), new Integer(93));
+	literals.put(new ANTLRHashString("float", this), new Integer(83));
+	literals.put(new ANTLRHashString("package", this), new Integer(61));
+	literals.put(new ANTLRHashString("return", this), new Integer(116));
+	literals.put(new ANTLRHashString("throw", this), new Integer(118));
+	literals.put(new ANTLRHashString("null", this), new Integer(156));
+	literals.put(new ANTLRHashString("threadsafe", this), new Integer(92));
+	literals.put(new ANTLRHashString("protected", this), new Integer(89));
+	literals.put(new ANTLRHashString("class", this), new Integer(101));
+	literals.put(new ANTLRHashString("throws", this), new Integer(108));
+	literals.put(new ANTLRHashString("strictfp", this), new Integer(40));
+	literals.put(new ANTLRHashString("super", this), new Integer(71));
+	literals.put(new ANTLRHashString("transient", this), new Integer(90));
+	literals.put(new ANTLRHashString("native", this), new Integer(91));
+	literals.put(new ANTLRHashString("interface", this), new Integer(102));
+	literals.put(new ANTLRHashString("final", this), new Integer(38));
+	literals.put(new ANTLRHashString("if", this), new Integer(111));
+	literals.put(new ANTLRHashString("double", this), new Integer(85));
+	literals.put(new ANTLRHashString("volatile", this), new Integer(94));
+	literals.put(new ANTLRHashString("assert", this), new Integer(119));
+	literals.put(new ANTLRHashString("catch", this), new Integer(124));
+	literals.put(new ANTLRHashString("try", this), new Integer(122));
+	literals.put(new ANTLRHashString("enum", this), new Integer(103));
+	literals.put(new ANTLRHashString("int", this), new Integer(82));
+	literals.put(new ANTLRHashString("for", this), new Integer(120));
+	literals.put(new ANTLRHashString("extends", this), new Integer(70));
+	literals.put(new ANTLRHashString("boolean", this), new Integer(78));
+	literals.put(new ANTLRHashString("char", this), new Integer(80));
+	literals.put(new ANTLRHashString("private", this), new Integer(87));
+	literals.put(new ANTLRHashString("default", this), new Integer(105));
+	literals.put(new ANTLRHashString("false", this), new Integer(155));
+	literals.put(new ANTLRHashString("this", this), new Integer(107));
+	literals.put(new ANTLRHashString("static", this), new Integer(64));
+	literals.put(new ANTLRHashString("abstract", this), new Integer(39));
+	literals.put(new ANTLRHashString("continue", this), new Integer(115));
+	literals.put(new ANTLRHashString("finally", this), new Integer(123));
+	literals.put(new ANTLRHashString("else", this), new Integer(112));
+	literals.put(new ANTLRHashString("import", this), new Integer(63));
+	literals.put(new ANTLRHashString("void", this), new Integer(77));
+	literals.put(new ANTLRHashString("switch", this), new Integer(117));
+	literals.put(new ANTLRHashString("true", this), new Integer(154));
+	literals.put(new ANTLRHashString("long", this), new Integer(84));
+}
+
+public Token nextToken() throws TokenStreamException {
+	Token theRetToken=null;
+tryAgain:
+	for (;;) {
+		Token _token = null;
+		int _ttype = Token.INVALID_TYPE;
+		resetText();
+		try {   // for char stream error handling
+			try {   // for lexical error handling
+				switch ( LA(1)) {
+				case '?':
+				{
+					mQUESTION(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				case '(':
+				{
+					mLPAREN(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				case ')':
+				{
+					mRPAREN(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				case '[':
+				{
+					mLBRACK(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				case ']':
+				{
+					mRBRACK(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				case '{':
+				{
+					mLCURLY(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				case '}':
+				{
+					mRCURLY(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				case ':':
+				{
+					mCOLON(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				case ',':
+				{
+					mCOMMA(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				case '~':
+				{
+					mBNOT(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				case ';':
+				{
+					mSEMI(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				case '\t':  case '\n':  case '\u000c':  case '\r':
+				case ' ':
+				{
+					mWS(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				case '"':  case '\'':
+				{
+					mSTRING_LITERAL(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				case '$':  case 'A':  case 'B':  case 'C':
+				case 'D':  case 'E':  case 'F':  case 'G':
+				case 'H':  case 'I':  case 'J':  case 'K':
+				case 'L':  case 'M':  case 'N':  case 'O':
+				case 'P':  case 'Q':  case 'R':  case 'S':
+				case 'T':  case 'U':  case 'V':  case 'W':
+				case 'X':  case 'Y':  case 'Z':  case '_':
+				case 'a':  case 'b':  case 'c':  case 'd':
+				case 'e':  case 'f':  case 'g':  case 'h':
+				case 'i':  case 'j':  case 'k':  case 'l':
+				case 'm':  case 'n':  case 'o':  case 'p':
+				case 'q':  case 'r':  case 's':  case 't':
+				case 'u':  case 'v':  case 'w':  case 'x':
+				case 'y':  case 'z':
+				{
+					mIDENT(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				case '.':  case '0':  case '1':  case '2':
+				case '3':  case '4':  case '5':  case '6':
+				case '7':  case '8':  case '9':
+				{
+					mNUM_INT(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				case '@':
+				{
+					mAT(true);
+					theRetToken=_returnToken;
+					break;
+				}
+				default:
+					if ((LA(1)=='>') && (LA(2)=='>') && (LA(3)=='>') && (LA(4)=='=')) {
+						mBSR_ASSIGN(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='>') && (LA(2)=='>') && (LA(3)=='=')) {
+						mSR_ASSIGN(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='>') && (LA(2)=='>') && (LA(3)=='>') && (true)) {
+						mBSR(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='<') && (LA(2)=='<') && (LA(3)=='=')) {
+						mSL_ASSIGN(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='=') && (LA(2)=='=')) {
+						mEQUAL(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='!') && (LA(2)=='=')) {
+						mNOT_EQUAL(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='/') && (LA(2)=='=')) {
+						mDIV_ASSIGN(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='+') && (LA(2)=='=')) {
+						mPLUS_ASSIGN(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='+') && (LA(2)=='+')) {
+						mINC(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='-') && (LA(2)=='=')) {
+						mMINUS_ASSIGN(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='-') && (LA(2)=='-')) {
+						mDEC(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='*') && (LA(2)=='=')) {
+						mSTAR_ASSIGN(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='%') && (LA(2)=='=')) {
+						mMOD_ASSIGN(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='>') && (LA(2)=='>') && (true)) {
+						mSR(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='>') && (LA(2)=='=')) {
+						mGE(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='<') && (LA(2)=='<') && (true)) {
+						mSL(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='<') && (LA(2)=='=')) {
+						mLE(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='^') && (LA(2)=='=')) {
+						mBXOR_ASSIGN(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='|') && (LA(2)=='=')) {
+						mBOR_ASSIGN(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='|') && (LA(2)=='|')) {
+						mLOR(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='&') && (LA(2)=='=')) {
+						mBAND_ASSIGN(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='&') && (LA(2)=='&')) {
+						mLAND(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='/') && (LA(2)=='/')) {
+						mSL_COMMENT(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='/') && (LA(2)=='*')) {
+						mML_COMMENT(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='=') && (true)) {
+						mASSIGN(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='!') && (true)) {
+						mLNOT(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='/') && (true)) {
+						mDIV(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='+') && (true)) {
+						mPLUS(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='-') && (true)) {
+						mMINUS(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='*') && (true)) {
+						mSTAR(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='%') && (true)) {
+						mMOD(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='>') && (true)) {
+						mGT(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='<') && (true)) {
+						mLT(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='^') && (true)) {
+						mBXOR(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='|') && (true)) {
+						mBOR(true);
+						theRetToken=_returnToken;
+					}
+					else if ((LA(1)=='&') && (true)) {
+						mBAND(true);
+						theRetToken=_returnToken;
+					}
+				else {
+					if (LA(1)==EOF_CHAR) {uponEOF(); _returnToken = makeToken(Token.EOF_TYPE);}
+				else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());}
+				}
+				}
+				if ( _returnToken==null ) continue tryAgain; // found SKIP token
+				_ttype = _returnToken.getType();
+				_returnToken.setType(_ttype);
+				return _returnToken;
+			}
+			catch (RecognitionException e) {
+				throw new TokenStreamRecognitionException(e);
+			}
+		}
+		catch (CharStreamException cse) {
+			if ( cse instanceof CharStreamIOException ) {
+				throw new TokenStreamIOException(((CharStreamIOException)cse).io);
+			}
+			else {
+				throw new TokenStreamException(cse.getMessage());
+			}
+		}
+	}
+}
+
+	public final void mQUESTION(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = QUESTION;
+		int _saveIndex;
+		
+		match('?');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mLPAREN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = LPAREN;
+		int _saveIndex;
+		
+		match('(');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mRPAREN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = RPAREN;
+		int _saveIndex;
+		
+		match(')');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mLBRACK(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = LBRACK;
+		int _saveIndex;
+		
+		match('[');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mRBRACK(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = RBRACK;
+		int _saveIndex;
+		
+		match(']');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mLCURLY(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = LCURLY;
+		int _saveIndex;
+		
+		match('{');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mRCURLY(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = RCURLY;
+		int _saveIndex;
+		
+		match('}');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mCOLON(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = COLON;
+		int _saveIndex;
+		
+		match(':');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mCOMMA(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = COMMA;
+		int _saveIndex;
+		
+		match(',');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mASSIGN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = ASSIGN;
+		int _saveIndex;
+		
+		match('=');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mEQUAL(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = EQUAL;
+		int _saveIndex;
+		
+		match("==");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mLNOT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = LNOT;
+		int _saveIndex;
+		
+		match('!');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mBNOT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = BNOT;
+		int _saveIndex;
+		
+		match('~');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mNOT_EQUAL(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = NOT_EQUAL;
+		int _saveIndex;
+		
+		match("!=");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mDIV(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = DIV;
+		int _saveIndex;
+		
+		match('/');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mDIV_ASSIGN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = DIV_ASSIGN;
+		int _saveIndex;
+		
+		match("/=");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mPLUS(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = PLUS;
+		int _saveIndex;
+		
+		match('+');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mPLUS_ASSIGN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = PLUS_ASSIGN;
+		int _saveIndex;
+		
+		match("+=");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mINC(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = INC;
+		int _saveIndex;
+		
+		match("++");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mMINUS(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = MINUS;
+		int _saveIndex;
+		
+		match('-');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mMINUS_ASSIGN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = MINUS_ASSIGN;
+		int _saveIndex;
+		
+		match("-=");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mDEC(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = DEC;
+		int _saveIndex;
+		
+		match("--");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mSTAR(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = STAR;
+		int _saveIndex;
+		
+		match('*');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mSTAR_ASSIGN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = STAR_ASSIGN;
+		int _saveIndex;
+		
+		match("*=");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mMOD(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = MOD;
+		int _saveIndex;
+		
+		match('%');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mMOD_ASSIGN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = MOD_ASSIGN;
+		int _saveIndex;
+		
+		match("%=");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mSR(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = SR;
+		int _saveIndex;
+		
+		match(">>");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mSR_ASSIGN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = SR_ASSIGN;
+		int _saveIndex;
+		
+		match(">>=");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mBSR(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = BSR;
+		int _saveIndex;
+		
+		match(">>>");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mBSR_ASSIGN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = BSR_ASSIGN;
+		int _saveIndex;
+		
+		match(">>>=");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mGE(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = GE;
+		int _saveIndex;
+		
+		match(">=");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mGT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = GT;
+		int _saveIndex;
+		
+		match(">");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mSL(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = SL;
+		int _saveIndex;
+		
+		match("<<");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mSL_ASSIGN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = SL_ASSIGN;
+		int _saveIndex;
+		
+		match("<<=");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mLE(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = LE;
+		int _saveIndex;
+		
+		match("<=");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mLT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = LT;
+		int _saveIndex;
+		
+		match('<');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mBXOR(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = BXOR;
+		int _saveIndex;
+		
+		match('^');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mBXOR_ASSIGN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = BXOR_ASSIGN;
+		int _saveIndex;
+		
+		match("^=");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mBOR(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = BOR;
+		int _saveIndex;
+		
+		match('|');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mBOR_ASSIGN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = BOR_ASSIGN;
+		int _saveIndex;
+		
+		match("|=");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mLOR(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = LOR;
+		int _saveIndex;
+		
+		match("||");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mBAND(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = BAND;
+		int _saveIndex;
+		
+		match('&');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mBAND_ASSIGN(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = BAND_ASSIGN;
+		int _saveIndex;
+		
+		match("&=");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mLAND(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = LAND;
+		int _saveIndex;
+		
+		match("&&");
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mSEMI(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = SEMI;
+		int _saveIndex;
+		
+		match(';');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mWS(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = WS;
+		int _saveIndex;
+		
+		{
+		int _cnt363=0;
+		_loop363:
+		do {
+			switch ( LA(1)) {
+			case ' ':
+			{
+				match(' ');
+				break;
+			}
+			case '\t':
+			{
+				match('\t');
+				break;
+			}
+			case '\u000c':
+			{
+				match('\f');
+				break;
+			}
+			case '\n':  case '\r':
+			{
+				{
+				if ((LA(1)=='\r') && (LA(2)=='\n') && (true) && (true)) {
+					match("\r\n");
+				}
+				else if ((LA(1)=='\r') && (true) && (true) && (true)) {
+					match('\r');
+				}
+				else if ((LA(1)=='\n')) {
+					match('\n');
+				}
+				else {
+					throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+				}
+				
+				}
+				if ( inputState.guessing==0 ) {
+					newline();
+				}
+				break;
+			}
+			default:
+			{
+				if ( _cnt363>=1 ) { break _loop363; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());}
+			}
+			}
+			_cnt363++;
+		} while (true);
+		}
+		if ( inputState.guessing==0 ) {
+			_ttype = Token.SKIP;
+		}
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mSL_COMMENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = SL_COMMENT;
+		int _saveIndex;
+		
+		match("//");
+		{
+		_loop367:
+		do {
+			if ((_tokenSet_0.member(LA(1)))) {
+				{
+				match(_tokenSet_0);
+				}
+			}
+			else {
+				break _loop367;
+			}
+			
+		} while (true);
+		}
+		{
+		switch ( LA(1)) {
+		case '\n':
+		{
+			match('\n');
+			break;
+		}
+		case '\r':
+		{
+			match('\r');
+			{
+			if ((LA(1)=='\n')) {
+				match('\n');
+			}
+			else {
+			}
+			
+			}
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+		}
+		}
+		}
+		if ( inputState.guessing==0 ) {
+			_ttype = Token.SKIP; newline();
+		}
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mML_COMMENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = ML_COMMENT;
+		int _saveIndex;
+		
+		match("/*");
+		{
+		_loop373:
+		do {
+			if ((LA(1)=='\r') && (LA(2)=='\n') && ((LA(3) >= '\u0003' && LA(3) <= '\uffff')) && ((LA(4) >= '\u0003' && LA(4) <= '\uffff'))) {
+				match('\r');
+				match('\n');
+				if ( inputState.guessing==0 ) {
+					newline();
+				}
+			}
+			else if (((LA(1)=='*') && ((LA(2) >= '\u0003' && LA(2) <= '\uffff')) && ((LA(3) >= '\u0003' && LA(3) <= '\uffff')))&&( LA(2)!='/' )) {
+				match('*');
+			}
+			else if ((LA(1)=='\r') && ((LA(2) >= '\u0003' && LA(2) <= '\uffff')) && ((LA(3) >= '\u0003' && LA(3) <= '\uffff')) && (true)) {
+				match('\r');
+				if ( inputState.guessing==0 ) {
+					newline();
+				}
+			}
+			else if ((LA(1)=='\n')) {
+				match('\n');
+				if ( inputState.guessing==0 ) {
+					newline();
+				}
+			}
+			else if ((_tokenSet_1.member(LA(1)))) {
+				{
+				match(_tokenSet_1);
+				}
+			}
+			else {
+				break _loop373;
+			}
+			
+		} while (true);
+		}
+		match("*/");
+		if ( inputState.guessing==0 ) {
+			_ttype = Token.SKIP;
+		}
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mSTRING_LITERAL(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = STRING_LITERAL;
+		int _saveIndex;
+		
+		switch ( LA(1)) {
+		case '"':
+		{
+			match('"');
+			{
+			_loop377:
+			do {
+				if ((LA(1)=='\\')) {
+					mESC(false);
+				}
+				else if ((_tokenSet_2.member(LA(1)))) {
+					{
+					match(_tokenSet_2);
+					}
+				}
+				else {
+					break _loop377;
+				}
+				
+			} while (true);
+			}
+			match('"');
+			break;
+		}
+		case '\'':
+		{
+			match('\'');
+			{
+			if ((LA(1)=='\\')) {
+				mESC(false);
+			}
+			else if ((_tokenSet_3.member(LA(1)))) {
+				{
+				match(_tokenSet_3);
+				}
+			}
+			else {
+				throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+			}
+			
+			}
+			match('\'');
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+		}
+		}
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	protected final void mESC(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = ESC;
+		int _saveIndex;
+		
+		match('\\');
+		{
+		switch ( LA(1)) {
+		case 'n':
+		{
+			match('n');
+			break;
+		}
+		case 'r':
+		{
+			match('r');
+			break;
+		}
+		case 't':
+		{
+			match('t');
+			break;
+		}
+		case 'b':
+		{
+			match('b');
+			break;
+		}
+		case 'f':
+		{
+			match('f');
+			break;
+		}
+		case '"':
+		{
+			match('"');
+			break;
+		}
+		case '\'':
+		{
+			match('\'');
+			break;
+		}
+		case '\\':
+		{
+			match('\\');
+			break;
+		}
+		case 'u':
+		{
+			{
+			int _cnt383=0;
+			_loop383:
+			do {
+				if ((LA(1)=='u')) {
+					match('u');
+				}
+				else {
+					if ( _cnt383>=1 ) { break _loop383; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());}
+				}
+				
+				_cnt383++;
+			} while (true);
+			}
+			mHEX_DIGIT(false);
+			mHEX_DIGIT(false);
+			mHEX_DIGIT(false);
+			mHEX_DIGIT(false);
+			break;
+		}
+		case '0':  case '1':  case '2':  case '3':
+		{
+			matchRange('0','3');
+			{
+			if (((LA(1) >= '0' && LA(1) <= '7')) && (_tokenSet_0.member(LA(2))) && (true) && (true)) {
+				matchRange('0','7');
+				{
+				if (((LA(1) >= '0' && LA(1) <= '7')) && (_tokenSet_0.member(LA(2))) && (true) && (true)) {
+					matchRange('0','7');
+				}
+				else if ((_tokenSet_0.member(LA(1))) && (true) && (true) && (true)) {
+				}
+				else {
+					throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+				}
+				
+				}
+			}
+			else if ((_tokenSet_0.member(LA(1))) && (true) && (true) && (true)) {
+			}
+			else {
+				throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+			}
+			
+			}
+			break;
+		}
+		case '4':  case '5':  case '6':  case '7':
+		{
+			matchRange('4','7');
+			{
+			if (((LA(1) >= '0' && LA(1) <= '7')) && (_tokenSet_0.member(LA(2))) && (true) && (true)) {
+				matchRange('0','7');
+			}
+			else if ((_tokenSet_0.member(LA(1))) && (true) && (true) && (true)) {
+			}
+			else {
+				throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+			}
+			
+			}
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+		}
+		}
+		}
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	protected final void mHEX_DIGIT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = HEX_DIGIT;
+		int _saveIndex;
+		
+		{
+		switch ( LA(1)) {
+		case '0':  case '1':  case '2':  case '3':
+		case '4':  case '5':  case '6':  case '7':
+		case '8':  case '9':
+		{
+			matchRange('0','9');
+			break;
+		}
+		case 'A':  case 'B':  case 'C':  case 'D':
+		case 'E':  case 'F':
+		{
+			matchRange('A','F');
+			break;
+		}
+		case 'a':  case 'b':  case 'c':  case 'd':
+		case 'e':  case 'f':
+		{
+			matchRange('a','f');
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+		}
+		}
+		}
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	protected final void mVOCAB(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = VOCAB;
+		int _saveIndex;
+		
+		matchRange('\3','\377');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mIDENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = IDENT;
+		int _saveIndex;
+		
+		{
+		switch ( LA(1)) {
+		case 'a':  case 'b':  case 'c':  case 'd':
+		case 'e':  case 'f':  case 'g':  case 'h':
+		case 'i':  case 'j':  case 'k':  case 'l':
+		case 'm':  case 'n':  case 'o':  case 'p':
+		case 'q':  case 'r':  case 's':  case 't':
+		case 'u':  case 'v':  case 'w':  case 'x':
+		case 'y':  case 'z':
+		{
+			matchRange('a','z');
+			break;
+		}
+		case 'A':  case 'B':  case 'C':  case 'D':
+		case 'E':  case 'F':  case 'G':  case 'H':
+		case 'I':  case 'J':  case 'K':  case 'L':
+		case 'M':  case 'N':  case 'O':  case 'P':
+		case 'Q':  case 'R':  case 'S':  case 'T':
+		case 'U':  case 'V':  case 'W':  case 'X':
+		case 'Y':  case 'Z':
+		{
+			matchRange('A','Z');
+			break;
+		}
+		case '_':
+		{
+			match('_');
+			break;
+		}
+		case '$':
+		{
+			match('$');
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+		}
+		}
+		}
+		{
+		_loop393:
+		do {
+			switch ( LA(1)) {
+			case 'a':  case 'b':  case 'c':  case 'd':
+			case 'e':  case 'f':  case 'g':  case 'h':
+			case 'i':  case 'j':  case 'k':  case 'l':
+			case 'm':  case 'n':  case 'o':  case 'p':
+			case 'q':  case 'r':  case 's':  case 't':
+			case 'u':  case 'v':  case 'w':  case 'x':
+			case 'y':  case 'z':
+			{
+				matchRange('a','z');
+				break;
+			}
+			case 'A':  case 'B':  case 'C':  case 'D':
+			case 'E':  case 'F':  case 'G':  case 'H':
+			case 'I':  case 'J':  case 'K':  case 'L':
+			case 'M':  case 'N':  case 'O':  case 'P':
+			case 'Q':  case 'R':  case 'S':  case 'T':
+			case 'U':  case 'V':  case 'W':  case 'X':
+			case 'Y':  case 'Z':
+			{
+				matchRange('A','Z');
+				break;
+			}
+			case '_':
+			{
+				match('_');
+				break;
+			}
+			case '0':  case '1':  case '2':  case '3':
+			case '4':  case '5':  case '6':  case '7':
+			case '8':  case '9':
+			{
+				matchRange('0','9');
+				break;
+			}
+			case '$':
+			{
+				match('$');
+				break;
+			}
+			default:
+			{
+				break _loop393;
+			}
+			}
+		} while (true);
+		}
+		if ( inputState.guessing==0 ) {
+			
+						// check if "assert" keyword is enabled
+						if (assertEnabled && "assert".equals(new String(text.getBuffer(),_begin,text.length()-_begin))) {
+							_ttype = LITERAL_assert; // set token type for the rule in the parser
+						}
+						// check if "enum" keyword is enabled
+						if (enumEnabled && "enum".equals(new String(text.getBuffer(),_begin,text.length()-_begin))) {
+							_ttype = LITERAL_enum; // set token type for the rule in the parser
+						}
+					
+		}
+		_ttype = testLiteralsTable(_ttype);
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mNUM_INT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = NUM_INT;
+		int _saveIndex;
+		Token f1=null;
+		Token f2=null;
+		Token f3=null;
+		Token f4=null;
+		boolean isDecimal=false; Token t=null;
+		
+		switch ( LA(1)) {
+		case '.':
+		{
+			match('.');
+			if ( inputState.guessing==0 ) {
+				_ttype = DOT;
+			}
+			{
+			switch ( LA(1)) {
+			case '0':  case '1':  case '2':  case '3':
+			case '4':  case '5':  case '6':  case '7':
+			case '8':  case '9':
+			{
+				{
+				{
+				int _cnt398=0;
+				_loop398:
+				do {
+					if (((LA(1) >= '0' && LA(1) <= '9'))) {
+						matchRange('0','9');
+					}
+					else {
+						if ( _cnt398>=1 ) { break _loop398; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());}
+					}
+					
+					_cnt398++;
+				} while (true);
+				}
+				{
+				if ((LA(1)=='E'||LA(1)=='e')) {
+					mEXPONENT(false);
+				}
+				else {
+				}
+				
+				}
+				{
+				if ((LA(1)=='D'||LA(1)=='F'||LA(1)=='d'||LA(1)=='f')) {
+					mFLOAT_SUFFIX(true);
+					f1=_returnToken;
+					if ( inputState.guessing==0 ) {
+						t=f1;
+					}
+				}
+				else {
+				}
+				
+				}
+				if ( inputState.guessing==0 ) {
+					
+									if (t != null && t.getText().toUpperCase().indexOf('F')>=0) {
+										_ttype = NUM_FLOAT;
+									}
+									else {
+										_ttype = NUM_DOUBLE; // assume double
+									}
+									
+				}
+				}
+				break;
+			}
+			case '.':
+			{
+				{
+				match("..");
+				if ( inputState.guessing==0 ) {
+					_ttype = TRIPLE_DOT;
+				}
+				}
+				break;
+			}
+			default:
+				{
+				}
+			}
+			}
+			break;
+		}
+		case '0':  case '1':  case '2':  case '3':
+		case '4':  case '5':  case '6':  case '7':
+		case '8':  case '9':
+		{
+			{
+			switch ( LA(1)) {
+			case '0':
+			{
+				match('0');
+				if ( inputState.guessing==0 ) {
+					isDecimal = true;
+				}
+				{
+				if ((LA(1)=='X'||LA(1)=='x')) {
+					{
+					switch ( LA(1)) {
+					case 'x':
+					{
+						match('x');
+						break;
+					}
+					case 'X':
+					{
+						match('X');
+						break;
+					}
+					default:
+					{
+						throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+					}
+					}
+					}
+					{
+					int _cnt406=0;
+					_loop406:
+					do {
+						if ((_tokenSet_4.member(LA(1))) && (true) && (true) && (true)) {
+							mHEX_DIGIT(false);
+						}
+						else {
+							if ( _cnt406>=1 ) { break _loop406; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());}
+						}
+						
+						_cnt406++;
+					} while (true);
+					}
+				}
+				else {
+					boolean synPredMatched411 = false;
+					if ((((LA(1) >= '0' && LA(1) <= '9')) && (true) && (true) && (true))) {
+						int _m411 = mark();
+						synPredMatched411 = true;
+						inputState.guessing++;
+						try {
+							{
+							{
+							int _cnt409=0;
+							_loop409:
+							do {
+								if (((LA(1) >= '0' && LA(1) <= '9'))) {
+									matchRange('0','9');
+								}
+								else {
+									if ( _cnt409>=1 ) { break _loop409; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());}
+								}
+								
+								_cnt409++;
+							} while (true);
+							}
+							{
+							switch ( LA(1)) {
+							case '.':
+							{
+								match('.');
+								break;
+							}
+							case 'E':  case 'e':
+							{
+								mEXPONENT(false);
+								break;
+							}
+							case 'D':  case 'F':  case 'd':  case 'f':
+							{
+								mFLOAT_SUFFIX(false);
+								break;
+							}
+							default:
+							{
+								throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+							}
+							}
+							}
+							}
+						}
+						catch (RecognitionException pe) {
+							synPredMatched411 = false;
+						}
+						rewind(_m411);
+						inputState.guessing--;
+					}
+					if ( synPredMatched411 ) {
+						{
+						int _cnt413=0;
+						_loop413:
+						do {
+							if (((LA(1) >= '0' && LA(1) <= '9'))) {
+								matchRange('0','9');
+							}
+							else {
+								if ( _cnt413>=1 ) { break _loop413; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());}
+							}
+							
+							_cnt413++;
+						} while (true);
+						}
+					}
+					else if (((LA(1) >= '0' && LA(1) <= '7')) && (true) && (true) && (true)) {
+						{
+						int _cnt415=0;
+						_loop415:
+						do {
+							if (((LA(1) >= '0' && LA(1) <= '7'))) {
+								matchRange('0','7');
+							}
+							else {
+								if ( _cnt415>=1 ) { break _loop415; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());}
+							}
+							
+							_cnt415++;
+						} while (true);
+						}
+					}
+					else {
+					}
+					}
+					}
+					break;
+				}
+				case '1':  case '2':  case '3':  case '4':
+				case '5':  case '6':  case '7':  case '8':
+				case '9':
+				{
+					{
+					matchRange('1','9');
+					}
+					{
+					_loop418:
+					do {
+						if (((LA(1) >= '0' && LA(1) <= '9'))) {
+							matchRange('0','9');
+						}
+						else {
+							break _loop418;
+						}
+						
+					} while (true);
+					}
+					if ( inputState.guessing==0 ) {
+						isDecimal=true;
+					}
+					break;
+				}
+				default:
+				{
+					throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+				}
+				}
+				}
+				{
+				if ((LA(1)=='L'||LA(1)=='l')) {
+					{
+					switch ( LA(1)) {
+					case 'l':
+					{
+						match('l');
+						break;
+					}
+					case 'L':
+					{
+						match('L');
+						break;
+					}
+					default:
+					{
+						throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+					}
+					}
+					}
+					if ( inputState.guessing==0 ) {
+						_ttype = NUM_LONG;
+					}
+				}
+				else if (((LA(1)=='.'||LA(1)=='D'||LA(1)=='E'||LA(1)=='F'||LA(1)=='d'||LA(1)=='e'||LA(1)=='f'))&&(isDecimal)) {
+					{
+					switch ( LA(1)) {
+					case '.':
+					{
+						match('.');
+						{
+						_loop423:
+						do {
+							if (((LA(1) >= '0' && LA(1) <= '9'))) {
+								matchRange('0','9');
+							}
+							else {
+								break _loop423;
+							}
+							
+						} while (true);
+						}
+						{
+						if ((LA(1)=='E'||LA(1)=='e')) {
+							mEXPONENT(false);
+						}
+						else {
+						}
+						
+						}
+						{
+						if ((LA(1)=='D'||LA(1)=='F'||LA(1)=='d'||LA(1)=='f')) {
+							mFLOAT_SUFFIX(true);
+							f2=_returnToken;
+							if ( inputState.guessing==0 ) {
+								t=f2;
+							}
+						}
+						else {
+						}
+						
+						}
+						break;
+					}
+					case 'E':  case 'e':
+					{
+						mEXPONENT(false);
+						{
+						if ((LA(1)=='D'||LA(1)=='F'||LA(1)=='d'||LA(1)=='f')) {
+							mFLOAT_SUFFIX(true);
+							f3=_returnToken;
+							if ( inputState.guessing==0 ) {
+								t=f3;
+							}
+						}
+						else {
+						}
+						
+						}
+						break;
+					}
+					case 'D':  case 'F':  case 'd':  case 'f':
+					{
+						mFLOAT_SUFFIX(true);
+						f4=_returnToken;
+						if ( inputState.guessing==0 ) {
+							t=f4;
+						}
+						break;
+					}
+					default:
+					{
+						throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+					}
+					}
+					}
+					if ( inputState.guessing==0 ) {
+						
+									if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {
+										_ttype = NUM_FLOAT;
+									}
+									else {
+										_ttype = NUM_DOUBLE; // assume double
+									}
+									
+					}
+				}
+				else {
+				}
+				
+				}
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+			}
+			}
+			if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+				_token = makeToken(_ttype);
+				_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+			}
+			_returnToken = _token;
+		}
+		
+	protected final void mEXPONENT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = EXPONENT;
+		int _saveIndex;
+		
+		{
+		switch ( LA(1)) {
+		case 'e':
+		{
+			match('e');
+			break;
+		}
+		case 'E':
+		{
+			match('E');
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+		}
+		}
+		}
+		{
+		switch ( LA(1)) {
+		case '+':
+		{
+			match('+');
+			break;
+		}
+		case '-':
+		{
+			match('-');
+			break;
+		}
+		case '0':  case '1':  case '2':  case '3':
+		case '4':  case '5':  case '6':  case '7':
+		case '8':  case '9':
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+		}
+		}
+		}
+		{
+		int _cnt432=0;
+		_loop432:
+		do {
+			if (((LA(1) >= '0' && LA(1) <= '9'))) {
+				matchRange('0','9');
+			}
+			else {
+				if ( _cnt432>=1 ) { break _loop432; } else {throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());}
+			}
+			
+			_cnt432++;
+		} while (true);
+		}
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	protected final void mFLOAT_SUFFIX(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = FLOAT_SUFFIX;
+		int _saveIndex;
+		
+		switch ( LA(1)) {
+		case 'f':
+		{
+			match('f');
+			break;
+		}
+		case 'F':
+		{
+			match('F');
+			break;
+		}
+		case 'd':
+		{
+			match('d');
+			break;
+		}
+		case 'D':
+		{
+			match('D');
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());
+		}
+		}
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	public final void mAT(boolean _createToken) throws RecognitionException, CharStreamException, TokenStreamException {
+		int _ttype; Token _token=null; int _begin=text.length();
+		_ttype = AT;
+		int _saveIndex;
+		
+		match('@');
+		if ( _createToken && _token==null && _ttype!=Token.SKIP ) {
+			_token = makeToken(_ttype);
+			_token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));
+		}
+		_returnToken = _token;
+	}
+	
+	
+	private static final long[] mk_tokenSet_0() {
+		long[] data = new long[2048];
+		data[0]=-9224L;
+		for (int i = 1; i<=1023; i++) { data[i]=-1L; }
+		return data;
+	}
+	public static final BitSet _tokenSet_0 = new BitSet(mk_tokenSet_0());
+	private static final long[] mk_tokenSet_1() {
+		long[] data = new long[2048];
+		data[0]=-4398046520328L;
+		for (int i = 1; i<=1023; i++) { data[i]=-1L; }
+		return data;
+	}
+	public static final BitSet _tokenSet_1 = new BitSet(mk_tokenSet_1());
+	private static final long[] mk_tokenSet_2() {
+		long[] data = new long[2048];
+		data[0]=-17179878408L;
+		data[1]=-268435457L;
+		for (int i = 2; i<=1023; i++) { data[i]=-1L; }
+		return data;
+	}
+	public static final BitSet _tokenSet_2 = new BitSet(mk_tokenSet_2());
+	private static final long[] mk_tokenSet_3() {
+		long[] data = new long[2048];
+		data[0]=-549755823112L;
+		data[1]=-268435457L;
+		for (int i = 2; i<=1023; i++) { data[i]=-1L; }
+		return data;
+	}
+	public static final BitSet _tokenSet_3 = new BitSet(mk_tokenSet_3());
+	private static final long[] mk_tokenSet_4() {
+		long[] data = new long[1025];
+		data[0]=287948901175001088L;
+		data[1]=541165879422L;
+		return data;
+	}
+	public static final BitSet _tokenSet_4 = new BitSet(mk_tokenSet_4());
+	
+	}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/java/JavaRecognizer.java b/groovy-core/src/main/org/codehaus/groovy/antlr/java/JavaRecognizer.java
new file mode 100644
index 0000000..a87cbb2
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/java/JavaRecognizer.java
@@ -0,0 +1,7686 @@
+// $ANTLR 2.7.2: "java.g" -> "JavaRecognizer.java"$
+
+package org.codehaus.groovy.antlr.java;
+import org.codehaus.groovy.antlr.*;
+import org.codehaus.groovy.antlr.parser.*;
+import java.util.*;
+import java.io.InputStream;
+import java.io.Reader;
+import antlr.InputBuffer;
+import antlr.LexerSharedInputState;
+
+import antlr.TokenBuffer;
+import antlr.TokenStreamException;
+import antlr.TokenStreamIOException;
+import antlr.ANTLRException;
+import antlr.LLkParser;
+import antlr.Token;
+import antlr.TokenStream;
+import antlr.RecognitionException;
+import antlr.NoViableAltException;
+import antlr.MismatchedTokenException;
+import antlr.SemanticException;
+import antlr.ParserSharedInputState;
+import antlr.collections.impl.BitSet;
+import antlr.collections.AST;
+import java.util.Hashtable;
+import antlr.ASTFactory;
+import antlr.ASTPair;
+import antlr.collections.impl.ASTArray;
+
+/** Java 1.5 Recognizer
+ *
+ * Run 'java Main [-showtree] directory-full-of-java-files'
+ *
+ * [The -showtree option pops up a Swing frame that shows
+ *  the AST constructed from the parser.]
+ *
+ * Run 'java Main <directory full of java files>'
+ *
+ * Contributing authors:
+ *      Jeremy Rayner       groovy@ross-rayner.com
+ *		John Mitchell		johnm@non.net
+ *		Terence Parr		parrt@magelang.com
+ *		John Lilley		jlilley@empathy.com
+ *		Scott Stanchfield	thetick@magelang.com
+ *		Markus Mohnen		mohnen@informatik.rwth-aachen.de
+ *		Peter Williams		pete.williams@sun.com
+ *		Allan Jacobs		Allan.Jacobs@eng.sun.com
+ *		Steve Messick		messick@redhills.com
+ *		John Pybus		john@pybus.org
+ *
+ * Version 1.00 December 9, 1997 -- initial release
+ * Version 1.01 December 10, 1997
+ *		fixed bug in octal def (0..7 not 0..8)
+ * Version 1.10 August 1998 (parrt)
+ *		added tree construction
+ *		fixed definition of WS,comments for mac,pc,unix newlines
+ *		added unary plus
+ * Version 1.11 (Nov 20, 1998)
+ *		Added "shutup" option to turn off last ambig warning.
+ *		Fixed inner class def to allow named class defs as statements
+ *		synchronized requires compound not simple statement
+ *		add [] after builtInType DOT class in primaryExpression
+ *		"const" is reserved but not valid..removed from modifiers
+ * Version 1.12 (Feb 2, 1999)
+ *		Changed LITERAL_xxx to xxx in tree grammar.
+ *		Updated java.g to use tokens {...} now for 2.6.0 (new feature).
+ *
+ * Version 1.13 (Apr 23, 1999)
+ *		Didn't have (stat)? for else clause in tree parser.
+ *		Didn't gen ASTs for interface extends.  Updated tree parser too.
+ *		Updated to 2.6.0.
+ * Version 1.14 (Jun 20, 1999)
+ *		Allowed final/abstract on local classes.
+ *		Removed local interfaces from methods
+ *		Put instanceof precedence where it belongs...in relationalExpr
+ *			It also had expr not type as arg; fixed it.
+ *		Missing ! on SEMI in classBlock
+ *		fixed: (expr) + "string" was parsed incorrectly (+ as unary plus).
+ *		fixed: didn't like Object[].class in parser or tree parser
+ * Version 1.15 (Jun 26, 1999)
+ *		Screwed up rule with instanceof in it. :(  Fixed.
+ *		Tree parser didn't like (expr).something; fixed.
+ *		Allowed multiple inheritance in tree grammar. oops.
+ * Version 1.16 (August 22, 1999)
+ *		Extending an interface built a wacky tree: had extra EXTENDS.
+ *		Tree grammar didn't allow multiple superinterfaces.
+ *		Tree grammar didn't allow empty var initializer: {}
+ * Version 1.17 (October 12, 1999)
+ *		ESC lexer rule allowed 399 max not 377 max.
+ *		java.tree.g didn't handle the expression of synchronized
+ *		statements.
+ * Version 1.18 (August 12, 2001)
+ *	  	Terence updated to Java 2 Version 1.3 by
+ *		observing/combining work of Allan Jacobs and Steve
+ *		Messick.  Handles 1.3 src.  Summary:
+ *		o  primary didn't include boolean.class kind of thing
+ *	  	o  constructor calls parsed explicitly now:
+ * 		   see explicitConstructorInvocation
+ *		o  add strictfp modifier
+ *	  	o  missing objBlock after new expression in tree grammar
+ *		o  merged local class definition alternatives, moved after declaration
+ *		o  fixed problem with ClassName.super.field
+ *	  	o  reordered some alternatives to make things more efficient
+ *		o  long and double constants were not differentiated from int/float
+ *		o  whitespace rule was inefficient: matched only one char
+ *		o  add an examples directory with some nasty 1.3 cases
+ *		o  made Main.java use buffered IO and a Reader for Unicode support
+ *		o  supports UNICODE?
+ *		   Using Unicode charVocabulay makes code file big, but only
+ *		   in the bitsets at the end. I need to make ANTLR generate
+ *		   unicode bitsets more efficiently.
+ * Version 1.19 (April 25, 2002)
+ *		Terence added in nice fixes by John Pybus concerning floating
+ *		constants and problems with super() calls.  John did a nice
+ *		reorg of the primary/postfix expression stuff to read better
+ *		and makes f.g.super() parse properly (it was METHOD_CALL not
+ *		a SUPER_CTOR_CALL).  Also:
+ *
+ *		o  "finally" clause was a root...made it a child of "try"
+ *		o  Added stuff for asserts too for Java 1.4, but *commented out*
+ *		   as it is not backward compatible.
+ *
+ * Version 1.20 (October 27, 2002)
+ *
+ *	  Terence ended up reorging John Pybus' stuff to
+ *	  remove some nondeterminisms and some syntactic predicates.
+ *	  Note that the grammar is stricter now; e.g., this(...) must
+ *	be the first statement.
+ *
+ *	  Trinary ?: operator wasn't working as array name:
+ *		  (isBig ? bigDigits : digits)[i];
+ *
+ *	  Checked parser/tree parser on source for
+ *		  Resin-2.0.5, jive-2.1.1, jdk 1.3.1, Lucene, antlr 2.7.2a4,
+ *		and the 110k-line jGuru server source.
+ *
+ * Version 1.21 (October 17, 2003)
+ *  Fixed lots of problems including:
+ *  Ray Waldin: add typeDefinition to interfaceBlock in java.tree.g
+ *  He found a problem/fix with floating point that start with 0
+ *  Ray also fixed problem that (int.class) was not recognized.
+ *  Thorsten van Ellen noticed that \n are allowed incorrectly in strings.
+ *  TJP fixed CHAR_LITERAL analogously.
+ *
+ * Version 1.21.2 (March, 2003)
+ *	  Changes by Matt Quail to support generics (as per JDK1.5/JSR14)
+ *	  Notes:
+ *	  o We only allow the "extends" keyword and not the "implements"
+ *		keyword, since thats what JSR14 seems to imply.
+ *	  o Thanks to Monty Zukowski for his help on the antlr-interest
+ *		mail list.
+ *	  o Thanks to Alan Eliasen for testing the grammar over his
+ *		Fink source base
+ *
+ * Version 1.22 (July, 2004)
+ *	  Changes by Michael Studman to support Java 1.5 language extensions
+ *	  Notes:
+ *	  o Added support for annotations types
+ *	  o Finished off Matt Quail's generics enhancements to support bound type arguments
+ *	  o Added support for new for statement syntax
+ *	  o Added support for static import syntax
+ *	  o Added support for enum types
+ *	  o Tested against JDK 1.5 source base and source base of jdigraph project
+ *	  o Thanks to Matt Quail for doing the hard part by doing most of the generics work
+ *
+ * Version 1.22.1 (July 28, 2004)
+ *	  Bug/omission fixes for Java 1.5 language support
+ *	  o Fixed tree structure bug with classOrInterface - thanks to Pieter Vangorpto for
+ *		spotting this
+ *	  o Fixed bug where incorrect handling of SR and BSR tokens would cause type
+ *		parameters to be recognised as type arguments.
+ *	  o Enabled type parameters on constructors, annotations on enum constants
+ *		and package definitions
+ *	  o Fixed problems when parsing if ((char.class.equals(c))) {} - solution by Matt Quail at Cenqua
+ *
+ * Version 1.22.2 (July 28, 2004)
+ *	  Slight refactoring of Java 1.5 language support
+ *	  o Refactored for/"foreach" productions so that original literal "for" literal
+ *	    is still used but the for sub-clauses vary by token type
+ *	  o Fixed bug where type parameter was not included in generic constructor's branch of AST
+ *
+ * Version 1.22.3 (August 26, 2004)
+ *	  Bug fixes as identified by Michael Stahl; clean up of tabs/spaces
+ *        and other refactorings
+ *	  o Fixed typeParameters omission in identPrimary and newStatement
+ *	  o Replaced GT reconcilliation code with simple semantic predicate
+ *	  o Adapted enum/assert keyword checking support from Michael Stahl's java15 grammar
+ *	  o Refactored typeDefinition production and field productions to reduce duplication
+ *
+ * Version 1.22.4 (October 21, 2004)
+ *    Small bux fixes
+ *    o Added typeArguments to explicitConstructorInvocation, e.g. new <String>MyParameterised()
+ *    o Added typeArguments to postfixExpression productions for anonymous inner class super
+ *      constructor invocation, e.g. new Outer().<String>super()
+ *    o Fixed bug in array declarations identified by Geoff Roy
+ *
+ * Version 1.22.4.j.1
+ *	  Changes by Jeremy Rayner to support java2groovy tool
+ *    o I have taken java.g for Java1.5 from Michael Studman (1.22.4)
+ *      and have made some changes to enable use by java2groovy tool (Jan 2007)
+ *
+ * This grammar is in the PUBLIC DOMAIN
+ */
+public class JavaRecognizer extends antlr.LLkParser       implements JavaTokenTypes
+ {
+
+    /** This factory is the correct way to wire together a Groovy parser and lexer. */
+    public static JavaRecognizer make(JavaLexer lexer) {
+        JavaRecognizer parser = new JavaRecognizer(lexer.plumb());
+        // TODO: set up a common error-handling control block, to avoid excessive tangle between these guys
+        parser.lexer = lexer;
+        lexer.parser = parser;
+        parser.setASTNodeClass("org.codehaus.groovy.antlr.GroovySourceAST");
+        return parser;
+    }
+    // Create a scanner that reads from the input stream passed to us...
+    public static JavaRecognizer make(InputStream in) { return make(new JavaLexer(in)); }
+    public static JavaRecognizer make(Reader in) { return make(new JavaLexer(in)); }
+    public static JavaRecognizer make(InputBuffer in) { return make(new JavaLexer(in)); }
+    public static JavaRecognizer make(LexerSharedInputState in) { return make(new JavaLexer(in)); }
+    
+    private static GroovySourceAST dummyVariableToforceClassLoaderToFindASTClass = new GroovySourceAST();
+    
+    JavaLexer lexer;
+    public JavaLexer getLexer() { return lexer; }
+    public void setFilename(String f) { super.setFilename(f); lexer.setFilename(f); }
+    private SourceBuffer sourceBuffer;
+    public void setSourceBuffer(SourceBuffer sourceBuffer) {
+        this.sourceBuffer = sourceBuffer;
+    }
+
+    /** Create an AST node with the token type and text passed in, but
+     *  with the same background information as another supplied Token (e.g. line numbers)
+     * to be used in place of antlr tree construction syntax,
+     * i.e. #[TOKEN,"text"]  becomes  create(TOKEN,"text",anotherToken)
+     *
+     * todo - change antlr.ASTFactory to do this instead...
+     */
+    public AST create(int type, String txt, Token first, Token last) {
+        AST t = astFactory.create(type,txt);
+        if ( t != null && first != null) {
+            // first copy details from first token
+            t.initialize(first);
+            // then ensure that type and txt are specific to this new node
+            t.initialize(type,txt);
+        }
+
+        if ((t instanceof GroovySourceAST) && last != null) {
+            GroovySourceAST node = (GroovySourceAST)t;
+            node.setLast(last);
+            // This is a good point to call node.setSnippet(),
+            // but it bulks up the AST too much for production code.
+        }
+        return t;
+    }
+
+    
+    /**
+	 * Counts the number of LT seen in the typeArguments production.
+	 * It is used in semantic predicates to ensure we have seen
+	 * enough closing '>' characters; which actually may have been
+	 * either GT, SR or BSR tokens.
+	 */
+	private int ltCounter = 0;
+
+protected JavaRecognizer(TokenBuffer tokenBuf, int k) {
+  super(tokenBuf,k);
+  tokenNames = _tokenNames;
+  buildTokenTypeASTClassMap();
+  astFactory = new ASTFactory(getTokenTypeToASTClassMap());
+}
+
+public JavaRecognizer(TokenBuffer tokenBuf) {
+  this(tokenBuf,2);
+}
+
+protected JavaRecognizer(TokenStream lexer, int k) {
+  super(lexer,k);
+  tokenNames = _tokenNames;
+  buildTokenTypeASTClassMap();
+  astFactory = new ASTFactory(getTokenTypeToASTClassMap());
+}
+
+public JavaRecognizer(TokenStream lexer) {
+  this(lexer,2);
+}
+
+public JavaRecognizer(ParserSharedInputState state) {
+  super(state,2);
+  tokenNames = _tokenNames;
+  buildTokenTypeASTClassMap();
+  astFactory = new ASTFactory(getTokenTypeToASTClassMap());
+}
+
+	public final void compilationUnit() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST compilationUnit_AST = null;
+		
+		{
+		boolean synPredMatched4 = false;
+		if (((LA(1)==LITERAL_package||LA(1)==AT) && (LA(2)==IDENT))) {
+			int _m4 = mark();
+			synPredMatched4 = true;
+			inputState.guessing++;
+			try {
+				{
+				annotations();
+				match(LITERAL_package);
+				}
+			}
+			catch (RecognitionException pe) {
+				synPredMatched4 = false;
+			}
+			rewind(_m4);
+			inputState.guessing--;
+		}
+		if ( synPredMatched4 ) {
+			packageDefinition();
+			astFactory.addASTChild(currentAST, returnAST);
+		}
+		else if ((_tokenSet_0.member(LA(1))) && (_tokenSet_1.member(LA(2)))) {
+		}
+		else {
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		
+		}
+		{
+		_loop6:
+		do {
+			if ((LA(1)==LITERAL_import)) {
+				importDefinition();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop6;
+			}
+			
+		} while (true);
+		}
+		{
+		_loop8:
+		do {
+			if ((_tokenSet_2.member(LA(1)))) {
+				typeDefinition();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop8;
+			}
+			
+		} while (true);
+		}
+		match(Token.EOF_TYPE);
+		compilationUnit_AST = (AST)currentAST.root;
+		returnAST = compilationUnit_AST;
+	}
+	
+	public final void annotations() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST annotations_AST = null;
+		Token first = LT(1);
+		
+		{
+		_loop62:
+		do {
+			if ((LA(1)==AT)) {
+				annotation();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop62;
+			}
+			
+		} while (true);
+		}
+		if ( inputState.guessing==0 ) {
+			annotations_AST = (AST)currentAST.root;
+			annotations_AST = (AST)astFactory.make( (new ASTArray(2)).add(astFactory.create(ANNOTATIONS,"ANNOTATIONS")).add(annotations_AST));
+			currentAST.root = annotations_AST;
+			currentAST.child = annotations_AST!=null &&annotations_AST.getFirstChild()!=null ?
+				annotations_AST.getFirstChild() : annotations_AST;
+			currentAST.advanceChildToEnd();
+		}
+		annotations_AST = (AST)currentAST.root;
+		returnAST = annotations_AST;
+	}
+	
+	public final void packageDefinition() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST packageDefinition_AST = null;
+		Token  p = null;
+		AST p_AST = null;
+		
+		try {      // for error handling
+			annotations();
+			astFactory.addASTChild(currentAST, returnAST);
+			p = LT(1);
+			p_AST = astFactory.create(p);
+			astFactory.makeASTRoot(currentAST, p_AST);
+			match(LITERAL_package);
+			if ( inputState.guessing==0 ) {
+				p_AST.setType(PACKAGE_DEF);
+			}
+			identifier();
+			astFactory.addASTChild(currentAST, returnAST);
+			match(SEMI);
+			packageDefinition_AST = (AST)currentAST.root;
+		}
+		catch (RecognitionException ex) {
+			if (inputState.guessing==0) {
+				reportError(ex);
+				consume();
+				consumeUntil(_tokenSet_0);
+			} else {
+			  throw ex;
+			}
+		}
+		returnAST = packageDefinition_AST;
+	}
+	
+	public final void importDefinition() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST importDefinition_AST = null;
+		Token  i = null;
+		AST i_AST = null;
+		boolean isStatic = false;
+		
+		try {      // for error handling
+			i = LT(1);
+			i_AST = astFactory.create(i);
+			astFactory.makeASTRoot(currentAST, i_AST);
+			match(LITERAL_import);
+			if ( inputState.guessing==0 ) {
+				i_AST.setType(IMPORT);
+			}
+			{
+			switch ( LA(1)) {
+			case LITERAL_static:
+			{
+				match(LITERAL_static);
+				if ( inputState.guessing==0 ) {
+					i_AST.setType(STATIC_IMPORT);
+				}
+				break;
+			}
+			case IDENT:
+			{
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+			}
+			identifierStar();
+			astFactory.addASTChild(currentAST, returnAST);
+			match(SEMI);
+			importDefinition_AST = (AST)currentAST.root;
+		}
+		catch (RecognitionException ex) {
+			if (inputState.guessing==0) {
+				reportError(ex);
+				consume();
+				consumeUntil(_tokenSet_0);
+			} else {
+			  throw ex;
+			}
+		}
+		returnAST = importDefinition_AST;
+	}
+	
+	public final void typeDefinition() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST typeDefinition_AST = null;
+		AST m_AST = null;
+		
+		try {      // for error handling
+			switch ( LA(1)) {
+			case FINAL:
+			case ABSTRACT:
+			case STRICTFP:
+			case LITERAL_static:
+			case LITERAL_private:
+			case LITERAL_public:
+			case LITERAL_protected:
+			case LITERAL_transient:
+			case LITERAL_native:
+			case LITERAL_threadsafe:
+			case LITERAL_synchronized:
+			case LITERAL_volatile:
+			case AT:
+			case LITERAL_class:
+			case LITERAL_interface:
+			case LITERAL_enum:
+			{
+				modifiers();
+				m_AST = (AST)returnAST;
+				typeDefinitionInternal(m_AST);
+				astFactory.addASTChild(currentAST, returnAST);
+				typeDefinition_AST = (AST)currentAST.root;
+				break;
+			}
+			case SEMI:
+			{
+				match(SEMI);
+				typeDefinition_AST = (AST)currentAST.root;
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+		}
+		catch (RecognitionException ex) {
+			if (inputState.guessing==0) {
+				reportError(ex);
+				consume();
+				consumeUntil(_tokenSet_3);
+			} else {
+			  throw ex;
+			}
+		}
+		returnAST = typeDefinition_AST;
+	}
+	
+	public final void identifier() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST identifier_AST = null;
+		
+		AST tmp6_AST = null;
+		tmp6_AST = astFactory.create(LT(1));
+		astFactory.addASTChild(currentAST, tmp6_AST);
+		match(IDENT);
+		{
+		_loop48:
+		do {
+			if ((LA(1)==DOT)) {
+				AST tmp7_AST = null;
+				tmp7_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp7_AST);
+				match(DOT);
+				AST tmp8_AST = null;
+				tmp8_AST = astFactory.create(LT(1));
+				astFactory.addASTChild(currentAST, tmp8_AST);
+				match(IDENT);
+			}
+			else {
+				break _loop48;
+			}
+			
+		} while (true);
+		}
+		identifier_AST = (AST)currentAST.root;
+		returnAST = identifier_AST;
+	}
+	
+	public final void identifierStar() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST identifierStar_AST = null;
+		
+		AST tmp9_AST = null;
+		tmp9_AST = astFactory.create(LT(1));
+		astFactory.addASTChild(currentAST, tmp9_AST);
+		match(IDENT);
+		{
+		_loop51:
+		do {
+			if ((LA(1)==DOT) && (LA(2)==IDENT)) {
+				AST tmp10_AST = null;
+				tmp10_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp10_AST);
+				match(DOT);
+				AST tmp11_AST = null;
+				tmp11_AST = astFactory.create(LT(1));
+				astFactory.addASTChild(currentAST, tmp11_AST);
+				match(IDENT);
+			}
+			else {
+				break _loop51;
+			}
+			
+		} while (true);
+		}
+		{
+		switch ( LA(1)) {
+		case DOT:
+		{
+			AST tmp12_AST = null;
+			tmp12_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp12_AST);
+			match(DOT);
+			AST tmp13_AST = null;
+			tmp13_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp13_AST);
+			match(STAR);
+			break;
+		}
+		case SEMI:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		identifierStar_AST = (AST)currentAST.root;
+		returnAST = identifierStar_AST;
+	}
+	
+	public final void modifiers() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST modifiers_AST = null;
+		Token first = LT(1);
+		
+		{
+		_loop55:
+		do {
+			if ((_tokenSet_4.member(LA(1)))) {
+				modifier();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else if (((LA(1)==AT) && (LA(2)==IDENT))&&(LA(1)==AT && !LT(2).getText().equals("interface"))) {
+				annotation();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop55;
+			}
+			
+		} while (true);
+		}
+		if ( inputState.guessing==0 ) {
+			modifiers_AST = (AST)currentAST.root;
+			modifiers_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(MODIFIERS,"MODIFIERS",first,LT(1))).add(modifiers_AST));
+			currentAST.root = modifiers_AST;
+			currentAST.child = modifiers_AST!=null &&modifiers_AST.getFirstChild()!=null ?
+				modifiers_AST.getFirstChild() : modifiers_AST;
+			currentAST.advanceChildToEnd();
+		}
+		modifiers_AST = (AST)currentAST.root;
+		returnAST = modifiers_AST;
+	}
+	
+	protected final void typeDefinitionInternal(
+		AST mods
+	) throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST typeDefinitionInternal_AST = null;
+		
+		switch ( LA(1)) {
+		case LITERAL_class:
+		{
+			classDefinition(mods);
+			astFactory.addASTChild(currentAST, returnAST);
+			typeDefinitionInternal_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_interface:
+		{
+			interfaceDefinition(mods);
+			astFactory.addASTChild(currentAST, returnAST);
+			typeDefinitionInternal_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_enum:
+		{
+			enumDefinition(mods);
+			astFactory.addASTChild(currentAST, returnAST);
+			typeDefinitionInternal_AST = (AST)currentAST.root;
+			break;
+		}
+		case AT:
+		{
+			annotationDefinition(mods);
+			astFactory.addASTChild(currentAST, returnAST);
+			typeDefinitionInternal_AST = (AST)currentAST.root;
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		returnAST = typeDefinitionInternal_AST;
+	}
+	
+	public final void classDefinition(
+		AST modifiers
+	) throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST classDefinition_AST = null;
+		AST tp_AST = null;
+		AST sc_AST = null;
+		AST ic_AST = null;
+		AST cb_AST = null;
+		Token first = LT(1);
+		
+		match(LITERAL_class);
+		AST tmp15_AST = null;
+		tmp15_AST = astFactory.create(LT(1));
+		match(IDENT);
+		{
+		switch ( LA(1)) {
+		case LT:
+		{
+			typeParameters();
+			tp_AST = (AST)returnAST;
+			break;
+		}
+		case LITERAL_extends:
+		case LCURLY:
+		case LITERAL_implements:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		superClassClause();
+		sc_AST = (AST)returnAST;
+		implementsClause();
+		ic_AST = (AST)returnAST;
+		classBlock();
+		cb_AST = (AST)returnAST;
+		if ( inputState.guessing==0 ) {
+			classDefinition_AST = (AST)currentAST.root;
+			classDefinition_AST = (AST)astFactory.make( (new ASTArray(7)).add(create(CLASS_DEF,"CLASS_DEF",first,LT(1))).add(modifiers).add(tmp15_AST).add(tp_AST).add(sc_AST).add(ic_AST).add(cb_AST));
+			currentAST.root = classDefinition_AST;
+			currentAST.child = classDefinition_AST!=null &&classDefinition_AST.getFirstChild()!=null ?
+				classDefinition_AST.getFirstChild() : classDefinition_AST;
+			currentAST.advanceChildToEnd();
+		}
+		returnAST = classDefinition_AST;
+	}
+	
+	public final void interfaceDefinition(
+		AST modifiers
+	) throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST interfaceDefinition_AST = null;
+		AST tp_AST = null;
+		AST ie_AST = null;
+		AST ib_AST = null;
+		Token first = LT(1);
+		
+		match(LITERAL_interface);
+		AST tmp17_AST = null;
+		tmp17_AST = astFactory.create(LT(1));
+		match(IDENT);
+		{
+		switch ( LA(1)) {
+		case LT:
+		{
+			typeParameters();
+			tp_AST = (AST)returnAST;
+			break;
+		}
+		case LITERAL_extends:
+		case LCURLY:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		interfaceExtends();
+		ie_AST = (AST)returnAST;
+		interfaceBlock();
+		ib_AST = (AST)returnAST;
+		if ( inputState.guessing==0 ) {
+			interfaceDefinition_AST = (AST)currentAST.root;
+			interfaceDefinition_AST = (AST)astFactory.make( (new ASTArray(6)).add(create(INTERFACE_DEF,"INTERFACE_DEF",first,LT(1))).add(modifiers).add(tmp17_AST).add(tp_AST).add(ie_AST).add(ib_AST));
+			currentAST.root = interfaceDefinition_AST;
+			currentAST.child = interfaceDefinition_AST!=null &&interfaceDefinition_AST.getFirstChild()!=null ?
+				interfaceDefinition_AST.getFirstChild() : interfaceDefinition_AST;
+			currentAST.advanceChildToEnd();
+		}
+		returnAST = interfaceDefinition_AST;
+	}
+	
+	public final void enumDefinition(
+		AST modifiers
+	) throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST enumDefinition_AST = null;
+		AST ic_AST = null;
+		AST eb_AST = null;
+		Token first = LT(1);
+		
+		match(LITERAL_enum);
+		AST tmp19_AST = null;
+		tmp19_AST = astFactory.create(LT(1));
+		match(IDENT);
+		implementsClause();
+		ic_AST = (AST)returnAST;
+		enumBlock();
+		eb_AST = (AST)returnAST;
+		if ( inputState.guessing==0 ) {
+			enumDefinition_AST = (AST)currentAST.root;
+			enumDefinition_AST = (AST)astFactory.make( (new ASTArray(5)).add(create(ENUM_DEF,"ENUM_DEF",first,LT(1))).add(modifiers).add(tmp19_AST).add(ic_AST).add(eb_AST));
+			currentAST.root = enumDefinition_AST;
+			currentAST.child = enumDefinition_AST!=null &&enumDefinition_AST.getFirstChild()!=null ?
+				enumDefinition_AST.getFirstChild() : enumDefinition_AST;
+			currentAST.advanceChildToEnd();
+		}
+		returnAST = enumDefinition_AST;
+	}
+	
+	public final void annotationDefinition(
+		AST modifiers
+	) throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST annotationDefinition_AST = null;
+		AST ab_AST = null;
+		Token first = LT(1);
+		
+		AST tmp20_AST = null;
+		tmp20_AST = astFactory.create(LT(1));
+		match(AT);
+		match(LITERAL_interface);
+		AST tmp22_AST = null;
+		tmp22_AST = astFactory.create(LT(1));
+		match(IDENT);
+		annotationBlock();
+		ab_AST = (AST)returnAST;
+		if ( inputState.guessing==0 ) {
+			annotationDefinition_AST = (AST)currentAST.root;
+			annotationDefinition_AST = (AST)astFactory.make( (new ASTArray(4)).add(create(ANNOTATION_DEF,"ANNOTATION_DEF",first,LT(1))).add(modifiers).add(tmp22_AST).add(ab_AST));
+			currentAST.root = annotationDefinition_AST;
+			currentAST.child = annotationDefinition_AST!=null &&annotationDefinition_AST.getFirstChild()!=null ?
+				annotationDefinition_AST.getFirstChild() : annotationDefinition_AST;
+			currentAST.advanceChildToEnd();
+		}
+		returnAST = annotationDefinition_AST;
+	}
+	
+	public final void declaration() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST declaration_AST = null;
+		AST m_AST = null;
+		AST t_AST = null;
+		AST v_AST = null;
+		
+		modifiers();
+		m_AST = (AST)returnAST;
+		typeSpec(false);
+		t_AST = (AST)returnAST;
+		variableDefinitions(m_AST,t_AST);
+		v_AST = (AST)returnAST;
+		if ( inputState.guessing==0 ) {
+			declaration_AST = (AST)currentAST.root;
+			declaration_AST = v_AST;
+			currentAST.root = declaration_AST;
+			currentAST.child = declaration_AST!=null &&declaration_AST.getFirstChild()!=null ?
+				declaration_AST.getFirstChild() : declaration_AST;
+			currentAST.advanceChildToEnd();
+		}
+		returnAST = declaration_AST;
+	}
+	
+	public final void typeSpec(
+		boolean addImagNode
+	) throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST typeSpec_AST = null;
+		
+		switch ( LA(1)) {
+		case IDENT:
+		{
+			classTypeSpec(addImagNode);
+			astFactory.addASTChild(currentAST, returnAST);
+			typeSpec_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		{
+			builtInTypeSpec(addImagNode);
+			astFactory.addASTChild(currentAST, returnAST);
+			typeSpec_AST = (AST)currentAST.root;
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		returnAST = typeSpec_AST;
+	}
+	
+	public final void variableDefinitions(
+		AST mods, AST t
+	) throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST variableDefinitions_AST = null;
+		
+		variableDeclarator(getASTFactory().dupTree(mods),
+							getASTFactory().dupTree(t));
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop155:
+		do {
+			if ((LA(1)==COMMA)) {
+				match(COMMA);
+				variableDeclarator(getASTFactory().dupTree(mods),
+							getASTFactory().dupTree(t));
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop155;
+			}
+			
+		} while (true);
+		}
+		variableDefinitions_AST = (AST)currentAST.root;
+		returnAST = variableDefinitions_AST;
+	}
+	
+	public final void classTypeSpec(
+		boolean addImagNode
+	) throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST classTypeSpec_AST = null;
+		Token  lb = null;
+		AST lb_AST = null;
+		Token first = LT(1);
+		
+		classOrInterfaceType(false);
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop18:
+		do {
+			if ((LA(1)==LBRACK) && (LA(2)==RBRACK)) {
+				lb = LT(1);
+				lb_AST = astFactory.create(lb);
+				astFactory.makeASTRoot(currentAST, lb_AST);
+				match(LBRACK);
+				if ( inputState.guessing==0 ) {
+					lb_AST.setType(ARRAY_DECLARATOR);
+				}
+				match(RBRACK);
+			}
+			else {
+				break _loop18;
+			}
+			
+		} while (true);
+		}
+		if ( inputState.guessing==0 ) {
+			classTypeSpec_AST = (AST)currentAST.root;
+			
+						if ( addImagNode ) {
+							classTypeSpec_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(TYPE,"TYPE",first,LT(1))).add(classTypeSpec_AST));
+						}
+					
+			currentAST.root = classTypeSpec_AST;
+			currentAST.child = classTypeSpec_AST!=null &&classTypeSpec_AST.getFirstChild()!=null ?
+				classTypeSpec_AST.getFirstChild() : classTypeSpec_AST;
+			currentAST.advanceChildToEnd();
+		}
+		classTypeSpec_AST = (AST)currentAST.root;
+		returnAST = classTypeSpec_AST;
+	}
+	
+	public final void builtInTypeSpec(
+		boolean addImagNode
+	) throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST builtInTypeSpec_AST = null;
+		Token  lb = null;
+		AST lb_AST = null;
+		Token first = LT(1);
+		
+		builtInType();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop43:
+		do {
+			if ((LA(1)==LBRACK)) {
+				lb = LT(1);
+				lb_AST = astFactory.create(lb);
+				astFactory.makeASTRoot(currentAST, lb_AST);
+				match(LBRACK);
+				if ( inputState.guessing==0 ) {
+					lb_AST.setType(ARRAY_DECLARATOR);
+				}
+				match(RBRACK);
+			}
+			else {
+				break _loop43;
+			}
+			
+		} while (true);
+		}
+		if ( inputState.guessing==0 ) {
+			builtInTypeSpec_AST = (AST)currentAST.root;
+			
+						if ( addImagNode ) {
+							builtInTypeSpec_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(TYPE,"TYPE",first,LT(1))).add(builtInTypeSpec_AST));
+						}
+					
+			currentAST.root = builtInTypeSpec_AST;
+			currentAST.child = builtInTypeSpec_AST!=null &&builtInTypeSpec_AST.getFirstChild()!=null ?
+				builtInTypeSpec_AST.getFirstChild() : builtInTypeSpec_AST;
+			currentAST.advanceChildToEnd();
+		}
+		builtInTypeSpec_AST = (AST)currentAST.root;
+		returnAST = builtInTypeSpec_AST;
+	}
+	
+	public final void classOrInterfaceType(
+		boolean addImagNode
+	) throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST classOrInterfaceType_AST = null;
+		Token first = LT(1);
+		
+		AST tmp26_AST = null;
+		tmp26_AST = astFactory.create(LT(1));
+		astFactory.makeASTRoot(currentAST, tmp26_AST);
+		match(IDENT);
+		{
+		switch ( LA(1)) {
+		case LT:
+		{
+			typeArguments();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		case SEMI:
+		case LBRACK:
+		case RBRACK:
+		case IDENT:
+		case DOT:
+		case QUESTION:
+		case LITERAL_extends:
+		case LITERAL_super:
+		case COMMA:
+		case GT:
+		case SR:
+		case BSR:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		case LPAREN:
+		case RPAREN:
+		case ASSIGN:
+		case LCURLY:
+		case RCURLY:
+		case BAND:
+		case LITERAL_implements:
+		case LITERAL_this:
+		case TRIPLE_DOT:
+		case COLON:
+		case PLUS_ASSIGN:
+		case MINUS_ASSIGN:
+		case STAR_ASSIGN:
+		case DIV_ASSIGN:
+		case MOD_ASSIGN:
+		case SR_ASSIGN:
+		case BSR_ASSIGN:
+		case SL_ASSIGN:
+		case BAND_ASSIGN:
+		case BXOR_ASSIGN:
+		case BOR_ASSIGN:
+		case LOR:
+		case LAND:
+		case BOR:
+		case BXOR:
+		case NOT_EQUAL:
+		case EQUAL:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		{
+		_loop23:
+		do {
+			if ((LA(1)==DOT) && (LA(2)==IDENT)) {
+				AST tmp27_AST = null;
+				tmp27_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp27_AST);
+				match(DOT);
+				AST tmp28_AST = null;
+				tmp28_AST = astFactory.create(LT(1));
+				astFactory.addASTChild(currentAST, tmp28_AST);
+				match(IDENT);
+				{
+				switch ( LA(1)) {
+				case LT:
+				{
+					typeArguments();
+					astFactory.addASTChild(currentAST, returnAST);
+					break;
+				}
+				case SEMI:
+				case LBRACK:
+				case RBRACK:
+				case IDENT:
+				case DOT:
+				case QUESTION:
+				case LITERAL_extends:
+				case LITERAL_super:
+				case COMMA:
+				case GT:
+				case SR:
+				case BSR:
+				case LITERAL_void:
+				case LITERAL_boolean:
+				case LITERAL_byte:
+				case LITERAL_char:
+				case LITERAL_short:
+				case LITERAL_int:
+				case LITERAL_float:
+				case LITERAL_long:
+				case LITERAL_double:
+				case LPAREN:
+				case RPAREN:
+				case ASSIGN:
+				case LCURLY:
+				case RCURLY:
+				case BAND:
+				case LITERAL_implements:
+				case LITERAL_this:
+				case TRIPLE_DOT:
+				case COLON:
+				case PLUS_ASSIGN:
+				case MINUS_ASSIGN:
+				case STAR_ASSIGN:
+				case DIV_ASSIGN:
+				case MOD_ASSIGN:
+				case SR_ASSIGN:
+				case BSR_ASSIGN:
+				case SL_ASSIGN:
+				case BAND_ASSIGN:
+				case BXOR_ASSIGN:
+				case BOR_ASSIGN:
+				case LOR:
+				case LAND:
+				case BOR:
+				case BXOR:
+				case NOT_EQUAL:
+				case EQUAL:
+				{
+					break;
+				}
+				default:
+				{
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				}
+				}
+			}
+			else {
+				break _loop23;
+			}
+			
+		} while (true);
+		}
+		if ( inputState.guessing==0 ) {
+			classOrInterfaceType_AST = (AST)currentAST.root;
+			
+						if ( addImagNode ) {
+							classOrInterfaceType_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(TYPE,"TYPE",first,LT(1))).add(classOrInterfaceType_AST));
+						}
+					
+			currentAST.root = classOrInterfaceType_AST;
+			currentAST.child = classOrInterfaceType_AST!=null &&classOrInterfaceType_AST.getFirstChild()!=null ?
+				classOrInterfaceType_AST.getFirstChild() : classOrInterfaceType_AST;
+			currentAST.advanceChildToEnd();
+		}
+		classOrInterfaceType_AST = (AST)currentAST.root;
+		returnAST = classOrInterfaceType_AST;
+	}
+	
+	public final void typeArguments() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST typeArguments_AST = null;
+		int currentLtLevel = 0;  Token first = LT(1);
+		
+		if ( inputState.guessing==0 ) {
+			currentLtLevel = ltCounter;
+		}
+		match(LT);
+		if ( inputState.guessing==0 ) {
+			ltCounter++;
+		}
+		typeArgument();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop33:
+		do {
+			if (((LA(1)==COMMA) && (_tokenSet_5.member(LA(2))))&&(inputState.guessing !=0 || ltCounter == currentLtLevel + 1)) {
+				match(COMMA);
+				typeArgument();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop33;
+			}
+			
+		} while (true);
+		}
+		{
+		if (((LA(1) >= GT && LA(1) <= BSR)) && (_tokenSet_6.member(LA(2)))) {
+			typeArgumentsOrParametersEnd();
+			astFactory.addASTChild(currentAST, returnAST);
+		}
+		else if ((_tokenSet_6.member(LA(1))) && (_tokenSet_7.member(LA(2)))) {
+		}
+		else {
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		
+		}
+		if (!((currentLtLevel != 0) || ltCounter == currentLtLevel))
+		  throw new SemanticException("(currentLtLevel != 0) || ltCounter == currentLtLevel");
+		if ( inputState.guessing==0 ) {
+			typeArguments_AST = (AST)currentAST.root;
+			typeArguments_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(TYPE_ARGUMENTS,"TYPE_ARGUMENTS",first,LT(1))).add(typeArguments_AST));
+			currentAST.root = typeArguments_AST;
+			currentAST.child = typeArguments_AST!=null &&typeArguments_AST.getFirstChild()!=null ?
+				typeArguments_AST.getFirstChild() : typeArguments_AST;
+			currentAST.advanceChildToEnd();
+		}
+		typeArguments_AST = (AST)currentAST.root;
+		returnAST = typeArguments_AST;
+	}
+	
+	public final void typeArgumentSpec() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST typeArgumentSpec_AST = null;
+		
+		switch ( LA(1)) {
+		case IDENT:
+		{
+			classTypeSpec(true);
+			astFactory.addASTChild(currentAST, returnAST);
+			typeArgumentSpec_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		{
+			builtInTypeArraySpec(true);
+			astFactory.addASTChild(currentAST, returnAST);
+			typeArgumentSpec_AST = (AST)currentAST.root;
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		returnAST = typeArgumentSpec_AST;
+	}
+	
+	public final void builtInTypeArraySpec(
+		boolean addImagNode
+	) throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST builtInTypeArraySpec_AST = null;
+		Token  lb = null;
+		AST lb_AST = null;
+		Token first = LT(1);
+		
+		builtInType();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		int _cnt40=0;
+		_loop40:
+		do {
+			if ((LA(1)==LBRACK) && (LA(2)==RBRACK)) {
+				lb = LT(1);
+				lb_AST = astFactory.create(lb);
+				astFactory.makeASTRoot(currentAST, lb_AST);
+				match(LBRACK);
+				if ( inputState.guessing==0 ) {
+					lb_AST.setType(ARRAY_DECLARATOR);
+				}
+				match(RBRACK);
+			}
+			else {
+				if ( _cnt40>=1 ) { break _loop40; } else {throw new NoViableAltException(LT(1), getFilename());}
+			}
+			
+			_cnt40++;
+		} while (true);
+		}
+		if ( inputState.guessing==0 ) {
+			builtInTypeArraySpec_AST = (AST)currentAST.root;
+			
+						if ( addImagNode ) {
+							builtInTypeArraySpec_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(TYPE,"TYPE",first,LT(1))).add(builtInTypeArraySpec_AST));
+						}
+					
+			currentAST.root = builtInTypeArraySpec_AST;
+			currentAST.child = builtInTypeArraySpec_AST!=null &&builtInTypeArraySpec_AST.getFirstChild()!=null ?
+				builtInTypeArraySpec_AST.getFirstChild() : builtInTypeArraySpec_AST;
+			currentAST.advanceChildToEnd();
+		}
+		builtInTypeArraySpec_AST = (AST)currentAST.root;
+		returnAST = builtInTypeArraySpec_AST;
+	}
+	
+	public final void typeArgument() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST typeArgument_AST = null;
+		Token first = LT(1);
+		
+		{
+		switch ( LA(1)) {
+		case IDENT:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		{
+			typeArgumentSpec();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		case QUESTION:
+		{
+			wildcardType();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		if ( inputState.guessing==0 ) {
+			typeArgument_AST = (AST)currentAST.root;
+			typeArgument_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(TYPE_ARGUMENT,"TYPE_ARGUMENT",first,LT(1))).add(typeArgument_AST));
+			currentAST.root = typeArgument_AST;
+			currentAST.child = typeArgument_AST!=null &&typeArgument_AST.getFirstChild()!=null ?
+				typeArgument_AST.getFirstChild() : typeArgument_AST;
+			currentAST.advanceChildToEnd();
+		}
+		typeArgument_AST = (AST)currentAST.root;
+		returnAST = typeArgument_AST;
+	}
+	
+	public final void wildcardType() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST wildcardType_AST = null;
+		Token  q = null;
+		AST q_AST = null;
+		
+		q = LT(1);
+		q_AST = astFactory.create(q);
+		astFactory.makeASTRoot(currentAST, q_AST);
+		match(QUESTION);
+		if ( inputState.guessing==0 ) {
+			q_AST.setType(WILDCARD_TYPE);
+		}
+		{
+		boolean synPredMatched30 = false;
+		if (((LA(1)==LITERAL_extends||LA(1)==LITERAL_super) && (LA(2)==IDENT))) {
+			int _m30 = mark();
+			synPredMatched30 = true;
+			inputState.guessing++;
+			try {
+				{
+				switch ( LA(1)) {
+				case LITERAL_extends:
+				{
+					match(LITERAL_extends);
+					break;
+				}
+				case LITERAL_super:
+				{
+					match(LITERAL_super);
+					break;
+				}
+				default:
+				{
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				}
+				}
+			}
+			catch (RecognitionException pe) {
+				synPredMatched30 = false;
+			}
+			rewind(_m30);
+			inputState.guessing--;
+		}
+		if ( synPredMatched30 ) {
+			typeArgumentBounds();
+			astFactory.addASTChild(currentAST, returnAST);
+		}
+		else if ((_tokenSet_8.member(LA(1))) && (_tokenSet_9.member(LA(2)))) {
+		}
+		else {
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		
+		}
+		wildcardType_AST = (AST)currentAST.root;
+		returnAST = wildcardType_AST;
+	}
+	
+	public final void typeArgumentBounds() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST typeArgumentBounds_AST = null;
+		boolean isUpperBounds = false;  Token first = LT(1);
+		
+		{
+		switch ( LA(1)) {
+		case LITERAL_extends:
+		{
+			match(LITERAL_extends);
+			if ( inputState.guessing==0 ) {
+				isUpperBounds=true;
+			}
+			break;
+		}
+		case LITERAL_super:
+		{
+			match(LITERAL_super);
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		classOrInterfaceType(false);
+		astFactory.addASTChild(currentAST, returnAST);
+		if ( inputState.guessing==0 ) {
+			typeArgumentBounds_AST = (AST)currentAST.root;
+			
+						if (isUpperBounds)
+						{
+							typeArgumentBounds_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(TYPE_UPPER_BOUNDS,"TYPE_UPPER_BOUNDS",first,LT(1))).add(typeArgumentBounds_AST));
+						}
+						else
+						{
+							typeArgumentBounds_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(TYPE_LOWER_BOUNDS,"TYPE_LOWER_BOUNDS",first,LT(1))).add(typeArgumentBounds_AST));
+						}
+					
+			currentAST.root = typeArgumentBounds_AST;
+			currentAST.child = typeArgumentBounds_AST!=null &&typeArgumentBounds_AST.getFirstChild()!=null ?
+				typeArgumentBounds_AST.getFirstChild() : typeArgumentBounds_AST;
+			currentAST.advanceChildToEnd();
+		}
+		typeArgumentBounds_AST = (AST)currentAST.root;
+		returnAST = typeArgumentBounds_AST;
+	}
+	
+	protected final void typeArgumentsOrParametersEnd() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST typeArgumentsOrParametersEnd_AST = null;
+		
+		switch ( LA(1)) {
+		case GT:
+		{
+			match(GT);
+			if ( inputState.guessing==0 ) {
+				ltCounter-=1;
+			}
+			typeArgumentsOrParametersEnd_AST = (AST)currentAST.root;
+			break;
+		}
+		case SR:
+		{
+			match(SR);
+			if ( inputState.guessing==0 ) {
+				ltCounter-=2;
+			}
+			typeArgumentsOrParametersEnd_AST = (AST)currentAST.root;
+			break;
+		}
+		case BSR:
+		{
+			match(BSR);
+			if ( inputState.guessing==0 ) {
+				ltCounter-=3;
+			}
+			typeArgumentsOrParametersEnd_AST = (AST)currentAST.root;
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		returnAST = typeArgumentsOrParametersEnd_AST;
+	}
+	
+	public final void builtInType() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST builtInType_AST = null;
+		
+		switch ( LA(1)) {
+		case LITERAL_void:
+		{
+			AST tmp37_AST = null;
+			tmp37_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp37_AST);
+			match(LITERAL_void);
+			builtInType_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_boolean:
+		{
+			AST tmp38_AST = null;
+			tmp38_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp38_AST);
+			match(LITERAL_boolean);
+			builtInType_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_byte:
+		{
+			AST tmp39_AST = null;
+			tmp39_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp39_AST);
+			match(LITERAL_byte);
+			builtInType_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_char:
+		{
+			AST tmp40_AST = null;
+			tmp40_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp40_AST);
+			match(LITERAL_char);
+			builtInType_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_short:
+		{
+			AST tmp41_AST = null;
+			tmp41_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp41_AST);
+			match(LITERAL_short);
+			builtInType_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_int:
+		{
+			AST tmp42_AST = null;
+			tmp42_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp42_AST);
+			match(LITERAL_int);
+			builtInType_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_float:
+		{
+			AST tmp43_AST = null;
+			tmp43_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp43_AST);
+			match(LITERAL_float);
+			builtInType_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_long:
+		{
+			AST tmp44_AST = null;
+			tmp44_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp44_AST);
+			match(LITERAL_long);
+			builtInType_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_double:
+		{
+			AST tmp45_AST = null;
+			tmp45_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp45_AST);
+			match(LITERAL_double);
+			builtInType_AST = (AST)currentAST.root;
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		returnAST = builtInType_AST;
+	}
+	
+	public final void type() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST type_AST = null;
+		
+		switch ( LA(1)) {
+		case IDENT:
+		{
+			classOrInterfaceType(false);
+			astFactory.addASTChild(currentAST, returnAST);
+			type_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		{
+			builtInType();
+			astFactory.addASTChild(currentAST, returnAST);
+			type_AST = (AST)currentAST.root;
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		returnAST = type_AST;
+	}
+	
+	public final void modifier() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST modifier_AST = null;
+		
+		switch ( LA(1)) {
+		case LITERAL_private:
+		{
+			AST tmp46_AST = null;
+			tmp46_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp46_AST);
+			match(LITERAL_private);
+			modifier_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_public:
+		{
+			AST tmp47_AST = null;
+			tmp47_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp47_AST);
+			match(LITERAL_public);
+			modifier_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_protected:
+		{
+			AST tmp48_AST = null;
+			tmp48_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp48_AST);
+			match(LITERAL_protected);
+			modifier_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_static:
+		{
+			AST tmp49_AST = null;
+			tmp49_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp49_AST);
+			match(LITERAL_static);
+			modifier_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_transient:
+		{
+			AST tmp50_AST = null;
+			tmp50_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp50_AST);
+			match(LITERAL_transient);
+			modifier_AST = (AST)currentAST.root;
+			break;
+		}
+		case FINAL:
+		{
+			AST tmp51_AST = null;
+			tmp51_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp51_AST);
+			match(FINAL);
+			modifier_AST = (AST)currentAST.root;
+			break;
+		}
+		case ABSTRACT:
+		{
+			AST tmp52_AST = null;
+			tmp52_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp52_AST);
+			match(ABSTRACT);
+			modifier_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_native:
+		{
+			AST tmp53_AST = null;
+			tmp53_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp53_AST);
+			match(LITERAL_native);
+			modifier_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_threadsafe:
+		{
+			AST tmp54_AST = null;
+			tmp54_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp54_AST);
+			match(LITERAL_threadsafe);
+			modifier_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_synchronized:
+		{
+			AST tmp55_AST = null;
+			tmp55_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp55_AST);
+			match(LITERAL_synchronized);
+			modifier_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_volatile:
+		{
+			AST tmp56_AST = null;
+			tmp56_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp56_AST);
+			match(LITERAL_volatile);
+			modifier_AST = (AST)currentAST.root;
+			break;
+		}
+		case STRICTFP:
+		{
+			AST tmp57_AST = null;
+			tmp57_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp57_AST);
+			match(STRICTFP);
+			modifier_AST = (AST)currentAST.root;
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		returnAST = modifier_AST;
+	}
+	
+	public final void annotation() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST annotation_AST = null;
+		AST i_AST = null;
+		AST args_AST = null;
+		Token first = LT(1);
+		
+		match(AT);
+		identifier();
+		i_AST = (AST)returnAST;
+		{
+		switch ( LA(1)) {
+		case LPAREN:
+		{
+			match(LPAREN);
+			{
+			switch ( LA(1)) {
+			case IDENT:
+			case LITERAL_super:
+			case LT:
+			case LITERAL_void:
+			case LITERAL_boolean:
+			case LITERAL_byte:
+			case LITERAL_char:
+			case LITERAL_short:
+			case LITERAL_int:
+			case LITERAL_float:
+			case LITERAL_long:
+			case LITERAL_double:
+			case AT:
+			case LPAREN:
+			case LCURLY:
+			case LITERAL_this:
+			case PLUS:
+			case MINUS:
+			case INC:
+			case DEC:
+			case BNOT:
+			case LNOT:
+			case LITERAL_true:
+			case LITERAL_false:
+			case LITERAL_null:
+			case LITERAL_new:
+			case NUM_INT:
+			case STRING_LITERAL:
+			case NUM_FLOAT:
+			case NUM_LONG:
+			case NUM_DOUBLE:
+			{
+				annotationArguments();
+				args_AST = (AST)returnAST;
+				break;
+			}
+			case RPAREN:
+			{
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+			}
+			match(RPAREN);
+			break;
+		}
+		case FINAL:
+		case ABSTRACT:
+		case STRICTFP:
+		case LITERAL_package:
+		case SEMI:
+		case LITERAL_static:
+		case IDENT:
+		case LT:
+		case COMMA:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		case LITERAL_private:
+		case LITERAL_public:
+		case LITERAL_protected:
+		case LITERAL_transient:
+		case LITERAL_native:
+		case LITERAL_threadsafe:
+		case LITERAL_synchronized:
+		case LITERAL_volatile:
+		case AT:
+		case RPAREN:
+		case RCURLY:
+		case LITERAL_class:
+		case LITERAL_interface:
+		case LITERAL_enum:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		if ( inputState.guessing==0 ) {
+			annotation_AST = (AST)currentAST.root;
+			annotation_AST = (AST)astFactory.make( (new ASTArray(3)).add(create(ANNOTATION,"ANNOTATION",first,LT(1))).add(i_AST).add(args_AST));
+			currentAST.root = annotation_AST;
+			currentAST.child = annotation_AST!=null &&annotation_AST.getFirstChild()!=null ?
+				annotation_AST.getFirstChild() : annotation_AST;
+			currentAST.advanceChildToEnd();
+		}
+		returnAST = annotation_AST;
+	}
+	
+	public final void annotationArguments() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST annotationArguments_AST = null;
+		
+		if ((_tokenSet_10.member(LA(1))) && (_tokenSet_11.member(LA(2)))) {
+			annotationMemberValueInitializer();
+			astFactory.addASTChild(currentAST, returnAST);
+			annotationArguments_AST = (AST)currentAST.root;
+		}
+		else if ((LA(1)==IDENT) && (LA(2)==ASSIGN)) {
+			anntotationMemberValuePairs();
+			astFactory.addASTChild(currentAST, returnAST);
+			annotationArguments_AST = (AST)currentAST.root;
+		}
+		else {
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		
+		returnAST = annotationArguments_AST;
+	}
+	
+	public final void annotationMemberValueInitializer() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST annotationMemberValueInitializer_AST = null;
+		
+		switch ( LA(1)) {
+		case IDENT:
+		case LITERAL_super:
+		case LT:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		case LPAREN:
+		case LITERAL_this:
+		case PLUS:
+		case MINUS:
+		case INC:
+		case DEC:
+		case BNOT:
+		case LNOT:
+		case LITERAL_true:
+		case LITERAL_false:
+		case LITERAL_null:
+		case LITERAL_new:
+		case NUM_INT:
+		case STRING_LITERAL:
+		case NUM_FLOAT:
+		case NUM_LONG:
+		case NUM_DOUBLE:
+		{
+			conditionalExpression();
+			astFactory.addASTChild(currentAST, returnAST);
+			annotationMemberValueInitializer_AST = (AST)currentAST.root;
+			break;
+		}
+		case AT:
+		{
+			annotation();
+			astFactory.addASTChild(currentAST, returnAST);
+			annotationMemberValueInitializer_AST = (AST)currentAST.root;
+			break;
+		}
+		case LCURLY:
+		{
+			annotationMemberArrayInitializer();
+			astFactory.addASTChild(currentAST, returnAST);
+			annotationMemberValueInitializer_AST = (AST)currentAST.root;
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		returnAST = annotationMemberValueInitializer_AST;
+	}
+	
+	public final void anntotationMemberValuePairs() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST anntotationMemberValuePairs_AST = null;
+		
+		annotationMemberValuePair();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop66:
+		do {
+			if ((LA(1)==COMMA)) {
+				match(COMMA);
+				annotationMemberValuePair();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop66;
+			}
+			
+		} while (true);
+		}
+		anntotationMemberValuePairs_AST = (AST)currentAST.root;
+		returnAST = anntotationMemberValuePairs_AST;
+	}
+	
+	public final void annotationMemberValuePair() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST annotationMemberValuePair_AST = null;
+		Token  i = null;
+		AST i_AST = null;
+		AST v_AST = null;
+		Token first = LT(1);
+		
+		i = LT(1);
+		i_AST = astFactory.create(i);
+		match(IDENT);
+		match(ASSIGN);
+		annotationMemberValueInitializer();
+		v_AST = (AST)returnAST;
+		if ( inputState.guessing==0 ) {
+			annotationMemberValuePair_AST = (AST)currentAST.root;
+			annotationMemberValuePair_AST = (AST)astFactory.make( (new ASTArray(3)).add(create(ANNOTATION_MEMBER_VALUE_PAIR,"ANNOTATION_MEMBER_VALUE_PAIR",first,LT(1))).add(i_AST).add(v_AST));
+			currentAST.root = annotationMemberValuePair_AST;
+			currentAST.child = annotationMemberValuePair_AST!=null &&annotationMemberValuePair_AST.getFirstChild()!=null ?
+				annotationMemberValuePair_AST.getFirstChild() : annotationMemberValuePair_AST;
+			currentAST.advanceChildToEnd();
+		}
+		returnAST = annotationMemberValuePair_AST;
+	}
+	
+	public final void conditionalExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST conditionalExpression_AST = null;
+		
+		logicalOrExpression();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		switch ( LA(1)) {
+		case QUESTION:
+		{
+			AST tmp63_AST = null;
+			tmp63_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp63_AST);
+			match(QUESTION);
+			assignmentExpression();
+			astFactory.addASTChild(currentAST, returnAST);
+			match(COLON);
+			conditionalExpression();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		case SEMI:
+		case RBRACK:
+		case COMMA:
+		case RPAREN:
+		case ASSIGN:
+		case RCURLY:
+		case COLON:
+		case PLUS_ASSIGN:
+		case MINUS_ASSIGN:
+		case STAR_ASSIGN:
+		case DIV_ASSIGN:
+		case MOD_ASSIGN:
+		case SR_ASSIGN:
+		case BSR_ASSIGN:
+		case SL_ASSIGN:
+		case BAND_ASSIGN:
+		case BXOR_ASSIGN:
+		case BOR_ASSIGN:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		conditionalExpression_AST = (AST)currentAST.root;
+		returnAST = conditionalExpression_AST;
+	}
+	
+	public final void annotationMemberArrayInitializer() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST annotationMemberArrayInitializer_AST = null;
+		Token  lc = null;
+		AST lc_AST = null;
+		
+		lc = LT(1);
+		lc_AST = astFactory.create(lc);
+		astFactory.makeASTRoot(currentAST, lc_AST);
+		match(LCURLY);
+		if ( inputState.guessing==0 ) {
+			lc_AST.setType(ANNOTATION_ARRAY_INIT);
+		}
+		{
+		switch ( LA(1)) {
+		case IDENT:
+		case LITERAL_super:
+		case LT:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		case AT:
+		case LPAREN:
+		case LITERAL_this:
+		case PLUS:
+		case MINUS:
+		case INC:
+		case DEC:
+		case BNOT:
+		case LNOT:
+		case LITERAL_true:
+		case LITERAL_false:
+		case LITERAL_null:
+		case LITERAL_new:
+		case NUM_INT:
+		case STRING_LITERAL:
+		case NUM_FLOAT:
+		case NUM_LONG:
+		case NUM_DOUBLE:
+		{
+			annotationMemberArrayValueInitializer();
+			astFactory.addASTChild(currentAST, returnAST);
+			{
+			_loop72:
+			do {
+				if ((LA(1)==COMMA) && (_tokenSet_12.member(LA(2)))) {
+					match(COMMA);
+					annotationMemberArrayValueInitializer();
+					astFactory.addASTChild(currentAST, returnAST);
+				}
+				else {
+					break _loop72;
+				}
+				
+			} while (true);
+			}
+			{
+			switch ( LA(1)) {
+			case COMMA:
+			{
+				match(COMMA);
+				break;
+			}
+			case RCURLY:
+			{
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+			}
+			break;
+		}
+		case RCURLY:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		match(RCURLY);
+		annotationMemberArrayInitializer_AST = (AST)currentAST.root;
+		returnAST = annotationMemberArrayInitializer_AST;
+	}
+	
+	public final void annotationMemberArrayValueInitializer() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST annotationMemberArrayValueInitializer_AST = null;
+		
+		switch ( LA(1)) {
+		case IDENT:
+		case LITERAL_super:
+		case LT:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		case LPAREN:
+		case LITERAL_this:
+		case PLUS:
+		case MINUS:
+		case INC:
+		case DEC:
+		case BNOT:
+		case LNOT:
+		case LITERAL_true:
+		case LITERAL_false:
+		case LITERAL_null:
+		case LITERAL_new:
+		case NUM_INT:
+		case STRING_LITERAL:
+		case NUM_FLOAT:
+		case NUM_LONG:
+		case NUM_DOUBLE:
+		{
+			conditionalExpression();
+			astFactory.addASTChild(currentAST, returnAST);
+			annotationMemberArrayValueInitializer_AST = (AST)currentAST.root;
+			break;
+		}
+		case AT:
+		{
+			annotation();
+			astFactory.addASTChild(currentAST, returnAST);
+			annotationMemberArrayValueInitializer_AST = (AST)currentAST.root;
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		returnAST = annotationMemberArrayValueInitializer_AST;
+	}
+	
+	public final void superClassClause() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST superClassClause_AST = null;
+		AST c_AST = null;
+		Token first = LT(1);
+		
+		{
+		switch ( LA(1)) {
+		case LITERAL_extends:
+		{
+			match(LITERAL_extends);
+			classOrInterfaceType(false);
+			c_AST = (AST)returnAST;
+			break;
+		}
+		case LCURLY:
+		case LITERAL_implements:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		if ( inputState.guessing==0 ) {
+			superClassClause_AST = (AST)currentAST.root;
+			superClassClause_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(EXTENDS_CLAUSE,"EXTENDS_CLAUSE",first,LT(1))).add(c_AST));
+			currentAST.root = superClassClause_AST;
+			currentAST.child = superClassClause_AST!=null &&superClassClause_AST.getFirstChild()!=null ?
+				superClassClause_AST.getFirstChild() : superClassClause_AST;
+			currentAST.advanceChildToEnd();
+		}
+		returnAST = superClassClause_AST;
+	}
+	
+	public final void typeParameters() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST typeParameters_AST = null;
+		int currentLtLevel = 0; Token first = LT(1);
+		
+		if ( inputState.guessing==0 ) {
+			currentLtLevel = ltCounter;
+		}
+		match(LT);
+		if ( inputState.guessing==0 ) {
+			ltCounter++;
+		}
+		typeParameter();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop85:
+		do {
+			if ((LA(1)==COMMA)) {
+				match(COMMA);
+				typeParameter();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop85;
+			}
+			
+		} while (true);
+		}
+		{
+		switch ( LA(1)) {
+		case GT:
+		case SR:
+		case BSR:
+		{
+			typeArgumentsOrParametersEnd();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		case IDENT:
+		case LITERAL_extends:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		case LCURLY:
+		case LITERAL_implements:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		if (!((currentLtLevel != 0) || ltCounter == currentLtLevel))
+		  throw new SemanticException("(currentLtLevel != 0) || ltCounter == currentLtLevel");
+		if ( inputState.guessing==0 ) {
+			typeParameters_AST = (AST)currentAST.root;
+			typeParameters_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(TYPE_PARAMETERS,"TYPE_PARAMETERS",first,LT(1))).add(typeParameters_AST));
+			currentAST.root = typeParameters_AST;
+			currentAST.child = typeParameters_AST!=null &&typeParameters_AST.getFirstChild()!=null ?
+				typeParameters_AST.getFirstChild() : typeParameters_AST;
+			currentAST.advanceChildToEnd();
+		}
+		typeParameters_AST = (AST)currentAST.root;
+		returnAST = typeParameters_AST;
+	}
+	
+	public final void implementsClause() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST implementsClause_AST = null;
+		Token  i = null;
+		AST i_AST = null;
+		Token first = LT(1);
+		
+		{
+		switch ( LA(1)) {
+		case LITERAL_implements:
+		{
+			i = LT(1);
+			i_AST = astFactory.create(i);
+			match(LITERAL_implements);
+			classOrInterfaceType(false);
+			astFactory.addASTChild(currentAST, returnAST);
+			{
+			_loop133:
+			do {
+				if ((LA(1)==COMMA)) {
+					match(COMMA);
+					classOrInterfaceType(false);
+					astFactory.addASTChild(currentAST, returnAST);
+				}
+				else {
+					break _loop133;
+				}
+				
+			} while (true);
+			}
+			break;
+		}
+		case LCURLY:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		if ( inputState.guessing==0 ) {
+			implementsClause_AST = (AST)currentAST.root;
+			implementsClause_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(IMPLEMENTS_CLAUSE,"IMPLEMENTS_CLAUSE",first,LT(1))).add(implementsClause_AST));
+			currentAST.root = implementsClause_AST;
+			currentAST.child = implementsClause_AST!=null &&implementsClause_AST.getFirstChild()!=null ?
+				implementsClause_AST.getFirstChild() : implementsClause_AST;
+			currentAST.advanceChildToEnd();
+		}
+		implementsClause_AST = (AST)currentAST.root;
+		returnAST = implementsClause_AST;
+	}
+	
+	public final void classBlock() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST classBlock_AST = null;
+		
+		match(LCURLY);
+		{
+		_loop95:
+		do {
+			switch ( LA(1)) {
+			case FINAL:
+			case ABSTRACT:
+			case STRICTFP:
+			case LITERAL_static:
+			case IDENT:
+			case LT:
+			case LITERAL_void:
+			case LITERAL_boolean:
+			case LITERAL_byte:
+			case LITERAL_char:
+			case LITERAL_short:
+			case LITERAL_int:
+			case LITERAL_float:
+			case LITERAL_long:
+			case LITERAL_double:
+			case LITERAL_private:
+			case LITERAL_public:
+			case LITERAL_protected:
+			case LITERAL_transient:
+			case LITERAL_native:
+			case LITERAL_threadsafe:
+			case LITERAL_synchronized:
+			case LITERAL_volatile:
+			case AT:
+			case LCURLY:
+			case LITERAL_class:
+			case LITERAL_interface:
+			case LITERAL_enum:
+			{
+				classField();
+				astFactory.addASTChild(currentAST, returnAST);
+				break;
+			}
+			case SEMI:
+			{
+				match(SEMI);
+				break;
+			}
+			default:
+			{
+				break _loop95;
+			}
+			}
+		} while (true);
+		}
+		match(RCURLY);
+		if ( inputState.guessing==0 ) {
+			classBlock_AST = (AST)currentAST.root;
+			classBlock_AST = (AST)astFactory.make( (new ASTArray(2)).add(astFactory.create(OBJBLOCK,"OBJBLOCK")).add(classBlock_AST));
+			currentAST.root = classBlock_AST;
+			currentAST.child = classBlock_AST!=null &&classBlock_AST.getFirstChild()!=null ?
+				classBlock_AST.getFirstChild() : classBlock_AST;
+			currentAST.advanceChildToEnd();
+		}
+		classBlock_AST = (AST)currentAST.root;
+		returnAST = classBlock_AST;
+	}
+	
+	public final void interfaceExtends() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST interfaceExtends_AST = null;
+		Token  e = null;
+		AST e_AST = null;
+		Token first = LT(1);
+		
+		{
+		switch ( LA(1)) {
+		case LITERAL_extends:
+		{
+			e = LT(1);
+			e_AST = astFactory.create(e);
+			match(LITERAL_extends);
+			classOrInterfaceType(false);
+			astFactory.addASTChild(currentAST, returnAST);
+			{
+			_loop129:
+			do {
+				if ((LA(1)==COMMA)) {
+					match(COMMA);
+					classOrInterfaceType(false);
+					astFactory.addASTChild(currentAST, returnAST);
+				}
+				else {
+					break _loop129;
+				}
+				
+			} while (true);
+			}
+			break;
+		}
+		case LCURLY:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		if ( inputState.guessing==0 ) {
+			interfaceExtends_AST = (AST)currentAST.root;
+			interfaceExtends_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(EXTENDS_CLAUSE,"EXTENDS_CLAUSE",first,LT(1))).add(interfaceExtends_AST));
+			currentAST.root = interfaceExtends_AST;
+			currentAST.child = interfaceExtends_AST!=null &&interfaceExtends_AST.getFirstChild()!=null ?
+				interfaceExtends_AST.getFirstChild() : interfaceExtends_AST;
+			currentAST.advanceChildToEnd();
+		}
+		interfaceExtends_AST = (AST)currentAST.root;
+		returnAST = interfaceExtends_AST;
+	}
+	
+	public final void interfaceBlock() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST interfaceBlock_AST = null;
+		
+		match(LCURLY);
+		{
+		_loop98:
+		do {
+			switch ( LA(1)) {
+			case FINAL:
+			case ABSTRACT:
+			case STRICTFP:
+			case LITERAL_static:
+			case IDENT:
+			case LT:
+			case LITERAL_void:
+			case LITERAL_boolean:
+			case LITERAL_byte:
+			case LITERAL_char:
+			case LITERAL_short:
+			case LITERAL_int:
+			case LITERAL_float:
+			case LITERAL_long:
+			case LITERAL_double:
+			case LITERAL_private:
+			case LITERAL_public:
+			case LITERAL_protected:
+			case LITERAL_transient:
+			case LITERAL_native:
+			case LITERAL_threadsafe:
+			case LITERAL_synchronized:
+			case LITERAL_volatile:
+			case AT:
+			case LITERAL_class:
+			case LITERAL_interface:
+			case LITERAL_enum:
+			{
+				interfaceField();
+				astFactory.addASTChild(currentAST, returnAST);
+				break;
+			}
+			case SEMI:
+			{
+				match(SEMI);
+				break;
+			}
+			default:
+			{
+				break _loop98;
+			}
+			}
+		} while (true);
+		}
+		match(RCURLY);
+		if ( inputState.guessing==0 ) {
+			interfaceBlock_AST = (AST)currentAST.root;
+			interfaceBlock_AST = (AST)astFactory.make( (new ASTArray(2)).add(astFactory.create(OBJBLOCK,"OBJBLOCK")).add(interfaceBlock_AST));
+			currentAST.root = interfaceBlock_AST;
+			currentAST.child = interfaceBlock_AST!=null &&interfaceBlock_AST.getFirstChild()!=null ?
+				interfaceBlock_AST.getFirstChild() : interfaceBlock_AST;
+			currentAST.advanceChildToEnd();
+		}
+		interfaceBlock_AST = (AST)currentAST.root;
+		returnAST = interfaceBlock_AST;
+	}
+	
+	public final void enumBlock() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST enumBlock_AST = null;
+		
+		match(LCURLY);
+		{
+		switch ( LA(1)) {
+		case IDENT:
+		case AT:
+		{
+			enumConstant();
+			astFactory.addASTChild(currentAST, returnAST);
+			{
+			_loop105:
+			do {
+				if ((LA(1)==COMMA) && (LA(2)==IDENT||LA(2)==AT)) {
+					match(COMMA);
+					enumConstant();
+					astFactory.addASTChild(currentAST, returnAST);
+				}
+				else {
+					break _loop105;
+				}
+				
+			} while (true);
+			}
+			{
+			switch ( LA(1)) {
+			case COMMA:
+			{
+				match(COMMA);
+				break;
+			}
+			case SEMI:
+			case RCURLY:
+			{
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+			}
+			break;
+		}
+		case SEMI:
+		case RCURLY:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		{
+		switch ( LA(1)) {
+		case SEMI:
+		{
+			match(SEMI);
+			{
+			_loop109:
+			do {
+				switch ( LA(1)) {
+				case FINAL:
+				case ABSTRACT:
+				case STRICTFP:
+				case LITERAL_static:
+				case IDENT:
+				case LT:
+				case LITERAL_void:
+				case LITERAL_boolean:
+				case LITERAL_byte:
+				case LITERAL_char:
+				case LITERAL_short:
+				case LITERAL_int:
+				case LITERAL_float:
+				case LITERAL_long:
+				case LITERAL_double:
+				case LITERAL_private:
+				case LITERAL_public:
+				case LITERAL_protected:
+				case LITERAL_transient:
+				case LITERAL_native:
+				case LITERAL_threadsafe:
+				case LITERAL_synchronized:
+				case LITERAL_volatile:
+				case AT:
+				case LCURLY:
+				case LITERAL_class:
+				case LITERAL_interface:
+				case LITERAL_enum:
+				{
+					classField();
+					astFactory.addASTChild(currentAST, returnAST);
+					break;
+				}
+				case SEMI:
+				{
+					match(SEMI);
+					break;
+				}
+				default:
+				{
+					break _loop109;
+				}
+				}
+			} while (true);
+			}
+			break;
+		}
+		case RCURLY:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		match(RCURLY);
+		if ( inputState.guessing==0 ) {
+			enumBlock_AST = (AST)currentAST.root;
+			enumBlock_AST = (AST)astFactory.make( (new ASTArray(2)).add(astFactory.create(OBJBLOCK,"OBJBLOCK")).add(enumBlock_AST));
+			currentAST.root = enumBlock_AST;
+			currentAST.child = enumBlock_AST!=null &&enumBlock_AST.getFirstChild()!=null ?
+				enumBlock_AST.getFirstChild() : enumBlock_AST;
+			currentAST.advanceChildToEnd();
+		}
+		enumBlock_AST = (AST)currentAST.root;
+		returnAST = enumBlock_AST;
+	}
+	
+	public final void annotationBlock() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST annotationBlock_AST = null;
+		
+		match(LCURLY);
+		{
+		_loop101:
+		do {
+			switch ( LA(1)) {
+			case FINAL:
+			case ABSTRACT:
+			case STRICTFP:
+			case LITERAL_static:
+			case IDENT:
+			case LITERAL_void:
+			case LITERAL_boolean:
+			case LITERAL_byte:
+			case LITERAL_char:
+			case LITERAL_short:
+			case LITERAL_int:
+			case LITERAL_float:
+			case LITERAL_long:
+			case LITERAL_double:
+			case LITERAL_private:
+			case LITERAL_public:
+			case LITERAL_protected:
+			case LITERAL_transient:
+			case LITERAL_native:
+			case LITERAL_threadsafe:
+			case LITERAL_synchronized:
+			case LITERAL_volatile:
+			case AT:
+			case LITERAL_class:
+			case LITERAL_interface:
+			case LITERAL_enum:
+			{
+				annotationField();
+				astFactory.addASTChild(currentAST, returnAST);
+				break;
+			}
+			case SEMI:
+			{
+				match(SEMI);
+				break;
+			}
+			default:
+			{
+				break _loop101;
+			}
+			}
+		} while (true);
+		}
+		match(RCURLY);
+		if ( inputState.guessing==0 ) {
+			annotationBlock_AST = (AST)currentAST.root;
+			annotationBlock_AST = (AST)astFactory.make( (new ASTArray(2)).add(astFactory.create(OBJBLOCK,"OBJBLOCK")).add(annotationBlock_AST));
+			currentAST.root = annotationBlock_AST;
+			currentAST.child = annotationBlock_AST!=null &&annotationBlock_AST.getFirstChild()!=null ?
+				annotationBlock_AST.getFirstChild() : annotationBlock_AST;
+			currentAST.advanceChildToEnd();
+		}
+		annotationBlock_AST = (AST)currentAST.root;
+		returnAST = annotationBlock_AST;
+	}
+	
+	public final void typeParameter() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST typeParameter_AST = null;
+		Token  id = null;
+		AST id_AST = null;
+		Token first = LT(1);
+		
+		{
+		id = LT(1);
+		id_AST = astFactory.create(id);
+		astFactory.addASTChild(currentAST, id_AST);
+		match(IDENT);
+		}
+		{
+		if ((LA(1)==LITERAL_extends) && (LA(2)==IDENT)) {
+			typeParameterBounds();
+			astFactory.addASTChild(currentAST, returnAST);
+		}
+		else if ((_tokenSet_13.member(LA(1))) && (_tokenSet_14.member(LA(2)))) {
+		}
+		else {
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		
+		}
+		if ( inputState.guessing==0 ) {
+			typeParameter_AST = (AST)currentAST.root;
+			typeParameter_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(TYPE_PARAMETER,"TYPE_PARAMETER",first,LT(1))).add(typeParameter_AST));
+			currentAST.root = typeParameter_AST;
+			currentAST.child = typeParameter_AST!=null &&typeParameter_AST.getFirstChild()!=null ?
+				typeParameter_AST.getFirstChild() : typeParameter_AST;
+			currentAST.advanceChildToEnd();
+		}
+		typeParameter_AST = (AST)currentAST.root;
+		returnAST = typeParameter_AST;
+	}
+	
+	public final void typeParameterBounds() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST typeParameterBounds_AST = null;
+		Token first = LT(1);
+		
+		match(LITERAL_extends);
+		classOrInterfaceType(false);
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop92:
+		do {
+			if ((LA(1)==BAND)) {
+				match(BAND);
+				classOrInterfaceType(false);
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop92;
+			}
+			
+		} while (true);
+		}
+		if ( inputState.guessing==0 ) {
+			typeParameterBounds_AST = (AST)currentAST.root;
+			typeParameterBounds_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(TYPE_UPPER_BOUNDS,"TYPE_UPPER_BOUNDS",first,LT(1))).add(typeParameterBounds_AST));
+			currentAST.root = typeParameterBounds_AST;
+			currentAST.child = typeParameterBounds_AST!=null &&typeParameterBounds_AST.getFirstChild()!=null ?
+				typeParameterBounds_AST.getFirstChild() : typeParameterBounds_AST;
+			currentAST.advanceChildToEnd();
+		}
+		typeParameterBounds_AST = (AST)currentAST.root;
+		returnAST = typeParameterBounds_AST;
+	}
+	
+	public final void classField() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST classField_AST = null;
+		AST mods_AST = null;
+		AST td_AST = null;
+		AST tp_AST = null;
+		AST h_AST = null;
+		AST s_AST = null;
+		AST t_AST = null;
+		AST param_AST = null;
+		AST rt_AST = null;
+		AST tc_AST = null;
+		AST s2_AST = null;
+		AST v_AST = null;
+		AST s3_AST = null;
+		AST s4_AST = null;
+		Token first = LT(1);
+		
+		if ((_tokenSet_15.member(LA(1))) && (_tokenSet_16.member(LA(2)))) {
+			modifiers();
+			mods_AST = (AST)returnAST;
+			{
+			switch ( LA(1)) {
+			case AT:
+			case LITERAL_class:
+			case LITERAL_interface:
+			case LITERAL_enum:
+			{
+				typeDefinitionInternal(mods_AST);
+				td_AST = (AST)returnAST;
+				if ( inputState.guessing==0 ) {
+					classField_AST = (AST)currentAST.root;
+					classField_AST = td_AST;
+					currentAST.root = classField_AST;
+					currentAST.child = classField_AST!=null &&classField_AST.getFirstChild()!=null ?
+						classField_AST.getFirstChild() : classField_AST;
+					currentAST.advanceChildToEnd();
+				}
+				break;
+			}
+			case IDENT:
+			case LT:
+			case LITERAL_void:
+			case LITERAL_boolean:
+			case LITERAL_byte:
+			case LITERAL_char:
+			case LITERAL_short:
+			case LITERAL_int:
+			case LITERAL_float:
+			case LITERAL_long:
+			case LITERAL_double:
+			{
+				{
+				switch ( LA(1)) {
+				case LT:
+				{
+					typeParameters();
+					tp_AST = (AST)returnAST;
+					break;
+				}
+				case IDENT:
+				case LITERAL_void:
+				case LITERAL_boolean:
+				case LITERAL_byte:
+				case LITERAL_char:
+				case LITERAL_short:
+				case LITERAL_int:
+				case LITERAL_float:
+				case LITERAL_long:
+				case LITERAL_double:
+				{
+					break;
+				}
+				default:
+				{
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				}
+				}
+				{
+				if ((LA(1)==IDENT) && (LA(2)==LPAREN)) {
+					ctorHead();
+					h_AST = (AST)returnAST;
+					constructorBody();
+					s_AST = (AST)returnAST;
+					if ( inputState.guessing==0 ) {
+						classField_AST = (AST)currentAST.root;
+						classField_AST = (AST)astFactory.make( (new ASTArray(5)).add(create(METHOD_DEF,"METHOD_DEF",first,LT(1))).add(mods_AST).add(tp_AST).add(h_AST).add(s_AST));
+						currentAST.root = classField_AST;
+						currentAST.child = classField_AST!=null &&classField_AST.getFirstChild()!=null ?
+							classField_AST.getFirstChild() : classField_AST;
+						currentAST.advanceChildToEnd();
+					}
+				}
+				else if ((_tokenSet_17.member(LA(1))) && (_tokenSet_18.member(LA(2)))) {
+					typeSpec(false);
+					t_AST = (AST)returnAST;
+					{
+					if ((LA(1)==IDENT) && (LA(2)==LPAREN)) {
+						AST tmp90_AST = null;
+						tmp90_AST = astFactory.create(LT(1));
+						match(IDENT);
+						match(LPAREN);
+						parameterDeclarationList();
+						param_AST = (AST)returnAST;
+						match(RPAREN);
+						declaratorBrackets(t_AST);
+						rt_AST = (AST)returnAST;
+						{
+						switch ( LA(1)) {
+						case LITERAL_throws:
+						{
+							throwsClause();
+							tc_AST = (AST)returnAST;
+							break;
+						}
+						case SEMI:
+						case LCURLY:
+						{
+							break;
+						}
+						default:
+						{
+							throw new NoViableAltException(LT(1), getFilename());
+						}
+						}
+						}
+						{
+						switch ( LA(1)) {
+						case LCURLY:
+						{
+							compoundStatement();
+							s2_AST = (AST)returnAST;
+							break;
+						}
+						case SEMI:
+						{
+							AST tmp93_AST = null;
+							tmp93_AST = astFactory.create(LT(1));
+							match(SEMI);
+							break;
+						}
+						default:
+						{
+							throw new NoViableAltException(LT(1), getFilename());
+						}
+						}
+						}
+						if ( inputState.guessing==0 ) {
+							classField_AST = (AST)currentAST.root;
+							classField_AST = (AST)astFactory.make( (new ASTArray(8)).add(create(METHOD_DEF,"METHOD_DEF",first,LT(1))).add(mods_AST).add(tp_AST).add((AST)astFactory.make( (new ASTArray(2)).add(create(TYPE,"TYPE",first,LT(1))).add(rt_AST))).add(tmp90_AST).add(param_AST).add(tc_AST).add(s2_AST));
+							currentAST.root = classField_AST;
+							currentAST.child = classField_AST!=null &&classField_AST.getFirstChild()!=null ?
+								classField_AST.getFirstChild() : classField_AST;
+							currentAST.advanceChildToEnd();
+						}
+					}
+					else if ((LA(1)==IDENT) && (_tokenSet_19.member(LA(2)))) {
+						variableDefinitions(mods_AST,t_AST);
+						v_AST = (AST)returnAST;
+						AST tmp94_AST = null;
+						tmp94_AST = astFactory.create(LT(1));
+						match(SEMI);
+						if ( inputState.guessing==0 ) {
+							classField_AST = (AST)currentAST.root;
+							classField_AST = v_AST;
+							currentAST.root = classField_AST;
+							currentAST.child = classField_AST!=null &&classField_AST.getFirstChild()!=null ?
+								classField_AST.getFirstChild() : classField_AST;
+							currentAST.advanceChildToEnd();
+						}
+					}
+					else {
+						throw new NoViableAltException(LT(1), getFilename());
+					}
+					
+					}
+				}
+				else {
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				
+				}
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+			}
+		}
+		else if ((LA(1)==LITERAL_static) && (LA(2)==LCURLY)) {
+			match(LITERAL_static);
+			compoundStatement();
+			s3_AST = (AST)returnAST;
+			if ( inputState.guessing==0 ) {
+				classField_AST = (AST)currentAST.root;
+				classField_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(STATIC_INIT,"STATIC_INIT",first,LT(1))).add(s3_AST));
+				currentAST.root = classField_AST;
+				currentAST.child = classField_AST!=null &&classField_AST.getFirstChild()!=null ?
+					classField_AST.getFirstChild() : classField_AST;
+				currentAST.advanceChildToEnd();
+			}
+		}
+		else if ((LA(1)==LCURLY)) {
+			compoundStatement();
+			s4_AST = (AST)returnAST;
+			if ( inputState.guessing==0 ) {
+				classField_AST = (AST)currentAST.root;
+				classField_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(INSTANCE_INIT,"INSTANCE_INIT",first,LT(1))).add(s4_AST));
+				currentAST.root = classField_AST;
+				currentAST.child = classField_AST!=null &&classField_AST.getFirstChild()!=null ?
+					classField_AST.getFirstChild() : classField_AST;
+				currentAST.advanceChildToEnd();
+			}
+		}
+		else {
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		
+		returnAST = classField_AST;
+	}
+	
+	public final void interfaceField() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST interfaceField_AST = null;
+		AST mods_AST = null;
+		AST td_AST = null;
+		AST tp_AST = null;
+		AST t_AST = null;
+		AST param_AST = null;
+		AST rt_AST = null;
+		AST tc_AST = null;
+		AST v_AST = null;
+		Token first = LT(1);
+		
+		modifiers();
+		mods_AST = (AST)returnAST;
+		{
+		switch ( LA(1)) {
+		case AT:
+		case LITERAL_class:
+		case LITERAL_interface:
+		case LITERAL_enum:
+		{
+			typeDefinitionInternal(mods_AST);
+			td_AST = (AST)returnAST;
+			if ( inputState.guessing==0 ) {
+				interfaceField_AST = (AST)currentAST.root;
+				interfaceField_AST = td_AST;
+				currentAST.root = interfaceField_AST;
+				currentAST.child = interfaceField_AST!=null &&interfaceField_AST.getFirstChild()!=null ?
+					interfaceField_AST.getFirstChild() : interfaceField_AST;
+				currentAST.advanceChildToEnd();
+			}
+			break;
+		}
+		case IDENT:
+		case LT:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		{
+			{
+			switch ( LA(1)) {
+			case LT:
+			{
+				typeParameters();
+				tp_AST = (AST)returnAST;
+				break;
+			}
+			case IDENT:
+			case LITERAL_void:
+			case LITERAL_boolean:
+			case LITERAL_byte:
+			case LITERAL_char:
+			case LITERAL_short:
+			case LITERAL_int:
+			case LITERAL_float:
+			case LITERAL_long:
+			case LITERAL_double:
+			{
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+			}
+			typeSpec(false);
+			t_AST = (AST)returnAST;
+			{
+			if ((LA(1)==IDENT) && (LA(2)==LPAREN)) {
+				AST tmp96_AST = null;
+				tmp96_AST = astFactory.create(LT(1));
+				match(IDENT);
+				match(LPAREN);
+				parameterDeclarationList();
+				param_AST = (AST)returnAST;
+				match(RPAREN);
+				declaratorBrackets(t_AST);
+				rt_AST = (AST)returnAST;
+				{
+				switch ( LA(1)) {
+				case LITERAL_throws:
+				{
+					throwsClause();
+					tc_AST = (AST)returnAST;
+					break;
+				}
+				case SEMI:
+				{
+					break;
+				}
+				default:
+				{
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				}
+				}
+				AST tmp99_AST = null;
+				tmp99_AST = astFactory.create(LT(1));
+				match(SEMI);
+				if ( inputState.guessing==0 ) {
+					interfaceField_AST = (AST)currentAST.root;
+					interfaceField_AST = (AST)astFactory.make( (new ASTArray(7)).add(create(METHOD_DEF,"METHOD_DEF",first,LT(1))).add(mods_AST).add(tp_AST).add((AST)astFactory.make( (new ASTArray(2)).add(create(TYPE,"TYPE",first,LT(1))).add(rt_AST))).add(tmp96_AST).add(param_AST).add(tc_AST));
+					currentAST.root = interfaceField_AST;
+					currentAST.child = interfaceField_AST!=null &&interfaceField_AST.getFirstChild()!=null ?
+						interfaceField_AST.getFirstChild() : interfaceField_AST;
+					currentAST.advanceChildToEnd();
+				}
+			}
+			else if ((LA(1)==IDENT) && (_tokenSet_19.member(LA(2)))) {
+				variableDefinitions(mods_AST,t_AST);
+				v_AST = (AST)returnAST;
+				AST tmp100_AST = null;
+				tmp100_AST = astFactory.create(LT(1));
+				match(SEMI);
+				if ( inputState.guessing==0 ) {
+					interfaceField_AST = (AST)currentAST.root;
+					interfaceField_AST = v_AST;
+					currentAST.root = interfaceField_AST;
+					currentAST.child = interfaceField_AST!=null &&interfaceField_AST.getFirstChild()!=null ?
+						interfaceField_AST.getFirstChild() : interfaceField_AST;
+					currentAST.advanceChildToEnd();
+				}
+			}
+			else {
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			
+			}
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		returnAST = interfaceField_AST;
+	}
+	
+	public final void annotationField() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST annotationField_AST = null;
+		AST mods_AST = null;
+		AST td_AST = null;
+		AST t_AST = null;
+		Token  i = null;
+		AST i_AST = null;
+		AST rt_AST = null;
+		AST amvi_AST = null;
+		AST v_AST = null;
+		Token first = LT(1);
+		
+		modifiers();
+		mods_AST = (AST)returnAST;
+		{
+		switch ( LA(1)) {
+		case AT:
+		case LITERAL_class:
+		case LITERAL_interface:
+		case LITERAL_enum:
+		{
+			typeDefinitionInternal(mods_AST);
+			td_AST = (AST)returnAST;
+			if ( inputState.guessing==0 ) {
+				annotationField_AST = (AST)currentAST.root;
+				annotationField_AST = td_AST;
+				currentAST.root = annotationField_AST;
+				currentAST.child = annotationField_AST!=null &&annotationField_AST.getFirstChild()!=null ?
+					annotationField_AST.getFirstChild() : annotationField_AST;
+				currentAST.advanceChildToEnd();
+			}
+			break;
+		}
+		case IDENT:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		{
+			typeSpec(false);
+			t_AST = (AST)returnAST;
+			{
+			if ((LA(1)==IDENT) && (LA(2)==LPAREN)) {
+				i = LT(1);
+				i_AST = astFactory.create(i);
+				match(IDENT);
+				match(LPAREN);
+				match(RPAREN);
+				declaratorBrackets(t_AST);
+				rt_AST = (AST)returnAST;
+				{
+				switch ( LA(1)) {
+				case LITERAL_default:
+				{
+					match(LITERAL_default);
+					annotationMemberValueInitializer();
+					amvi_AST = (AST)returnAST;
+					break;
+				}
+				case SEMI:
+				{
+					break;
+				}
+				default:
+				{
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				}
+				}
+				AST tmp104_AST = null;
+				tmp104_AST = astFactory.create(LT(1));
+				match(SEMI);
+				if ( inputState.guessing==0 ) {
+					annotationField_AST = (AST)currentAST.root;
+					annotationField_AST =
+										(AST)astFactory.make( (new ASTArray(5)).add(create(ANNOTATION_FIELD_DEF,"ANNOTATION_FIELD_DEF",first,LT(1))).add(mods_AST).add((AST)astFactory.make( (new ASTArray(2)).add(create(TYPE,"TYPE",first,LT(1))).add(rt_AST))).add(i_AST).add(amvi_AST));
+					currentAST.root = annotationField_AST;
+					currentAST.child = annotationField_AST!=null &&annotationField_AST.getFirstChild()!=null ?
+						annotationField_AST.getFirstChild() : annotationField_AST;
+					currentAST.advanceChildToEnd();
+				}
+			}
+			else if ((LA(1)==IDENT) && (_tokenSet_19.member(LA(2)))) {
+				variableDefinitions(mods_AST,t_AST);
+				v_AST = (AST)returnAST;
+				AST tmp105_AST = null;
+				tmp105_AST = astFactory.create(LT(1));
+				match(SEMI);
+				if ( inputState.guessing==0 ) {
+					annotationField_AST = (AST)currentAST.root;
+					annotationField_AST = v_AST;
+					currentAST.root = annotationField_AST;
+					currentAST.child = annotationField_AST!=null &&annotationField_AST.getFirstChild()!=null ?
+						annotationField_AST.getFirstChild() : annotationField_AST;
+					currentAST.advanceChildToEnd();
+				}
+			}
+			else {
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			
+			}
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		returnAST = annotationField_AST;
+	}
+	
+	public final void enumConstant() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST enumConstant_AST = null;
+		AST an_AST = null;
+		Token  i = null;
+		AST i_AST = null;
+		AST a_AST = null;
+		AST b_AST = null;
+		
+		annotations();
+		an_AST = (AST)returnAST;
+		i = LT(1);
+		i_AST = astFactory.create(i);
+		match(IDENT);
+		{
+		switch ( LA(1)) {
+		case LPAREN:
+		{
+			match(LPAREN);
+			argList();
+			a_AST = (AST)returnAST;
+			match(RPAREN);
+			break;
+		}
+		case SEMI:
+		case COMMA:
+		case LCURLY:
+		case RCURLY:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		{
+		switch ( LA(1)) {
+		case LCURLY:
+		{
+			enumConstantBlock();
+			b_AST = (AST)returnAST;
+			break;
+		}
+		case SEMI:
+		case COMMA:
+		case RCURLY:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		if ( inputState.guessing==0 ) {
+			enumConstant_AST = (AST)currentAST.root;
+			enumConstant_AST = (AST)astFactory.make( (new ASTArray(5)).add(astFactory.create(ENUM_CONSTANT_DEF,"ENUM_CONSTANT_DEF")).add(an_AST).add(i_AST).add(a_AST).add(b_AST));
+			currentAST.root = enumConstant_AST;
+			currentAST.child = enumConstant_AST!=null &&enumConstant_AST.getFirstChild()!=null ?
+				enumConstant_AST.getFirstChild() : enumConstant_AST;
+			currentAST.advanceChildToEnd();
+		}
+		returnAST = enumConstant_AST;
+	}
+	
+	public final void declaratorBrackets(
+		AST typ
+	) throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST declaratorBrackets_AST = null;
+		Token  lb = null;
+		AST lb_AST = null;
+		
+		if ( inputState.guessing==0 ) {
+			declaratorBrackets_AST = (AST)currentAST.root;
+			declaratorBrackets_AST=typ;
+			currentAST.root = declaratorBrackets_AST;
+			currentAST.child = declaratorBrackets_AST!=null &&declaratorBrackets_AST.getFirstChild()!=null ?
+				declaratorBrackets_AST.getFirstChild() : declaratorBrackets_AST;
+			currentAST.advanceChildToEnd();
+		}
+		{
+		_loop159:
+		do {
+			if ((LA(1)==LBRACK)) {
+				lb = LT(1);
+				lb_AST = astFactory.create(lb);
+				astFactory.makeASTRoot(currentAST, lb_AST);
+				match(LBRACK);
+				if ( inputState.guessing==0 ) {
+					lb_AST.setType(ARRAY_DECLARATOR);
+				}
+				match(RBRACK);
+			}
+			else {
+				break _loop159;
+			}
+			
+		} while (true);
+		}
+		declaratorBrackets_AST = (AST)currentAST.root;
+		returnAST = declaratorBrackets_AST;
+	}
+	
+	public final void argList() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST argList_AST = null;
+		Token first = LT(1);
+		
+		{
+		switch ( LA(1)) {
+		case IDENT:
+		case LITERAL_super:
+		case LT:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		case LPAREN:
+		case LITERAL_this:
+		case PLUS:
+		case MINUS:
+		case INC:
+		case DEC:
+		case BNOT:
+		case LNOT:
+		case LITERAL_true:
+		case LITERAL_false:
+		case LITERAL_null:
+		case LITERAL_new:
+		case NUM_INT:
+		case STRING_LITERAL:
+		case NUM_FLOAT:
+		case NUM_LONG:
+		case NUM_DOUBLE:
+		{
+			expressionList();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		case RPAREN:
+		{
+			if ( inputState.guessing==0 ) {
+				argList_AST = (AST)currentAST.root;
+				argList_AST = create(ELIST,"ELIST",first,LT(1));
+				currentAST.root = argList_AST;
+				currentAST.child = argList_AST!=null &&argList_AST.getFirstChild()!=null ?
+					argList_AST.getFirstChild() : argList_AST;
+				currentAST.advanceChildToEnd();
+			}
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		argList_AST = (AST)currentAST.root;
+		returnAST = argList_AST;
+	}
+	
+	public final void enumConstantBlock() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST enumConstantBlock_AST = null;
+		
+		match(LCURLY);
+		{
+		_loop119:
+		do {
+			switch ( LA(1)) {
+			case FINAL:
+			case ABSTRACT:
+			case STRICTFP:
+			case LITERAL_static:
+			case IDENT:
+			case LT:
+			case LITERAL_void:
+			case LITERAL_boolean:
+			case LITERAL_byte:
+			case LITERAL_char:
+			case LITERAL_short:
+			case LITERAL_int:
+			case LITERAL_float:
+			case LITERAL_long:
+			case LITERAL_double:
+			case LITERAL_private:
+			case LITERAL_public:
+			case LITERAL_protected:
+			case LITERAL_transient:
+			case LITERAL_native:
+			case LITERAL_threadsafe:
+			case LITERAL_synchronized:
+			case LITERAL_volatile:
+			case AT:
+			case LCURLY:
+			case LITERAL_class:
+			case LITERAL_interface:
+			case LITERAL_enum:
+			{
+				enumConstantField();
+				astFactory.addASTChild(currentAST, returnAST);
+				break;
+			}
+			case SEMI:
+			{
+				match(SEMI);
+				break;
+			}
+			default:
+			{
+				break _loop119;
+			}
+			}
+		} while (true);
+		}
+		match(RCURLY);
+		if ( inputState.guessing==0 ) {
+			enumConstantBlock_AST = (AST)currentAST.root;
+			enumConstantBlock_AST = (AST)astFactory.make( (new ASTArray(2)).add(astFactory.create(OBJBLOCK,"OBJBLOCK")).add(enumConstantBlock_AST));
+			currentAST.root = enumConstantBlock_AST;
+			currentAST.child = enumConstantBlock_AST!=null &&enumConstantBlock_AST.getFirstChild()!=null ?
+				enumConstantBlock_AST.getFirstChild() : enumConstantBlock_AST;
+			currentAST.advanceChildToEnd();
+		}
+		enumConstantBlock_AST = (AST)currentAST.root;
+		returnAST = enumConstantBlock_AST;
+	}
+	
+	public final void enumConstantField() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST enumConstantField_AST = null;
+		AST mods_AST = null;
+		AST td_AST = null;
+		AST tp_AST = null;
+		AST t_AST = null;
+		AST param_AST = null;
+		AST rt_AST = null;
+		AST tc_AST = null;
+		AST s2_AST = null;
+		AST v_AST = null;
+		AST s4_AST = null;
+		Token first = LT(1);
+		
+		switch ( LA(1)) {
+		case FINAL:
+		case ABSTRACT:
+		case STRICTFP:
+		case LITERAL_static:
+		case IDENT:
+		case LT:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		case LITERAL_private:
+		case LITERAL_public:
+		case LITERAL_protected:
+		case LITERAL_transient:
+		case LITERAL_native:
+		case LITERAL_threadsafe:
+		case LITERAL_synchronized:
+		case LITERAL_volatile:
+		case AT:
+		case LITERAL_class:
+		case LITERAL_interface:
+		case LITERAL_enum:
+		{
+			modifiers();
+			mods_AST = (AST)returnAST;
+			{
+			switch ( LA(1)) {
+			case AT:
+			case LITERAL_class:
+			case LITERAL_interface:
+			case LITERAL_enum:
+			{
+				typeDefinitionInternal(mods_AST);
+				td_AST = (AST)returnAST;
+				if ( inputState.guessing==0 ) {
+					enumConstantField_AST = (AST)currentAST.root;
+					enumConstantField_AST = td_AST;
+					currentAST.root = enumConstantField_AST;
+					currentAST.child = enumConstantField_AST!=null &&enumConstantField_AST.getFirstChild()!=null ?
+						enumConstantField_AST.getFirstChild() : enumConstantField_AST;
+					currentAST.advanceChildToEnd();
+				}
+				break;
+			}
+			case IDENT:
+			case LT:
+			case LITERAL_void:
+			case LITERAL_boolean:
+			case LITERAL_byte:
+			case LITERAL_char:
+			case LITERAL_short:
+			case LITERAL_int:
+			case LITERAL_float:
+			case LITERAL_long:
+			case LITERAL_double:
+			{
+				{
+				switch ( LA(1)) {
+				case LT:
+				{
+					typeParameters();
+					tp_AST = (AST)returnAST;
+					break;
+				}
+				case IDENT:
+				case LITERAL_void:
+				case LITERAL_boolean:
+				case LITERAL_byte:
+				case LITERAL_char:
+				case LITERAL_short:
+				case LITERAL_int:
+				case LITERAL_float:
+				case LITERAL_long:
+				case LITERAL_double:
+				{
+					break;
+				}
+				default:
+				{
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				}
+				}
+				typeSpec(false);
+				t_AST = (AST)returnAST;
+				{
+				if ((LA(1)==IDENT) && (LA(2)==LPAREN)) {
+					AST tmp112_AST = null;
+					tmp112_AST = astFactory.create(LT(1));
+					match(IDENT);
+					match(LPAREN);
+					parameterDeclarationList();
+					param_AST = (AST)returnAST;
+					match(RPAREN);
+					declaratorBrackets(t_AST);
+					rt_AST = (AST)returnAST;
+					{
+					switch ( LA(1)) {
+					case LITERAL_throws:
+					{
+						throwsClause();
+						tc_AST = (AST)returnAST;
+						break;
+					}
+					case SEMI:
+					case LCURLY:
+					{
+						break;
+					}
+					default:
+					{
+						throw new NoViableAltException(LT(1), getFilename());
+					}
+					}
+					}
+					{
+					switch ( LA(1)) {
+					case LCURLY:
+					{
+						compoundStatement();
+						s2_AST = (AST)returnAST;
+						break;
+					}
+					case SEMI:
+					{
+						AST tmp115_AST = null;
+						tmp115_AST = astFactory.create(LT(1));
+						match(SEMI);
+						break;
+					}
+					default:
+					{
+						throw new NoViableAltException(LT(1), getFilename());
+					}
+					}
+					}
+					if ( inputState.guessing==0 ) {
+						enumConstantField_AST = (AST)currentAST.root;
+						enumConstantField_AST = (AST)astFactory.make( (new ASTArray(8)).add(create(METHOD_DEF,"METHOD_DEF",first,LT(1))).add(mods_AST).add(tp_AST).add((AST)astFactory.make( (new ASTArray(2)).add(create(TYPE,"TYPE",first,LT(1))).add(rt_AST))).add(tmp112_AST).add(param_AST).add(tc_AST).add(s2_AST));
+						currentAST.root = enumConstantField_AST;
+						currentAST.child = enumConstantField_AST!=null &&enumConstantField_AST.getFirstChild()!=null ?
+							enumConstantField_AST.getFirstChild() : enumConstantField_AST;
+						currentAST.advanceChildToEnd();
+					}
+				}
+				else if ((LA(1)==IDENT) && (_tokenSet_19.member(LA(2)))) {
+					variableDefinitions(mods_AST,t_AST);
+					v_AST = (AST)returnAST;
+					AST tmp116_AST = null;
+					tmp116_AST = astFactory.create(LT(1));
+					match(SEMI);
+					if ( inputState.guessing==0 ) {
+						enumConstantField_AST = (AST)currentAST.root;
+						enumConstantField_AST = v_AST;
+						currentAST.root = enumConstantField_AST;
+						currentAST.child = enumConstantField_AST!=null &&enumConstantField_AST.getFirstChild()!=null ?
+							enumConstantField_AST.getFirstChild() : enumConstantField_AST;
+						currentAST.advanceChildToEnd();
+					}
+				}
+				else {
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				
+				}
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+			}
+			break;
+		}
+		case LCURLY:
+		{
+			compoundStatement();
+			s4_AST = (AST)returnAST;
+			if ( inputState.guessing==0 ) {
+				enumConstantField_AST = (AST)currentAST.root;
+				enumConstantField_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(INSTANCE_INIT,"INSTANCE_INIT",first,LT(1))).add(s4_AST));
+				currentAST.root = enumConstantField_AST;
+				currentAST.child = enumConstantField_AST!=null &&enumConstantField_AST.getFirstChild()!=null ?
+					enumConstantField_AST.getFirstChild() : enumConstantField_AST;
+				currentAST.advanceChildToEnd();
+			}
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		returnAST = enumConstantField_AST;
+	}
+	
+	public final void parameterDeclarationList() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST parameterDeclarationList_AST = null;
+		Token first = LT(1);
+		
+		{
+		boolean synPredMatched171 = false;
+		if (((_tokenSet_20.member(LA(1))) && (_tokenSet_21.member(LA(2))))) {
+			int _m171 = mark();
+			synPredMatched171 = true;
+			inputState.guessing++;
+			try {
+				{
+				parameterDeclaration();
+				}
+			}
+			catch (RecognitionException pe) {
+				synPredMatched171 = false;
+			}
+			rewind(_m171);
+			inputState.guessing--;
+		}
+		if ( synPredMatched171 ) {
+			parameterDeclaration();
+			astFactory.addASTChild(currentAST, returnAST);
+			{
+			_loop175:
+			do {
+				boolean synPredMatched174 = false;
+				if (((LA(1)==COMMA) && (_tokenSet_20.member(LA(2))))) {
+					int _m174 = mark();
+					synPredMatched174 = true;
+					inputState.guessing++;
+					try {
+						{
+						match(COMMA);
+						parameterDeclaration();
+						}
+					}
+					catch (RecognitionException pe) {
+						synPredMatched174 = false;
+					}
+					rewind(_m174);
+					inputState.guessing--;
+				}
+				if ( synPredMatched174 ) {
+					match(COMMA);
+					parameterDeclaration();
+					astFactory.addASTChild(currentAST, returnAST);
+				}
+				else {
+					break _loop175;
+				}
+				
+			} while (true);
+			}
+			{
+			switch ( LA(1)) {
+			case COMMA:
+			{
+				match(COMMA);
+				variableLengthParameterDeclaration();
+				astFactory.addASTChild(currentAST, returnAST);
+				break;
+			}
+			case RPAREN:
+			{
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+			}
+		}
+		else if ((_tokenSet_20.member(LA(1))) && (_tokenSet_22.member(LA(2)))) {
+			variableLengthParameterDeclaration();
+			astFactory.addASTChild(currentAST, returnAST);
+		}
+		else if ((LA(1)==RPAREN)) {
+		}
+		else {
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		
+		}
+		if ( inputState.guessing==0 ) {
+			parameterDeclarationList_AST = (AST)currentAST.root;
+			parameterDeclarationList_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(PARAMETERS,"PARAMETERS",first,LT(1))).add(parameterDeclarationList_AST));
+			currentAST.root = parameterDeclarationList_AST;
+			currentAST.child = parameterDeclarationList_AST!=null &&parameterDeclarationList_AST.getFirstChild()!=null ?
+				parameterDeclarationList_AST.getFirstChild() : parameterDeclarationList_AST;
+			currentAST.advanceChildToEnd();
+		}
+		parameterDeclarationList_AST = (AST)currentAST.root;
+		returnAST = parameterDeclarationList_AST;
+	}
+	
+	public final void throwsClause() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST throwsClause_AST = null;
+		
+		AST tmp119_AST = null;
+		tmp119_AST = astFactory.create(LT(1));
+		astFactory.makeASTRoot(currentAST, tmp119_AST);
+		match(LITERAL_throws);
+		identifier();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop167:
+		do {
+			if ((LA(1)==COMMA)) {
+				match(COMMA);
+				identifier();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop167;
+			}
+			
+		} while (true);
+		}
+		throwsClause_AST = (AST)currentAST.root;
+		returnAST = throwsClause_AST;
+	}
+	
+	public final void compoundStatement() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST compoundStatement_AST = null;
+		Token  lc = null;
+		AST lc_AST = null;
+		
+		lc = LT(1);
+		lc_AST = astFactory.create(lc);
+		astFactory.makeASTRoot(currentAST, lc_AST);
+		match(LCURLY);
+		if ( inputState.guessing==0 ) {
+			lc_AST.setType(SLIST);
+		}
+		{
+		_loop187:
+		do {
+			if ((_tokenSet_23.member(LA(1)))) {
+				statement();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop187;
+			}
+			
+		} while (true);
+		}
+		match(RCURLY);
+		compoundStatement_AST = (AST)currentAST.root;
+		returnAST = compoundStatement_AST;
+	}
+	
+	public final void ctorHead() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST ctorHead_AST = null;
+		
+		AST tmp122_AST = null;
+		tmp122_AST = astFactory.create(LT(1));
+		astFactory.addASTChild(currentAST, tmp122_AST);
+		match(IDENT);
+		match(LPAREN);
+		parameterDeclarationList();
+		astFactory.addASTChild(currentAST, returnAST);
+		match(RPAREN);
+		{
+		switch ( LA(1)) {
+		case LITERAL_throws:
+		{
+			throwsClause();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		case LCURLY:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		ctorHead_AST = (AST)currentAST.root;
+		returnAST = ctorHead_AST;
+	}
+	
+	public final void constructorBody() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST constructorBody_AST = null;
+		Token  lc = null;
+		AST lc_AST = null;
+		
+		lc = LT(1);
+		lc_AST = astFactory.create(lc);
+		astFactory.makeASTRoot(currentAST, lc_AST);
+		match(LCURLY);
+		if ( inputState.guessing==0 ) {
+			lc_AST.setType(SLIST);
+		}
+		{
+		if ((_tokenSet_24.member(LA(1))) && (_tokenSet_25.member(LA(2)))) {
+			explicitConstructorInvocation();
+			astFactory.addASTChild(currentAST, returnAST);
+		}
+		else if ((_tokenSet_26.member(LA(1))) && (_tokenSet_27.member(LA(2)))) {
+		}
+		else {
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		
+		}
+		{
+		_loop149:
+		do {
+			if ((_tokenSet_23.member(LA(1)))) {
+				statement();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop149;
+			}
+			
+		} while (true);
+		}
+		match(RCURLY);
+		constructorBody_AST = (AST)currentAST.root;
+		returnAST = constructorBody_AST;
+	}
+	
+/** Catch obvious constructor calls, but not the expr.super(...) calls */
+	public final void explicitConstructorInvocation() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST explicitConstructorInvocation_AST = null;
+		Token  lp1 = null;
+		AST lp1_AST = null;
+		Token  lp2 = null;
+		AST lp2_AST = null;
+		
+		{
+		switch ( LA(1)) {
+		case LT:
+		{
+			typeArguments();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		case LITERAL_super:
+		case LITERAL_this:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		{
+		switch ( LA(1)) {
+		case LITERAL_this:
+		{
+			match(LITERAL_this);
+			lp1 = LT(1);
+			lp1_AST = astFactory.create(lp1);
+			astFactory.makeASTRoot(currentAST, lp1_AST);
+			match(LPAREN);
+			argList();
+			astFactory.addASTChild(currentAST, returnAST);
+			match(RPAREN);
+			match(SEMI);
+			if ( inputState.guessing==0 ) {
+				lp1_AST.setType(CTOR_CALL);
+			}
+			break;
+		}
+		case LITERAL_super:
+		{
+			match(LITERAL_super);
+			lp2 = LT(1);
+			lp2_AST = astFactory.create(lp2);
+			astFactory.makeASTRoot(currentAST, lp2_AST);
+			match(LPAREN);
+			argList();
+			astFactory.addASTChild(currentAST, returnAST);
+			match(RPAREN);
+			match(SEMI);
+			if ( inputState.guessing==0 ) {
+				lp2_AST.setType(SUPER_CTOR_CALL);
+			}
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		explicitConstructorInvocation_AST = (AST)currentAST.root;
+		returnAST = explicitConstructorInvocation_AST;
+	}
+	
+	public final void statement() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST statement_AST = null;
+		AST m_AST = null;
+		Token  c = null;
+		AST c_AST = null;
+		Token  s = null;
+		AST s_AST = null;
+		
+		switch ( LA(1)) {
+		case LCURLY:
+		{
+			compoundStatement();
+			astFactory.addASTChild(currentAST, returnAST);
+			statement_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_if:
+		{
+			AST tmp132_AST = null;
+			tmp132_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp132_AST);
+			match(LITERAL_if);
+			match(LPAREN);
+			expression();
+			astFactory.addASTChild(currentAST, returnAST);
+			match(RPAREN);
+			statement();
+			astFactory.addASTChild(currentAST, returnAST);
+			{
+			if ((LA(1)==LITERAL_else) && (_tokenSet_23.member(LA(2)))) {
+				match(LITERAL_else);
+				statement();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else if ((_tokenSet_28.member(LA(1))) && (_tokenSet_29.member(LA(2)))) {
+			}
+			else {
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			
+			}
+			statement_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_for:
+		{
+			forStatement();
+			astFactory.addASTChild(currentAST, returnAST);
+			statement_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_while:
+		{
+			AST tmp136_AST = null;
+			tmp136_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp136_AST);
+			match(LITERAL_while);
+			match(LPAREN);
+			expression();
+			astFactory.addASTChild(currentAST, returnAST);
+			match(RPAREN);
+			statement();
+			astFactory.addASTChild(currentAST, returnAST);
+			statement_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_break:
+		{
+			AST tmp139_AST = null;
+			tmp139_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp139_AST);
+			match(LITERAL_break);
+			{
+			switch ( LA(1)) {
+			case IDENT:
+			{
+				AST tmp140_AST = null;
+				tmp140_AST = astFactory.create(LT(1));
+				astFactory.addASTChild(currentAST, tmp140_AST);
+				match(IDENT);
+				break;
+			}
+			case SEMI:
+			{
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+			}
+			match(SEMI);
+			statement_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_continue:
+		{
+			AST tmp142_AST = null;
+			tmp142_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp142_AST);
+			match(LITERAL_continue);
+			{
+			switch ( LA(1)) {
+			case IDENT:
+			{
+				AST tmp143_AST = null;
+				tmp143_AST = astFactory.create(LT(1));
+				astFactory.addASTChild(currentAST, tmp143_AST);
+				match(IDENT);
+				break;
+			}
+			case SEMI:
+			{
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+			}
+			match(SEMI);
+			statement_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_return:
+		{
+			AST tmp145_AST = null;
+			tmp145_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp145_AST);
+			match(LITERAL_return);
+			{
+			switch ( LA(1)) {
+			case IDENT:
+			case LITERAL_super:
+			case LT:
+			case LITERAL_void:
+			case LITERAL_boolean:
+			case LITERAL_byte:
+			case LITERAL_char:
+			case LITERAL_short:
+			case LITERAL_int:
+			case LITERAL_float:
+			case LITERAL_long:
+			case LITERAL_double:
+			case LPAREN:
+			case LITERAL_this:
+			case PLUS:
+			case MINUS:
+			case INC:
+			case DEC:
+			case BNOT:
+			case LNOT:
+			case LITERAL_true:
+			case LITERAL_false:
+			case LITERAL_null:
+			case LITERAL_new:
+			case NUM_INT:
+			case STRING_LITERAL:
+			case NUM_FLOAT:
+			case NUM_LONG:
+			case NUM_DOUBLE:
+			{
+				expression();
+				astFactory.addASTChild(currentAST, returnAST);
+				break;
+			}
+			case SEMI:
+			{
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+			}
+			match(SEMI);
+			statement_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_switch:
+		{
+			AST tmp147_AST = null;
+			tmp147_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp147_AST);
+			match(LITERAL_switch);
+			match(LPAREN);
+			expression();
+			astFactory.addASTChild(currentAST, returnAST);
+			match(RPAREN);
+			match(LCURLY);
+			{
+			_loop196:
+			do {
+				if ((LA(1)==LITERAL_default||LA(1)==LITERAL_case)) {
+					casesGroup();
+					astFactory.addASTChild(currentAST, returnAST);
+				}
+				else {
+					break _loop196;
+				}
+				
+			} while (true);
+			}
+			match(RCURLY);
+			statement_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_try:
+		{
+			tryBlock();
+			astFactory.addASTChild(currentAST, returnAST);
+			statement_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_throw:
+		{
+			AST tmp152_AST = null;
+			tmp152_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp152_AST);
+			match(LITERAL_throw);
+			expression();
+			astFactory.addASTChild(currentAST, returnAST);
+			match(SEMI);
+			statement_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_assert:
+		{
+			AST tmp154_AST = null;
+			tmp154_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp154_AST);
+			match(LITERAL_assert);
+			expression();
+			astFactory.addASTChild(currentAST, returnAST);
+			{
+			switch ( LA(1)) {
+			case COLON:
+			{
+				match(COLON);
+				expression();
+				astFactory.addASTChild(currentAST, returnAST);
+				break;
+			}
+			case SEMI:
+			{
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+			}
+			match(SEMI);
+			statement_AST = (AST)currentAST.root;
+			break;
+		}
+		case SEMI:
+		{
+			s = LT(1);
+			s_AST = astFactory.create(s);
+			astFactory.addASTChild(currentAST, s_AST);
+			match(SEMI);
+			if ( inputState.guessing==0 ) {
+				s_AST.setType(EMPTY_STAT);
+			}
+			statement_AST = (AST)currentAST.root;
+			break;
+		}
+		default:
+			boolean synPredMatched190 = false;
+			if (((_tokenSet_30.member(LA(1))) && (_tokenSet_31.member(LA(2))))) {
+				int _m190 = mark();
+				synPredMatched190 = true;
+				inputState.guessing++;
+				try {
+					{
+					declaration();
+					}
+				}
+				catch (RecognitionException pe) {
+					synPredMatched190 = false;
+				}
+				rewind(_m190);
+				inputState.guessing--;
+			}
+			if ( synPredMatched190 ) {
+				declaration();
+				astFactory.addASTChild(currentAST, returnAST);
+				match(SEMI);
+				statement_AST = (AST)currentAST.root;
+			}
+			else if ((_tokenSet_32.member(LA(1))) && (_tokenSet_33.member(LA(2)))) {
+				expression();
+				astFactory.addASTChild(currentAST, returnAST);
+				match(SEMI);
+				statement_AST = (AST)currentAST.root;
+			}
+			else if ((_tokenSet_34.member(LA(1))) && (_tokenSet_35.member(LA(2)))) {
+				modifiers();
+				m_AST = (AST)returnAST;
+				classDefinition(m_AST);
+				astFactory.addASTChild(currentAST, returnAST);
+				statement_AST = (AST)currentAST.root;
+			}
+			else if ((LA(1)==IDENT) && (LA(2)==COLON)) {
+				AST tmp159_AST = null;
+				tmp159_AST = astFactory.create(LT(1));
+				astFactory.addASTChild(currentAST, tmp159_AST);
+				match(IDENT);
+				c = LT(1);
+				c_AST = astFactory.create(c);
+				astFactory.makeASTRoot(currentAST, c_AST);
+				match(COLON);
+				if ( inputState.guessing==0 ) {
+					c_AST.setType(LABELED_STAT);
+				}
+				statement();
+				astFactory.addASTChild(currentAST, returnAST);
+				statement_AST = (AST)currentAST.root;
+			}
+			else if ((LA(1)==LITERAL_synchronized) && (LA(2)==LPAREN)) {
+				AST tmp160_AST = null;
+				tmp160_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp160_AST);
+				match(LITERAL_synchronized);
+				match(LPAREN);
+				expression();
+				astFactory.addASTChild(currentAST, returnAST);
+				match(RPAREN);
+				compoundStatement();
+				astFactory.addASTChild(currentAST, returnAST);
+				statement_AST = (AST)currentAST.root;
+			}
+		else {
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		returnAST = statement_AST;
+	}
+	
+/** Declaration of a variable. This can be a class/instance variable,
+ *  or a local variable in a method
+ *  It can also include possible initialization.
+ */
+	public final void variableDeclarator(
+		AST mods, AST t
+	) throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST variableDeclarator_AST = null;
+		Token  id = null;
+		AST id_AST = null;
+		AST d_AST = null;
+		AST v_AST = null;
+		Token first = LT(1);
+		
+		id = LT(1);
+		id_AST = astFactory.create(id);
+		match(IDENT);
+		declaratorBrackets(t);
+		d_AST = (AST)returnAST;
+		varInitializer();
+		v_AST = (AST)returnAST;
+		if ( inputState.guessing==0 ) {
+			variableDeclarator_AST = (AST)currentAST.root;
+			variableDeclarator_AST = (AST)astFactory.make( (new ASTArray(5)).add(create(VARIABLE_DEF,"VARIABLE_DEF",first,LT(1))).add(mods).add((AST)astFactory.make( (new ASTArray(2)).add(create(TYPE,"TYPE",first,LT(1))).add(d_AST))).add(id_AST).add(v_AST));
+			currentAST.root = variableDeclarator_AST;
+			currentAST.child = variableDeclarator_AST!=null &&variableDeclarator_AST.getFirstChild()!=null ?
+				variableDeclarator_AST.getFirstChild() : variableDeclarator_AST;
+			currentAST.advanceChildToEnd();
+		}
+		returnAST = variableDeclarator_AST;
+	}
+	
+	public final void varInitializer() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST varInitializer_AST = null;
+		
+		{
+		switch ( LA(1)) {
+		case ASSIGN:
+		{
+			AST tmp163_AST = null;
+			tmp163_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp163_AST);
+			match(ASSIGN);
+			initializer();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		case SEMI:
+		case COMMA:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		varInitializer_AST = (AST)currentAST.root;
+		returnAST = varInitializer_AST;
+	}
+	
+	public final void initializer() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST initializer_AST = null;
+		
+		expression();
+		astFactory.addASTChild(currentAST, returnAST);
+		initializer_AST = (AST)currentAST.root;
+		returnAST = initializer_AST;
+	}
+	
+	public final void expression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST expression_AST = null;
+		Token first = LT(1);
+		
+		assignmentExpression();
+		astFactory.addASTChild(currentAST, returnAST);
+		if ( inputState.guessing==0 ) {
+			expression_AST = (AST)currentAST.root;
+			expression_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(EXPR,"EXPR",first,LT(1))).add(expression_AST));
+			currentAST.root = expression_AST;
+			currentAST.child = expression_AST!=null &&expression_AST.getFirstChild()!=null ?
+				expression_AST.getFirstChild() : expression_AST;
+			currentAST.advanceChildToEnd();
+		}
+		expression_AST = (AST)currentAST.root;
+		returnAST = expression_AST;
+	}
+	
+	public final void parameterDeclaration() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST parameterDeclaration_AST = null;
+		AST pm_AST = null;
+		AST t_AST = null;
+		Token  id = null;
+		AST id_AST = null;
+		AST pd_AST = null;
+		Token first = LT(1);
+		
+		parameterModifier();
+		pm_AST = (AST)returnAST;
+		typeSpec(false);
+		t_AST = (AST)returnAST;
+		id = LT(1);
+		id_AST = astFactory.create(id);
+		match(IDENT);
+		declaratorBrackets(t_AST);
+		pd_AST = (AST)returnAST;
+		if ( inputState.guessing==0 ) {
+			parameterDeclaration_AST = (AST)currentAST.root;
+			parameterDeclaration_AST = (AST)astFactory.make( (new ASTArray(4)).add(create(PARAMETER_DEF,"PARAMETER_DEF",first,LT(1))).add(pm_AST).add((AST)astFactory.make( (new ASTArray(2)).add(create(TYPE,"TYPE",first,LT(1))).add(pd_AST))).add(id_AST));
+			currentAST.root = parameterDeclaration_AST;
+			currentAST.child = parameterDeclaration_AST!=null &&parameterDeclaration_AST.getFirstChild()!=null ?
+				parameterDeclaration_AST.getFirstChild() : parameterDeclaration_AST;
+			currentAST.advanceChildToEnd();
+		}
+		returnAST = parameterDeclaration_AST;
+	}
+	
+	public final void variableLengthParameterDeclaration() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST variableLengthParameterDeclaration_AST = null;
+		AST pm_AST = null;
+		AST t_AST = null;
+		Token  id = null;
+		AST id_AST = null;
+		AST pd_AST = null;
+		Token first = LT(1);
+		
+		parameterModifier();
+		pm_AST = (AST)returnAST;
+		typeSpec(false);
+		t_AST = (AST)returnAST;
+		match(TRIPLE_DOT);
+		id = LT(1);
+		id_AST = astFactory.create(id);
+		match(IDENT);
+		declaratorBrackets(t_AST);
+		pd_AST = (AST)returnAST;
+		if ( inputState.guessing==0 ) {
+			variableLengthParameterDeclaration_AST = (AST)currentAST.root;
+			variableLengthParameterDeclaration_AST = (AST)astFactory.make( (new ASTArray(4)).add(create(VARIABLE_PARAMETER_DEF,"VARIABLE_PARAMETER_DEF",first,LT(1))).add(pm_AST).add((AST)astFactory.make( (new ASTArray(2)).add(create(TYPE,"TYPE",first,LT(1))).add(pd_AST))).add(id_AST));
+			currentAST.root = variableLengthParameterDeclaration_AST;
+			currentAST.child = variableLengthParameterDeclaration_AST!=null &&variableLengthParameterDeclaration_AST.getFirstChild()!=null ?
+				variableLengthParameterDeclaration_AST.getFirstChild() : variableLengthParameterDeclaration_AST;
+			currentAST.advanceChildToEnd();
+		}
+		returnAST = variableLengthParameterDeclaration_AST;
+	}
+	
+	public final void parameterModifier() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST parameterModifier_AST = null;
+		Token  f = null;
+		AST f_AST = null;
+		Token first = LT(1);
+		
+		{
+		_loop181:
+		do {
+			if ((LA(1)==AT) && (LA(2)==IDENT)) {
+				annotation();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop181;
+			}
+			
+		} while (true);
+		}
+		{
+		switch ( LA(1)) {
+		case FINAL:
+		{
+			f = LT(1);
+			f_AST = astFactory.create(f);
+			astFactory.addASTChild(currentAST, f_AST);
+			match(FINAL);
+			break;
+		}
+		case IDENT:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		case AT:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		{
+		_loop184:
+		do {
+			if ((LA(1)==AT)) {
+				annotation();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop184;
+			}
+			
+		} while (true);
+		}
+		if ( inputState.guessing==0 ) {
+			parameterModifier_AST = (AST)currentAST.root;
+			parameterModifier_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(MODIFIERS,"MODIFIERS",first,LT(1))).add(parameterModifier_AST));
+			currentAST.root = parameterModifier_AST;
+			currentAST.child = parameterModifier_AST!=null &&parameterModifier_AST.getFirstChild()!=null ?
+				parameterModifier_AST.getFirstChild() : parameterModifier_AST;
+			currentAST.advanceChildToEnd();
+		}
+		parameterModifier_AST = (AST)currentAST.root;
+		returnAST = parameterModifier_AST;
+	}
+	
+	public final void forStatement() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST forStatement_AST = null;
+		Token  f = null;
+		AST f_AST = null;
+		
+		f = LT(1);
+		f_AST = astFactory.create(f);
+		astFactory.makeASTRoot(currentAST, f_AST);
+		match(LITERAL_for);
+		match(LPAREN);
+		{
+		boolean synPredMatched201 = false;
+		if (((_tokenSet_36.member(LA(1))) && (_tokenSet_37.member(LA(2))))) {
+			int _m201 = mark();
+			synPredMatched201 = true;
+			inputState.guessing++;
+			try {
+				{
+				forInit();
+				match(SEMI);
+				}
+			}
+			catch (RecognitionException pe) {
+				synPredMatched201 = false;
+			}
+			rewind(_m201);
+			inputState.guessing--;
+		}
+		if ( synPredMatched201 ) {
+			traditionalForClause();
+			astFactory.addASTChild(currentAST, returnAST);
+		}
+		else if ((_tokenSet_20.member(LA(1))) && (_tokenSet_21.member(LA(2)))) {
+			forEachClause();
+			astFactory.addASTChild(currentAST, returnAST);
+		}
+		else {
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		
+		}
+		match(RPAREN);
+		statement();
+		astFactory.addASTChild(currentAST, returnAST);
+		forStatement_AST = (AST)currentAST.root;
+		returnAST = forStatement_AST;
+	}
+	
+	public final void casesGroup() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST casesGroup_AST = null;
+		
+		{
+		int _cnt206=0;
+		_loop206:
+		do {
+			if ((LA(1)==LITERAL_default||LA(1)==LITERAL_case) && (_tokenSet_38.member(LA(2)))) {
+				aCase();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				if ( _cnt206>=1 ) { break _loop206; } else {throw new NoViableAltException(LT(1), getFilename());}
+			}
+			
+			_cnt206++;
+		} while (true);
+		}
+		caseSList();
+		astFactory.addASTChild(currentAST, returnAST);
+		if ( inputState.guessing==0 ) {
+			casesGroup_AST = (AST)currentAST.root;
+			casesGroup_AST = (AST)astFactory.make( (new ASTArray(2)).add(astFactory.create(CASE_GROUP,"CASE_GROUP")).add(casesGroup_AST));
+			currentAST.root = casesGroup_AST;
+			currentAST.child = casesGroup_AST!=null &&casesGroup_AST.getFirstChild()!=null ?
+				casesGroup_AST.getFirstChild() : casesGroup_AST;
+			currentAST.advanceChildToEnd();
+		}
+		casesGroup_AST = (AST)currentAST.root;
+		returnAST = casesGroup_AST;
+	}
+	
+	public final void tryBlock() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST tryBlock_AST = null;
+		
+		AST tmp167_AST = null;
+		tmp167_AST = astFactory.create(LT(1));
+		astFactory.makeASTRoot(currentAST, tmp167_AST);
+		match(LITERAL_try);
+		compoundStatement();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop222:
+		do {
+			if ((LA(1)==LITERAL_catch)) {
+				handler();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop222;
+			}
+			
+		} while (true);
+		}
+		{
+		switch ( LA(1)) {
+		case LITERAL_finally:
+		{
+			finallyClause();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		case FINAL:
+		case ABSTRACT:
+		case STRICTFP:
+		case SEMI:
+		case LITERAL_static:
+		case IDENT:
+		case LITERAL_super:
+		case LT:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		case LITERAL_private:
+		case LITERAL_public:
+		case LITERAL_protected:
+		case LITERAL_transient:
+		case LITERAL_native:
+		case LITERAL_threadsafe:
+		case LITERAL_synchronized:
+		case LITERAL_volatile:
+		case AT:
+		case LPAREN:
+		case LCURLY:
+		case RCURLY:
+		case LITERAL_class:
+		case LITERAL_default:
+		case LITERAL_this:
+		case LITERAL_if:
+		case LITERAL_else:
+		case LITERAL_while:
+		case LITERAL_break:
+		case LITERAL_continue:
+		case LITERAL_return:
+		case LITERAL_switch:
+		case LITERAL_throw:
+		case LITERAL_assert:
+		case LITERAL_for:
+		case LITERAL_case:
+		case LITERAL_try:
+		case PLUS:
+		case MINUS:
+		case INC:
+		case DEC:
+		case BNOT:
+		case LNOT:
+		case LITERAL_true:
+		case LITERAL_false:
+		case LITERAL_null:
+		case LITERAL_new:
+		case NUM_INT:
+		case STRING_LITERAL:
+		case NUM_FLOAT:
+		case NUM_LONG:
+		case NUM_DOUBLE:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		tryBlock_AST = (AST)currentAST.root;
+		returnAST = tryBlock_AST;
+	}
+	
+	public final void forInit() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST forInit_AST = null;
+		Token first = LT(1);
+		
+		{
+		boolean synPredMatched215 = false;
+		if (((_tokenSet_30.member(LA(1))) && (_tokenSet_31.member(LA(2))))) {
+			int _m215 = mark();
+			synPredMatched215 = true;
+			inputState.guessing++;
+			try {
+				{
+				declaration();
+				}
+			}
+			catch (RecognitionException pe) {
+				synPredMatched215 = false;
+			}
+			rewind(_m215);
+			inputState.guessing--;
+		}
+		if ( synPredMatched215 ) {
+			declaration();
+			astFactory.addASTChild(currentAST, returnAST);
+		}
+		else if ((_tokenSet_32.member(LA(1))) && (_tokenSet_39.member(LA(2)))) {
+			expressionList();
+			astFactory.addASTChild(currentAST, returnAST);
+		}
+		else if ((LA(1)==SEMI)) {
+		}
+		else {
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		
+		}
+		if ( inputState.guessing==0 ) {
+			forInit_AST = (AST)currentAST.root;
+			forInit_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(FOR_INIT,"FOR_INIT",first,LT(1))).add(forInit_AST));
+			currentAST.root = forInit_AST;
+			currentAST.child = forInit_AST!=null &&forInit_AST.getFirstChild()!=null ?
+				forInit_AST.getFirstChild() : forInit_AST;
+			currentAST.advanceChildToEnd();
+		}
+		forInit_AST = (AST)currentAST.root;
+		returnAST = forInit_AST;
+	}
+	
+	public final void traditionalForClause() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST traditionalForClause_AST = null;
+		
+		forInit();
+		astFactory.addASTChild(currentAST, returnAST);
+		match(SEMI);
+		forCond();
+		astFactory.addASTChild(currentAST, returnAST);
+		match(SEMI);
+		forIter();
+		astFactory.addASTChild(currentAST, returnAST);
+		traditionalForClause_AST = (AST)currentAST.root;
+		returnAST = traditionalForClause_AST;
+	}
+	
+	public final void forEachClause() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST forEachClause_AST = null;
+		AST p_AST = null;
+		Token first = LT(1);
+		
+		parameterDeclaration();
+		p_AST = (AST)returnAST;
+		astFactory.addASTChild(currentAST, returnAST);
+		match(COLON);
+		expression();
+		astFactory.addASTChild(currentAST, returnAST);
+		if ( inputState.guessing==0 ) {
+			forEachClause_AST = (AST)currentAST.root;
+			forEachClause_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(FOR_EACH_CLAUSE,"FOR_EACH_CLAUSE",first,LT(1))).add(forEachClause_AST));
+			currentAST.root = forEachClause_AST;
+			currentAST.child = forEachClause_AST!=null &&forEachClause_AST.getFirstChild()!=null ?
+				forEachClause_AST.getFirstChild() : forEachClause_AST;
+			currentAST.advanceChildToEnd();
+		}
+		forEachClause_AST = (AST)currentAST.root;
+		returnAST = forEachClause_AST;
+	}
+	
+	public final void forCond() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST forCond_AST = null;
+		Token first = LT(1);
+		
+		{
+		switch ( LA(1)) {
+		case IDENT:
+		case LITERAL_super:
+		case LT:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		case LPAREN:
+		case LITERAL_this:
+		case PLUS:
+		case MINUS:
+		case INC:
+		case DEC:
+		case BNOT:
+		case LNOT:
+		case LITERAL_true:
+		case LITERAL_false:
+		case LITERAL_null:
+		case LITERAL_new:
+		case NUM_INT:
+		case STRING_LITERAL:
+		case NUM_FLOAT:
+		case NUM_LONG:
+		case NUM_DOUBLE:
+		{
+			expression();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		case SEMI:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		if ( inputState.guessing==0 ) {
+			forCond_AST = (AST)currentAST.root;
+			forCond_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(FOR_CONDITION,"FOR_CONDITION",first,LT(1))).add(forCond_AST));
+			currentAST.root = forCond_AST;
+			currentAST.child = forCond_AST!=null &&forCond_AST.getFirstChild()!=null ?
+				forCond_AST.getFirstChild() : forCond_AST;
+			currentAST.advanceChildToEnd();
+		}
+		forCond_AST = (AST)currentAST.root;
+		returnAST = forCond_AST;
+	}
+	
+	public final void forIter() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST forIter_AST = null;
+		Token first = LT(1);
+		
+		{
+		switch ( LA(1)) {
+		case IDENT:
+		case LITERAL_super:
+		case LT:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		case LPAREN:
+		case LITERAL_this:
+		case PLUS:
+		case MINUS:
+		case INC:
+		case DEC:
+		case BNOT:
+		case LNOT:
+		case LITERAL_true:
+		case LITERAL_false:
+		case LITERAL_null:
+		case LITERAL_new:
+		case NUM_INT:
+		case STRING_LITERAL:
+		case NUM_FLOAT:
+		case NUM_LONG:
+		case NUM_DOUBLE:
+		{
+			expressionList();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		case RPAREN:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		if ( inputState.guessing==0 ) {
+			forIter_AST = (AST)currentAST.root;
+			forIter_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(FOR_ITERATOR,"FOR_ITERATOR",first,LT(1))).add(forIter_AST));
+			currentAST.root = forIter_AST;
+			currentAST.child = forIter_AST!=null &&forIter_AST.getFirstChild()!=null ?
+				forIter_AST.getFirstChild() : forIter_AST;
+			currentAST.advanceChildToEnd();
+		}
+		forIter_AST = (AST)currentAST.root;
+		returnAST = forIter_AST;
+	}
+	
+	public final void aCase() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST aCase_AST = null;
+		
+		{
+		switch ( LA(1)) {
+		case LITERAL_case:
+		{
+			AST tmp171_AST = null;
+			tmp171_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp171_AST);
+			match(LITERAL_case);
+			expression();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		case LITERAL_default:
+		{
+			AST tmp172_AST = null;
+			tmp172_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp172_AST);
+			match(LITERAL_default);
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		match(COLON);
+		aCase_AST = (AST)currentAST.root;
+		returnAST = aCase_AST;
+	}
+	
+	public final void caseSList() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST caseSList_AST = null;
+		Token first = LT(1);
+		
+		{
+		_loop211:
+		do {
+			if ((_tokenSet_23.member(LA(1)))) {
+				statement();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop211;
+			}
+			
+		} while (true);
+		}
+		if ( inputState.guessing==0 ) {
+			caseSList_AST = (AST)currentAST.root;
+			caseSList_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(SLIST,"SLIST",first,LT(1))).add(caseSList_AST));
+			currentAST.root = caseSList_AST;
+			currentAST.child = caseSList_AST!=null &&caseSList_AST.getFirstChild()!=null ?
+				caseSList_AST.getFirstChild() : caseSList_AST;
+			currentAST.advanceChildToEnd();
+		}
+		caseSList_AST = (AST)currentAST.root;
+		returnAST = caseSList_AST;
+	}
+	
+	public final void expressionList() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST expressionList_AST = null;
+		Token first = LT(1);
+		
+		expression();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop229:
+		do {
+			if ((LA(1)==COMMA)) {
+				match(COMMA);
+				expression();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop229;
+			}
+			
+		} while (true);
+		}
+		if ( inputState.guessing==0 ) {
+			expressionList_AST = (AST)currentAST.root;
+			expressionList_AST = (AST)astFactory.make( (new ASTArray(2)).add(create(ELIST,"ELIST",first,LT(1))).add(expressionList_AST));
+			currentAST.root = expressionList_AST;
+			currentAST.child = expressionList_AST!=null &&expressionList_AST.getFirstChild()!=null ?
+				expressionList_AST.getFirstChild() : expressionList_AST;
+			currentAST.advanceChildToEnd();
+		}
+		expressionList_AST = (AST)currentAST.root;
+		returnAST = expressionList_AST;
+	}
+	
+	public final void handler() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST handler_AST = null;
+		
+		AST tmp175_AST = null;
+		tmp175_AST = astFactory.create(LT(1));
+		astFactory.makeASTRoot(currentAST, tmp175_AST);
+		match(LITERAL_catch);
+		match(LPAREN);
+		parameterDeclaration();
+		astFactory.addASTChild(currentAST, returnAST);
+		match(RPAREN);
+		compoundStatement();
+		astFactory.addASTChild(currentAST, returnAST);
+		handler_AST = (AST)currentAST.root;
+		returnAST = handler_AST;
+	}
+	
+	public final void finallyClause() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST finallyClause_AST = null;
+		
+		AST tmp178_AST = null;
+		tmp178_AST = astFactory.create(LT(1));
+		astFactory.makeASTRoot(currentAST, tmp178_AST);
+		match(LITERAL_finally);
+		compoundStatement();
+		astFactory.addASTChild(currentAST, returnAST);
+		finallyClause_AST = (AST)currentAST.root;
+		returnAST = finallyClause_AST;
+	}
+	
+	public final void assignmentExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST assignmentExpression_AST = null;
+		
+		conditionalExpression();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		switch ( LA(1)) {
+		case ASSIGN:
+		case PLUS_ASSIGN:
+		case MINUS_ASSIGN:
+		case STAR_ASSIGN:
+		case DIV_ASSIGN:
+		case MOD_ASSIGN:
+		case SR_ASSIGN:
+		case BSR_ASSIGN:
+		case SL_ASSIGN:
+		case BAND_ASSIGN:
+		case BXOR_ASSIGN:
+		case BOR_ASSIGN:
+		{
+			{
+			switch ( LA(1)) {
+			case ASSIGN:
+			{
+				AST tmp179_AST = null;
+				tmp179_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp179_AST);
+				match(ASSIGN);
+				break;
+			}
+			case PLUS_ASSIGN:
+			{
+				AST tmp180_AST = null;
+				tmp180_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp180_AST);
+				match(PLUS_ASSIGN);
+				break;
+			}
+			case MINUS_ASSIGN:
+			{
+				AST tmp181_AST = null;
+				tmp181_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp181_AST);
+				match(MINUS_ASSIGN);
+				break;
+			}
+			case STAR_ASSIGN:
+			{
+				AST tmp182_AST = null;
+				tmp182_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp182_AST);
+				match(STAR_ASSIGN);
+				break;
+			}
+			case DIV_ASSIGN:
+			{
+				AST tmp183_AST = null;
+				tmp183_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp183_AST);
+				match(DIV_ASSIGN);
+				break;
+			}
+			case MOD_ASSIGN:
+			{
+				AST tmp184_AST = null;
+				tmp184_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp184_AST);
+				match(MOD_ASSIGN);
+				break;
+			}
+			case SR_ASSIGN:
+			{
+				AST tmp185_AST = null;
+				tmp185_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp185_AST);
+				match(SR_ASSIGN);
+				break;
+			}
+			case BSR_ASSIGN:
+			{
+				AST tmp186_AST = null;
+				tmp186_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp186_AST);
+				match(BSR_ASSIGN);
+				break;
+			}
+			case SL_ASSIGN:
+			{
+				AST tmp187_AST = null;
+				tmp187_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp187_AST);
+				match(SL_ASSIGN);
+				break;
+			}
+			case BAND_ASSIGN:
+			{
+				AST tmp188_AST = null;
+				tmp188_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp188_AST);
+				match(BAND_ASSIGN);
+				break;
+			}
+			case BXOR_ASSIGN:
+			{
+				AST tmp189_AST = null;
+				tmp189_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp189_AST);
+				match(BXOR_ASSIGN);
+				break;
+			}
+			case BOR_ASSIGN:
+			{
+				AST tmp190_AST = null;
+				tmp190_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp190_AST);
+				match(BOR_ASSIGN);
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+			}
+			assignmentExpression();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		case SEMI:
+		case RBRACK:
+		case COMMA:
+		case RPAREN:
+		case COLON:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		assignmentExpression_AST = (AST)currentAST.root;
+		returnAST = assignmentExpression_AST;
+	}
+	
+	public final void logicalOrExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST logicalOrExpression_AST = null;
+		
+		logicalAndExpression();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop237:
+		do {
+			if ((LA(1)==LOR)) {
+				AST tmp191_AST = null;
+				tmp191_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp191_AST);
+				match(LOR);
+				logicalAndExpression();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop237;
+			}
+			
+		} while (true);
+		}
+		logicalOrExpression_AST = (AST)currentAST.root;
+		returnAST = logicalOrExpression_AST;
+	}
+	
+	public final void logicalAndExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST logicalAndExpression_AST = null;
+		
+		inclusiveOrExpression();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop240:
+		do {
+			if ((LA(1)==LAND)) {
+				AST tmp192_AST = null;
+				tmp192_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp192_AST);
+				match(LAND);
+				inclusiveOrExpression();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop240;
+			}
+			
+		} while (true);
+		}
+		logicalAndExpression_AST = (AST)currentAST.root;
+		returnAST = logicalAndExpression_AST;
+	}
+	
+	public final void inclusiveOrExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST inclusiveOrExpression_AST = null;
+		
+		exclusiveOrExpression();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop243:
+		do {
+			if ((LA(1)==BOR)) {
+				AST tmp193_AST = null;
+				tmp193_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp193_AST);
+				match(BOR);
+				exclusiveOrExpression();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop243;
+			}
+			
+		} while (true);
+		}
+		inclusiveOrExpression_AST = (AST)currentAST.root;
+		returnAST = inclusiveOrExpression_AST;
+	}
+	
+	public final void exclusiveOrExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST exclusiveOrExpression_AST = null;
+		
+		andExpression();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop246:
+		do {
+			if ((LA(1)==BXOR)) {
+				AST tmp194_AST = null;
+				tmp194_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp194_AST);
+				match(BXOR);
+				andExpression();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop246;
+			}
+			
+		} while (true);
+		}
+		exclusiveOrExpression_AST = (AST)currentAST.root;
+		returnAST = exclusiveOrExpression_AST;
+	}
+	
+	public final void andExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST andExpression_AST = null;
+		
+		equalityExpression();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop249:
+		do {
+			if ((LA(1)==BAND)) {
+				AST tmp195_AST = null;
+				tmp195_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp195_AST);
+				match(BAND);
+				equalityExpression();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop249;
+			}
+			
+		} while (true);
+		}
+		andExpression_AST = (AST)currentAST.root;
+		returnAST = andExpression_AST;
+	}
+	
+	public final void equalityExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST equalityExpression_AST = null;
+		
+		relationalExpression();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop253:
+		do {
+			if ((LA(1)==NOT_EQUAL||LA(1)==EQUAL)) {
+				{
+				switch ( LA(1)) {
+				case NOT_EQUAL:
+				{
+					AST tmp196_AST = null;
+					tmp196_AST = astFactory.create(LT(1));
+					astFactory.makeASTRoot(currentAST, tmp196_AST);
+					match(NOT_EQUAL);
+					break;
+				}
+				case EQUAL:
+				{
+					AST tmp197_AST = null;
+					tmp197_AST = astFactory.create(LT(1));
+					astFactory.makeASTRoot(currentAST, tmp197_AST);
+					match(EQUAL);
+					break;
+				}
+				default:
+				{
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				}
+				}
+				relationalExpression();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop253;
+			}
+			
+		} while (true);
+		}
+		equalityExpression_AST = (AST)currentAST.root;
+		returnAST = equalityExpression_AST;
+	}
+	
+	public final void relationalExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST relationalExpression_AST = null;
+		
+		shiftExpression();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		switch ( LA(1)) {
+		case SEMI:
+		case RBRACK:
+		case QUESTION:
+		case LT:
+		case COMMA:
+		case GT:
+		case RPAREN:
+		case ASSIGN:
+		case RCURLY:
+		case BAND:
+		case COLON:
+		case PLUS_ASSIGN:
+		case MINUS_ASSIGN:
+		case STAR_ASSIGN:
+		case DIV_ASSIGN:
+		case MOD_ASSIGN:
+		case SR_ASSIGN:
+		case BSR_ASSIGN:
+		case SL_ASSIGN:
+		case BAND_ASSIGN:
+		case BXOR_ASSIGN:
+		case BOR_ASSIGN:
+		case LOR:
+		case LAND:
+		case BOR:
+		case BXOR:
+		case NOT_EQUAL:
+		case EQUAL:
+		case LE:
+		case GE:
+		{
+			{
+			_loop258:
+			do {
+				if ((_tokenSet_40.member(LA(1)))) {
+					{
+					switch ( LA(1)) {
+					case LT:
+					{
+						AST tmp198_AST = null;
+						tmp198_AST = astFactory.create(LT(1));
+						astFactory.makeASTRoot(currentAST, tmp198_AST);
+						match(LT);
+						break;
+					}
+					case GT:
+					{
+						AST tmp199_AST = null;
+						tmp199_AST = astFactory.create(LT(1));
+						astFactory.makeASTRoot(currentAST, tmp199_AST);
+						match(GT);
+						break;
+					}
+					case LE:
+					{
+						AST tmp200_AST = null;
+						tmp200_AST = astFactory.create(LT(1));
+						astFactory.makeASTRoot(currentAST, tmp200_AST);
+						match(LE);
+						break;
+					}
+					case GE:
+					{
+						AST tmp201_AST = null;
+						tmp201_AST = astFactory.create(LT(1));
+						astFactory.makeASTRoot(currentAST, tmp201_AST);
+						match(GE);
+						break;
+					}
+					default:
+					{
+						throw new NoViableAltException(LT(1), getFilename());
+					}
+					}
+					}
+					shiftExpression();
+					astFactory.addASTChild(currentAST, returnAST);
+				}
+				else {
+					break _loop258;
+				}
+				
+			} while (true);
+			}
+			break;
+		}
+		case LITERAL_instanceof:
+		{
+			AST tmp202_AST = null;
+			tmp202_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp202_AST);
+			match(LITERAL_instanceof);
+			typeSpec(true);
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		relationalExpression_AST = (AST)currentAST.root;
+		returnAST = relationalExpression_AST;
+	}
+	
+	public final void shiftExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST shiftExpression_AST = null;
+		
+		additiveExpression();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop262:
+		do {
+			if ((_tokenSet_41.member(LA(1)))) {
+				{
+				switch ( LA(1)) {
+				case SL:
+				{
+					AST tmp203_AST = null;
+					tmp203_AST = astFactory.create(LT(1));
+					astFactory.makeASTRoot(currentAST, tmp203_AST);
+					match(SL);
+					break;
+				}
+				case SR:
+				{
+					AST tmp204_AST = null;
+					tmp204_AST = astFactory.create(LT(1));
+					astFactory.makeASTRoot(currentAST, tmp204_AST);
+					match(SR);
+					break;
+				}
+				case BSR:
+				{
+					AST tmp205_AST = null;
+					tmp205_AST = astFactory.create(LT(1));
+					astFactory.makeASTRoot(currentAST, tmp205_AST);
+					match(BSR);
+					break;
+				}
+				default:
+				{
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				}
+				}
+				additiveExpression();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop262;
+			}
+			
+		} while (true);
+		}
+		shiftExpression_AST = (AST)currentAST.root;
+		returnAST = shiftExpression_AST;
+	}
+	
+	public final void additiveExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST additiveExpression_AST = null;
+		
+		multiplicativeExpression();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop266:
+		do {
+			if ((LA(1)==PLUS||LA(1)==MINUS)) {
+				{
+				switch ( LA(1)) {
+				case PLUS:
+				{
+					AST tmp206_AST = null;
+					tmp206_AST = astFactory.create(LT(1));
+					astFactory.makeASTRoot(currentAST, tmp206_AST);
+					match(PLUS);
+					break;
+				}
+				case MINUS:
+				{
+					AST tmp207_AST = null;
+					tmp207_AST = astFactory.create(LT(1));
+					astFactory.makeASTRoot(currentAST, tmp207_AST);
+					match(MINUS);
+					break;
+				}
+				default:
+				{
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				}
+				}
+				multiplicativeExpression();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop266;
+			}
+			
+		} while (true);
+		}
+		additiveExpression_AST = (AST)currentAST.root;
+		returnAST = additiveExpression_AST;
+	}
+	
+	public final void multiplicativeExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST multiplicativeExpression_AST = null;
+		
+		unaryExpression();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop270:
+		do {
+			if ((_tokenSet_42.member(LA(1)))) {
+				{
+				switch ( LA(1)) {
+				case STAR:
+				{
+					AST tmp208_AST = null;
+					tmp208_AST = astFactory.create(LT(1));
+					astFactory.makeASTRoot(currentAST, tmp208_AST);
+					match(STAR);
+					break;
+				}
+				case DIV:
+				{
+					AST tmp209_AST = null;
+					tmp209_AST = astFactory.create(LT(1));
+					astFactory.makeASTRoot(currentAST, tmp209_AST);
+					match(DIV);
+					break;
+				}
+				case MOD:
+				{
+					AST tmp210_AST = null;
+					tmp210_AST = astFactory.create(LT(1));
+					astFactory.makeASTRoot(currentAST, tmp210_AST);
+					match(MOD);
+					break;
+				}
+				default:
+				{
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				}
+				}
+				unaryExpression();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				break _loop270;
+			}
+			
+		} while (true);
+		}
+		multiplicativeExpression_AST = (AST)currentAST.root;
+		returnAST = multiplicativeExpression_AST;
+	}
+	
+	public final void unaryExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST unaryExpression_AST = null;
+		
+		switch ( LA(1)) {
+		case INC:
+		{
+			AST tmp211_AST = null;
+			tmp211_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp211_AST);
+			match(INC);
+			unaryExpression();
+			astFactory.addASTChild(currentAST, returnAST);
+			unaryExpression_AST = (AST)currentAST.root;
+			break;
+		}
+		case DEC:
+		{
+			AST tmp212_AST = null;
+			tmp212_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp212_AST);
+			match(DEC);
+			unaryExpression();
+			astFactory.addASTChild(currentAST, returnAST);
+			unaryExpression_AST = (AST)currentAST.root;
+			break;
+		}
+		case MINUS:
+		{
+			AST tmp213_AST = null;
+			tmp213_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp213_AST);
+			match(MINUS);
+			if ( inputState.guessing==0 ) {
+				tmp213_AST.setType(UNARY_MINUS);
+			}
+			unaryExpression();
+			astFactory.addASTChild(currentAST, returnAST);
+			unaryExpression_AST = (AST)currentAST.root;
+			break;
+		}
+		case PLUS:
+		{
+			AST tmp214_AST = null;
+			tmp214_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp214_AST);
+			match(PLUS);
+			if ( inputState.guessing==0 ) {
+				tmp214_AST.setType(UNARY_PLUS);
+			}
+			unaryExpression();
+			astFactory.addASTChild(currentAST, returnAST);
+			unaryExpression_AST = (AST)currentAST.root;
+			break;
+		}
+		case IDENT:
+		case LITERAL_super:
+		case LT:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		case LPAREN:
+		case LITERAL_this:
+		case BNOT:
+		case LNOT:
+		case LITERAL_true:
+		case LITERAL_false:
+		case LITERAL_null:
+		case LITERAL_new:
+		case NUM_INT:
+		case STRING_LITERAL:
+		case NUM_FLOAT:
+		case NUM_LONG:
+		case NUM_DOUBLE:
+		{
+			unaryExpressionNotPlusMinus();
+			astFactory.addASTChild(currentAST, returnAST);
+			unaryExpression_AST = (AST)currentAST.root;
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		returnAST = unaryExpression_AST;
+	}
+	
+	public final void unaryExpressionNotPlusMinus() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST unaryExpressionNotPlusMinus_AST = null;
+		Token  lpb = null;
+		AST lpb_AST = null;
+		Token  lp = null;
+		AST lp_AST = null;
+		
+		switch ( LA(1)) {
+		case BNOT:
+		{
+			AST tmp215_AST = null;
+			tmp215_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp215_AST);
+			match(BNOT);
+			unaryExpression();
+			astFactory.addASTChild(currentAST, returnAST);
+			unaryExpressionNotPlusMinus_AST = (AST)currentAST.root;
+			break;
+		}
+		case LNOT:
+		{
+			AST tmp216_AST = null;
+			tmp216_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp216_AST);
+			match(LNOT);
+			unaryExpression();
+			astFactory.addASTChild(currentAST, returnAST);
+			unaryExpressionNotPlusMinus_AST = (AST)currentAST.root;
+			break;
+		}
+		case IDENT:
+		case LITERAL_super:
+		case LT:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		case LPAREN:
+		case LITERAL_this:
+		case LITERAL_true:
+		case LITERAL_false:
+		case LITERAL_null:
+		case LITERAL_new:
+		case NUM_INT:
+		case STRING_LITERAL:
+		case NUM_FLOAT:
+		case NUM_LONG:
+		case NUM_DOUBLE:
+		{
+			{
+			boolean synPredMatched275 = false;
+			if (((LA(1)==LPAREN) && ((LA(2) >= LITERAL_void && LA(2) <= LITERAL_double)))) {
+				int _m275 = mark();
+				synPredMatched275 = true;
+				inputState.guessing++;
+				try {
+					{
+					match(LPAREN);
+					builtInTypeSpec(true);
+					match(RPAREN);
+					unaryExpression();
+					}
+				}
+				catch (RecognitionException pe) {
+					synPredMatched275 = false;
+				}
+				rewind(_m275);
+				inputState.guessing--;
+			}
+			if ( synPredMatched275 ) {
+				lpb = LT(1);
+				lpb_AST = astFactory.create(lpb);
+				astFactory.makeASTRoot(currentAST, lpb_AST);
+				match(LPAREN);
+				if ( inputState.guessing==0 ) {
+					lpb_AST.setType(TYPECAST);
+				}
+				builtInTypeSpec(true);
+				astFactory.addASTChild(currentAST, returnAST);
+				match(RPAREN);
+				unaryExpression();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else {
+				boolean synPredMatched277 = false;
+				if (((LA(1)==LPAREN) && (LA(2)==IDENT))) {
+					int _m277 = mark();
+					synPredMatched277 = true;
+					inputState.guessing++;
+					try {
+						{
+						match(LPAREN);
+						classTypeSpec(true);
+						match(RPAREN);
+						unaryExpressionNotPlusMinus();
+						}
+					}
+					catch (RecognitionException pe) {
+						synPredMatched277 = false;
+					}
+					rewind(_m277);
+					inputState.guessing--;
+				}
+				if ( synPredMatched277 ) {
+					lp = LT(1);
+					lp_AST = astFactory.create(lp);
+					astFactory.makeASTRoot(currentAST, lp_AST);
+					match(LPAREN);
+					if ( inputState.guessing==0 ) {
+						lp_AST.setType(TYPECAST);
+					}
+					classTypeSpec(true);
+					astFactory.addASTChild(currentAST, returnAST);
+					match(RPAREN);
+					unaryExpressionNotPlusMinus();
+					astFactory.addASTChild(currentAST, returnAST);
+				}
+				else if ((_tokenSet_43.member(LA(1))) && (_tokenSet_44.member(LA(2)))) {
+					postfixExpression();
+					astFactory.addASTChild(currentAST, returnAST);
+				}
+				else {
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				}
+				}
+				unaryExpressionNotPlusMinus_AST = (AST)currentAST.root;
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+			returnAST = unaryExpressionNotPlusMinus_AST;
+		}
+		
+	public final void postfixExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST postfixExpression_AST = null;
+		Token  lp = null;
+		AST lp_AST = null;
+		Token  lp3 = null;
+		AST lp3_AST = null;
+		Token  lps = null;
+		AST lps_AST = null;
+		Token  lb = null;
+		AST lb_AST = null;
+		Token  in = null;
+		AST in_AST = null;
+		Token  de = null;
+		AST de_AST = null;
+		
+		primaryExpression();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		_loop286:
+		do {
+			if ((LA(1)==DOT) && (_tokenSet_45.member(LA(2)))) {
+				AST tmp219_AST = null;
+				tmp219_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp219_AST);
+				match(DOT);
+				{
+				switch ( LA(1)) {
+				case LT:
+				{
+					typeArguments();
+					astFactory.addASTChild(currentAST, returnAST);
+					break;
+				}
+				case IDENT:
+				case LITERAL_super:
+				{
+					break;
+				}
+				default:
+				{
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				}
+				}
+				{
+				switch ( LA(1)) {
+				case IDENT:
+				{
+					AST tmp220_AST = null;
+					tmp220_AST = astFactory.create(LT(1));
+					astFactory.addASTChild(currentAST, tmp220_AST);
+					match(IDENT);
+					{
+					switch ( LA(1)) {
+					case LPAREN:
+					{
+						lp = LT(1);
+						lp_AST = astFactory.create(lp);
+						astFactory.makeASTRoot(currentAST, lp_AST);
+						match(LPAREN);
+						if ( inputState.guessing==0 ) {
+							lp_AST.setType(METHOD_CALL);
+						}
+						argList();
+						astFactory.addASTChild(currentAST, returnAST);
+						match(RPAREN);
+						break;
+					}
+					case SEMI:
+					case LBRACK:
+					case RBRACK:
+					case DOT:
+					case QUESTION:
+					case LT:
+					case COMMA:
+					case GT:
+					case SR:
+					case BSR:
+					case STAR:
+					case RPAREN:
+					case ASSIGN:
+					case RCURLY:
+					case BAND:
+					case COLON:
+					case PLUS_ASSIGN:
+					case MINUS_ASSIGN:
+					case STAR_ASSIGN:
+					case DIV_ASSIGN:
+					case MOD_ASSIGN:
+					case SR_ASSIGN:
+					case BSR_ASSIGN:
+					case SL_ASSIGN:
+					case BAND_ASSIGN:
+					case BXOR_ASSIGN:
+					case BOR_ASSIGN:
+					case LOR:
+					case LAND:
+					case BOR:
+					case BXOR:
+					case NOT_EQUAL:
+					case EQUAL:
+					case LE:
+					case GE:
+					case LITERAL_instanceof:
+					case SL:
+					case PLUS:
+					case MINUS:
+					case DIV:
+					case MOD:
+					case INC:
+					case DEC:
+					{
+						break;
+					}
+					default:
+					{
+						throw new NoViableAltException(LT(1), getFilename());
+					}
+					}
+					}
+					break;
+				}
+				case LITERAL_super:
+				{
+					AST tmp222_AST = null;
+					tmp222_AST = astFactory.create(LT(1));
+					astFactory.addASTChild(currentAST, tmp222_AST);
+					match(LITERAL_super);
+					{
+					switch ( LA(1)) {
+					case LPAREN:
+					{
+						lp3 = LT(1);
+						lp3_AST = astFactory.create(lp3);
+						astFactory.makeASTRoot(currentAST, lp3_AST);
+						match(LPAREN);
+						argList();
+						astFactory.addASTChild(currentAST, returnAST);
+						match(RPAREN);
+						if ( inputState.guessing==0 ) {
+							lp3_AST.setType(SUPER_CTOR_CALL);
+						}
+						break;
+					}
+					case DOT:
+					{
+						AST tmp224_AST = null;
+						tmp224_AST = astFactory.create(LT(1));
+						astFactory.makeASTRoot(currentAST, tmp224_AST);
+						match(DOT);
+						{
+						switch ( LA(1)) {
+						case LT:
+						{
+							typeArguments();
+							astFactory.addASTChild(currentAST, returnAST);
+							break;
+						}
+						case IDENT:
+						{
+							break;
+						}
+						default:
+						{
+							throw new NoViableAltException(LT(1), getFilename());
+						}
+						}
+						}
+						AST tmp225_AST = null;
+						tmp225_AST = astFactory.create(LT(1));
+						astFactory.addASTChild(currentAST, tmp225_AST);
+						match(IDENT);
+						{
+						switch ( LA(1)) {
+						case LPAREN:
+						{
+							lps = LT(1);
+							lps_AST = astFactory.create(lps);
+							astFactory.makeASTRoot(currentAST, lps_AST);
+							match(LPAREN);
+							if ( inputState.guessing==0 ) {
+								lps_AST.setType(METHOD_CALL);
+							}
+							argList();
+							astFactory.addASTChild(currentAST, returnAST);
+							match(RPAREN);
+							break;
+						}
+						case SEMI:
+						case LBRACK:
+						case RBRACK:
+						case DOT:
+						case QUESTION:
+						case LT:
+						case COMMA:
+						case GT:
+						case SR:
+						case BSR:
+						case STAR:
+						case RPAREN:
+						case ASSIGN:
+						case RCURLY:
+						case BAND:
+						case COLON:
+						case PLUS_ASSIGN:
+						case MINUS_ASSIGN:
+						case STAR_ASSIGN:
+						case DIV_ASSIGN:
+						case MOD_ASSIGN:
+						case SR_ASSIGN:
+						case BSR_ASSIGN:
+						case SL_ASSIGN:
+						case BAND_ASSIGN:
+						case BXOR_ASSIGN:
+						case BOR_ASSIGN:
+						case LOR:
+						case LAND:
+						case BOR:
+						case BXOR:
+						case NOT_EQUAL:
+						case EQUAL:
+						case LE:
+						case GE:
+						case LITERAL_instanceof:
+						case SL:
+						case PLUS:
+						case MINUS:
+						case DIV:
+						case MOD:
+						case INC:
+						case DEC:
+						{
+							break;
+						}
+						default:
+						{
+							throw new NoViableAltException(LT(1), getFilename());
+						}
+						}
+						}
+						break;
+					}
+					default:
+					{
+						throw new NoViableAltException(LT(1), getFilename());
+					}
+					}
+					}
+					break;
+				}
+				default:
+				{
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				}
+				}
+			}
+			else if ((LA(1)==DOT) && (LA(2)==LITERAL_this)) {
+				AST tmp227_AST = null;
+				tmp227_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp227_AST);
+				match(DOT);
+				AST tmp228_AST = null;
+				tmp228_AST = astFactory.create(LT(1));
+				astFactory.addASTChild(currentAST, tmp228_AST);
+				match(LITERAL_this);
+			}
+			else if ((LA(1)==DOT) && (LA(2)==LITERAL_new)) {
+				AST tmp229_AST = null;
+				tmp229_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp229_AST);
+				match(DOT);
+				newExpression();
+				astFactory.addASTChild(currentAST, returnAST);
+			}
+			else if ((LA(1)==LBRACK)) {
+				lb = LT(1);
+				lb_AST = astFactory.create(lb);
+				astFactory.makeASTRoot(currentAST, lb_AST);
+				match(LBRACK);
+				if ( inputState.guessing==0 ) {
+					lb_AST.setType(INDEX_OP);
+				}
+				expression();
+				astFactory.addASTChild(currentAST, returnAST);
+				match(RBRACK);
+			}
+			else {
+				break _loop286;
+			}
+			
+		} while (true);
+		}
+		{
+		switch ( LA(1)) {
+		case INC:
+		{
+			in = LT(1);
+			in_AST = astFactory.create(in);
+			astFactory.makeASTRoot(currentAST, in_AST);
+			match(INC);
+			if ( inputState.guessing==0 ) {
+				in_AST.setType(POST_INC);
+			}
+			break;
+		}
+		case DEC:
+		{
+			de = LT(1);
+			de_AST = astFactory.create(de);
+			astFactory.makeASTRoot(currentAST, de_AST);
+			match(DEC);
+			if ( inputState.guessing==0 ) {
+				de_AST.setType(POST_DEC);
+			}
+			break;
+		}
+		case SEMI:
+		case RBRACK:
+		case QUESTION:
+		case LT:
+		case COMMA:
+		case GT:
+		case SR:
+		case BSR:
+		case STAR:
+		case RPAREN:
+		case ASSIGN:
+		case RCURLY:
+		case BAND:
+		case COLON:
+		case PLUS_ASSIGN:
+		case MINUS_ASSIGN:
+		case STAR_ASSIGN:
+		case DIV_ASSIGN:
+		case MOD_ASSIGN:
+		case SR_ASSIGN:
+		case BSR_ASSIGN:
+		case SL_ASSIGN:
+		case BAND_ASSIGN:
+		case BXOR_ASSIGN:
+		case BOR_ASSIGN:
+		case LOR:
+		case LAND:
+		case BOR:
+		case BXOR:
+		case NOT_EQUAL:
+		case EQUAL:
+		case LE:
+		case GE:
+		case LITERAL_instanceof:
+		case SL:
+		case PLUS:
+		case MINUS:
+		case DIV:
+		case MOD:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		postfixExpression_AST = (AST)currentAST.root;
+		returnAST = postfixExpression_AST;
+	}
+	
+	public final void primaryExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST primaryExpression_AST = null;
+		Token  lbt = null;
+		AST lbt_AST = null;
+		
+		switch ( LA(1)) {
+		case IDENT:
+		case LT:
+		{
+			identPrimary();
+			astFactory.addASTChild(currentAST, returnAST);
+			{
+			if ((LA(1)==DOT) && (LA(2)==LITERAL_class)) {
+				AST tmp231_AST = null;
+				tmp231_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp231_AST);
+				match(DOT);
+				AST tmp232_AST = null;
+				tmp232_AST = astFactory.create(LT(1));
+				astFactory.addASTChild(currentAST, tmp232_AST);
+				match(LITERAL_class);
+			}
+			else if ((_tokenSet_46.member(LA(1))) && (_tokenSet_47.member(LA(2)))) {
+			}
+			else {
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			
+			}
+			primaryExpression_AST = (AST)currentAST.root;
+			break;
+		}
+		case NUM_INT:
+		case STRING_LITERAL:
+		case NUM_FLOAT:
+		case NUM_LONG:
+		case NUM_DOUBLE:
+		{
+			constant();
+			astFactory.addASTChild(currentAST, returnAST);
+			primaryExpression_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_true:
+		{
+			AST tmp233_AST = null;
+			tmp233_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp233_AST);
+			match(LITERAL_true);
+			primaryExpression_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_false:
+		{
+			AST tmp234_AST = null;
+			tmp234_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp234_AST);
+			match(LITERAL_false);
+			primaryExpression_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_null:
+		{
+			AST tmp235_AST = null;
+			tmp235_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp235_AST);
+			match(LITERAL_null);
+			primaryExpression_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_new:
+		{
+			newExpression();
+			astFactory.addASTChild(currentAST, returnAST);
+			primaryExpression_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_this:
+		{
+			AST tmp236_AST = null;
+			tmp236_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp236_AST);
+			match(LITERAL_this);
+			primaryExpression_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_super:
+		{
+			AST tmp237_AST = null;
+			tmp237_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp237_AST);
+			match(LITERAL_super);
+			primaryExpression_AST = (AST)currentAST.root;
+			break;
+		}
+		case LPAREN:
+		{
+			match(LPAREN);
+			assignmentExpression();
+			astFactory.addASTChild(currentAST, returnAST);
+			match(RPAREN);
+			primaryExpression_AST = (AST)currentAST.root;
+			break;
+		}
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		{
+			builtInType();
+			astFactory.addASTChild(currentAST, returnAST);
+			{
+			_loop291:
+			do {
+				if ((LA(1)==LBRACK)) {
+					lbt = LT(1);
+					lbt_AST = astFactory.create(lbt);
+					astFactory.makeASTRoot(currentAST, lbt_AST);
+					match(LBRACK);
+					if ( inputState.guessing==0 ) {
+						lbt_AST.setType(ARRAY_DECLARATOR);
+					}
+					match(RBRACK);
+				}
+				else {
+					break _loop291;
+				}
+				
+			} while (true);
+			}
+			AST tmp241_AST = null;
+			tmp241_AST = astFactory.create(LT(1));
+			astFactory.makeASTRoot(currentAST, tmp241_AST);
+			match(DOT);
+			AST tmp242_AST = null;
+			tmp242_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp242_AST);
+			match(LITERAL_class);
+			primaryExpression_AST = (AST)currentAST.root;
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		returnAST = primaryExpression_AST;
+	}
+	
+/** object instantiation.
+ *  Trees are built as illustrated by the following input/tree pairs:
+ *
+ *  new T()
+ *
+ *  new
+ *   |
+ *   T --  ELIST
+ *		   |
+ *		  arg1 -- arg2 -- .. -- argn
+ *
+ *  new int[]
+ *
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR
+ *
+ *  new int[] {1,2}
+ *
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR -- ARRAY_INIT
+ *								  |
+ *								EXPR -- EXPR
+ *								  |	  |
+ *								  1	  2
+ *
+ *  new int[3]
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR
+ *				|
+ *			  EXPR
+ *				|
+ *				3
+ *
+ *  new int[1][2]
+ *
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR
+ *			   |
+ *		 ARRAY_DECLARATOR -- EXPR
+ *			   |			  |
+ *			 EXPR			 1
+ *			   |
+ *			   2
+ *
+ */
+	public final void newExpression() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST newExpression_AST = null;
+		
+		AST tmp243_AST = null;
+		tmp243_AST = astFactory.create(LT(1));
+		astFactory.makeASTRoot(currentAST, tmp243_AST);
+		match(LITERAL_new);
+		{
+		switch ( LA(1)) {
+		case LT:
+		{
+			typeArguments();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		case IDENT:
+		case LITERAL_void:
+		case LITERAL_boolean:
+		case LITERAL_byte:
+		case LITERAL_char:
+		case LITERAL_short:
+		case LITERAL_int:
+		case LITERAL_float:
+		case LITERAL_long:
+		case LITERAL_double:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		type();
+		astFactory.addASTChild(currentAST, returnAST);
+		{
+		switch ( LA(1)) {
+		case LPAREN:
+		{
+			match(LPAREN);
+			argList();
+			astFactory.addASTChild(currentAST, returnAST);
+			match(RPAREN);
+			{
+			switch ( LA(1)) {
+			case LCURLY:
+			{
+				classBlock();
+				astFactory.addASTChild(currentAST, returnAST);
+				break;
+			}
+			case SEMI:
+			case LBRACK:
+			case RBRACK:
+			case DOT:
+			case QUESTION:
+			case LT:
+			case COMMA:
+			case GT:
+			case SR:
+			case BSR:
+			case STAR:
+			case RPAREN:
+			case ASSIGN:
+			case RCURLY:
+			case BAND:
+			case COLON:
+			case PLUS_ASSIGN:
+			case MINUS_ASSIGN:
+			case STAR_ASSIGN:
+			case DIV_ASSIGN:
+			case MOD_ASSIGN:
+			case SR_ASSIGN:
+			case BSR_ASSIGN:
+			case SL_ASSIGN:
+			case BAND_ASSIGN:
+			case BXOR_ASSIGN:
+			case BOR_ASSIGN:
+			case LOR:
+			case LAND:
+			case BOR:
+			case BXOR:
+			case NOT_EQUAL:
+			case EQUAL:
+			case LE:
+			case GE:
+			case LITERAL_instanceof:
+			case SL:
+			case PLUS:
+			case MINUS:
+			case DIV:
+			case MOD:
+			case INC:
+			case DEC:
+			{
+				break;
+			}
+			default:
+			{
+				throw new NoViableAltException(LT(1), getFilename());
+			}
+			}
+			}
+			break;
+		}
+		case LBRACK:
+		{
+			newArrayDeclarator();
+			astFactory.addASTChild(currentAST, returnAST);
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		newExpression_AST = (AST)currentAST.root;
+		returnAST = newExpression_AST;
+	}
+	
+/** Match a, a.b.c refs, a.b.c(...) refs, a.b.c[], a.b.c[].class,
+ *  and a.b.c.class refs. Also this(...) and super(...). Match
+ *  this or super.
+ */
+	public final void identPrimary() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST identPrimary_AST = null;
+		AST ta1_AST = null;
+		AST ta2_AST = null;
+		Token  lp = null;
+		AST lp_AST = null;
+		Token  lbc = null;
+		AST lbc_AST = null;
+		
+		{
+		switch ( LA(1)) {
+		case LT:
+		{
+			typeArguments();
+			ta1_AST = (AST)returnAST;
+			break;
+		}
+		case IDENT:
+		{
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		}
+		AST tmp246_AST = null;
+		tmp246_AST = astFactory.create(LT(1));
+		astFactory.addASTChild(currentAST, tmp246_AST);
+		match(IDENT);
+		{
+		_loop299:
+		do {
+			boolean synPredMatched297 = false;
+			if (((LA(1)==DOT) && (LA(2)==IDENT||LA(2)==LT))) {
+				int _m297 = mark();
+				synPredMatched297 = true;
+				inputState.guessing++;
+				try {
+					{
+					match(DOT);
+					{
+					switch ( LA(1)) {
+					case LT:
+					{
+						typeArguments();
+						break;
+					}
+					case IDENT:
+					{
+						break;
+					}
+					default:
+					{
+						throw new NoViableAltException(LT(1), getFilename());
+					}
+					}
+					}
+					match(IDENT);
+					}
+				}
+				catch (RecognitionException pe) {
+					synPredMatched297 = false;
+				}
+				rewind(_m297);
+				inputState.guessing--;
+			}
+			if ( synPredMatched297 ) {
+				AST tmp247_AST = null;
+				tmp247_AST = astFactory.create(LT(1));
+				astFactory.makeASTRoot(currentAST, tmp247_AST);
+				match(DOT);
+				{
+				switch ( LA(1)) {
+				case LT:
+				{
+					typeArguments();
+					ta2_AST = (AST)returnAST;
+					break;
+				}
+				case IDENT:
+				{
+					break;
+				}
+				default:
+				{
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				}
+				}
+				AST tmp248_AST = null;
+				tmp248_AST = astFactory.create(LT(1));
+				astFactory.addASTChild(currentAST, tmp248_AST);
+				match(IDENT);
+			}
+			else if (((_tokenSet_48.member(LA(1))) && (_tokenSet_47.member(LA(2))))&&(false)) {
+			}
+			else {
+				break _loop299;
+			}
+			
+		} while (true);
+		}
+		{
+		if ((LA(1)==LPAREN)) {
+			{
+			lp = LT(1);
+			lp_AST = astFactory.create(lp);
+			astFactory.makeASTRoot(currentAST, lp_AST);
+			match(LPAREN);
+			if ( inputState.guessing==0 ) {
+				lp_AST.setType(METHOD_CALL);
+			}
+			if ( inputState.guessing==0 ) {
+				if (ta2_AST != null) astFactory.addASTChild(currentAST, ta2_AST);
+			}
+			if ( inputState.guessing==0 ) {
+				if (ta2_AST == null) astFactory.addASTChild(currentAST, ta1_AST);
+			}
+			argList();
+			astFactory.addASTChild(currentAST, returnAST);
+			match(RPAREN);
+			}
+		}
+		else if ((LA(1)==LBRACK) && (LA(2)==RBRACK)) {
+			{
+			int _cnt303=0;
+			_loop303:
+			do {
+				if ((LA(1)==LBRACK) && (LA(2)==RBRACK)) {
+					lbc = LT(1);
+					lbc_AST = astFactory.create(lbc);
+					astFactory.makeASTRoot(currentAST, lbc_AST);
+					match(LBRACK);
+					if ( inputState.guessing==0 ) {
+						lbc_AST.setType(ARRAY_DECLARATOR);
+					}
+					match(RBRACK);
+				}
+				else {
+					if ( _cnt303>=1 ) { break _loop303; } else {throw new NoViableAltException(LT(1), getFilename());}
+				}
+				
+				_cnt303++;
+			} while (true);
+			}
+		}
+		else if ((_tokenSet_46.member(LA(1))) && (_tokenSet_47.member(LA(2)))) {
+		}
+		else {
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		
+		}
+		identPrimary_AST = (AST)currentAST.root;
+		returnAST = identPrimary_AST;
+	}
+	
+	public final void constant() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST constant_AST = null;
+		
+		switch ( LA(1)) {
+		case NUM_INT:
+		{
+			AST tmp251_AST = null;
+			tmp251_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp251_AST);
+			match(NUM_INT);
+			constant_AST = (AST)currentAST.root;
+			break;
+		}
+		case STRING_LITERAL:
+		{
+			AST tmp252_AST = null;
+			tmp252_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp252_AST);
+			match(STRING_LITERAL);
+			constant_AST = (AST)currentAST.root;
+			break;
+		}
+		case NUM_FLOAT:
+		{
+			AST tmp253_AST = null;
+			tmp253_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp253_AST);
+			match(NUM_FLOAT);
+			constant_AST = (AST)currentAST.root;
+			break;
+		}
+		case NUM_LONG:
+		{
+			AST tmp254_AST = null;
+			tmp254_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp254_AST);
+			match(NUM_LONG);
+			constant_AST = (AST)currentAST.root;
+			break;
+		}
+		case NUM_DOUBLE:
+		{
+			AST tmp255_AST = null;
+			tmp255_AST = astFactory.create(LT(1));
+			astFactory.addASTChild(currentAST, tmp255_AST);
+			match(NUM_DOUBLE);
+			constant_AST = (AST)currentAST.root;
+			break;
+		}
+		default:
+		{
+			throw new NoViableAltException(LT(1), getFilename());
+		}
+		}
+		returnAST = constant_AST;
+	}
+	
+	public final void newArrayDeclarator() throws RecognitionException, TokenStreamException {
+		
+		returnAST = null;
+		ASTPair currentAST = new ASTPair();
+		AST newArrayDeclarator_AST = null;
+		Token  lb = null;
+		AST lb_AST = null;
+		
+		{
+		int _cnt313=0;
+		_loop313:
+		do {
+			if ((LA(1)==LBRACK) && (_tokenSet_49.member(LA(2)))) {
+				lb = LT(1);
+				lb_AST = astFactory.create(lb);
+				astFactory.makeASTRoot(currentAST, lb_AST);
+				match(LBRACK);
+				if ( inputState.guessing==0 ) {
+					lb_AST.setType(ARRAY_DECLARATOR);
+				}
+				{
+				switch ( LA(1)) {
+				case IDENT:
+				case LITERAL_super:
+				case LT:
+				case LITERAL_void:
+				case LITERAL_boolean:
+				case LITERAL_byte:
+				case LITERAL_char:
+				case LITERAL_short:
+				case LITERAL_int:
+				case LITERAL_float:
+				case LITERAL_long:
+				case LITERAL_double:
+				case LPAREN:
+				case LITERAL_this:
+				case PLUS:
+				case MINUS:
+				case INC:
+				case DEC:
+				case BNOT:
+				case LNOT:
+				case LITERAL_true:
+				case LITERAL_false:
+				case LITERAL_null:
+				case LITERAL_new:
+				case NUM_INT:
+				case STRING_LITERAL:
+				case NUM_FLOAT:
+				case NUM_LONG:
+				case NUM_DOUBLE:
+				{
+					expression();
+					astFactory.addASTChild(currentAST, returnAST);
+					break;
+				}
+				case RBRACK:
+				{
+					break;
+				}
+				default:
+				{
+					throw new NoViableAltException(LT(1), getFilename());
+				}
+				}
+				}
+				match(RBRACK);
+			}
+			else {
+				if ( _cnt313>=1 ) { break _loop313; } else {throw new NoViableAltException(LT(1), getFilename());}
+			}
+			
+			_cnt313++;
+		} while (true);
+		}
+		newArrayDeclarator_AST = (AST)currentAST.root;
+		returnAST = newArrayDeclarator_AST;
+	}
+	
+	
+	public static final String[] _tokenNames = {
+		"<0>",
+		"EOF",
+		"<2>",
+		"NULL_TREE_LOOKAHEAD",
+		"BLOCK",
+		"MODIFIERS",
+		"OBJBLOCK",
+		"SLIST",
+		"METHOD_DEF",
+		"VARIABLE_DEF",
+		"INSTANCE_INIT",
+		"STATIC_INIT",
+		"TYPE",
+		"CLASS_DEF",
+		"INTERFACE_DEF",
+		"PACKAGE_DEF",
+		"ARRAY_DECLARATOR",
+		"EXTENDS_CLAUSE",
+		"IMPLEMENTS_CLAUSE",
+		"PARAMETERS",
+		"PARAMETER_DEF",
+		"LABELED_STAT",
+		"TYPECAST",
+		"INDEX_OP",
+		"POST_INC",
+		"POST_DEC",
+		"METHOD_CALL",
+		"EXPR",
+		"ARRAY_INIT",
+		"IMPORT",
+		"UNARY_MINUS",
+		"UNARY_PLUS",
+		"CASE_GROUP",
+		"ELIST",
+		"FOR_INIT",
+		"FOR_CONDITION",
+		"FOR_ITERATOR",
+		"EMPTY_STAT",
+		"\"final\"",
+		"\"abstract\"",
+		"\"strictfp\"",
+		"SUPER_CTOR_CALL",
+		"CTOR_CALL",
+		"VARIABLE_PARAMETER_DEF",
+		"STATIC_IMPORT",
+		"ENUM_DEF",
+		"ENUM_CONSTANT_DEF",
+		"FOR_EACH_CLAUSE",
+		"ANNOTATION_DEF",
+		"ANNOTATIONS",
+		"ANNOTATION",
+		"ANNOTATION_MEMBER_VALUE_PAIR",
+		"ANNOTATION_FIELD_DEF",
+		"ANNOTATION_ARRAY_INIT",
+		"TYPE_ARGUMENTS",
+		"TYPE_ARGUMENT",
+		"TYPE_PARAMETERS",
+		"TYPE_PARAMETER",
+		"WILDCARD_TYPE",
+		"TYPE_UPPER_BOUNDS",
+		"TYPE_LOWER_BOUNDS",
+		"\"package\"",
+		"SEMI",
+		"\"import\"",
+		"\"static\"",
+		"LBRACK",
+		"RBRACK",
+		"IDENT",
+		"DOT",
+		"QUESTION",
+		"\"extends\"",
+		"\"super\"",
+		"LT",
+		"COMMA",
+		"GT",
+		"SR",
+		"BSR",
+		"\"void\"",
+		"\"boolean\"",
+		"\"byte\"",
+		"\"char\"",
+		"\"short\"",
+		"\"int\"",
+		"\"float\"",
+		"\"long\"",
+		"\"double\"",
+		"STAR",
+		"\"private\"",
+		"\"public\"",
+		"\"protected\"",
+		"\"transient\"",
+		"\"native\"",
+		"\"threadsafe\"",
+		"\"synchronized\"",
+		"\"volatile\"",
+		"AT",
+		"LPAREN",
+		"RPAREN",
+		"ASSIGN",
+		"LCURLY",
+		"RCURLY",
+		"\"class\"",
+		"\"interface\"",
+		"\"enum\"",
+		"BAND",
+		"\"default\"",
+		"\"implements\"",
+		"\"this\"",
+		"\"throws\"",
+		"TRIPLE_DOT",
+		"COLON",
+		"\"if\"",
+		"\"else\"",
+		"\"while\"",
+		"\"break\"",
+		"\"continue\"",
+		"\"return\"",
+		"\"switch\"",
+		"\"throw\"",
+		"\"assert\"",
+		"\"for\"",
+		"\"case\"",
+		"\"try\"",
+		"\"finally\"",
+		"\"catch\"",
+		"PLUS_ASSIGN",
+		"MINUS_ASSIGN",
+		"STAR_ASSIGN",
+		"DIV_ASSIGN",
+		"MOD_ASSIGN",
+		"SR_ASSIGN",
+		"BSR_ASSIGN",
+		"SL_ASSIGN",
+		"BAND_ASSIGN",
+		"BXOR_ASSIGN",
+		"BOR_ASSIGN",
+		"LOR",
+		"LAND",
+		"BOR",
+		"BXOR",
+		"NOT_EQUAL",
+		"EQUAL",
+		"LE",
+		"GE",
+		"\"instanceof\"",
+		"SL",
+		"PLUS",
+		"MINUS",
+		"DIV",
+		"MOD",
+		"INC",
+		"DEC",
+		"BNOT",
+		"LNOT",
+		"\"true\"",
+		"\"false\"",
+		"\"null\"",
+		"\"new\"",
+		"NUM_INT",
+		"STRING_LITERAL",
+		"NUM_FLOAT",
+		"NUM_LONG",
+		"NUM_DOUBLE",
+		"WS",
+		"SL_COMMENT",
+		"ML_COMMENT",
+		"ESC",
+		"HEX_DIGIT",
+		"VOCAB",
+		"EXPONENT",
+		"FLOAT_SUFFIX"
+	};
+	
+	protected void buildTokenTypeASTClassMap() {
+		tokenTypeToASTClassMap=null;
+	};
+	
+	private static final long[] mk_tokenSet_0() {
+		long[] data = { -4611684094282039294L, 966359252993L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_0 = new BitSet(mk_tokenSet_0());
+	private static final long[] mk_tokenSet_1() {
+		long[] data = { 4611687942572736514L, 966359253001L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_1 = new BitSet(mk_tokenSet_1());
+	private static final long[] mk_tokenSet_2() {
+		long[] data = { 4611687942572736512L, 966359252993L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_2 = new BitSet(mk_tokenSet_2());
+	private static final long[] mk_tokenSet_3() {
+		long[] data = { 4611687942572736514L, 966359252993L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_3 = new BitSet(mk_tokenSet_3());
+	private static final long[] mk_tokenSet_4() {
+		long[] data = { 1924145348608L, 2139095041L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_4 = new BitSet(mk_tokenSet_4());
+	private static final long[] mk_tokenSet_5() {
+		long[] data = { 0L, 4186152L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_5 = new BitSet(mk_tokenSet_5());
+	private static final long[] mk_tokenSet_6() {
+		long[] data = { 4611686018427387904L, -2305723029298086146L, 16383L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_6 = new BitSet(mk_tokenSet_6());
+	private static final long[] mk_tokenSet_7() {
+		long[] data = { 6917530951786430464L, -1729399849096314881L, 34359738367L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_7 = new BitSet(mk_tokenSet_7());
+	private static final long[] mk_tokenSet_8() {
+		long[] data = { 0L, 14332310060762L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_8 = new BitSet(mk_tokenSet_8());
+	private static final long[] mk_tokenSet_9() {
+		long[] data = { 4611687942572736512L, -2305722062934638593L, 34359738367L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_9 = new BitSet(mk_tokenSet_9());
+	private static final long[] mk_tokenSet_10() {
+		long[] data = { 0L, 8836899398024L, 34356330496L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_10 = new BitSet(mk_tokenSet_10());
+	private static final long[] mk_tokenSet_11() {
+		long[] data = { 0L, 9979364900282L, 34359738112L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_11 = new BitSet(mk_tokenSet_11());
+	private static final long[] mk_tokenSet_12() {
+		long[] data = { 0L, 8802539659656L, 34356330496L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_12 = new BitSet(mk_tokenSet_12());
+	private static final long[] mk_tokenSet_13() {
+		long[] data = { 0L, 4432410443336L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_13 = new BitSet(mk_tokenSet_13());
+	private static final long[] mk_tokenSet_14() {
+		long[] data = { 4611687942572736512L, 5471784132955L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_14 = new BitSet(mk_tokenSet_14());
+	private static final long[] mk_tokenSet_15() {
+		long[] data = { 1924145348608L, 966363439369L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_15 = new BitSet(mk_tokenSet_15());
+	private static final long[] mk_tokenSet_16() {
+		long[] data = { 1924145348608L, 970658406683L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_16 = new BitSet(mk_tokenSet_16());
+	private static final long[] mk_tokenSet_17() {
+		long[] data = { 0L, 4186120L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_17 = new BitSet(mk_tokenSet_17());
+	private static final long[] mk_tokenSet_18() {
+		long[] data = { 0L, 282L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_18 = new BitSet(mk_tokenSet_18());
+	private static final long[] mk_tokenSet_19() {
+		long[] data = { 4611686018427387904L, 17179869698L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_19 = new BitSet(mk_tokenSet_19());
+	private static final long[] mk_tokenSet_20() {
+		long[] data = { 274877906944L, 2151669768L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_20 = new BitSet(mk_tokenSet_20());
+	private static final long[] mk_tokenSet_21() {
+		long[] data = { 0L, 2151670042L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_21 = new BitSet(mk_tokenSet_21());
+	private static final long[] mk_tokenSet_22() {
+		long[] data = { 0L, 35186523758874L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_22 = new BitSet(mk_tokenSet_22());
+	private static final long[] mk_tokenSet_23() {
+		long[] data = { 4611687942572736512L, 431932328239948169L, 34356330496L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_23 = new BitSet(mk_tokenSet_23());
+	private static final long[] mk_tokenSet_24() {
+		long[] data = { 0L, 8796093022592L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_24 = new BitSet(mk_tokenSet_24());
+	private static final long[] mk_tokenSet_25() {
+		long[] data = { 0L, 4299153448L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_25 = new BitSet(mk_tokenSet_25());
+	private static final long[] mk_tokenSet_26() {
+		long[] data = { 4611687942572736512L, 431932396959424905L, 34356330496L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_26 = new BitSet(mk_tokenSet_26());
+	private static final long[] mk_tokenSet_27() {
+		long[] data = { 4611687942572736512L, -1873838302180672069L, 34359738367L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_27 = new BitSet(mk_tokenSet_27());
+	private static final long[] mk_tokenSet_28() {
+		long[] data = { 4611687942572736512L, 576331259035246985L, 34356330496L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_28 = new BitSet(mk_tokenSet_28());
+	private static final long[] mk_tokenSet_29() {
+		long[] data = { 4611687942572736512L, -57183194579525L, 34359738367L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_29 = new BitSet(mk_tokenSet_29());
+	private static final long[] mk_tokenSet_30() {
+		long[] data = { 1924145348608L, 4290764809L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_30 = new BitSet(mk_tokenSet_30());
+	private static final long[] mk_tokenSet_31() {
+		long[] data = { 1924145348608L, 4290765083L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_31 = new BitSet(mk_tokenSet_31());
+	private static final long[] mk_tokenSet_32() {
+		long[] data = { 0L, 8800392176008L, 34356330496L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_32 = new BitSet(mk_tokenSet_32());
+	private static final long[] mk_tokenSet_33() {
+		long[] data = { 4611686018427387904L, -2305833092125819462L, 34359738367L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_33 = new BitSet(mk_tokenSet_33());
+	private static final long[] mk_tokenSet_34() {
+		long[] data = { 1924145348608L, 141725532161L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_34 = new BitSet(mk_tokenSet_34());
+	private static final long[] mk_tokenSet_35() {
+		long[] data = { 1924145348608L, 141725532169L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_35 = new BitSet(mk_tokenSet_35());
+	private static final long[] mk_tokenSet_36() {
+		long[] data = { 4611687942572736512L, 8804678754697L, 34356330496L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_36 = new BitSet(mk_tokenSet_36());
+	private static final long[] mk_tokenSet_37() {
+		long[] data = { 4611687942572736512L, -2305833087839240261L, 34359738367L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_37 = new BitSet(mk_tokenSet_37());
+	private static final long[] mk_tokenSet_38() {
+		long[] data = { 0L, 79169136353672L, 34356330496L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_38 = new BitSet(mk_tokenSet_38());
+	private static final long[] mk_tokenSet_39() {
+		long[] data = { 4611686018427387904L, -2305833092125818950L, 34359738367L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_39 = new BitSet(mk_tokenSet_39());
+	private static final long[] mk_tokenSet_40() {
+		long[] data = { 0L, 1280L, 49152L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_40 = new BitSet(mk_tokenSet_40());
+	private static final long[] mk_tokenSet_41() {
+		long[] data = { 0L, 6144L, 131072L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_41 = new BitSet(mk_tokenSet_41());
+	private static final long[] mk_tokenSet_42() {
+		long[] data = { 0L, 4194304L, 3145728L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_42 = new BitSet(mk_tokenSet_42());
+	private static final long[] mk_tokenSet_43() {
+		long[] data = { 0L, 8800392176008L, 34292629504L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_43 = new BitSet(mk_tokenSet_43());
+	private static final long[] mk_tokenSet_44() {
+		long[] data = { 4611686018427387904L, -2305762646072229954L, 34359738367L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_44 = new BitSet(mk_tokenSet_44());
+	private static final long[] mk_tokenSet_45() {
+		long[] data = { 0L, 392L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_45 = new BitSet(mk_tokenSet_45());
+	private static final long[] mk_tokenSet_46() {
+		long[] data = { 4611686018427387904L, -2305771446464405706L, 16777215L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_46 = new BitSet(mk_tokenSet_46());
+	private static final long[] mk_tokenSet_47() {
+		long[] data = { 6917530951786430464L, -1729439431514914881L, 34359738367L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_47 = new BitSet(mk_tokenSet_47());
+	private static final long[] mk_tokenSet_48() {
+		long[] data = { 4611686018427387904L, -2305771442169438410L, 16777215L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_48 = new BitSet(mk_tokenSet_48());
+	private static final long[] mk_tokenSet_49() {
+		long[] data = { 0L, 8800392176012L, 34356330496L, 0L, 0L, 0L};
+		return data;
+	}
+	public static final BitSet _tokenSet_49 = new BitSet(mk_tokenSet_49());
+	
+	}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/java/JavaTokenTypes.java b/groovy-core/src/main/org/codehaus/groovy/antlr/java/JavaTokenTypes.java
new file mode 100644
index 0000000..dffa491
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/java/JavaTokenTypes.java
@@ -0,0 +1,182 @@
+// $ANTLR 2.7.2: "java.g" -> "JavaLexer.java"$
+
+package org.codehaus.groovy.antlr.java;
+import org.codehaus.groovy.antlr.*;
+import org.codehaus.groovy.antlr.parser.*;
+import java.util.*;
+import java.io.InputStream;
+import java.io.Reader;
+import antlr.InputBuffer;
+import antlr.LexerSharedInputState;
+
+public interface JavaTokenTypes {
+	int EOF = 1;
+	int NULL_TREE_LOOKAHEAD = 3;
+	int BLOCK = 4;
+	int MODIFIERS = 5;
+	int OBJBLOCK = 6;
+	int SLIST = 7;
+	int METHOD_DEF = 8;
+	int VARIABLE_DEF = 9;
+	int INSTANCE_INIT = 10;
+	int STATIC_INIT = 11;
+	int TYPE = 12;
+	int CLASS_DEF = 13;
+	int INTERFACE_DEF = 14;
+	int PACKAGE_DEF = 15;
+	int ARRAY_DECLARATOR = 16;
+	int EXTENDS_CLAUSE = 17;
+	int IMPLEMENTS_CLAUSE = 18;
+	int PARAMETERS = 19;
+	int PARAMETER_DEF = 20;
+	int LABELED_STAT = 21;
+	int TYPECAST = 22;
+	int INDEX_OP = 23;
+	int POST_INC = 24;
+	int POST_DEC = 25;
+	int METHOD_CALL = 26;
+	int EXPR = 27;
+	int ARRAY_INIT = 28;
+	int IMPORT = 29;
+	int UNARY_MINUS = 30;
+	int UNARY_PLUS = 31;
+	int CASE_GROUP = 32;
+	int ELIST = 33;
+	int FOR_INIT = 34;
+	int FOR_CONDITION = 35;
+	int FOR_ITERATOR = 36;
+	int EMPTY_STAT = 37;
+	int FINAL = 38;
+	int ABSTRACT = 39;
+	int STRICTFP = 40;
+	int SUPER_CTOR_CALL = 41;
+	int CTOR_CALL = 42;
+	int VARIABLE_PARAMETER_DEF = 43;
+	int STATIC_IMPORT = 44;
+	int ENUM_DEF = 45;
+	int ENUM_CONSTANT_DEF = 46;
+	int FOR_EACH_CLAUSE = 47;
+	int ANNOTATION_DEF = 48;
+	int ANNOTATIONS = 49;
+	int ANNOTATION = 50;
+	int ANNOTATION_MEMBER_VALUE_PAIR = 51;
+	int ANNOTATION_FIELD_DEF = 52;
+	int ANNOTATION_ARRAY_INIT = 53;
+	int TYPE_ARGUMENTS = 54;
+	int TYPE_ARGUMENT = 55;
+	int TYPE_PARAMETERS = 56;
+	int TYPE_PARAMETER = 57;
+	int WILDCARD_TYPE = 58;
+	int TYPE_UPPER_BOUNDS = 59;
+	int TYPE_LOWER_BOUNDS = 60;
+	int LITERAL_package = 61;
+	int SEMI = 62;
+	int LITERAL_import = 63;
+	int LITERAL_static = 64;
+	int LBRACK = 65;
+	int RBRACK = 66;
+	int IDENT = 67;
+	int DOT = 68;
+	int QUESTION = 69;
+	int LITERAL_extends = 70;
+	int LITERAL_super = 71;
+	int LT = 72;
+	int COMMA = 73;
+	int GT = 74;
+	int SR = 75;
+	int BSR = 76;
+	int LITERAL_void = 77;
+	int LITERAL_boolean = 78;
+	int LITERAL_byte = 79;
+	int LITERAL_char = 80;
+	int LITERAL_short = 81;
+	int LITERAL_int = 82;
+	int LITERAL_float = 83;
+	int LITERAL_long = 84;
+	int LITERAL_double = 85;
+	int STAR = 86;
+	int LITERAL_private = 87;
+	int LITERAL_public = 88;
+	int LITERAL_protected = 89;
+	int LITERAL_transient = 90;
+	int LITERAL_native = 91;
+	int LITERAL_threadsafe = 92;
+	int LITERAL_synchronized = 93;
+	int LITERAL_volatile = 94;
+	int AT = 95;
+	int LPAREN = 96;
+	int RPAREN = 97;
+	int ASSIGN = 98;
+	int LCURLY = 99;
+	int RCURLY = 100;
+	int LITERAL_class = 101;
+	int LITERAL_interface = 102;
+	int LITERAL_enum = 103;
+	int BAND = 104;
+	int LITERAL_default = 105;
+	int LITERAL_implements = 106;
+	int LITERAL_this = 107;
+	int LITERAL_throws = 108;
+	int TRIPLE_DOT = 109;
+	int COLON = 110;
+	int LITERAL_if = 111;
+	int LITERAL_else = 112;
+	int LITERAL_while = 113;
+	int LITERAL_break = 114;
+	int LITERAL_continue = 115;
+	int LITERAL_return = 116;
+	int LITERAL_switch = 117;
+	int LITERAL_throw = 118;
+	int LITERAL_assert = 119;
+	int LITERAL_for = 120;
+	int LITERAL_case = 121;
+	int LITERAL_try = 122;
+	int LITERAL_finally = 123;
+	int LITERAL_catch = 124;
+	int PLUS_ASSIGN = 125;
+	int MINUS_ASSIGN = 126;
+	int STAR_ASSIGN = 127;
+	int DIV_ASSIGN = 128;
+	int MOD_ASSIGN = 129;
+	int SR_ASSIGN = 130;
+	int BSR_ASSIGN = 131;
+	int SL_ASSIGN = 132;
+	int BAND_ASSIGN = 133;
+	int BXOR_ASSIGN = 134;
+	int BOR_ASSIGN = 135;
+	int LOR = 136;
+	int LAND = 137;
+	int BOR = 138;
+	int BXOR = 139;
+	int NOT_EQUAL = 140;
+	int EQUAL = 141;
+	int LE = 142;
+	int GE = 143;
+	int LITERAL_instanceof = 144;
+	int SL = 145;
+	int PLUS = 146;
+	int MINUS = 147;
+	int DIV = 148;
+	int MOD = 149;
+	int INC = 150;
+	int DEC = 151;
+	int BNOT = 152;
+	int LNOT = 153;
+	int LITERAL_true = 154;
+	int LITERAL_false = 155;
+	int LITERAL_null = 156;
+	int LITERAL_new = 157;
+	int NUM_INT = 158;
+	int STRING_LITERAL = 159;
+	int NUM_FLOAT = 160;
+	int NUM_LONG = 161;
+	int NUM_DOUBLE = 162;
+	int WS = 163;
+	int SL_COMMENT = 164;
+	int ML_COMMENT = 165;
+	int ESC = 166;
+	int HEX_DIGIT = 167;
+	int VOCAB = 168;
+	int EXPONENT = 169;
+	int FLOAT_SUFFIX = 170;
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/java/JavaTokenTypes.txt b/groovy-core/src/main/org/codehaus/groovy/antlr/java/JavaTokenTypes.txt
new file mode 100644
index 0000000..c80d90f
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/java/JavaTokenTypes.txt
@@ -0,0 +1,169 @@
+// $ANTLR 2.7.2: java.g -> JavaTokenTypes.txt$
+Java    // output token vocab name
+BLOCK=4
+MODIFIERS=5
+OBJBLOCK=6
+SLIST=7
+METHOD_DEF=8
+VARIABLE_DEF=9
+INSTANCE_INIT=10
+STATIC_INIT=11
+TYPE=12
+CLASS_DEF=13
+INTERFACE_DEF=14
+PACKAGE_DEF=15
+ARRAY_DECLARATOR=16
+EXTENDS_CLAUSE=17
+IMPLEMENTS_CLAUSE=18
+PARAMETERS=19
+PARAMETER_DEF=20
+LABELED_STAT=21
+TYPECAST=22
+INDEX_OP=23
+POST_INC=24
+POST_DEC=25
+METHOD_CALL=26
+EXPR=27
+ARRAY_INIT=28
+IMPORT=29
+UNARY_MINUS=30
+UNARY_PLUS=31
+CASE_GROUP=32
+ELIST=33
+FOR_INIT=34
+FOR_CONDITION=35
+FOR_ITERATOR=36
+EMPTY_STAT=37
+FINAL="final"=38
+ABSTRACT="abstract"=39
+STRICTFP="strictfp"=40
+SUPER_CTOR_CALL=41
+CTOR_CALL=42
+VARIABLE_PARAMETER_DEF=43
+STATIC_IMPORT=44
+ENUM_DEF=45
+ENUM_CONSTANT_DEF=46
+FOR_EACH_CLAUSE=47
+ANNOTATION_DEF=48
+ANNOTATIONS=49
+ANNOTATION=50
+ANNOTATION_MEMBER_VALUE_PAIR=51
+ANNOTATION_FIELD_DEF=52
+ANNOTATION_ARRAY_INIT=53
+TYPE_ARGUMENTS=54
+TYPE_ARGUMENT=55
+TYPE_PARAMETERS=56
+TYPE_PARAMETER=57
+WILDCARD_TYPE=58
+TYPE_UPPER_BOUNDS=59
+TYPE_LOWER_BOUNDS=60
+LITERAL_package="package"=61
+SEMI=62
+LITERAL_import="import"=63
+LITERAL_static="static"=64
+LBRACK=65
+RBRACK=66
+IDENT=67
+DOT=68
+QUESTION=69
+LITERAL_extends="extends"=70
+LITERAL_super="super"=71
+LT=72
+COMMA=73
+GT=74
+SR=75
+BSR=76
+LITERAL_void="void"=77
+LITERAL_boolean="boolean"=78
+LITERAL_byte="byte"=79
+LITERAL_char="char"=80
+LITERAL_short="short"=81
+LITERAL_int="int"=82
+LITERAL_float="float"=83
+LITERAL_long="long"=84
+LITERAL_double="double"=85
+STAR=86
+LITERAL_private="private"=87
+LITERAL_public="public"=88
+LITERAL_protected="protected"=89
+LITERAL_transient="transient"=90
+LITERAL_native="native"=91
+LITERAL_threadsafe="threadsafe"=92
+LITERAL_synchronized="synchronized"=93
+LITERAL_volatile="volatile"=94
+AT=95
+LPAREN=96
+RPAREN=97
+ASSIGN=98
+LCURLY=99
+RCURLY=100
+LITERAL_class="class"=101
+LITERAL_interface="interface"=102
+LITERAL_enum="enum"=103
+BAND=104
+LITERAL_default="default"=105
+LITERAL_implements="implements"=106
+LITERAL_this="this"=107
+LITERAL_throws="throws"=108
+TRIPLE_DOT=109
+COLON=110
+LITERAL_if="if"=111
+LITERAL_else="else"=112
+LITERAL_while="while"=113
+LITERAL_break="break"=114
+LITERAL_continue="continue"=115
+LITERAL_return="return"=116
+LITERAL_switch="switch"=117
+LITERAL_throw="throw"=118
+LITERAL_assert="assert"=119
+LITERAL_for="for"=120
+LITERAL_case="case"=121
+LITERAL_try="try"=122
+LITERAL_finally="finally"=123
+LITERAL_catch="catch"=124
+PLUS_ASSIGN=125
+MINUS_ASSIGN=126
+STAR_ASSIGN=127
+DIV_ASSIGN=128
+MOD_ASSIGN=129
+SR_ASSIGN=130
+BSR_ASSIGN=131
+SL_ASSIGN=132
+BAND_ASSIGN=133
+BXOR_ASSIGN=134
+BOR_ASSIGN=135
+LOR=136
+LAND=137
+BOR=138
+BXOR=139
+NOT_EQUAL=140
+EQUAL=141
+LE=142
+GE=143
+LITERAL_instanceof="instanceof"=144
+SL=145
+PLUS=146
+MINUS=147
+DIV=148
+MOD=149
+INC=150
+DEC=151
+BNOT=152
+LNOT=153
+LITERAL_true="true"=154
+LITERAL_false="false"=155
+LITERAL_null="null"=156
+LITERAL_new="new"=157
+NUM_INT=158
+STRING_LITERAL=159
+NUM_FLOAT=160
+NUM_LONG=161
+NUM_DOUBLE=162
+WS=163
+SL_COMMENT=164
+ML_COMMENT=165
+ESC=166
+HEX_DIGIT=167
+VOCAB=168
+EXPONENT=169
+FLOAT_SUFFIX=170
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/java/java.g b/groovy-core/src/main/org/codehaus/groovy/antlr/java/java.g
new file mode 100644
index 0000000..fc23e8d
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/java/java.g
@@ -0,0 +1,1960 @@
+// Note: Please don't use physical tabs.  Logical tabs for indent are width 4.
+header {
+package org.codehaus.groovy.antlr.java;
+import org.codehaus.groovy.antlr.*;
+import org.codehaus.groovy.antlr.parser.*;
+import java.util.*;
+import java.io.InputStream;
+import java.io.Reader;
+import antlr.InputBuffer;
+import antlr.LexerSharedInputState;
+}
+ 
+/** Java 1.5 Recognizer
+ *
+ * Run 'java Main [-showtree] directory-full-of-java-files'
+ *
+ * [The -showtree option pops up a Swing frame that shows
+ *  the AST constructed from the parser.]
+ *
+ * Run 'java Main <directory full of java files>'
+ *
+ * Contributing authors:
+ *      Jeremy Rayner       groovy@ross-rayner.com
+ *		John Mitchell		johnm@non.net
+ *		Terence Parr		parrt@magelang.com
+ *		John Lilley		jlilley@empathy.com
+ *		Scott Stanchfield	thetick@magelang.com
+ *		Markus Mohnen		mohnen@informatik.rwth-aachen.de
+ *		Peter Williams		pete.williams@sun.com
+ *		Allan Jacobs		Allan.Jacobs@eng.sun.com
+ *		Steve Messick		messick@redhills.com
+ *		John Pybus		john@pybus.org
+ *
+ * Version 1.00 December 9, 1997 -- initial release
+ * Version 1.01 December 10, 1997
+ *		fixed bug in octal def (0..7 not 0..8)
+ * Version 1.10 August 1998 (parrt)
+ *		added tree construction
+ *		fixed definition of WS,comments for mac,pc,unix newlines
+ *		added unary plus
+ * Version 1.11 (Nov 20, 1998)
+ *		Added "shutup" option to turn off last ambig warning.
+ *		Fixed inner class def to allow named class defs as statements
+ *		synchronized requires compound not simple statement
+ *		add [] after builtInType DOT class in primaryExpression
+ *		"const" is reserved but not valid..removed from modifiers
+ * Version 1.12 (Feb 2, 1999)
+ *		Changed LITERAL_xxx to xxx in tree grammar.
+ *		Updated java.g to use tokens {...} now for 2.6.0 (new feature).
+ *
+ * Version 1.13 (Apr 23, 1999)
+ *		Didn't have (stat)? for else clause in tree parser.
+ *		Didn't gen ASTs for interface extends.  Updated tree parser too.
+ *		Updated to 2.6.0.
+ * Version 1.14 (Jun 20, 1999)
+ *		Allowed final/abstract on local classes.
+ *		Removed local interfaces from methods
+ *		Put instanceof precedence where it belongs...in relationalExpr
+ *			It also had expr not type as arg; fixed it.
+ *		Missing ! on SEMI in classBlock
+ *		fixed: (expr) + "string" was parsed incorrectly (+ as unary plus).
+ *		fixed: didn't like Object[].class in parser or tree parser
+ * Version 1.15 (Jun 26, 1999)
+ *		Screwed up rule with instanceof in it. :(  Fixed.
+ *		Tree parser didn't like (expr).something; fixed.
+ *		Allowed multiple inheritance in tree grammar. oops.
+ * Version 1.16 (August 22, 1999)
+ *		Extending an interface built a wacky tree: had extra EXTENDS.
+ *		Tree grammar didn't allow multiple superinterfaces.
+ *		Tree grammar didn't allow empty var initializer: {}
+ * Version 1.17 (October 12, 1999)
+ *		ESC lexer rule allowed 399 max not 377 max.
+ *		java.tree.g didn't handle the expression of synchronized
+ *		statements.
+ * Version 1.18 (August 12, 2001)
+ *	  	Terence updated to Java 2 Version 1.3 by
+ *		observing/combining work of Allan Jacobs and Steve
+ *		Messick.  Handles 1.3 src.  Summary:
+ *		o  primary didn't include boolean.class kind of thing
+ *	  	o  constructor calls parsed explicitly now:
+ * 		   see explicitConstructorInvocation
+ *		o  add strictfp modifier
+ *	  	o  missing objBlock after new expression in tree grammar
+ *		o  merged local class definition alternatives, moved after declaration
+ *		o  fixed problem with ClassName.super.field
+ *	  	o  reordered some alternatives to make things more efficient
+ *		o  long and double constants were not differentiated from int/float
+ *		o  whitespace rule was inefficient: matched only one char
+ *		o  add an examples directory with some nasty 1.3 cases
+ *		o  made Main.java use buffered IO and a Reader for Unicode support
+ *		o  supports UNICODE?
+ *		   Using Unicode charVocabulay makes code file big, but only
+ *		   in the bitsets at the end. I need to make ANTLR generate
+ *		   unicode bitsets more efficiently.
+ * Version 1.19 (April 25, 2002)
+ *		Terence added in nice fixes by John Pybus concerning floating
+ *		constants and problems with super() calls.  John did a nice
+ *		reorg of the primary/postfix expression stuff to read better
+ *		and makes f.g.super() parse properly (it was METHOD_CALL not
+ *		a SUPER_CTOR_CALL).  Also:
+ *
+ *		o  "finally" clause was a root...made it a child of "try"
+ *		o  Added stuff for asserts too for Java 1.4, but *commented out*
+ *		   as it is not backward compatible.
+ *
+ * Version 1.20 (October 27, 2002)
+ *
+ *	  Terence ended up reorging John Pybus' stuff to
+ *	  remove some nondeterminisms and some syntactic predicates.
+ *	  Note that the grammar is stricter now; e.g., this(...) must
+ *	be the first statement.
+ *
+ *	  Trinary ?: operator wasn't working as array name:
+ *		  (isBig ? bigDigits : digits)[i];
+ *
+ *	  Checked parser/tree parser on source for
+ *		  Resin-2.0.5, jive-2.1.1, jdk 1.3.1, Lucene, antlr 2.7.2a4,
+ *		and the 110k-line jGuru server source.
+ *
+ * Version 1.21 (October 17, 2003)
+ *  Fixed lots of problems including:
+ *  Ray Waldin: add typeDefinition to interfaceBlock in java.tree.g
+ *  He found a problem/fix with floating point that start with 0
+ *  Ray also fixed problem that (int.class) was not recognized.
+ *  Thorsten van Ellen noticed that \n are allowed incorrectly in strings.
+ *  TJP fixed CHAR_LITERAL analogously.
+ *
+ * Version 1.21.2 (March, 2003)
+ *	  Changes by Matt Quail to support generics (as per JDK1.5/JSR14)
+ *	  Notes:
+ *	  o We only allow the "extends" keyword and not the "implements"
+ *		keyword, since thats what JSR14 seems to imply.
+ *	  o Thanks to Monty Zukowski for his help on the antlr-interest
+ *		mail list.
+ *	  o Thanks to Alan Eliasen for testing the grammar over his
+ *		Fink source base
+ *
+ * Version 1.22 (July, 2004)
+ *	  Changes by Michael Studman to support Java 1.5 language extensions
+ *	  Notes:
+ *	  o Added support for annotations types
+ *	  o Finished off Matt Quail's generics enhancements to support bound type arguments
+ *	  o Added support for new for statement syntax
+ *	  o Added support for static import syntax
+ *	  o Added support for enum types
+ *	  o Tested against JDK 1.5 source base and source base of jdigraph project
+ *	  o Thanks to Matt Quail for doing the hard part by doing most of the generics work
+ *
+ * Version 1.22.1 (July 28, 2004)
+ *	  Bug/omission fixes for Java 1.5 language support
+ *	  o Fixed tree structure bug with classOrInterface - thanks to Pieter Vangorpto for
+ *		spotting this
+ *	  o Fixed bug where incorrect handling of SR and BSR tokens would cause type
+ *		parameters to be recognised as type arguments.
+ *	  o Enabled type parameters on constructors, annotations on enum constants
+ *		and package definitions
+ *	  o Fixed problems when parsing if ((char.class.equals(c))) {} - solution by Matt Quail at Cenqua
+ *
+ * Version 1.22.2 (July 28, 2004)
+ *	  Slight refactoring of Java 1.5 language support
+ *	  o Refactored for/"foreach" productions so that original literal "for" literal
+ *	    is still used but the for sub-clauses vary by token type
+ *	  o Fixed bug where type parameter was not included in generic constructor's branch of AST
+ *
+ * Version 1.22.3 (August 26, 2004)
+ *	  Bug fixes as identified by Michael Stahl; clean up of tabs/spaces
+ *        and other refactorings
+ *	  o Fixed typeParameters omission in identPrimary and newStatement
+ *	  o Replaced GT reconcilliation code with simple semantic predicate
+ *	  o Adapted enum/assert keyword checking support from Michael Stahl's java15 grammar
+ *	  o Refactored typeDefinition production and field productions to reduce duplication
+ *
+ * Version 1.22.4 (October 21, 2004)
+ *    Small bux fixes
+ *    o Added typeArguments to explicitConstructorInvocation, e.g. new <String>MyParameterised()
+ *    o Added typeArguments to postfixExpression productions for anonymous inner class super
+ *      constructor invocation, e.g. new Outer().<String>super()
+ *    o Fixed bug in array declarations identified by Geoff Roy
+ *
+ * Version 1.22.4.j.1
+ *	  Changes by Jeremy Rayner to support java2groovy tool
+ *    o I have taken java.g for Java1.5 from Michael Studman (1.22.4)
+ *      and have made some changes to enable use by java2groovy tool (Jan 2007)
+ *
+ * This grammar is in the PUBLIC DOMAIN
+ */
+
+class JavaRecognizer extends Parser;
+options {
+	k = 2;							// two token lookahead
+	exportVocab=Java;				// Call its vocabulary "Java"
+	codeGenMakeSwitchThreshold = 2;	// Some optimizations
+	codeGenBitsetTestThreshold = 3;
+	defaultErrorHandler = false;	// Don't generate parser error handlers
+	buildAST = true;
+}
+
+tokens {
+	BLOCK; MODIFIERS; OBJBLOCK; SLIST; METHOD_DEF; VARIABLE_DEF;
+	INSTANCE_INIT; STATIC_INIT; TYPE; CLASS_DEF; INTERFACE_DEF;
+	PACKAGE_DEF; ARRAY_DECLARATOR; EXTENDS_CLAUSE; IMPLEMENTS_CLAUSE;
+	PARAMETERS; PARAMETER_DEF; LABELED_STAT; TYPECAST; INDEX_OP;
+	POST_INC; POST_DEC; METHOD_CALL; EXPR; ARRAY_INIT;
+	IMPORT; UNARY_MINUS; UNARY_PLUS; CASE_GROUP; ELIST; FOR_INIT; FOR_CONDITION;
+	FOR_ITERATOR; EMPTY_STAT; FINAL="final"; ABSTRACT="abstract";
+	STRICTFP="strictfp"; SUPER_CTOR_CALL; CTOR_CALL; VARIABLE_PARAMETER_DEF;
+	STATIC_IMPORT; ENUM_DEF; ENUM_CONSTANT_DEF; FOR_EACH_CLAUSE; ANNOTATION_DEF; ANNOTATIONS;
+	ANNOTATION; ANNOTATION_MEMBER_VALUE_PAIR; ANNOTATION_FIELD_DEF; ANNOTATION_ARRAY_INIT;
+	TYPE_ARGUMENTS; TYPE_ARGUMENT; TYPE_PARAMETERS; TYPE_PARAMETER; WILDCARD_TYPE;
+	TYPE_UPPER_BOUNDS; TYPE_LOWER_BOUNDS;
+}
+
+{
+    /** This factory is the correct way to wire together a Groovy parser and lexer. */
+    public static JavaRecognizer make(JavaLexer lexer) {
+        JavaRecognizer parser = new JavaRecognizer(lexer.plumb());
+        // TODO: set up a common error-handling control block, to avoid excessive tangle between these guys
+        parser.lexer = lexer;
+        lexer.parser = parser;
+        parser.setASTNodeClass("org.codehaus.groovy.antlr.GroovySourceAST");
+        return parser;
+    }
+    // Create a scanner that reads from the input stream passed to us...
+    public static JavaRecognizer make(InputStream in) { return make(new JavaLexer(in)); }
+    public static JavaRecognizer make(Reader in) { return make(new JavaLexer(in)); }
+    public static JavaRecognizer make(InputBuffer in) { return make(new JavaLexer(in)); }
+    public static JavaRecognizer make(LexerSharedInputState in) { return make(new JavaLexer(in)); }
+    
+    private static GroovySourceAST dummyVariableToforceClassLoaderToFindASTClass = new GroovySourceAST();
+    
+    JavaLexer lexer;
+    public JavaLexer getLexer() { return lexer; }
+    public void setFilename(String f) { super.setFilename(f); lexer.setFilename(f); }
+    private SourceBuffer sourceBuffer;
+    public void setSourceBuffer(SourceBuffer sourceBuffer) {
+        this.sourceBuffer = sourceBuffer;
+    }
+
+    /** Create an AST node with the token type and text passed in, but
+     *  with the same background information as another supplied Token (e.g. line numbers)
+     * to be used in place of antlr tree construction syntax,
+     * i.e. #[TOKEN,"text"]  becomes  create(TOKEN,"text",anotherToken)
+     *
+     * todo - change antlr.ASTFactory to do this instead...
+     */
+    public AST create(int type, String txt, Token first, Token last) {
+        AST t = astFactory.create(type,txt);
+        if ( t != null && first != null) {
+            // first copy details from first token
+            t.initialize(first);
+            // then ensure that type and txt are specific to this new node
+            t.initialize(type,txt);
+        }
+
+        if ((t instanceof GroovySourceAST) && last != null) {
+            GroovySourceAST node = (GroovySourceAST)t;
+            node.setLast(last);
+            // This is a good point to call node.setSnippet(),
+            // but it bulks up the AST too much for production code.
+        }
+        return t;
+    }
+
+    
+    /**
+	 * Counts the number of LT seen in the typeArguments production.
+	 * It is used in semantic predicates to ensure we have seen
+	 * enough closing '>' characters; which actually may have been
+	 * either GT, SR or BSR tokens.
+	 */
+	private int ltCounter = 0;
+}
+
+// Compilation Unit: In Java, this is a single file. This is the start
+// rule for this parser
+compilationUnit
+	:	// A compilation unit starts with an optional package definition
+		(	(annotations "package")=> packageDefinition
+		|	/* nothing */
+		)
+
+		// Next we have a series of zero or more import statements
+		( importDefinition )*
+
+		// Wrapping things up with any number of class or interface
+		// definitions
+		( typeDefinition )*
+
+		EOF!
+	;
+
+
+// Package statement: optional annotations followed by "package" then the package identifier.
+packageDefinition
+	options {defaultErrorHandler = true;} // let ANTLR handle errors
+	:	annotations p:"package"^ {#p.setType(PACKAGE_DEF);} identifier SEMI!
+	;
+
+
+// Import statement: import followed by a package or class name
+importDefinition
+	options {defaultErrorHandler = true;}
+	{ boolean isStatic = false; }
+	:	i:"import"^ {#i.setType(IMPORT);} ( "static"! {#i.setType(STATIC_IMPORT);} )? identifierStar SEMI!
+	;
+
+// A type definition is either a class, interface, enum or annotation with possible additional semis.
+typeDefinition
+	options {defaultErrorHandler = true;}
+	:	m:modifiers!
+		typeDefinitionInternal[#m]
+	|	SEMI!
+	;
+
+// Protected type definitions production for reuse in other productions
+protected typeDefinitionInternal[AST mods]
+	:	classDefinition[#mods]		// inner class
+	|	interfaceDefinition[#mods]	// inner interface
+	|	enumDefinition[#mods]		// inner enum
+	|	annotationDefinition[#mods]	// inner annotation
+	;
+
+// A declaration is the creation of a reference or primitive-type variable
+// Create a separate Type/Var tree for each var in the var list.
+declaration!
+	:	m:modifiers t:typeSpec[false] v:variableDefinitions[#m,#t]
+		{#declaration = #v;}
+	;
+
+// A type specification is a type name with possible brackets afterwards
+// (which would make it an array type).
+typeSpec[boolean addImagNode]
+	:	classTypeSpec[addImagNode]
+	|	builtInTypeSpec[addImagNode]
+	;
+
+// A class type specification is a class type with either:
+// - possible brackets afterwards
+//   (which would make it an array type).
+// - generic type arguments after
+classTypeSpec[boolean addImagNode]  {Token first = LT(1);}
+	:	classOrInterfaceType[false]
+		(options{greedy=true;}: // match as many as possible
+			lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!
+		)*
+		{
+			if ( addImagNode ) {
+				#classTypeSpec = #(create(TYPE,"TYPE",first,LT(1)), #classTypeSpec);
+			}
+		}
+	;
+
+// A non-built in type name, with possible type parameters
+classOrInterfaceType[boolean addImagNode]  {Token first = LT(1);}
+	:	IDENT^ (typeArguments)?
+		(options{greedy=true;}: // match as many as possible
+			DOT^
+			IDENT (typeArguments)?
+		)*
+		{
+			if ( addImagNode ) {
+				#classOrInterfaceType = #(create(TYPE,"TYPE",first,LT(1)), #classOrInterfaceType);
+			}
+		}
+	;
+
+// A specialised form of typeSpec where built in types must be arrays
+typeArgumentSpec
+	:	classTypeSpec[true]
+	|	builtInTypeArraySpec[true]
+	;
+
+// A generic type argument is a class type, a possibly bounded wildcard type or a built-in type array
+typeArgument  {Token first = LT(1);}
+	:	(	typeArgumentSpec
+		|	wildcardType
+		)
+		{#typeArgument = #(create(TYPE_ARGUMENT,"TYPE_ARGUMENT",first,LT(1)), #typeArgument);}
+	;
+
+// Wildcard type indicating all types (with possible constraint)
+wildcardType
+	:	q:QUESTION^ {#q.setType(WILDCARD_TYPE);}
+		(("extends" | "super")=> typeArgumentBounds)?
+	;
+
+// Type arguments to a class or interface type
+typeArguments
+{int currentLtLevel = 0;  Token first = LT(1);}
+	:
+		{currentLtLevel = ltCounter;}
+		LT! {ltCounter++;}
+		typeArgument
+		(options{greedy=true;}: // match as many as possible
+			{inputState.guessing !=0 || ltCounter == currentLtLevel + 1}?
+			COMMA! typeArgument
+		)*
+
+		(	// turn warning off since Antlr generates the right code,
+			// plus we have our semantic predicate below
+			options{generateAmbigWarnings=false;}:
+			typeArgumentsOrParametersEnd
+		)?
+
+		// make sure we have gobbled up enough '>' characters
+		// if we are at the "top level" of nested typeArgument productions
+		{(currentLtLevel != 0) || ltCounter == currentLtLevel}?
+
+		{#typeArguments = #(create(TYPE_ARGUMENTS,"TYPE_ARGUMENTS",first,LT(1)), #typeArguments);}
+	;
+
+// this gobbles up *some* amount of '>' characters, and counts how many
+// it gobbled.
+protected typeArgumentsOrParametersEnd
+	:	GT! {ltCounter-=1;}
+	|	SR! {ltCounter-=2;}
+	|	BSR! {ltCounter-=3;}
+	;
+
+// Restriction on wildcard types based on super class or derrived class
+typeArgumentBounds
+	{boolean isUpperBounds = false;  Token first = LT(1);}
+	:
+		( "extends"! {isUpperBounds=true;} | "super"! ) classOrInterfaceType[false]
+		{
+			if (isUpperBounds)
+			{
+				#typeArgumentBounds = #(create(TYPE_UPPER_BOUNDS,"TYPE_UPPER_BOUNDS",first,LT(1)), #typeArgumentBounds);
+			}
+			else
+			{
+				#typeArgumentBounds = #(create(TYPE_LOWER_BOUNDS,"TYPE_LOWER_BOUNDS",first,LT(1)), #typeArgumentBounds);
+			}
+		}
+	;
+
+// A builtin type array specification is a builtin type with brackets afterwards
+builtInTypeArraySpec[boolean addImagNode]  {Token first = LT(1);}
+	:	builtInType
+		(options{greedy=true;}: // match as many as possible
+			lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!
+		)+
+
+		{
+			if ( addImagNode ) {
+				#builtInTypeArraySpec = #(create(TYPE,"TYPE",first,LT(1)), #builtInTypeArraySpec);
+			}
+		}
+	;
+
+// A builtin type specification is a builtin type with possible brackets
+// afterwards (which would make it an array type).
+builtInTypeSpec[boolean addImagNode]  {Token first = LT(1);}
+	:	builtInType
+		(options{greedy=true;}: // match as many as possible
+			lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!
+		)*
+		{
+			if ( addImagNode ) {
+				#builtInTypeSpec = #(create(TYPE,"TYPE",first,LT(1)), #builtInTypeSpec);
+			}
+		}
+	;
+
+// A type name. which is either a (possibly qualified and parameterized)
+// class name or a primitive (builtin) type
+type
+	:	classOrInterfaceType[false]
+	|	builtInType
+	;
+
+// The primitive types.
+builtInType
+	:	"void"
+	|	"boolean"
+	|	"byte"
+	|	"char"
+	|	"short"
+	|	"int"
+	|	"float"
+	|	"long"
+	|	"double"
+	;
+
+// A (possibly-qualified) java identifier. We start with the first IDENT
+// and expand its name by adding dots and following IDENTS
+identifier
+	:	IDENT ( DOT^ IDENT )*
+	;
+
+identifierStar
+	:	IDENT
+		( DOT^ IDENT )*
+		( DOT^ STAR )?
+	;
+
+// A list of zero or more modifiers. We could have used (modifier)* in
+// place of a call to modifiers, but I thought it was a good idea to keep
+// this rule separate so they can easily be collected in a Vector if
+// someone so desires
+modifiers {Token first = LT(1);}
+	:
+		(
+			//hush warnings since the semantic check for "@interface" solves the non-determinism
+			options{generateAmbigWarnings=false;}:
+
+			modifier
+			|
+			//Semantic check that we aren't matching @interface as this is not an annotation
+			//A nicer way to do this would be nice
+			{LA(1)==AT && !LT(2).getText().equals("interface")}? annotation
+		)*
+
+		{#modifiers = #(create(MODIFIERS, "MODIFIERS",first,LT(1)), #modifiers);}
+	;
+
+// modifiers for Java classes, interfaces, class/instance vars and methods
+modifier
+	:	"private"
+	|	"public"
+	|	"protected"
+	|	"static"
+	|	"transient"
+	|	"final"
+	|	"abstract"
+	|	"native"
+	|	"threadsafe"
+	|	"synchronized"
+	|	"volatile"
+	|	"strictfp"
+	;
+
+annotation!  {Token first = LT(1);}
+	:	AT! i:identifier ( LPAREN! ( args:annotationArguments )? RPAREN! )?
+		{#annotation = #(create(ANNOTATION,"ANNOTATION",first,LT(1)), i, args);}
+	;
+
+annotations  {Token first = LT(1);}
+    :   (annotation)*
+		{#annotations = #([ANNOTATIONS, "ANNOTATIONS"], #annotations);}
+    ;
+
+annotationArguments
+	:	annotationMemberValueInitializer | anntotationMemberValuePairs
+	;
+
+anntotationMemberValuePairs
+	:	annotationMemberValuePair ( COMMA! annotationMemberValuePair )*
+	;
+
+annotationMemberValuePair!  {Token first = LT(1);}
+	:	i:IDENT ASSIGN! v:annotationMemberValueInitializer
+		{#annotationMemberValuePair = #(create(ANNOTATION_MEMBER_VALUE_PAIR,"ANNOTATION_MEMBER_VALUE_PAIR",first,LT(1)), i, v);}
+	;
+
+annotationMemberValueInitializer
+	:
+		conditionalExpression | annotation | annotationMemberArrayInitializer
+	;
+
+// This is an initializer used to set up an annotation member array.
+annotationMemberArrayInitializer
+	:	lc:LCURLY^ {#lc.setType(ANNOTATION_ARRAY_INIT);}
+			(	annotationMemberArrayValueInitializer
+				(
+					// CONFLICT: does a COMMA after an initializer start a new
+					// initializer or start the option ',' at end?
+					// ANTLR generates proper code by matching
+					// the comma as soon as possible.
+					options {
+						warnWhenFollowAmbig = false;
+					}
+				:
+					COMMA! annotationMemberArrayValueInitializer
+				)*
+				(COMMA!)?
+			)?
+		RCURLY!
+	;
+
+// The two things that can initialize an annotation array element are a conditional expression
+// and an annotation (nested annotation array initialisers are not valid)
+annotationMemberArrayValueInitializer
+	:	conditionalExpression
+	|	annotation
+	;
+
+superClassClause!  {Token first = LT(1);}
+	:	( "extends" c:classOrInterfaceType[false] )?
+		{#superClassClause = #(create(EXTENDS_CLAUSE,"EXTENDS_CLAUSE",first,LT(1)),c);}
+	;
+
+// Definition of a Java class
+classDefinition![AST modifiers] {Token first = LT(1);}
+	:	"class" IDENT
+		// it _might_ have type paramaters
+		(tp:typeParameters)?
+		// it _might_ have a superclass...
+		sc:superClassClause
+		// it might implement some interfaces...
+		ic:implementsClause
+		// now parse the body of the class
+		cb:classBlock
+		{#classDefinition = #(create(CLASS_DEF,"CLASS_DEF",first,LT(1)),
+								modifiers,IDENT,tp,sc,ic,cb);}
+	;
+
+// Definition of a Java Interface
+interfaceDefinition![AST modifiers]  {Token first = LT(1);}
+	:	"interface" IDENT
+		// it _might_ have type paramaters
+		(tp:typeParameters)?
+		// it might extend some other interfaces
+		ie:interfaceExtends
+		// now parse the body of the interface (looks like a class...)
+		ib:interfaceBlock
+		{#interfaceDefinition = #(create(INTERFACE_DEF,"INTERFACE_DEF",first,LT(1)),
+									modifiers,IDENT,tp,ie,ib);}
+	;
+
+enumDefinition![AST modifiers]  {Token first = LT(1);}
+	:	"enum" IDENT
+		// it might implement some interfaces...
+		ic:implementsClause
+		// now parse the body of the enum
+		eb:enumBlock
+		{#enumDefinition = #(create(ENUM_DEF,"ENUM_DEF",first,LT(1)),
+								modifiers,IDENT,ic,eb);}
+	;
+
+annotationDefinition![AST modifiers]  {Token first = LT(1);}
+	:	AT "interface" IDENT
+		// now parse the body of the annotation
+		ab:annotationBlock
+		{#annotationDefinition = #(create(ANNOTATION_DEF,"ANNOTATION_DEF",first,LT(1)),
+									modifiers,IDENT,ab);}
+	;
+
+typeParameters
+{int currentLtLevel = 0; Token first = LT(1);}
+	:
+		{currentLtLevel = ltCounter;}
+		LT! {ltCounter++;}
+		typeParameter (COMMA! typeParameter)*
+		(typeArgumentsOrParametersEnd)?
+
+		// make sure we have gobbled up enough '>' characters
+		// if we are at the "top level" of nested typeArgument productions
+		{(currentLtLevel != 0) || ltCounter == currentLtLevel}?
+
+		{#typeParameters = #(create(TYPE_PARAMETERS,"TYPE_PARAMETERS",first,LT(1)), #typeParameters);}
+	;
+
+typeParameter   {Token first = LT(1);}
+	:
+		// I'm pretty sure Antlr generates the right thing here:
+		(id:IDENT) ( options{generateAmbigWarnings=false;}: typeParameterBounds )?
+		{#typeParameter = #(create(TYPE_PARAMETER,"TYPE_PARAMETER",first,LT(1)), #typeParameter);}
+	;
+
+typeParameterBounds  {Token first = LT(1);}
+	:
+		"extends"! classOrInterfaceType[false]
+		(BAND! classOrInterfaceType[false])*
+		{#typeParameterBounds = #(create(TYPE_UPPER_BOUNDS,"TYPE_UPPER_BOUNDS",first,LT(1)), #typeParameterBounds);}
+	;
+
+// This is the body of a class. You can have classFields and extra semicolons.
+classBlock
+	:	LCURLY!
+			( classField | SEMI! )*
+		RCURLY!
+		{#classBlock = #([OBJBLOCK, "OBJBLOCK"], #classBlock);}
+	;
+
+// This is the body of an interface. You can have interfaceField and extra semicolons.
+interfaceBlock
+	:	LCURLY!
+			( interfaceField | SEMI! )*
+		RCURLY!
+		{#interfaceBlock = #([OBJBLOCK, "OBJBLOCK"], #interfaceBlock);}
+	;
+	
+// This is the body of an annotation. You can have annotation fields and extra semicolons,
+// That's about it (until you see what an annoation field is...)
+annotationBlock
+	:	LCURLY!
+		( annotationField | SEMI! )*
+		RCURLY!
+		{#annotationBlock = #([OBJBLOCK, "OBJBLOCK"], #annotationBlock);}
+	;
+
+// This is the body of an enum. You can have zero or more enum constants
+// followed by any number of fields like a regular class
+enumBlock
+	:	LCURLY!
+			( enumConstant ( options{greedy=true;}: COMMA! enumConstant )* ( COMMA! )? )?
+			( SEMI! ( classField | SEMI! )* )?
+		RCURLY!
+		{#enumBlock = #([OBJBLOCK, "OBJBLOCK"], #enumBlock);}
+	;
+
+// An annotation field
+annotationField!  {Token first = LT(1);}
+	:	mods:modifiers
+		(	td:typeDefinitionInternal[#mods]
+			{#annotationField = #td;}
+		|	t:typeSpec[false]		// annotation field
+			(	i:IDENT				// the name of the field
+
+				LPAREN! RPAREN!
+
+				rt:declaratorBrackets[#t]
+
+				( "default" amvi:annotationMemberValueInitializer )?
+
+				SEMI
+
+				{#annotationField =
+					#(create(ANNOTATION_FIELD_DEF,"ANNOTATION_FIELD_DEF",first,LT(1)),
+						 mods,
+						 #(create(TYPE,"TYPE",first,LT(1)),rt),
+						 i,amvi
+						 );}
+			|	v:variableDefinitions[#mods,#t] SEMI	// variable
+				{#annotationField = #v;}
+			)
+		)
+	;
+
+//An enum constant may have optional parameters and may have a
+//a class body
+enumConstant!
+	:	an:annotations
+		i:IDENT
+		(	LPAREN!
+			a:argList
+			RPAREN!
+		)?
+		( b:enumConstantBlock )?
+		{#enumConstant = #([ENUM_CONSTANT_DEF, "ENUM_CONSTANT_DEF"], an, i, a, b);}
+	;
+
+//The class-like body of an enum constant
+enumConstantBlock
+	:	LCURLY!
+		( enumConstantField | SEMI! )*
+		RCURLY!
+		{#enumConstantBlock = #([OBJBLOCK, "OBJBLOCK"], #enumConstantBlock);}
+	;
+
+//An enum constant field is just like a class field but without
+//the posibility of a constructor definition or a static initializer
+enumConstantField! {Token first = LT(1);}
+	:	mods:modifiers
+		(	td:typeDefinitionInternal[#mods]
+			{#enumConstantField = #td;}
+
+		|	// A generic method has the typeParameters before the return type.
+			// This is not allowed for variable definitions, but this production
+			// allows it, a semantic check could be used if you wanted.
+			(tp:typeParameters)? t:typeSpec[false]		// method or variable declaration(s)
+			(	IDENT									// the name of the method
+
+				// parse the formal parameter declarations.
+				LPAREN! param:parameterDeclarationList RPAREN!
+
+				rt:declaratorBrackets[#t]
+
+				// get the list of exceptions that this method is
+				// declared to throw
+				(tc:throwsClause)?
+
+				( s2:compoundStatement | SEMI )
+				{#enumConstantField = #(create(METHOD_DEF,"METHOD_DEF",first,LT(1)),
+							 mods,
+							 tp,
+							 #(create(TYPE,"TYPE",first,LT(1)),rt),
+							 IDENT,
+							 param,
+							 tc,
+							 s2);}
+			|	v:variableDefinitions[#mods,#t] SEMI
+				{#enumConstantField = #v;}
+			)
+		)
+
+	// "{ ... }" instance initializer
+	|	s4:compoundStatement
+		{#enumConstantField = #(create(INSTANCE_INIT,"INSTANCE_INIT",first,LT(1)), s4);}
+	;
+
+// An interface can extend several other interfaces...
+interfaceExtends  {Token first = LT(1);}
+	:	(
+		e:"extends"!
+		classOrInterfaceType[false] ( COMMA! classOrInterfaceType[false] )*
+		)?
+		{#interfaceExtends = #(create(EXTENDS_CLAUSE,"EXTENDS_CLAUSE",first,LT(1)),
+								#interfaceExtends);}
+	;
+
+// A class can implement several interfaces...
+implementsClause  {Token first = LT(1);}
+	:	(
+			i:"implements"! classOrInterfaceType[false] ( COMMA! classOrInterfaceType[false] )*
+		)?
+		{#implementsClause = #(create(IMPLEMENTS_CLAUSE,"IMPLEMENTS_CLAUSE",first,LT(1)),
+								 #implementsClause);}
+	;
+
+// Now the various things that can be defined inside a class
+classField!   {Token first = LT(1);}
+	:	// method, constructor, or variable declaration
+		mods:modifiers
+		(	td:typeDefinitionInternal[#mods]
+			{#classField = #td;}
+
+		|	(tp:typeParameters)?
+			(
+				h:ctorHead s:constructorBody // constructor
+				// just treat CTOR_DEF like METHOD_DEF for java2groovy
+				{#classField = #(create(METHOD_DEF,"METHOD_DEF",first,LT(1)), mods, tp, h, s);}
+
+				|	// A generic method/ctor has the typeParameters before the return type.
+					// This is not allowed for variable definitions, but this production
+					// allows it, a semantic check could be used if you wanted.
+					t:typeSpec[false]		// method or variable declaration(s)
+					(	IDENT				// the name of the method
+
+						// parse the formal parameter declarations.
+						LPAREN! param:parameterDeclarationList RPAREN!
+
+						rt:declaratorBrackets[#t]
+
+						// get the list of exceptions that this method is
+						// declared to throw
+						(tc:throwsClause)?
+
+						( s2:compoundStatement | SEMI )
+						{#classField = #(create(METHOD_DEF,"METHOD_DEF",first,LT(1)),
+									 mods,
+									 tp,
+									 #(create(TYPE,"TYPE",first,LT(1)),rt),
+									 IDENT,
+									 param,
+									 tc,
+									 s2);}
+					|	v:variableDefinitions[#mods,#t] SEMI
+						{#classField = #v;}
+					)
+			)
+		)
+
+	// "static { ... }" class initializer
+	|	"static" s3:compoundStatement
+		{#classField = #(create(STATIC_INIT,"STATIC_INIT",first,LT(1)), s3);}
+
+	// "{ ... }" instance initializer
+	|	s4:compoundStatement
+		{#classField = #(create(INSTANCE_INIT,"INSTANCE_INIT",first,LT(1)), s4);}
+	;
+
+// Now the various things that can be defined inside a interface
+interfaceField!    {Token first = LT(1);}
+	:	// method, constructor, or variable declaration
+		mods:modifiers
+		(	td:typeDefinitionInternal[#mods]
+			{#interfaceField = #td;}
+
+		|	(tp:typeParameters)?
+			// A generic method has the typeParameters before the return type.
+			// This is not allowed for variable definitions, but this production
+			// allows it, a semantic check could be used if you want a more strict
+			// grammar.
+			t:typeSpec[false]		// method or variable declaration(s)
+			(	IDENT				// the name of the method
+
+				// parse the formal parameter declarations.
+				LPAREN! param:parameterDeclarationList RPAREN!
+
+				rt:declaratorBrackets[#t]
+
+				// get the list of exceptions that this method is
+				// declared to throw
+				(tc:throwsClause)?
+
+				SEMI
+				
+				{#interfaceField = #(create(METHOD_DEF,"METHOD_DEF",first,LT(1)),
+							 mods,
+							 tp,
+							 #(create(TYPE,"TYPE",first,LT(1)),rt),
+							 IDENT,
+							 param,
+							 tc);}
+			|	v:variableDefinitions[#mods,#t] SEMI
+				{#interfaceField = #v;}
+			)
+		)
+	;
+
+constructorBody
+	:	lc:LCURLY^ {#lc.setType(SLIST);}
+			( options { greedy=true; } : explicitConstructorInvocation)?
+			(statement)*
+		RCURLY!
+	;
+
+/** Catch obvious constructor calls, but not the expr.super(...) calls */
+explicitConstructorInvocation
+	:	(typeArguments)?
+		(	"this"! lp1:LPAREN^ argList RPAREN! SEMI!
+			{#lp1.setType(CTOR_CALL);}
+		|	"super"! lp2:LPAREN^ argList RPAREN! SEMI!
+			{#lp2.setType(SUPER_CTOR_CALL);}
+		)
+	;
+
+variableDefinitions[AST mods, AST t]
+	:	variableDeclarator[getASTFactory().dupTree(mods),
+							getASTFactory().dupTree(t)]
+		(	COMMA!
+			variableDeclarator[getASTFactory().dupTree(mods),
+							getASTFactory().dupTree(t)]
+		)*
+	;
+
+/** Declaration of a variable. This can be a class/instance variable,
+ *  or a local variable in a method
+ *  It can also include possible initialization.
+ */
+variableDeclarator![AST mods, AST t] { Token first = LT(1);}
+	:	id:IDENT d:declaratorBrackets[t] v:varInitializer
+		{#variableDeclarator = #(create(VARIABLE_DEF,"VARIABLE_DEF",first,LT(1)), mods, #(create(TYPE,"TYPE",first,LT(1)),d), id, v);}
+	;
+
+declaratorBrackets[AST typ]
+	:	{#declaratorBrackets=typ;}
+		(lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+	;
+
+varInitializer
+	:	( ASSIGN^ initializer )?
+	;
+
+// This is an initializer used to set up an array.
+/*arrayInitializer
+	:	lc:LCURLY^ {#lc.setType(ARRAY_INIT);}
+			(	initializer
+				(
+					// CONFLICT: does a COMMA after an initializer start a new
+					// initializer or start the option ',' at end?
+					// ANTLR generates proper code by matching
+					// the comma as soon as possible.
+					options {
+						warnWhenFollowAmbig = false;
+					}
+				:
+					COMMA! initializer
+				)*
+				(COMMA!)?
+			)?
+		RCURLY!
+	;
+*/
+
+// The two "things" that can initialize an array element are an expression
+// and another (nested) array initializer.
+initializer
+	:	expression
+//	|	arrayInitializer
+	;
+
+// This is the header of a method. It includes the name and parameters
+// for the method.
+// This also watches for a list of exception classes in a "throws" clause.
+ctorHead
+	:	IDENT // the name of the method
+
+		// parse the formal parameter declarations.
+		LPAREN! parameterDeclarationList RPAREN!
+
+		// get the list of exceptions that this method is declared to throw
+		(throwsClause)?
+	;
+
+// This is a list of exception classes that the method is declared to throw
+throwsClause
+	:	"throws"^ identifier ( COMMA! identifier )*
+	;
+
+// A list of formal parameters
+//	 Zero or more parameters
+//	 If a parameter is variable length (e.g. String... myArg) it is the right-most parameter
+parameterDeclarationList {Token first = LT(1);}
+	// The semantic check in ( .... )* block is flagged as superfluous, and seems superfluous but
+	// is the only way I could make this work. If my understanding is correct this is a known bug
+	:	(	( parameterDeclaration )=> parameterDeclaration
+			( options {warnWhenFollowAmbig=false;} : ( COMMA! parameterDeclaration ) => COMMA! parameterDeclaration )*
+			( COMMA! variableLengthParameterDeclaration )?
+		|
+			variableLengthParameterDeclaration
+		)?
+		{#parameterDeclarationList = #(create(PARAMETERS,"PARAMETERS",first,LT(1)),
+                						#parameterDeclarationList);}
+	;
+
+// A formal parameter.
+parameterDeclaration! {Token first = LT(1);}
+	:	pm:parameterModifier t:typeSpec[false] id:IDENT
+		pd:declaratorBrackets[#t]
+		{#parameterDeclaration = #(create(PARAMETER_DEF,"PARAMETER_DEF",first,LT(1)),
+									pm, #(create(TYPE,"TYPE",first,LT(1)),pd), id);}
+	;
+
+variableLengthParameterDeclaration!  {Token first = LT(1);}
+	:	pm:parameterModifier t:typeSpec[false] TRIPLE_DOT! id:IDENT
+		pd:declaratorBrackets[#t]
+		{#variableLengthParameterDeclaration = #(create(VARIABLE_PARAMETER_DEF,"VARIABLE_PARAMETER_DEF",first,LT(1)),
+												pm, #(create(TYPE,"TYPE",first,LT(1)),pd), id);}
+	;
+
+parameterModifier  {Token first = LT(1);}
+	//final can appear amongst annotations in any order - greedily consume any preceding
+	//annotations to shut nond-eterminism warnings off
+	:	(options{greedy=true;} : annotation)* (f:"final")? (annotation)*
+		{#parameterModifier = #(create(MODIFIERS,"MODIFIERS",first,LT(1)), #parameterModifier);}
+	;
+
+// Compound statement. This is used in many contexts:
+// Inside a class definition prefixed with "static":
+// it is a class initializer
+// Inside a class definition without "static":
+// it is an instance initializer
+// As the body of a method
+// As a completely indepdent braced block of code inside a method
+// it starts a new scope for variable definitions
+
+compoundStatement
+	:	lc:LCURLY^ {#lc.setType(SLIST);}
+			// include the (possibly-empty) list of statements
+			(statement)*
+		RCURLY!
+	;
+
+
+statement
+	// A list of statements in curly braces -- start a new scope!
+	:	compoundStatement
+
+	// declarations are ambiguous with "ID DOT" relative to expression
+	// statements. Must backtrack to be sure. Could use a semantic
+	// predicate to test symbol table to see what the type was coming
+	// up, but that's pretty hard without a symbol table ;)
+	|	(declaration)=> declaration SEMI!
+
+	// An expression statement. This could be a method call,
+	// assignment statement, or any other expression evaluated for
+	// side-effects.
+	|	expression SEMI!
+
+	//TODO: what abour interfaces, enums and annotations
+	// class definition
+	|	m:modifiers! classDefinition[#m]
+
+	// Attach a label to the front of a statement
+	|	IDENT c:COLON^ {#c.setType(LABELED_STAT);} statement
+
+	// If-else statement
+	|	"if"^ LPAREN! expression RPAREN! statement
+		(
+			// CONFLICT: the old "dangling-else" problem...
+			// ANTLR generates proper code matching
+			// as soon as possible. Hush warning.
+			options {
+				warnWhenFollowAmbig = false;
+			}
+		:
+			"else"! statement
+		)?
+
+	// For statement
+	|	forStatement
+
+	// While statement
+	|	"while"^ LPAREN! expression RPAREN! statement
+
+	// do-while statement
+//not supported in java2groovy
+	//	|	"do"^ statement "while"! LPAREN! expression RPAREN! SEMI!
+
+	// get out of a loop (or switch)
+	|	"break"^ (IDENT)? SEMI!
+
+	// do next iteration of a loop
+	|	"continue"^ (IDENT)? SEMI!
+
+	// Return an expression
+	|	"return"^ (expression)? SEMI!
+
+	// switch/case statement
+	|	"switch"^ LPAREN! expression RPAREN! LCURLY!
+			( casesGroup )*
+		RCURLY!
+
+	// exception try-catch block
+	|	tryBlock
+
+	// throw an exception
+	|	"throw"^ expression SEMI!
+
+	// synchronize a statement
+	|	"synchronized"^ LPAREN! expression RPAREN! compoundStatement
+
+	// asserts (uncomment if you want 1.4 compatibility)
+	|	"assert"^ expression ( COLON! expression )? SEMI!
+
+	// empty statement
+	|	s:SEMI {#s.setType(EMPTY_STAT);}
+	;
+
+forStatement
+	:	f:"for"^
+		LPAREN!
+			(	(forInit SEMI)=>traditionalForClause
+			|	forEachClause
+			)
+		RPAREN!
+		statement					 // statement to loop over
+	;
+
+traditionalForClause
+	:
+		forInit SEMI!	// initializer
+		forCond SEMI!	// condition test
+		forIter			// updater
+	;
+
+forEachClause  {Token first = LT(1);}
+	:
+		p:parameterDeclaration COLON! expression
+		{#forEachClause = #(create(FOR_EACH_CLAUSE,"FOR_EACH_CLAUSE",first,LT(1)), #forEachClause);}
+	;
+
+casesGroup
+	:	(	// CONFLICT: to which case group do the statements bind?
+			// ANTLR generates proper code: it groups the
+			// many "case"/"default" labels together then
+			// follows them with the statements
+			options {
+				greedy = true;
+			}
+			:
+			aCase
+		)+
+		caseSList
+		{#casesGroup = #([CASE_GROUP, "CASE_GROUP"], #casesGroup);}
+	;
+
+aCase
+	:	("case"^ expression | "default") COLON!
+	;
+
+caseSList  {Token first = LT(1);}
+	:	(statement)*
+		{#caseSList = #(create(SLIST,"SLIST",first,LT(1)),#caseSList);}
+	;
+
+// The initializer for a for loop
+forInit  {Token first = LT(1);}
+		// if it looks like a declaration, it is
+	:	((declaration)=> declaration
+		// otherwise it could be an expression list...
+		|	expressionList
+		)?
+		{#forInit = #(create(FOR_INIT,"FOR_INIT",first,LT(1)),#forInit);}
+	;
+
+forCond  {Token first = LT(1);}
+	:	(expression)?
+		{#forCond = #(create(FOR_CONDITION,"FOR_CONDITION",first,LT(1)),#forCond);}
+	;
+
+forIter  {Token first = LT(1);}
+	:	(expressionList)?
+		{#forIter = #(create(FOR_ITERATOR,"FOR_ITERATOR",first,LT(1)),#forIter);}
+	;
+
+// an exception handler try/catch block
+tryBlock
+	:	"try"^ compoundStatement
+		(handler)*
+		( finallyClause )?
+	;
+
+finallyClause
+	:	"finally"^ compoundStatement
+	;
+
+// an exception handler
+handler
+	:	"catch"^ LPAREN! parameterDeclaration RPAREN! compoundStatement
+	;
+
+
+// expressions
+// Note that most of these expressions follow the pattern
+//   thisLevelExpression :
+//	   nextHigherPrecedenceExpression
+//		   (OPERATOR nextHigherPrecedenceExpression)*
+// which is a standard recursive definition for a parsing an expression.
+// The operators in java have the following precedences:
+//	lowest  (13)  = *= /= %= += -= <<= >>= >>>= &= ^= |=
+//			(12)  ?:
+//			(11)  ||
+//			(10)  &&
+//			( 9)  |
+//			( 8)  ^
+//			( 7)  &
+//			( 6)  == !=
+//			( 5)  < <= > >=
+//			( 4)  << >>
+//			( 3)  +(binary) -(binary)
+//			( 2)  * / %
+//			( 1)  ++ -- +(unary) -(unary)  ~  !  (type)
+//				  []   () (method call)  . (dot -- identifier qualification)
+//				  new   ()  (explicit parenthesis)
+//
+// the last two are not usually on a precedence chart; I put them in
+// to point out that new has a higher precedence than '.', so you
+// can validy use
+//	 new Frame().show()
+//
+// Note that the above precedence levels map to the rules below...
+// Once you have a precedence chart, writing the appropriate rules as below
+//   is usually very straightfoward
+
+
+
+// the mother of all expressions
+expression  {Token first = LT(1);}
+	:	assignmentExpression
+		{#expression = #(create(EXPR,"EXPR",first,LT(1)),#expression);}
+	;
+
+
+// This is a list of expressions.
+expressionList  {Token first = LT(1);}
+	:	expression (COMMA! expression)*
+		{#expressionList = #(create(ELIST,"ELIST",first,LT(1)), #expressionList);}
+	;
+
+
+// assignment expression (level 13)
+assignmentExpression
+	:	conditionalExpression
+		(	(	ASSIGN^
+			|	PLUS_ASSIGN^
+			|	MINUS_ASSIGN^
+			|	STAR_ASSIGN^
+			|	DIV_ASSIGN^
+			|	MOD_ASSIGN^
+			|	SR_ASSIGN^
+			|	BSR_ASSIGN^
+			|	SL_ASSIGN^
+			|	BAND_ASSIGN^
+			|	BXOR_ASSIGN^
+			|	BOR_ASSIGN^
+			)
+			assignmentExpression
+		)?
+	;
+
+
+// conditional test (level 12)
+conditionalExpression
+	:	logicalOrExpression
+		( QUESTION^ assignmentExpression COLON! conditionalExpression )?
+	;
+
+
+// logical or (||) (level 11)
+logicalOrExpression
+	:	logicalAndExpression (LOR^ logicalAndExpression)*
+	;
+
+
+// logical and (&&) (level 10)
+logicalAndExpression
+	:	inclusiveOrExpression (LAND^ inclusiveOrExpression)*
+	;
+
+
+// bitwise or non-short-circuiting or (|) (level 9)
+inclusiveOrExpression
+	:	exclusiveOrExpression (BOR^ exclusiveOrExpression)*
+	;
+
+
+// exclusive or (^) (level 8)
+exclusiveOrExpression
+	:	andExpression (BXOR^ andExpression)*
+	;
+
+
+// bitwise or non-short-circuiting and (&) (level 7)
+andExpression
+	:	equalityExpression (BAND^ equalityExpression)*
+	;
+
+
+// equality/inequality (==/!=) (level 6)
+equalityExpression
+	:	relationalExpression ((NOT_EQUAL^ | EQUAL^) relationalExpression)*
+	;
+
+
+// boolean relational expressions (level 5)
+relationalExpression
+	:	shiftExpression
+		(	(	(	LT^
+				|	GT^
+				|	LE^
+				|	GE^
+				)
+				shiftExpression
+			)*
+		|	"instanceof"^ typeSpec[true]
+		)
+	;
+
+
+// bit shift expressions (level 4)
+shiftExpression
+	:	additiveExpression ((SL^ | SR^ | BSR^) additiveExpression)*
+	;
+
+
+// binary addition/subtraction (level 3)
+additiveExpression
+	:	multiplicativeExpression ((PLUS^ | MINUS^) multiplicativeExpression)*
+	;
+
+
+// multiplication/division/modulo (level 2)
+multiplicativeExpression
+	:	unaryExpression ((STAR^ | DIV^ | MOD^ ) unaryExpression)*
+	;
+
+unaryExpression
+	:	INC^ unaryExpression
+	|	DEC^ unaryExpression
+	|	MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression
+	|	PLUS^ {#PLUS.setType(UNARY_PLUS);} unaryExpression
+	|	unaryExpressionNotPlusMinus
+	;
+
+unaryExpressionNotPlusMinus
+	:	BNOT^ unaryExpression
+	|	LNOT^ unaryExpression
+	|	(	// subrule allows option to shut off warnings
+			options {
+				// "(int" ambig with postfixExpr due to lack of sequence
+				// info in linear approximate LL(k). It's ok. Shut up.
+				generateAmbigWarnings=false;
+			}
+		:	// If typecast is built in type, must be numeric operand
+			// Have to backtrack to see if operator follows
+		(LPAREN builtInTypeSpec[true] RPAREN unaryExpression)=>
+		lpb:LPAREN^ {#lpb.setType(TYPECAST);} builtInTypeSpec[true] RPAREN!
+		unaryExpression
+
+		// Have to backtrack to see if operator follows. If no operator
+		// follows, it's a typecast. No semantic checking needed to parse.
+		// if it _looks_ like a cast, it _is_ a cast; else it's a "(expr)"
+	|	(LPAREN classTypeSpec[true] RPAREN unaryExpressionNotPlusMinus)=>
+		lp:LPAREN^ {#lp.setType(TYPECAST);} classTypeSpec[true] RPAREN!
+		unaryExpressionNotPlusMinus
+
+	|	postfixExpression
+	)
+	;
+
+// qualified names, array expressions, method invocation, post inc/dec
+postfixExpression
+	:
+		primaryExpression
+
+		(
+			/*
+			options {
+				// the use of postfixExpression in SUPER_CTOR_CALL adds DOT
+				// to the lookahead set, and gives loads of false non-det
+				// warnings.
+				// shut them off.
+				generateAmbigWarnings=false;
+			}
+		:	*/
+			//type arguments are only appropriate for a parameterized method/ctor invocations
+			//semantic check may be needed here to ensure that this is the case
+			DOT^ (typeArguments)?
+				(	IDENT
+					(	lp:LPAREN^ {#lp.setType(METHOD_CALL);}
+						argList
+						RPAREN!
+					)?
+				|	"super"
+					(	// (new Outer()).super() (create enclosing instance)
+						lp3:LPAREN^ argList RPAREN!
+						{#lp3.setType(SUPER_CTOR_CALL);}
+					|	DOT^ (typeArguments)? IDENT
+						(	lps:LPAREN^ {#lps.setType(METHOD_CALL);}
+							argList
+							RPAREN!
+						)?
+					)
+				)
+		|	DOT^ "this"
+		|	DOT^ newExpression
+		|	lb:LBRACK^ {#lb.setType(INDEX_OP);} expression RBRACK!
+		)*
+
+		(	// possibly add on a post-increment or post-decrement.
+			// allows INC/DEC on too much, but semantics can check
+			in:INC^ {#in.setType(POST_INC);}
+	 	|	de:DEC^ {#de.setType(POST_DEC);}
+		)?
+ 	;
+
+// the basic element of an expression
+primaryExpression
+	:	identPrimary ( options {greedy=true;} : DOT^ "class" )?
+	|	constant
+	|	"true"
+	|	"false"
+	|	"null"
+	|	newExpression
+	|	"this"
+	|	"super"
+	|	LPAREN! assignmentExpression RPAREN!
+		// look for int.class and int[].class
+	|	builtInType
+		( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )*
+		DOT^ "class"
+	;
+
+/** Match a, a.b.c refs, a.b.c(...) refs, a.b.c[], a.b.c[].class,
+ *  and a.b.c.class refs. Also this(...) and super(...). Match
+ *  this or super.
+ */
+identPrimary
+	:	(ta1:typeArguments!)?
+		IDENT
+		// Syntax for method invocation with type arguments is
+		// <String>foo("blah")
+		(
+			options {
+				// .ident could match here or in postfixExpression.
+				// We do want to match here. Turn off warning.
+				greedy=true;
+				// This turns the ambiguity warning of the second alternative
+				// off. See below. (The "false" predicate makes it non-issue)
+				warnWhenFollowAmbig=false;
+			}
+			// we have a new nondeterminism because of
+			// typeArguments... only a syntactic predicate will help...
+			// The problem is that this loop here conflicts with
+			// DOT typeArguments "super" in postfixExpression (k=2)
+			// A proper solution would require a lot of refactoring...
+		:	(DOT (typeArguments)? IDENT) =>
+				DOT^ (ta2:typeArguments!)? IDENT
+		|	{false}?	// FIXME: this is very ugly but it seems to work...
+						// this will also produce an ANTLR warning!
+				// Unfortunately a syntactic predicate can only select one of
+				// multiple alternatives on the same level, not break out of
+				// an enclosing loop, which is why this ugly hack (a fake
+				// empty alternative with always-false semantic predicate)
+				// is necessary.
+		)*
+		(
+			options {
+				// ARRAY_DECLARATOR here conflicts with INDEX_OP in
+				// postfixExpression on LBRACK RBRACK.
+				// We want to match [] here, so greedy. This overcomes
+				// limitation of linear approximate lookahead.
+				greedy=true;
+			}
+		:	(	lp:LPAREN^ {#lp.setType(METHOD_CALL);}
+				// if the input is valid, only the last IDENT may
+				// have preceding typeArguments... rather hacky, this is...
+				{if (#ta2 != null) astFactory.addASTChild(currentAST, #ta2);}
+				{if (#ta2 == null) astFactory.addASTChild(currentAST, #ta1);}
+				argList RPAREN!
+			)
+		|	( options {greedy=true;} :
+				lbc:LBRACK^ {#lbc.setType(ARRAY_DECLARATOR);} RBRACK!
+			)+
+		)?
+	;
+
+/** object instantiation.
+ *  Trees are built as illustrated by the following input/tree pairs:
+ *
+ *  new T()
+ *
+ *  new
+ *   |
+ *   T --  ELIST
+ *		   |
+ *		  arg1 -- arg2 -- .. -- argn
+ *
+ *  new int[]
+ *
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR
+ *
+ *  new int[] {1,2}
+ *
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR -- ARRAY_INIT
+ *								  |
+ *								EXPR -- EXPR
+ *								  |	  |
+ *								  1	  2
+ *
+ *  new int[3]
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR
+ *				|
+ *			  EXPR
+ *				|
+ *				3
+ *
+ *  new int[1][2]
+ *
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR
+ *			   |
+ *		 ARRAY_DECLARATOR -- EXPR
+ *			   |			  |
+ *			 EXPR			 1
+ *			   |
+ *			   2
+ *
+ */
+newExpression
+	:	"new"^ (typeArguments)? type
+		(	LPAREN! argList RPAREN! (classBlock)?
+
+			//java 1.1
+			// Note: This will allow bad constructs like
+			//	new int[4][][3] {exp,exp}.
+			//	There needs to be a semantic check here...
+			// to make sure:
+			//   a) [ expr ] and [ ] are not mixed
+			//   b) [ expr ] and an init are not used together
+
+		|	newArrayDeclarator// (arrayInitializer)?
+		)
+	;
+
+argList {Token first = LT(1);}
+	:	(	expressionList
+		|	/*nothing*/
+			{#argList = create(ELIST,"ELIST",first,LT(1));}
+		)
+	;
+
+newArrayDeclarator
+	:	(
+			// CONFLICT:
+			// newExpression is a primaryExpression which can be
+			// followed by an array index reference. This is ok,
+			// as the generated code will stay in this loop as
+			// long as it sees an LBRACK (proper behavior)
+			options {
+				warnWhenFollowAmbig = false;
+			}
+		:
+			lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);}
+				(expression)?
+			RBRACK!
+		)+
+	;
+
+constant
+	:	NUM_INT
+	|	STRING_LITERAL
+	|	NUM_FLOAT
+	|	NUM_LONG
+	|	NUM_DOUBLE
+	;
+
+
+//----------------------------------------------------------------------------
+// The Java scanner
+//----------------------------------------------------------------------------
+class JavaLexer extends Lexer;
+
+options {
+	exportVocab=Java;		// call the vocabulary "Java"
+	testLiterals=false;		// don't automatically test for literals
+	k=4;					// four characters of lookahead
+	charVocabulary='\u0003'..'\uFFFF';
+	// without inlining some bitset tests, couldn't do unicode;
+	// I need to make ANTLR generate smaller bitsets; see
+	// bottom of JavaLexer.java
+	codeGenBitsetTestThreshold=20;
+}
+
+{
+    protected static final int SCS_TYPE = 3, SCS_VAL = 4, SCS_LIT = 8, SCS_LIMIT = 16;
+    protected static final int SCS_SQ_TYPE = 0, SCS_TQ_TYPE = 1, SCS_RE_TYPE = 2;
+    protected int stringCtorState = 0;  // hack string and regexp constructor boundaries
+    protected int lastSigTokenType = EOF;  // last returned non-whitespace token
+
+    /** flag for enabling the "assert" keyword */
+	private boolean assertEnabled = true;
+	/** flag for enabling the "enum" keyword */
+	private boolean enumEnabled = true;
+    /** flag for including whitespace tokens (for IDE preparsing) */
+    private boolean whitespaceIncluded = false;
+
+	/** Enable the "assert" keyword */
+	public void enableAssert(boolean shouldEnable) { assertEnabled = shouldEnable; }
+	/** Query the "assert" keyword state */
+	public boolean isAssertEnabled() { return assertEnabled; }
+	/** Enable the "enum" keyword */
+	public void enableEnum(boolean shouldEnable) { enumEnabled = shouldEnable; }
+	/** Query the "enum" keyword state */
+	public boolean isEnumEnabled() { return enumEnabled; }
+
+    /** This is a bit of plumbing which resumes collection of string constructor bodies,
+     *  after an embedded expression has been parsed.
+     *  Usage:  new JavaRecognizer(new JavaLexer(in).plumb()).
+     */
+    public TokenStream plumb() {
+        return new TokenStream() {
+            public Token nextToken() throws TokenStreamException {
+                if (stringCtorState >= SCS_LIT) {
+                    // This goo is modeled upon the ANTLR code for nextToken:
+                    int quoteType = (stringCtorState & SCS_TYPE);
+                    stringCtorState = 0;  // get out of this mode, now
+                    resetText();
+/*                    try {
+                        switch (quoteType) {
+                        case SCS_SQ_TYPE:
+//todo: suitable replacement???     mSTRING_CTOR_END(true, false, false); 
+                        	break;
+                        case SCS_TQ_TYPE:
+//                            mSTRING_CTOR_END(true, false, true); 
+                        	break;
+                        case SCS_RE_TYPE:
+//                            mREGEXP_CTOR_END(true, false); 
+                        	break;
+                        default:  throw new AssertionError(false);
+                        }
+                        lastSigTokenType = _returnToken.getType();
+                        return _returnToken;
+                    }*//* catch (RecognitionException e) {
+                        throw new TokenStreamRecognitionException(e);
+                    }*/ /*catch (CharStreamException cse) {
+                        if ( cse instanceof CharStreamIOException ) {
+                            throw new TokenStreamIOException(((CharStreamIOException)cse).io);
+                        }
+                        else {
+                            throw new TokenStreamException(cse.getMessage());
+                        }
+                    }*/
+                }
+                Token token = JavaLexer.this.nextToken();
+                int lasttype = token.getType();
+                if (whitespaceIncluded) {
+                    switch (lasttype) {  // filter out insignificant types
+                    case WS:
+                    case SL_COMMENT:
+                    case ML_COMMENT:
+                        lasttype = lastSigTokenType;  // back up!
+                    }
+                }
+                lastSigTokenType = lasttype;
+                return token;
+            }
+        };
+    }
+    
+    protected JavaRecognizer parser;  // little-used link; TODO: get rid of
+}
+
+// OPERATORS
+QUESTION		:	'?'		;
+LPAREN			:	'('		;
+RPAREN			:	')'		;
+LBRACK			:	'['		;
+RBRACK			:	']'		;
+LCURLY			:	'{'		;
+RCURLY			:	'}'		;
+COLON			:	':'		;
+COMMA			:	','		;
+//DOT			:	'.'		;
+ASSIGN			:	'='		;
+EQUAL			:	"=="	;
+LNOT			:	'!'		;
+BNOT			:	'~'		;
+NOT_EQUAL		:	"!="	;
+DIV				:	'/'		;
+DIV_ASSIGN		:	"/="	;
+PLUS			:	'+'		;
+PLUS_ASSIGN		:	"+="	;
+INC				:	"++"	;
+MINUS			:	'-'		;
+MINUS_ASSIGN	:	"-="	;
+DEC				:	"--"	;
+STAR			:	'*'		;
+STAR_ASSIGN		:	"*="	;
+MOD				:	'%'		;
+MOD_ASSIGN		:	"%="	;
+SR				:	">>"	;
+SR_ASSIGN		:	">>="	;
+BSR				:	">>>"	;
+BSR_ASSIGN		:	">>>="	;
+GE				:	">="	;
+GT				:	">"		;
+SL				:	"<<"	;
+SL_ASSIGN		:	"<<="	;
+LE				:	"<="	;
+LT				:	'<'		;
+BXOR			:	'^'		;
+BXOR_ASSIGN		:	"^="	;
+BOR				:	'|'		;
+BOR_ASSIGN		:	"|="	;
+LOR				:	"||"	;
+BAND			:	'&'		;
+BAND_ASSIGN		:	"&="	;
+LAND			:	"&&"	;
+SEMI			:	';'		;
+
+
+// Whitespace -- ignored
+WS	:	(	' '
+		|	'\t'
+		|	'\f'
+			// handle newlines
+		|	(	options {generateAmbigWarnings=false;}
+			:	"\r\n"	// Evil DOS
+			|	'\r'	// Macintosh
+			|	'\n'	// Unix (the right way)
+			)
+			{ newline(); }
+		)+
+		{ _ttype = Token.SKIP; }
+	;
+
+// Single-line comments
+SL_COMMENT
+	:	"//"
+		(~('\n'|'\r'))* ('\n'|'\r'('\n')?)
+		{$setType(Token.SKIP); newline();}
+	;
+
+// multiple-line comments
+ML_COMMENT
+	:	"/*"
+		(	/*	'\r' '\n' can be matched in one alternative or by matching
+				'\r' in one iteration and '\n' in another. I am trying to
+				handle any flavor of newline that comes in, but the language
+				that allows both "\r\n" and "\r" and "\n" to all be valid
+				newline is ambiguous. Consequently, the resulting grammar
+				must be ambiguous. I'm shutting this warning off.
+			 */
+			options {
+				generateAmbigWarnings=false;
+			}
+		:
+			{ LA(2)!='/' }? '*'
+		|	'\r' '\n'		{newline();}
+		|	'\r'			{newline();}
+		|	'\n'			{newline();}
+		|	~('*'|'\n'|'\r')
+		)*
+		"*/"
+		{$setType(Token.SKIP);}
+	;
+
+
+// string literals
+STRING_LITERAL
+	:	'"' (ESC|~('"'|'\\'|'\n'|'\r'))* '"'
+	// no CHAR_LITERALs in groovy...
+	|	'\'' ( ESC | ~('\''|'\n'|'\r'|'\\') ) '\''
+	;
+
+
+// escape sequence -- note that this is protected; it can only be called
+// from another lexer rule -- it will not ever directly return a token to
+// the parser
+// There are various ambiguities hushed in this rule. The optional
+// '0'...'9' digit matches should be matched here rather than letting
+// them go back to STRING_LITERAL to be matched. ANTLR does the
+// right thing by matching immediately; hence, it's ok to shut off
+// the FOLLOW ambig warnings.
+protected
+ESC
+	:	'\\'
+		(	'n'
+		|	'r'
+		|	't'
+		|	'b'
+		|	'f'
+		|	'"'
+		|	'\''
+		|	'\\'
+		|	('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
+		|	'0'..'3'
+			(
+				options {
+					warnWhenFollowAmbig = false;
+				}
+			:	'0'..'7'
+				(
+					options {
+						warnWhenFollowAmbig = false;
+					}
+				:	'0'..'7'
+				)?
+			)?
+		|	'4'..'7'
+			(
+				options {
+					warnWhenFollowAmbig = false;
+				}
+			:	'0'..'7'
+			)?
+		)
+	;
+
+
+// hexadecimal digit (again, note it's protected!)
+protected
+HEX_DIGIT
+	:	('0'..'9'|'A'..'F'|'a'..'f')
+	;
+
+
+// a dummy rule to force vocabulary to be all characters (except special
+// ones that ANTLR uses internally (0 to 2)
+protected
+VOCAB
+	:	'\3'..'\377'
+	;
+
+
+// an identifier. Note that testLiterals is set to true! This means
+// that after we match the rule, we look in the literals table to see
+// if it's a literal or really an identifer
+IDENT
+	options {testLiterals=true;}
+	:	('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')*
+		{
+			// check if "assert" keyword is enabled
+			if (assertEnabled && "assert".equals($getText)) {
+				$setType(LITERAL_assert); // set token type for the rule in the parser
+			}
+			// check if "enum" keyword is enabled
+			if (enumEnabled && "enum".equals($getText)) {
+				$setType(LITERAL_enum); // set token type for the rule in the parser
+			}
+		}
+	;
+
+
+// a numeric literal
+NUM_INT
+	{boolean isDecimal=false; Token t=null;}
+	:	'.' {_ttype = DOT;}
+			(
+				(('0'..'9')+ (EXPONENT)? (f1:FLOAT_SUFFIX {t=f1;})?
+				{
+				if (t != null && t.getText().toUpperCase().indexOf('F')>=0) {
+					_ttype = NUM_FLOAT;
+				}
+				else {
+					_ttype = NUM_DOUBLE; // assume double
+				}
+				})
+				|
+				// JDK 1.5 token for variable length arguments
+				(".." {_ttype = TRIPLE_DOT;})
+			)?
+
+	|	(	'0' {isDecimal = true;} // special case for just '0'
+			(	('x'|'X')
+				(											// hex
+					// the 'e'|'E' and float suffix stuff look
+					// like hex digits, hence the (...)+ doesn't
+					// know when to stop: ambig. ANTLR resolves
+					// it correctly by matching immediately. It
+					// is therefor ok to hush warning.
+					options {
+						warnWhenFollowAmbig=false;
+					}
+				:	HEX_DIGIT
+				)+
+
+			|	//float or double with leading zero
+				(('0'..'9')+ ('.'|EXPONENT|FLOAT_SUFFIX)) => ('0'..'9')+
+
+			|	('0'..'7')+									// octal
+			)?
+		|	('1'..'9') ('0'..'9')*  {isDecimal=true;}		// non-zero decimal
+		)
+		(	('l'|'L') { _ttype = NUM_LONG; }
+
+		// only check to see if it's a float if looks like decimal so far
+		|	{isDecimal}?
+			(	'.' ('0'..'9')* (EXPONENT)? (f2:FLOAT_SUFFIX {t=f2;})?
+			|	EXPONENT (f3:FLOAT_SUFFIX {t=f3;})?
+			|	f4:FLOAT_SUFFIX {t=f4;}
+			)
+			{
+			if (t != null && t.getText().toUpperCase() .indexOf('F') >= 0) {
+				_ttype = NUM_FLOAT;
+			}
+			else {
+				_ttype = NUM_DOUBLE; // assume double
+			}
+			}
+		)?
+	;
+
+// JDK 1.5 token for annotations and their declarations
+AT
+	:	'@'
+	;
+
+// a couple protected methods to assist in matching floating point numbers
+protected
+EXPONENT
+	:	('e'|'E') ('+'|'-')? ('0'..'9')+
+	;
+
+
+protected
+FLOAT_SUFFIX
+	:	'f'|'F'|'d'|'D'
+	;
+			
+
+//			 Note: Please don't use physical tabs.  Logical tabs for indent are width 4.
+//			 Here's a little hint for you, Emacs:
+//			 Local Variables:
+//			 tab-width: 4
+//			 mode: antlr-mode
+//			 indent-tabs-mode: nil
+//			 End:
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/parser/.cvsignore b/groovy-core/src/main/org/codehaus/groovy/antlr/parser/.cvsignore
new file mode 100644
index 0000000..098efa5
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/parser/.cvsignore
@@ -0,0 +1,4 @@
+GroovyLexer.java
+GroovyRecognizer.java
+GroovyTokenTypes.java
+GroovyTokenTypes.txt
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/syntax/AntlrClassSource.java b/groovy-core/src/main/org/codehaus/groovy/antlr/syntax/AntlrClassSource.java
new file mode 100644
index 0000000..15d43b9
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/syntax/AntlrClassSource.java
@@ -0,0 +1,70 @@
+/*
+ $Id$
+
+ Copyright 2005 (C) Jeremy Rayner. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.antlr.syntax;
+
+import org.codehaus.groovy.syntax.ClassSource;
+import org.codehaus.groovy.antlr.GroovySourceAST;
+
+/**
+ * Provides a container with a handy name for an Antlr AST node that represents a class.
+ */
+public class AntlrClassSource implements ClassSource {
+    private String name;
+    private GroovySourceAST ast;
+    
+    public AntlrClassSource(String name,GroovySourceAST ast) {
+        this.name = name;
+        this.ast = ast;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public GroovySourceAST getAST() {
+        return ast;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/CompositeVisitor.java b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/CompositeVisitor.java
new file mode 100644
index 0000000..9b7e73c
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/CompositeVisitor.java
@@ -0,0 +1,1178 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr.treewalker;
+
+import java.util.*;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+
+/**
+ * A composite of many visitors. Any call to a method from Visitor
+ * will invoke each visitor in turn, and reverse the invocation
+ * order on a closing visit.
+ * i.e.
+ * with the list of visitors = [a,b,c]
+ * composite.visitDefault() would...
+ * call on the opening visit - a.visitDefault() then b.visitDefault() then c.visitDefault()
+ * call on the closing visit - c.visitDefault() then b.visitDefault() then a.visitDefault()
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+public class CompositeVisitor implements Visitor{
+    List visitors;
+    List backToFrontVisitors;
+    private Stack stack;
+
+    /**
+     * A composite of the supplied list of antlr AST visitors.
+     * @param visitors a List of implementations of the Visitor interface
+     */
+    public CompositeVisitor(List visitors) {
+        this.visitors = visitors;
+        this.stack = new Stack();
+        backToFrontVisitors = new ArrayList();
+        backToFrontVisitors.addAll(visitors);
+        Collections.reverse(backToFrontVisitors);
+    }
+
+    private Iterator itr(int visit) {
+        Iterator itr=visitors.iterator();
+        if (visit == CLOSING_VISIT) {
+            itr = backToFrontVisitors.iterator();
+        }
+        return itr;
+    }
+
+    public void setUp() {
+        Iterator itr = visitors.iterator();
+        while (itr.hasNext()) {((Visitor)itr.next()).setUp();}
+    }
+
+    public void visitAbstract(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAbstract(t,visit);}
+    }
+
+    public void visitAnnotation(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAnnotation(t,visit);}
+    }
+
+    public void visitAnnotations(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAnnotations(t,visit);}
+    }
+
+    public void visitAnnotationArrayInit(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAnnotationArrayInit(t,visit);}
+    }
+
+    public void visitAnnotationDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAnnotationDef(t,visit);}
+    }
+
+    public void visitAnnotationFieldDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAnnotationFieldDef(t,visit);}
+    }
+
+    public void visitAnnotationMemberValuePair(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAnnotationMemberValuePair(t,visit);}
+    }
+
+    public void visitArrayDeclarator(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitArrayDeclarator(t,visit);}
+    }
+
+    public void visitAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAssign(t,visit);}
+    }
+
+    public void visitAt(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAt(t,visit);}
+    }
+
+    public void visitBand(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBand(t,visit);}
+    }
+
+    public void visitBandAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBandAssign(t,visit);}
+    }
+
+    public void visitBigSuffix(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBigSuffix(t,visit);}
+    }
+
+    public void visitBlock(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBlock(t,visit);}
+    }
+
+    public void visitBnot(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBnot(t,visit);}
+    }
+
+    public void visitBor(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBor(t,visit);}
+    }
+
+    public void visitBorAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBorAssign(t,visit);}
+    }
+
+    public void visitBsr(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBsr(t,visit);}
+    }
+
+    public void visitBsrAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBsrAssign(t,visit);}
+    }
+
+    public void visitBxor(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBxor(t,visit);}
+    }
+
+    public void visitBxorAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBxorAssign(t,visit);}
+    }
+
+    public void visitCaseGroup(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitCaseGroup(t,visit);}
+    }
+
+    public void visitClassDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitClassDef(t,visit);}
+    }
+
+    public void visitClosedBlock(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitClosedBlock(t,visit);}
+    }
+
+    public void visitClosureOp(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitClosureOp(t,visit);}
+    }
+
+    public void visitColon(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitColon(t,visit);}
+    }
+
+    public void visitComma(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitComma(t,visit);}
+    }
+
+    public void visitCompareTo(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitCompareTo(t,visit);}
+    }
+
+    public void visitCtorCall(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitCtorCall(t,visit);}
+    }
+
+    public void visitCtorIdent(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitCtorIdent(t,visit);}
+    }
+
+    public void visitDec(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDec(t,visit);}
+    }
+
+    public void visitDigit(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDigit(t,visit);}
+    }
+
+    public void visitDiv(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDiv(t,visit);}
+    }
+
+    public void visitDivAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDivAssign(t,visit);}
+    }
+
+    public void visitDollar(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDollar(t,visit);}
+    }
+
+    public void visitDot(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDot(t,visit);}
+    }
+
+    public void visitDynamicMember(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDynamicMember(t,visit);}
+    }
+
+    public void visitElist(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitElist(t,visit);}
+    }
+
+    public void visitEmptyStat(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitEmptyStat(t,visit);}
+    }
+
+    public void visitEnumConstantDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitEnumConstantDef(t,visit);}
+    }
+
+    public void visitEnumDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitEnumDef(t,visit);}
+    }
+
+    public void visitEof(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitEof(t,visit);}
+    }
+
+    public void visitEqual(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitEqual(t,visit);}
+    }
+
+    public void visitEsc(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitEsc(t,visit);}
+    }
+
+    public void visitExponent(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitExponent(t,visit);}
+    }
+
+    public void visitExpr(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitExpr(t,visit);}
+    }
+
+    public void visitExtendsClause(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitExtendsClause(t,visit);}
+    }
+
+    public void visitFinal(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitFinal(t,visit);}
+    }
+
+    public void visitFloatSuffix(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitFloatSuffix(t,visit);}
+    }
+
+    public void visitForCondition(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitForCondition(t,visit);}
+    }
+
+    public void visitForEachClause(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitForEachClause(t,visit);}
+    }
+
+    public void visitForInit(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitForInit(t,visit);}
+    }
+
+    public void visitForInIterable(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitForInIterable(t,visit);}
+    }
+
+    public void visitForIterator(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitForIterator(t,visit);}
+    }
+
+    public void visitGe(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitGe(t,visit);}
+    }
+
+    public void visitGt(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitGt(t,visit);}
+    }
+
+    public void visitHexDigit(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitHexDigit(t,visit);}
+    }
+
+    public void visitIdent(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitIdent(t,visit);}
+    }
+
+    public void visitImplementsClause(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitImplementsClause(t,visit);}
+    }
+
+    public void visitImplicitParameters(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitImplicitParameters(t,visit);}
+    }
+
+    public void visitImport(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitImport(t,visit);}
+    }
+
+    public void visitInc(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitInc(t,visit);}
+    }
+
+    public void visitIndexOp(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitIndexOp(t,visit);}
+    }
+
+    public void visitInstanceInit(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitInstanceInit(t,visit);}
+    }
+
+    public void visitInterfaceDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitInterfaceDef(t,visit);}
+    }
+
+    public void visitLabeledArg(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLabeledArg(t,visit);}
+    }
+
+    public void visitLabeledStat(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLabeledStat(t,visit);}
+    }
+
+    public void visitLand(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLand(t,visit);}
+    }
+
+    public void visitLbrack(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLbrack(t,visit);}
+    }
+
+    public void visitLcurly(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLcurly(t,visit);}
+    }
+
+    public void visitLe(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLe(t,visit);}
+    }
+
+    public void visitLetter(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLetter(t,visit);}
+    }
+
+    public void visitListConstructor(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitListConstructor(t,visit);}
+    }
+
+    public void visitLiteralAny(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralAny(t,visit);}
+    }
+
+    public void visitLiteralAs(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralAs(t,visit);}
+    }
+
+    public void visitLiteralAssert(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralAssert(t,visit);}
+    }
+
+    public void visitLiteralBoolean(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralBoolean(t,visit);}
+    }
+
+    public void visitLiteralBreak(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralBreak(t,visit);}
+    }
+
+    public void visitLiteralByte(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralByte(t,visit);}
+    }
+
+    public void visitLiteralCase(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralCase(t,visit);}
+    }
+
+    public void visitLiteralCatch(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralCatch(t,visit);}
+    }
+
+    public void visitLiteralChar(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralChar(t,visit);}
+    }
+
+    public void visitLiteralClass(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralClass(t,visit);}
+    }
+
+    public void visitLiteralContinue(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralContinue(t,visit);}
+    }
+
+    public void visitLiteralDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralDef(t,visit);}
+    }
+
+    public void visitLiteralDefault(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralDefault(t,visit);}
+    }
+
+    public void visitLiteralDouble(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralDouble(t,visit);}
+    }
+
+    public void visitLiteralElse(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralElse(t,visit);}
+    }
+
+    public void visitLiteralEnum(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralEnum(t,visit);}
+    }
+
+    public void visitLiteralExtends(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralExtends(t,visit);}
+    }
+
+    public void visitLiteralFalse(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralFalse(t,visit);}
+    }
+
+    public void visitLiteralFinally(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralFinally(t,visit);}
+    }
+
+    public void visitLiteralFloat(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralFloat(t,visit);}
+    }
+
+    public void visitLiteralFor(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralFor(t,visit);}
+    }
+
+    public void visitLiteralIf(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralIf(t,visit);}
+    }
+
+    public void visitLiteralImplements(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralImplements(t,visit);}
+    }
+
+    public void visitLiteralImport(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralImport(t,visit);}
+    }
+
+    public void visitLiteralIn(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralIn(t,visit);}
+    }
+
+    public void visitLiteralInstanceof(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralInstanceof(t,visit);}
+    }
+
+    public void visitLiteralInt(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralInt(t,visit);}
+    }
+
+    public void visitLiteralInterface(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralInterface(t,visit);}
+    }
+
+    public void visitLiteralLong(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralLong(t,visit);}
+    }
+
+    public void visitLiteralNative(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralNative(t,visit);}
+    }
+
+    public void visitLiteralNew(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralNew(t,visit);}
+    }
+
+    public void visitLiteralNull(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralNull(t,visit);}
+    }
+
+    public void visitLiteralPackage(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralPackage(t,visit);}
+    }
+
+    public void visitLiteralPrivate(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralPrivate(t,visit);}
+    }
+
+    public void visitLiteralProtected(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralProtected(t,visit);}
+    }
+
+    public void visitLiteralPublic(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralPublic(t,visit);}
+    }
+
+    public void visitLiteralReturn(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralReturn(t,visit);}
+    }
+
+    public void visitLiteralShort(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralShort(t,visit);}
+    }
+
+    public void visitLiteralStatic(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralStatic(t,visit);}
+    }
+
+    public void visitLiteralSuper(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralSuper(t,visit);}
+    }
+
+    public void visitLiteralSwitch(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralSwitch(t,visit);}
+    }
+
+    public void visitLiteralSynchronized(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralSynchronized(t,visit);}
+    }
+
+    public void visitLiteralThis(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralThis(t,visit);}
+    }
+
+    public void visitLiteralThreadsafe(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralThreadsafe(t,visit);}
+    }
+
+    public void visitLiteralThrow(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralThrow(t,visit);}
+    }
+
+    public void visitLiteralThrows(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralThrows(t,visit);}
+    }
+
+    public void visitLiteralTransient(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralTransient(t,visit);}
+    }
+
+    public void visitLiteralTrue(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralTrue(t,visit);}
+    }
+
+    public void visitLiteralTry(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralTry(t,visit);}
+    }
+
+    public void visitLiteralVoid(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralVoid(t,visit);}
+    }
+
+    public void visitLiteralVolatile(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralVolatile(t,visit);}
+    }
+
+    public void visitLiteralWhile(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralWhile(t,visit);}
+    }
+
+    public void visitLiteralWith(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralWith(t,visit);}
+    }
+
+    public void visitLnot(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLnot(t,visit);}
+    }
+
+    public void visitLor(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLor(t,visit);}
+    }
+
+    public void visitLparen(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLparen(t,visit);}
+    }
+
+    public void visitLt(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLt(t,visit);}
+    }
+
+    public void visitMapConstructor(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMapConstructor(t,visit);}
+    }
+
+    public void visitMemberPointer(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMemberPointer(t,visit);}
+    }
+
+    public void visitMethodCall(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMethodCall(t,visit);}
+    }
+
+    public void visitMethodDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMethodDef(t,visit);}
+    }
+
+    public void visitMinus(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMinus(t,visit);}
+    }
+
+    public void visitMinusAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMinusAssign(t,visit);}
+    }
+
+    public void visitMlComment(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMlComment(t,visit);}
+    }
+
+    public void visitMod(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMod(t,visit);}
+    }
+
+    public void visitModifiers(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitModifiers(t,visit);}
+    }
+
+    public void visitModAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitModAssign(t,visit);}
+    }
+
+    public void visitNls(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNls(t,visit);}
+    }
+
+    public void visitNotEqual(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNotEqual(t,visit);}
+    }
+
+    public void visitNullTreeLookahead(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNullTreeLookahead(t,visit);}
+    }
+
+    public void visitNumBigDecimal(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNumBigDecimal(t,visit);}
+    }
+
+    public void visitNumBigInt(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNumBigInt(t,visit);}
+    }
+
+    public void visitNumDouble(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNumDouble(t,visit);}
+    }
+
+    public void visitNumFloat(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNumFloat(t,visit);}
+    }
+
+    public void visitNumInt(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNumInt(t,visit);}
+    }
+
+    public void visitNumLong(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNumLong(t,visit);}
+    }
+
+    public void visitObjblock(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitObjblock(t,visit);}
+    }
+
+    public void visitOneNl(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitOneNl(t,visit);}
+    }
+
+    public void visitOptionalDot(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitOptionalDot(t,visit);}
+    }
+
+    public void visitPackageDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitPackageDef(t,visit);}
+    }
+
+    public void visitParameters(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitParameters(t,visit);}
+    }
+
+    public void visitParameterDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitParameterDef(t,visit);}
+    }
+
+    public void visitPlus(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitPlus(t,visit);}
+    }
+
+    public void visitPlusAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitPlusAssign(t,visit);}
+    }
+
+    public void visitPostDec(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitPostDec(t,visit);}
+    }
+
+    public void visitPostInc(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitPostInc(t,visit);}
+    }
+
+    public void visitQuestion(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitQuestion(t,visit);}
+    }
+
+    public void visitRangeExclusive(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRangeExclusive(t,visit);}
+    }
+
+    public void visitRangeInclusive(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRangeInclusive(t,visit);}
+    }
+
+    public void visitRbrack(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRbrack(t,visit);}
+    }
+
+    public void visitRcurly(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRcurly(t,visit);}
+    }
+
+    public void visitRegexpCtorEnd(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRegexpCtorEnd(t,visit);}
+    }
+
+    public void visitRegexpLiteral(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRegexpLiteral(t,visit);}
+    }
+
+    public void visitRegexpSymbol(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRegexpSymbol(t,visit);}
+    }
+
+    public void visitRegexFind(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRegexFind(t,visit);}
+    }
+
+    public void visitRegexMatch(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRegexMatch(t,visit);}
+    }
+
+    public void visitRparen(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRparen(t,visit);}
+    }
+
+    public void visitScopeEscape(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitScopeEscape(t,visit);}
+    }
+
+    public void visitSelectSlot(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSelectSlot(t,visit);}
+    }
+
+    public void visitSemi(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSemi(t,visit);}
+    }
+
+    public void visitShComment(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitShComment(t,visit);}
+    }
+
+    public void visitSl(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSl(t,visit);}
+    }
+
+    public void visitSlist(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSlist(t,visit);}
+    }
+
+    public void visitSlAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSlAssign(t,visit);}
+    }
+
+    public void visitSlComment(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSlComment(t,visit);}
+    }
+
+    public void visitSpreadArg(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSpreadArg(t,visit);}
+    }
+
+    public void visitSpreadDot(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSpreadDot(t,visit);}
+    }
+
+    public void visitSpreadMapArg(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSpreadMapArg(t,visit);}
+    }
+
+    public void visitSr(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSr(t,visit);}
+    }
+
+    public void visitSrAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSrAssign(t,visit);}
+    }
+
+    public void visitStar(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStar(t,visit);}
+    }
+
+    public void visitStarAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStarAssign(t,visit);}
+    }
+
+    public void visitStarStar(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStarStar(t,visit);}
+    }
+
+    public void visitStarStarAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStarStarAssign(t,visit);}
+    }
+
+    public void visitStaticImport(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStaticImport(t,visit);}
+    }
+
+    public void visitStaticInit(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStaticInit(t,visit);}
+    }
+
+    public void visitStrictfp(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStrictfp(t,visit);}
+    }
+
+    public void visitStringCh(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStringCh(t,visit);}
+    }
+
+    public void visitStringConstructor(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStringConstructor(t,visit);}
+    }
+
+    public void visitStringCtorEnd(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStringCtorEnd(t,visit);}
+    }
+
+    public void visitStringCtorMiddle(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStringCtorMiddle(t,visit);}
+    }
+
+    public void visitStringCtorStart(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStringCtorStart(t,visit);}
+    }
+
+    public void visitStringLiteral(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStringLiteral(t,visit);}
+    }
+
+    public void visitStringNl(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStringNl(t,visit);}
+    }
+
+    public void visitSuperCtorCall(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSuperCtorCall(t,visit);}
+    }
+
+    public void visitTripleDot(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTripleDot(t,visit);}
+    }
+
+    public void visitType(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitType(t,visit);}
+    }
+
+    public void visitTypecast(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTypecast(t,visit);}
+    }
+
+    public void visitTypeArgument(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTypeArgument(t,visit);}
+    }
+
+    public void visitTypeArguments(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTypeArguments(t,visit);}
+    }
+
+    public void visitTypeLowerBounds(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTypeLowerBounds(t,visit);}
+    }
+
+    public void visitTypeParameter(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTypeParameter(t,visit);}
+    }
+
+    public void visitTypeParameters(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTypeParameters(t,visit);}
+    }
+
+    public void visitTypeUpperBounds(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTypeUpperBounds(t,visit);}
+    }
+
+    public void visitUnaryMinus(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitUnaryMinus(t,visit);}
+    }
+
+    public void visitUnaryPlus(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitUnaryPlus(t,visit);}
+    }
+
+    public void visitUnusedConst(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitUnusedConst(t,visit);}
+    }
+
+    public void visitUnusedDo(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitUnusedDo(t,visit);}
+    }
+
+    public void visitUnusedGoto(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitUnusedGoto(t,visit);}
+    }
+
+    public void visitVariableDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitVariableDef(t,visit);}
+    }
+
+    public void visitVariableParameterDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitVariableParameterDef(t,visit);}
+    }
+
+    public void visitVocab(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitVocab(t,visit);}
+    }
+
+    public void visitWildcardType(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitWildcardType(t,visit);}
+    }
+
+    public void visitWs(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitWs(t,visit);}
+    }
+
+
+
+
+
+    public void visitDefault(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDefault(t,visit);}
+    }
+
+    public void tearDown() {
+        Iterator itr = backToFrontVisitors.iterator();
+        while (itr.hasNext()) {((Visitor)itr.next()).tearDown();}
+    }
+
+    public void push(GroovySourceAST t) {
+        Iterator itr = visitors.iterator();
+        while (itr.hasNext()) {((Visitor)itr.next()).push(t);}
+    }
+    public GroovySourceAST pop() {
+        GroovySourceAST lastNodePopped = null;
+        Iterator itr = backToFrontVisitors.iterator();
+        while (itr.hasNext()) {lastNodePopped = (GroovySourceAST) ((Visitor)itr.next()).pop();}
+        return lastNodePopped;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/MindMapPrinter.java b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/MindMapPrinter.java
new file mode 100644
index 0000000..ee2f01a
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/MindMapPrinter.java
@@ -0,0 +1,360 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr.treewalker;
+
+import java.io.PrintStream;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+
+/**
+ * An antlr AST visitor that prints a format suitable for viewing in http://freemind.sourceforge.net
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+public class MindMapPrinter extends VisitorAdapter {
+    private String[] tokenNames;
+    private PrintStream out;
+    private int depth;
+
+    /**
+     * A visitor that prints a format suitable for viewing in http://freemind.sourceforge.net
+     * @param out where to print the mindmap file contents to
+     * @param tokenNames an array of token names from antlr
+     */
+
+    public MindMapPrinter(PrintStream out,String[] tokenNames) {
+        this.tokenNames = tokenNames;
+        this.out = out;
+    }
+
+    public void setUp() {
+        depth = 0;
+        out.println("<map version='0.7.1'><node TEXT='AST'>");
+    }
+
+    public void visitDefault(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            depth++;
+            String name = getName(t);
+            String colour = getColour(t);
+            String folded = getFolded(t);
+            out.print("<node TEXT='" + name + "' POSITION='right'" + colour + folded + ">");
+        } else {
+            out.println("</node>");
+            depth--;
+        }
+    }
+
+    public void tearDown() {
+        out.println("</node></map>");
+    }
+
+    private String getFolded(GroovySourceAST t) {
+        if (depth > 2 && t.getNumberOfChildren() > 0) {
+            switch (t.getType()) {
+                case GroovyTokenTypes.EXPR :
+                case GroovyTokenTypes.METHOD_DEF :
+                case GroovyTokenTypes.VARIABLE_DEF :
+                    return " FOLDED='true'";
+            }
+        }
+        if (t.getType() == GroovyTokenTypes.IMPORT) {
+            return " FOLDED='true'";
+        }
+        return "";
+    }
+
+    private String getColour(GroovySourceAST t) {
+        String colour = "";
+        String black = " COLOR=\"#000000\"";
+        String cyan = " COLOR=\"#006699\"";
+        String blue = " COLOR=\"#17178B\"";
+        String green = " COLOR=\"#008000\"";
+        switch (t.getType()) {
+            case GroovyTokenTypes.ABSTRACT                      :
+            case GroovyTokenTypes.ANNOTATION                    :
+            case GroovyTokenTypes.ANNOTATIONS                   :
+            case GroovyTokenTypes.ANNOTATION_ARRAY_INIT         :
+            case GroovyTokenTypes.ANNOTATION_DEF                :
+            case GroovyTokenTypes.ANNOTATION_FIELD_DEF          :
+            case GroovyTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR  :
+            case GroovyTokenTypes.ARRAY_DECLARATOR              :
+            case GroovyTokenTypes.ASSIGN                        :
+            case GroovyTokenTypes.AT                            :
+            case GroovyTokenTypes.BAND                          :
+            case GroovyTokenTypes.BAND_ASSIGN                   :
+            case GroovyTokenTypes.BIG_SUFFIX                    :
+            case GroovyTokenTypes.BLOCK                         :
+            case GroovyTokenTypes.BNOT                          :
+            case GroovyTokenTypes.BOR                           :
+            case GroovyTokenTypes.BOR_ASSIGN                    :
+            case GroovyTokenTypes.BSR                           :
+            case GroovyTokenTypes.BSR_ASSIGN                    :
+            case GroovyTokenTypes.BXOR                          :
+            case GroovyTokenTypes.BXOR_ASSIGN                   :
+            case GroovyTokenTypes.CASE_GROUP                    :
+            case GroovyTokenTypes.CLOSABLE_BLOCK                :
+            case GroovyTokenTypes.CLOSABLE_BLOCK_OP             :
+            case GroovyTokenTypes.COLON                         :
+            case GroovyTokenTypes.COMMA                         :
+            case GroovyTokenTypes.COMPARE_TO                    :
+            case GroovyTokenTypes.CTOR_CALL                     :
+            case GroovyTokenTypes.CTOR_IDENT                    :
+            case GroovyTokenTypes.DEC                           :
+            case GroovyTokenTypes.DIGIT                         :
+            case GroovyTokenTypes.DIV                           :
+            case GroovyTokenTypes.DIV_ASSIGN                    :
+            case GroovyTokenTypes.DOLLAR                        :
+            case GroovyTokenTypes.DOT                           :
+            case GroovyTokenTypes.DYNAMIC_MEMBER                :
+            case GroovyTokenTypes.ELIST                         :
+            case GroovyTokenTypes.EMPTY_STAT                    :
+            case GroovyTokenTypes.ENUM_CONSTANT_DEF             :
+            case GroovyTokenTypes.ENUM_DEF                      :
+            case GroovyTokenTypes.EOF                           :
+            case GroovyTokenTypes.EQUAL                         :
+            case GroovyTokenTypes.ESC                           :
+            case GroovyTokenTypes.EXPONENT                      :
+            case GroovyTokenTypes.EXPR                          :
+            case GroovyTokenTypes.FINAL                         :
+            case GroovyTokenTypes.FLOAT_SUFFIX                  :
+            case GroovyTokenTypes.FOR_CONDITION                 :
+            case GroovyTokenTypes.FOR_EACH_CLAUSE               :
+            case GroovyTokenTypes.FOR_INIT                      :
+            case GroovyTokenTypes.FOR_IN_ITERABLE               :
+            case GroovyTokenTypes.FOR_ITERATOR                  :
+            case GroovyTokenTypes.GE                            :
+            case GroovyTokenTypes.GT                            :
+            case GroovyTokenTypes.HEX_DIGIT                     :
+            case GroovyTokenTypes.IMPLICIT_PARAMETERS           :
+            case GroovyTokenTypes.INC                           :
+            case GroovyTokenTypes.INDEX_OP                      :
+            case GroovyTokenTypes.INSTANCE_INIT                 :
+            case GroovyTokenTypes.INTERFACE_DEF                 :
+            case GroovyTokenTypes.LABELED_ARG                   :
+            case GroovyTokenTypes.LABELED_STAT                  :
+            case GroovyTokenTypes.LAND                          :
+            case GroovyTokenTypes.LBRACK                        :
+            case GroovyTokenTypes.LCURLY                        :
+            case GroovyTokenTypes.LE                            :
+            case GroovyTokenTypes.LETTER                        :
+            case GroovyTokenTypes.LIST_CONSTRUCTOR              :
+            case GroovyTokenTypes.LNOT                          :
+            case GroovyTokenTypes.LOR                           :
+            case GroovyTokenTypes.LPAREN                        :
+            case GroovyTokenTypes.LT                            :
+            case GroovyTokenTypes.MAP_CONSTRUCTOR               :
+            case GroovyTokenTypes.MEMBER_POINTER                :
+            case GroovyTokenTypes.METHOD_CALL                   :
+            case GroovyTokenTypes.METHOD_DEF                    :
+            case GroovyTokenTypes.MINUS                         :
+            case GroovyTokenTypes.MINUS_ASSIGN                  :
+            case GroovyTokenTypes.ML_COMMENT                    :
+            case GroovyTokenTypes.MOD                           :
+            case GroovyTokenTypes.MODIFIERS                     :
+            case GroovyTokenTypes.MOD_ASSIGN                    :
+            case GroovyTokenTypes.NLS                           :
+            case GroovyTokenTypes.NOT_EQUAL                     :
+            case GroovyTokenTypes.NULL_TREE_LOOKAHEAD           :
+            case GroovyTokenTypes.NUM_BIG_DECIMAL               :
+            case GroovyTokenTypes.NUM_BIG_INT                   :
+            case GroovyTokenTypes.NUM_DOUBLE                    :
+            case GroovyTokenTypes.NUM_FLOAT                     :
+            case GroovyTokenTypes.NUM_INT                       :
+            case GroovyTokenTypes.NUM_LONG                      :
+            case GroovyTokenTypes.OBJBLOCK                      :
+            case GroovyTokenTypes.ONE_NL                        :
+            case GroovyTokenTypes.OPTIONAL_DOT                  :
+            case GroovyTokenTypes.PARAMETERS                    :
+            case GroovyTokenTypes.PARAMETER_DEF                 :
+            case GroovyTokenTypes.PLUS                          :
+            case GroovyTokenTypes.PLUS_ASSIGN                   :
+            case GroovyTokenTypes.POST_DEC                      :
+            case GroovyTokenTypes.POST_INC                      :
+            case GroovyTokenTypes.QUESTION                      :
+            case GroovyTokenTypes.RANGE_EXCLUSIVE               :
+            case GroovyTokenTypes.RANGE_INCLUSIVE               :
+            case GroovyTokenTypes.RBRACK                        :
+            case GroovyTokenTypes.RCURLY                        :
+            case GroovyTokenTypes.REGEXP_CTOR_END               :
+            case GroovyTokenTypes.REGEXP_SYMBOL                 :
+            case GroovyTokenTypes.REGEX_FIND                    :
+            case GroovyTokenTypes.REGEX_MATCH                   :
+            case GroovyTokenTypes.RPAREN                        :
+            case GroovyTokenTypes.SCOPE_ESCAPE                  :
+            case GroovyTokenTypes.SELECT_SLOT                   :
+            case GroovyTokenTypes.SEMI                          :
+            case GroovyTokenTypes.SH_COMMENT                    :
+            case GroovyTokenTypes.SL                            :
+            case GroovyTokenTypes.SLIST                         :
+            case GroovyTokenTypes.SL_ASSIGN                     :
+            case GroovyTokenTypes.SL_COMMENT                    :
+            case GroovyTokenTypes.SPREAD_ARG                    :
+            case GroovyTokenTypes.SPREAD_DOT                    :
+            case GroovyTokenTypes.SPREAD_MAP_ARG                :
+            case GroovyTokenTypes.SR                            :
+            case GroovyTokenTypes.SR_ASSIGN                     :
+            case GroovyTokenTypes.STAR                          :
+            case GroovyTokenTypes.STAR_ASSIGN                   :
+            case GroovyTokenTypes.STAR_STAR                     :
+            case GroovyTokenTypes.STAR_STAR_ASSIGN              :
+            case GroovyTokenTypes.STATIC_IMPORT                 :
+            case GroovyTokenTypes.STATIC_INIT                   :
+            case GroovyTokenTypes.STRICTFP                      :
+            case GroovyTokenTypes.STRING_CH                     :
+            case GroovyTokenTypes.STRING_CONSTRUCTOR            :
+            case GroovyTokenTypes.STRING_CTOR_END               :
+            case GroovyTokenTypes.STRING_CTOR_MIDDLE            :
+            case GroovyTokenTypes.STRING_CTOR_START             :
+            case GroovyTokenTypes.STRING_NL                     :
+            case GroovyTokenTypes.SUPER_CTOR_CALL               :
+            case GroovyTokenTypes.TRIPLE_DOT                    :
+            case GroovyTokenTypes.TYPECAST                      :
+            case GroovyTokenTypes.TYPE_ARGUMENT                 :
+            case GroovyTokenTypes.TYPE_ARGUMENTS                :
+            case GroovyTokenTypes.TYPE_LOWER_BOUNDS             :
+            case GroovyTokenTypes.TYPE_PARAMETER                :
+            case GroovyTokenTypes.TYPE_PARAMETERS               :
+            case GroovyTokenTypes.TYPE_UPPER_BOUNDS             :
+            case GroovyTokenTypes.UNARY_MINUS                   :
+            case GroovyTokenTypes.UNARY_PLUS                    :
+            case GroovyTokenTypes.UNUSED_CONST                  :
+            case GroovyTokenTypes.UNUSED_DO                     :
+            case GroovyTokenTypes.UNUSED_GOTO                   :
+            case GroovyTokenTypes.VARIABLE_DEF                  :
+            case GroovyTokenTypes.VARIABLE_PARAMETER_DEF        :
+            case GroovyTokenTypes.VOCAB                         :
+            case GroovyTokenTypes.WILDCARD_TYPE                 :
+            case GroovyTokenTypes.WS                            :
+                colour = black;
+                break;
+
+            case GroovyTokenTypes.STRING_LITERAL                :
+            case GroovyTokenTypes.REGEXP_LITERAL                :
+                colour = green;
+                break;
+
+            case GroovyTokenTypes.CLASS_DEF                     :
+            case GroovyTokenTypes.EXTENDS_CLAUSE                :
+            case GroovyTokenTypes.IMPLEMENTS_CLAUSE             :
+            case GroovyTokenTypes.IMPORT                        :
+            case GroovyTokenTypes.LITERAL_any                   :
+            case GroovyTokenTypes.LITERAL_as                    :
+            case GroovyTokenTypes.LITERAL_assert                :
+            case GroovyTokenTypes.LITERAL_boolean               :
+            case GroovyTokenTypes.LITERAL_break                 :
+            case GroovyTokenTypes.LITERAL_byte                  :
+            case GroovyTokenTypes.LITERAL_case                  :
+            case GroovyTokenTypes.LITERAL_catch                 :
+            case GroovyTokenTypes.LITERAL_char                  :
+            case GroovyTokenTypes.LITERAL_class                 :
+            case GroovyTokenTypes.LITERAL_continue              :
+            case GroovyTokenTypes.LITERAL_def                   :
+            case GroovyTokenTypes.LITERAL_default               :
+            case GroovyTokenTypes.LITERAL_double                :
+            case GroovyTokenTypes.LITERAL_else                  :
+            case GroovyTokenTypes.LITERAL_enum                  :
+            case GroovyTokenTypes.LITERAL_extends               :
+            case GroovyTokenTypes.LITERAL_false                 :
+            case GroovyTokenTypes.LITERAL_finally               :
+            case GroovyTokenTypes.LITERAL_float                 :
+            case GroovyTokenTypes.LITERAL_for                   :
+            case GroovyTokenTypes.LITERAL_if                    :
+            case GroovyTokenTypes.LITERAL_implements            :
+            case GroovyTokenTypes.LITERAL_import                :
+            case GroovyTokenTypes.LITERAL_in                    :
+            case GroovyTokenTypes.LITERAL_instanceof            :
+            case GroovyTokenTypes.LITERAL_int                   :
+            case GroovyTokenTypes.LITERAL_interface             :
+            case GroovyTokenTypes.LITERAL_long                  :
+            case GroovyTokenTypes.LITERAL_native                :
+            case GroovyTokenTypes.LITERAL_new                   :
+            case GroovyTokenTypes.LITERAL_null                  :
+            case GroovyTokenTypes.LITERAL_package               :
+            case GroovyTokenTypes.LITERAL_private               :
+            case GroovyTokenTypes.LITERAL_protected             :
+            case GroovyTokenTypes.LITERAL_public                :
+            case GroovyTokenTypes.LITERAL_return                :
+            case GroovyTokenTypes.LITERAL_short                 :
+            case GroovyTokenTypes.LITERAL_static                :
+            case GroovyTokenTypes.LITERAL_super                 :
+            case GroovyTokenTypes.LITERAL_switch                :
+            case GroovyTokenTypes.LITERAL_synchronized          :
+            case GroovyTokenTypes.LITERAL_this                  :
+            case GroovyTokenTypes.LITERAL_threadsafe            :
+            case GroovyTokenTypes.LITERAL_throw                 :
+            case GroovyTokenTypes.LITERAL_throws                :
+            case GroovyTokenTypes.LITERAL_transient             :
+            case GroovyTokenTypes.LITERAL_true                  :
+            case GroovyTokenTypes.LITERAL_try                   :
+            case GroovyTokenTypes.LITERAL_void                  :
+            case GroovyTokenTypes.LITERAL_volatile              :
+            case GroovyTokenTypes.LITERAL_while                 :
+            case GroovyTokenTypes.LITERAL_with                  :
+            case GroovyTokenTypes.PACKAGE_DEF                   :
+            case GroovyTokenTypes.TYPE                          :
+                colour = blue;
+                break;
+
+            case GroovyTokenTypes.IDENT                         :
+                colour = cyan;
+                break;
+
+            default:
+                colour = black;
+                break;
+        }
+
+        // leaf nodes that haven't been coloured yet
+        if (black.equals(colour) && t.getNumberOfChildren() == 0) {
+            colour = cyan;
+        }
+
+
+
+        return colour;
+    }
+
+    private String getName(GroovySourceAST t) {
+        String name = tokenNames[t.getType()] + " <" + t.getType() + ">";
+        if (!(escape(tokenNames[t.getType()]).equals(escape(t.getText())))) {
+            name = name + " : " + t.getText();
+        }
+        switch (t.getType()) {
+            case GroovyTokenTypes.METHOD_DEF :
+            case GroovyTokenTypes.VARIABLE_DEF :
+                GroovySourceAST identNode = t.childOfType(GroovyTokenTypes.IDENT);
+                if (identNode != null) {
+                    name = name + " : " + identNode.getText() + "";
+                }
+        }
+        name = escape(name);
+        return name;
+    }
+
+    private String escape(String name) {
+        name = name.replace('"',' ');
+        name = name.replace('\'',' ');
+        name = name.replaceAll("&","&amp;");
+        name = name.trim();
+        return name;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/NodeAsHTMLPrinter.java b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/NodeAsHTMLPrinter.java
new file mode 100644
index 0000000..32eca09
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/NodeAsHTMLPrinter.java
@@ -0,0 +1,314 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr.treewalker;
+
+import java.io.PrintStream;
+import java.util.Stack;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+
+/**
+ * A visitor that prints a html tags of each node to the supplied PrintStream
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+public class NodeAsHTMLPrinter extends VisitorAdapter {
+    private String[] tokenNames;
+    private PrintStream out;
+    private Stack stack;
+
+    /**
+     * A visitor that prints a html tags, for each node, to the supplied PrintStream.
+     * @param out supplied PrintStream to output nodes to
+     * @param tokenNames an array of token names to use
+     */
+    public NodeAsHTMLPrinter(PrintStream out,String[] tokenNames) {
+        this.tokenNames = tokenNames;
+        this.out = out;
+        this.stack = new Stack();
+    }
+
+    public void setUp() {
+        out.println("<html><head></head><body><pre>");
+    }
+
+    public void visitDefault(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            out.print("<code title='" + tokenNames[t.getType()] + "'><font color='#" + colour(t) + "'>");
+        } else {
+            out.print("</font></code>");
+        }
+    }
+
+    public void tearDown() {
+        out.println("</pre></body></html>");
+    }
+
+    private String colour(GroovySourceAST t) {
+        String black = "000000";
+        String blue = "17178B";
+        String green = "008000";
+        //String purple = "7C308D";
+        String colour = black;
+        switch (t.getType()) {
+            case GroovyTokenTypes.ABSTRACT                      :
+            case GroovyTokenTypes.ANNOTATION                    :
+            case GroovyTokenTypes.ANNOTATIONS                   :
+            case GroovyTokenTypes.ANNOTATION_ARRAY_INIT         :
+            case GroovyTokenTypes.ANNOTATION_DEF                :
+            case GroovyTokenTypes.ANNOTATION_FIELD_DEF          :
+            case GroovyTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR  :
+            case GroovyTokenTypes.ARRAY_DECLARATOR              :
+            case GroovyTokenTypes.ASSIGN                        :
+            case GroovyTokenTypes.AT                            :
+            case GroovyTokenTypes.BAND                          :
+            case GroovyTokenTypes.BAND_ASSIGN                   :
+            case GroovyTokenTypes.BIG_SUFFIX                    :
+            case GroovyTokenTypes.BLOCK                         :
+            case GroovyTokenTypes.BNOT                          :
+            case GroovyTokenTypes.BOR                           :
+            case GroovyTokenTypes.BOR_ASSIGN                    :
+            case GroovyTokenTypes.BSR                           :
+            case GroovyTokenTypes.BSR_ASSIGN                    :
+            case GroovyTokenTypes.BXOR                          :
+            case GroovyTokenTypes.BXOR_ASSIGN                   :
+            case GroovyTokenTypes.CASE_GROUP                    :
+            case GroovyTokenTypes.CLOSABLE_BLOCK                :
+            case GroovyTokenTypes.CLOSABLE_BLOCK_OP             :
+            case GroovyTokenTypes.COLON                         :
+            case GroovyTokenTypes.COMMA                         :
+            case GroovyTokenTypes.COMPARE_TO                    :
+            case GroovyTokenTypes.CTOR_CALL                     :
+            case GroovyTokenTypes.CTOR_IDENT                    :
+            case GroovyTokenTypes.DEC                           :
+            case GroovyTokenTypes.DIGIT                         :
+            case GroovyTokenTypes.DIV                           :
+            case GroovyTokenTypes.DIV_ASSIGN                    :
+            case GroovyTokenTypes.DOLLAR                        :
+            case GroovyTokenTypes.DOT                           :
+            case GroovyTokenTypes.DYNAMIC_MEMBER                :
+            case GroovyTokenTypes.ELIST                         :
+            case GroovyTokenTypes.EMPTY_STAT                    :
+            case GroovyTokenTypes.ENUM_CONSTANT_DEF             :
+            case GroovyTokenTypes.ENUM_DEF                      :
+            case GroovyTokenTypes.EOF                           :
+            case GroovyTokenTypes.EQUAL                         :
+            case GroovyTokenTypes.ESC                           :
+            case GroovyTokenTypes.EXPONENT                      :
+            case GroovyTokenTypes.EXPR                          :
+            case GroovyTokenTypes.FINAL                         :
+            case GroovyTokenTypes.FLOAT_SUFFIX                  :
+            case GroovyTokenTypes.FOR_CONDITION                 :
+            case GroovyTokenTypes.FOR_EACH_CLAUSE               :
+            case GroovyTokenTypes.FOR_INIT                      :
+            case GroovyTokenTypes.FOR_IN_ITERABLE               :
+            case GroovyTokenTypes.FOR_ITERATOR                  :
+            case GroovyTokenTypes.GE                            :
+            case GroovyTokenTypes.GT                            :
+            case GroovyTokenTypes.HEX_DIGIT                     :
+            case GroovyTokenTypes.IDENT                         :
+            case GroovyTokenTypes.IMPLICIT_PARAMETERS           :
+            case GroovyTokenTypes.INC                           :
+            case GroovyTokenTypes.INDEX_OP                      :
+            case GroovyTokenTypes.INSTANCE_INIT                 :
+            case GroovyTokenTypes.INTERFACE_DEF                 :
+            case GroovyTokenTypes.LABELED_ARG                   :
+            case GroovyTokenTypes.LABELED_STAT                  :
+            case GroovyTokenTypes.LAND                          :
+            case GroovyTokenTypes.LBRACK                        :
+            case GroovyTokenTypes.LCURLY                        :
+            case GroovyTokenTypes.LE                            :
+            case GroovyTokenTypes.LETTER                        :
+            case GroovyTokenTypes.LIST_CONSTRUCTOR              :
+            case GroovyTokenTypes.LNOT                          :
+            case GroovyTokenTypes.LOR                           :
+            case GroovyTokenTypes.LPAREN                        :
+            case GroovyTokenTypes.LT                            :
+            case GroovyTokenTypes.MAP_CONSTRUCTOR               :
+            case GroovyTokenTypes.MEMBER_POINTER                :
+            case GroovyTokenTypes.METHOD_CALL                   :
+            case GroovyTokenTypes.METHOD_DEF                    :
+            case GroovyTokenTypes.MINUS                         :
+            case GroovyTokenTypes.MINUS_ASSIGN                  :
+            case GroovyTokenTypes.ML_COMMENT                    :
+            case GroovyTokenTypes.MOD                           :
+            case GroovyTokenTypes.MODIFIERS                     :
+            case GroovyTokenTypes.MOD_ASSIGN                    :
+            case GroovyTokenTypes.NLS                           :
+            case GroovyTokenTypes.NOT_EQUAL                     :
+            case GroovyTokenTypes.NULL_TREE_LOOKAHEAD           :
+            case GroovyTokenTypes.NUM_BIG_DECIMAL               :
+            case GroovyTokenTypes.NUM_BIG_INT                   :
+            case GroovyTokenTypes.NUM_DOUBLE                    :
+            case GroovyTokenTypes.NUM_FLOAT                     :
+            case GroovyTokenTypes.NUM_INT                       :
+            case GroovyTokenTypes.NUM_LONG                      :
+            case GroovyTokenTypes.OBJBLOCK                      :
+            case GroovyTokenTypes.ONE_NL                        :
+            case GroovyTokenTypes.OPTIONAL_DOT                  :
+            case GroovyTokenTypes.PARAMETERS                    :
+            case GroovyTokenTypes.PARAMETER_DEF                 :
+            case GroovyTokenTypes.PLUS                          :
+            case GroovyTokenTypes.PLUS_ASSIGN                   :
+            case GroovyTokenTypes.POST_DEC                      :
+            case GroovyTokenTypes.POST_INC                      :
+            case GroovyTokenTypes.QUESTION                      :
+            case GroovyTokenTypes.RANGE_EXCLUSIVE               :
+            case GroovyTokenTypes.RANGE_INCLUSIVE               :
+            case GroovyTokenTypes.RBRACK                        :
+            case GroovyTokenTypes.RCURLY                        :
+            case GroovyTokenTypes.REGEXP_CTOR_END               :
+            case GroovyTokenTypes.REGEXP_SYMBOL                 :
+            case GroovyTokenTypes.REGEX_FIND                    :
+            case GroovyTokenTypes.REGEX_MATCH                   :
+            case GroovyTokenTypes.RPAREN                        :
+            case GroovyTokenTypes.SCOPE_ESCAPE                  :
+            case GroovyTokenTypes.SELECT_SLOT                   :
+            case GroovyTokenTypes.SEMI                          :
+            case GroovyTokenTypes.SH_COMMENT                    :
+            case GroovyTokenTypes.SL                            :
+            case GroovyTokenTypes.SLIST                         :
+            case GroovyTokenTypes.SL_ASSIGN                     :
+            case GroovyTokenTypes.SL_COMMENT                    :
+            case GroovyTokenTypes.SPREAD_ARG                    :
+            case GroovyTokenTypes.SPREAD_DOT                    :
+            case GroovyTokenTypes.SPREAD_MAP_ARG                :
+            case GroovyTokenTypes.SR                            :
+            case GroovyTokenTypes.SR_ASSIGN                     :
+            case GroovyTokenTypes.STAR                          :
+            case GroovyTokenTypes.STAR_ASSIGN                   :
+            case GroovyTokenTypes.STAR_STAR                     :
+            case GroovyTokenTypes.STAR_STAR_ASSIGN              :
+            case GroovyTokenTypes.STATIC_IMPORT                 :
+            case GroovyTokenTypes.STATIC_INIT                   :
+            case GroovyTokenTypes.STRICTFP                      :
+            case GroovyTokenTypes.STRING_CH                     :
+            case GroovyTokenTypes.STRING_CONSTRUCTOR            :
+            case GroovyTokenTypes.STRING_CTOR_END               :
+            case GroovyTokenTypes.STRING_CTOR_MIDDLE            :
+            case GroovyTokenTypes.STRING_CTOR_START             :
+            case GroovyTokenTypes.STRING_NL                     :
+            case GroovyTokenTypes.SUPER_CTOR_CALL               :
+            case GroovyTokenTypes.TRIPLE_DOT                    :
+            case GroovyTokenTypes.TYPECAST                      :
+            case GroovyTokenTypes.TYPE_ARGUMENT                 :
+            case GroovyTokenTypes.TYPE_ARGUMENTS                :
+            case GroovyTokenTypes.TYPE_LOWER_BOUNDS             :
+            case GroovyTokenTypes.TYPE_PARAMETER                :
+            case GroovyTokenTypes.TYPE_PARAMETERS               :
+            case GroovyTokenTypes.TYPE_UPPER_BOUNDS             :
+            case GroovyTokenTypes.UNARY_MINUS                   :
+            case GroovyTokenTypes.UNARY_PLUS                    :
+            case GroovyTokenTypes.UNUSED_CONST                  :
+            case GroovyTokenTypes.UNUSED_DO                     :
+            case GroovyTokenTypes.UNUSED_GOTO                   :
+            case GroovyTokenTypes.VARIABLE_DEF                  :
+            case GroovyTokenTypes.VARIABLE_PARAMETER_DEF        :
+            case GroovyTokenTypes.VOCAB                         :
+            case GroovyTokenTypes.WILDCARD_TYPE                 :
+            case GroovyTokenTypes.WS                            :
+                colour = black;
+                break;
+
+            case GroovyTokenTypes.STRING_LITERAL                :
+            case GroovyTokenTypes.REGEXP_LITERAL                :
+                colour = green;
+                break;
+
+            case GroovyTokenTypes.CLASS_DEF                     :
+            case GroovyTokenTypes.EXTENDS_CLAUSE                :
+            case GroovyTokenTypes.IMPLEMENTS_CLAUSE             :
+            case GroovyTokenTypes.IMPORT                        :
+            case GroovyTokenTypes.LITERAL_any                   :
+            case GroovyTokenTypes.LITERAL_as                    :
+            case GroovyTokenTypes.LITERAL_assert                :
+            case GroovyTokenTypes.LITERAL_boolean               :
+            case GroovyTokenTypes.LITERAL_break                 :
+            case GroovyTokenTypes.LITERAL_byte                  :
+            case GroovyTokenTypes.LITERAL_case                  :
+            case GroovyTokenTypes.LITERAL_catch                 :
+            case GroovyTokenTypes.LITERAL_char                  :
+            case GroovyTokenTypes.LITERAL_class                 :
+            case GroovyTokenTypes.LITERAL_continue              :
+            case GroovyTokenTypes.LITERAL_def                   :
+            case GroovyTokenTypes.LITERAL_default               :
+            case GroovyTokenTypes.LITERAL_double                :
+            case GroovyTokenTypes.LITERAL_else                  :
+            case GroovyTokenTypes.LITERAL_enum                  :
+            case GroovyTokenTypes.LITERAL_extends               :
+            case GroovyTokenTypes.LITERAL_false                 :
+            case GroovyTokenTypes.LITERAL_finally               :
+            case GroovyTokenTypes.LITERAL_float                 :
+            case GroovyTokenTypes.LITERAL_for                   :
+            case GroovyTokenTypes.LITERAL_if                    :
+            case GroovyTokenTypes.LITERAL_implements            :
+            case GroovyTokenTypes.LITERAL_import                :
+            case GroovyTokenTypes.LITERAL_in                    :
+            case GroovyTokenTypes.LITERAL_instanceof            :
+            case GroovyTokenTypes.LITERAL_int                   :
+            case GroovyTokenTypes.LITERAL_interface             :
+            case GroovyTokenTypes.LITERAL_long                  :
+            case GroovyTokenTypes.LITERAL_native                :
+            case GroovyTokenTypes.LITERAL_new                   :
+            case GroovyTokenTypes.LITERAL_null                  :
+            case GroovyTokenTypes.LITERAL_package               :
+            case GroovyTokenTypes.LITERAL_private               :
+            case GroovyTokenTypes.LITERAL_protected             :
+            case GroovyTokenTypes.LITERAL_public                :
+            case GroovyTokenTypes.LITERAL_return                :
+            case GroovyTokenTypes.LITERAL_short                 :
+            case GroovyTokenTypes.LITERAL_static                :
+            case GroovyTokenTypes.LITERAL_super                 :
+            case GroovyTokenTypes.LITERAL_switch                :
+            case GroovyTokenTypes.LITERAL_synchronized          :
+            case GroovyTokenTypes.LITERAL_this                  :
+            case GroovyTokenTypes.LITERAL_threadsafe            :
+            case GroovyTokenTypes.LITERAL_throw                 :
+            case GroovyTokenTypes.LITERAL_throws                :
+            case GroovyTokenTypes.LITERAL_transient             :
+            case GroovyTokenTypes.LITERAL_true                  :
+            case GroovyTokenTypes.LITERAL_try                   :
+            case GroovyTokenTypes.LITERAL_void                  :
+            case GroovyTokenTypes.LITERAL_volatile              :
+            case GroovyTokenTypes.LITERAL_while                 :
+            case GroovyTokenTypes.LITERAL_with                  :
+            case GroovyTokenTypes.PACKAGE_DEF                   :
+            case GroovyTokenTypes.TYPE                          :
+                colour = blue;
+                break;
+
+            default:
+                colour = black;
+                break;
+        }
+        return colour;
+    }
+
+    public void push(GroovySourceAST t) {
+        stack.push(t);
+    }
+    public GroovySourceAST pop() {
+        if (!stack.empty()) {
+            return (GroovySourceAST) stack.pop();
+        }
+        return null;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/NodePrinter.java b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/NodePrinter.java
new file mode 100644
index 0000000..1ecaf5a
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/NodePrinter.java
@@ -0,0 +1,52 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr.treewalker;
+
+import java.io.PrintStream;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+
+/**
+ * A simple antlr AST visitor that outputs the tokenName of each node in a pseudo xml style.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+public class NodePrinter extends VisitorAdapter {
+    private String[] tokenNames;
+    private PrintStream out;
+
+    /**
+     * A visitor that prints a pseudo xml output to the supplied PrintStream
+     * @param out supplied PrintStream to output nodes to
+     * @param tokenNames an array of token names to use
+     */
+    public NodePrinter(PrintStream out,String[] tokenNames) {
+        this.tokenNames = tokenNames;
+        this.out = out;
+    }
+
+    public void visitDefault(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            out.print("<"+ tokenNames[t.getType()] + ">");
+        } else {
+            out.print("</" + tokenNames[t.getType()] + ">");
+        }
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/PreOrderTraversal.java b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/PreOrderTraversal.java
new file mode 100644
index 0000000..98a0ccf
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/PreOrderTraversal.java
@@ -0,0 +1,45 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr.treewalker;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+
+/**
+ * A simple preorder traversal over the supplied antlr AST.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+public class PreOrderTraversal extends TraversalHelper {
+    
+    /**
+     * A simple preorder traversal over the supplied antlr AST.
+     * @param visitor the Visitor to call for each node visited 
+     */
+    public PreOrderTraversal(Visitor visitor) {
+        super(visitor);
+    }
+
+    public void accept(GroovySourceAST currentNode) {
+        push(currentNode);
+        openingVisit(currentNode);
+        acceptChildren(currentNode);
+        closingVisit(currentNode);
+        pop();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/SourceCodeTraversal.java b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/SourceCodeTraversal.java
new file mode 100644
index 0000000..5b5b575
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/SourceCodeTraversal.java
@@ -0,0 +1,251 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr.treewalker;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+
+/**
+ * A treewalker for the antlr generated AST that attempts to visit the
+ * AST nodes in the order needed to generate valid groovy source code.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+public class SourceCodeTraversal extends TraversalHelper {
+    /**
+     * Constructs a treewalker for the antlr generated AST that attempts to visit the
+     * AST nodes in the order needed to generate valid groovy source code.
+     * @param visitor the visitor implementation to call for each AST node.
+     */
+    public SourceCodeTraversal(Visitor visitor) {
+        super(visitor);
+    }
+
+    /**
+     * gather, sort and process all unvisited nodes
+     * @param t the AST to process
+     */
+    public void setUp(GroovySourceAST t) {
+        super.setUp(t);
+        
+        // gather and sort all unvisited AST nodes
+        unvisitedNodes = new ArrayList();
+        traverse((GroovySourceAST)t);
+        Collections.sort(unvisitedNodes);
+    }
+
+    /**
+     * traverse an AST node
+     * @param t the AST node to traverse
+     */
+    private void traverse(GroovySourceAST t) {
+        if (t == null) { return; }
+        if (unvisitedNodes != null) {
+           unvisitedNodes.add(t);
+        }
+        GroovySourceAST child = (GroovySourceAST)t.getFirstChild();
+        if (child != null) {
+            traverse(child);
+        }
+        GroovySourceAST sibling = (GroovySourceAST)t.getNextSibling();
+        if (sibling != null) {
+            traverse(sibling);
+        }
+    }
+
+    protected void accept(GroovySourceAST currentNode) {
+        if (currentNode != null && unvisitedNodes != null && unvisitedNodes.size() > 0) {
+            GroovySourceAST t = currentNode;
+
+            if (!(unvisitedNodes.contains(currentNode))) {
+                return;
+            }
+            push(t);
+            switch (t.getType()) {
+                case GroovyTokenTypes.QUESTION: // expr?foo:bar
+                    accept_FirstChild_v_SecondChild_v_ThirdChild_v(t);
+                    break;
+
+                case GroovyTokenTypes.CASE_GROUP: //
+                case GroovyTokenTypes.LITERAL_instanceof: // foo instanceof MyType
+                    accept_FirstChild_v_SecondChildsChildren_v(t);
+                    break;
+
+                case GroovyTokenTypes.ANNOTATION:
+                    accept_v_FirstChild_2ndv_SecondChild_v___LastChild_v(t);
+                    break;
+
+                case GroovyTokenTypes.ELIST: // a,b,c
+                case GroovyTokenTypes.PARAMETERS: // a,b,c
+                case GroovyTokenTypes.TYPE_ARGUMENTS: // <String, Object>
+                case GroovyTokenTypes.STRING_CONSTRUCTOR: // "foo${bar}wibble"
+                case GroovyTokenTypes.TYPE_PARAMETER: // class Foo<T extends F>
+                case GroovyTokenTypes.TYPE_PARAMETERS: // class Foo<T>
+                case GroovyTokenTypes.TYPE_UPPER_BOUNDS: // class Foo<T extends F>
+                    accept_v_FirstChild_v_SecondChild_v___LastChild_v(t);
+                    // todo : confirm that TYPE_LOWER_BOUNDS does not have multiple children
+                    break;
+
+                case GroovyTokenTypes.VARIABLE_PARAMETER_DEF: // void f(String ... others) {}
+                    accept_v_FirstChild_SecondChild_v_ThirdChild_v(t);
+                    break;
+
+                case GroovyTokenTypes.INDEX_OP:
+                    accept_FirstChild_v_SecondChild_v(t);
+                    break;
+
+                case GroovyTokenTypes.ENUM_CONSTANT_DEF: // enum Foo(THESE,ARE,THEY)
+                case GroovyTokenTypes.EXPR:
+                case GroovyTokenTypes.IMPORT:
+                case GroovyTokenTypes.VARIABLE_DEF:
+                case GroovyTokenTypes.METHOD_DEF:
+                case GroovyTokenTypes.OBJBLOCK: //class Foo {def bar()}  <-- this block
+                case GroovyTokenTypes.PARAMETER_DEF: // void f(String me) {}
+                case GroovyTokenTypes.SLIST: // list of expressions, variable defs etc
+                    accept_v_AllChildren_v(t);
+                    break;
+
+                case GroovyTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR: // @Blue(foo=123)
+                case GroovyTokenTypes.ASSIGN: // a = b
+                case GroovyTokenTypes.BAND_ASSIGN: // a &= b
+                case GroovyTokenTypes.BOR_ASSIGN: // a |= b
+                case GroovyTokenTypes.BSR_ASSIGN: // a >>>= b
+                case GroovyTokenTypes.BXOR_ASSIGN: // a ^= b
+                case GroovyTokenTypes.COMPARE_TO: // a <=> b
+                case GroovyTokenTypes.DIV_ASSIGN: // a /= b
+                case GroovyTokenTypes.EQUAL: // a == b
+                case GroovyTokenTypes.MINUS_ASSIGN: // a -= b
+                case GroovyTokenTypes.MOD_ASSIGN: // a %= b
+                case GroovyTokenTypes.NOT_EQUAL: // a != b
+                case GroovyTokenTypes.PLUS_ASSIGN: // a += b
+                case GroovyTokenTypes.REGEX_FIND: // a =~ b
+                case GroovyTokenTypes.REGEX_MATCH: // a ==~ b
+                case GroovyTokenTypes.SL_ASSIGN: // a <<= b
+                case GroovyTokenTypes.SR_ASSIGN: // a >>= b
+                case GroovyTokenTypes.STAR_ASSIGN: // a *= b
+                case GroovyTokenTypes.STAR_STAR_ASSIGN: // x **= 3
+                    if (t.childAt(1) != null) {
+                        accept_FirstChild_v_RestOfTheChildren(t);
+                    } else {
+                        accept_v_FirstChild_v_RestOfTheChildren(t);
+                    }
+                    break;
+
+                case GroovyTokenTypes.ANNOTATION_FIELD_DEF: // @interface Foo{ int bar()...
+                    accept_FirstSecondAndThirdChild_v_v_ForthChild(t);
+                    break;
+                    
+                case GroovyTokenTypes.ANNOTATION_DEF: // @interface Foo...
+                case GroovyTokenTypes.BAND: // 1 & 2
+                case GroovyTokenTypes.BOR: // 1 | 2
+                case GroovyTokenTypes.BSR: // 1 >>> 2
+                case GroovyTokenTypes.BXOR: // 1 ^ 2
+                case GroovyTokenTypes.CLASS_DEF: // class Foo...
+                case GroovyTokenTypes.CTOR_IDENT: // private Foo() {...
+                case GroovyTokenTypes.DIV: //  3/4
+                case GroovyTokenTypes.DOT: // foo.bar
+                case GroovyTokenTypes.ENUM_DEF: // enum Foo...
+                case GroovyTokenTypes.GE: // a >= b
+                case GroovyTokenTypes.GT: // a > b
+                case GroovyTokenTypes.INTERFACE_DEF: // interface Foo...
+                case GroovyTokenTypes.LABELED_ARG: // myMethod(name:"Jez")
+                case GroovyTokenTypes.LABELED_STAT: // foo:x=1                    	
+                case GroovyTokenTypes.LAND: // true && false
+                case GroovyTokenTypes.LE: // a <= b
+                case GroovyTokenTypes.LITERAL_as: // foo as Bar
+                case GroovyTokenTypes.LITERAL_in: // if (i in myList) ...
+                case GroovyTokenTypes.LOR: // true && false
+                case GroovyTokenTypes.LT: // a < b
+                case GroovyTokenTypes.MEMBER_POINTER: // this.&foo()
+                case GroovyTokenTypes.MOD: //  4 % 3
+                case GroovyTokenTypes.MINUS: // 1 - 1
+                case GroovyTokenTypes.OPTIONAL_DOT: // foo?.bar
+                case GroovyTokenTypes.PACKAGE_DEF:
+                case GroovyTokenTypes.PLUS: // 1 + 1
+                case GroovyTokenTypes.RANGE_EXCLUSIVE: // [1..<10]
+                case GroovyTokenTypes.RANGE_INCLUSIVE: // [1..10]
+                case GroovyTokenTypes.SL: // a << b
+                case GroovyTokenTypes.SR: // a >> b
+                case GroovyTokenTypes.STAR: // a * b   or    import foo.*
+                case GroovyTokenTypes.STAR_STAR: // x ** 3
+                    accept_FirstChild_v_RestOfTheChildren(t);
+                    break;
+
+                case GroovyTokenTypes.CTOR_CALL:
+                case GroovyTokenTypes.METHOD_CALL:
+                    if (t.getNumberOfChildren() == 2 && t.childAt(1) != null && t.childAt(1).getType() == GroovyTokenTypes.CLOSABLE_BLOCK) {
+                        // myMethod {...
+                        accept_FirstChild_v_SecondChild(t);
+                    } else {
+                        GroovySourceAST lastChild = t.childAt(t.getNumberOfChildren() -1);
+                        if (lastChild != null && lastChild.getType() == GroovyTokenTypes.CLOSABLE_BLOCK) {
+                            // myMethod(a,b) {...
+                            accept_FirstChild_v_RestOfTheChildren_v_LastChild(t);
+                        } else {
+                            // myMethod(a,b)
+                            accept_FirstChild_v_RestOfTheChildren_v(t);
+                        }
+                    }
+                    break;
+
+                case GroovyTokenTypes.LITERAL_while:
+                case GroovyTokenTypes.LITERAL_with:
+                case GroovyTokenTypes.TYPECAST: // (String)itr.next()
+                    accept_v_FirstChildsFirstChild_v_RestOfTheChildren(t);
+                    break;
+
+                case GroovyTokenTypes.LITERAL_if: // if (grandchild) {child1} else {child2} ...
+                    accept_v_FirstChildsFirstChild_v_Child2_Child3_v_Child4_v___v_LastChild(t);
+                    break;
+
+                case GroovyTokenTypes.CLOSABLE_BLOCK: // [1,2,3].each {foo(it)}  <-- Closure
+                    if (t.childAt(0) != null && t.childAt(0).getType() == GroovyTokenTypes.IMPLICIT_PARAMETERS) {
+                        accept_v_AllChildren_v(t);
+                    } else {
+                        accept_v_FirstChild_v_RestOfTheChildren_v(t);
+                    }
+                    break;
+
+                case GroovyTokenTypes.FOR_IN_ITERABLE:
+                case GroovyTokenTypes.LITERAL_for:
+                case GroovyTokenTypes.LITERAL_new:
+                case GroovyTokenTypes.LITERAL_switch:
+                    accept_v_FirstChild_v_RestOfTheChildren_v(t);
+                    break;
+ 
+                case GroovyTokenTypes.ANNOTATIONS: // just like modifiers but for package/enum declarations
+                case GroovyTokenTypes.LITERAL_assert:
+                case GroovyTokenTypes.LITERAL_catch:
+                case GroovyTokenTypes.LITERAL_synchronized:
+                case GroovyTokenTypes.LITERAL_try:
+                case GroovyTokenTypes.MODIFIERS:
+                    accept_v_FirstChild_v_RestOfTheChildren(t);
+                    break;
+
+                default:
+                    accept_v_FirstChild_v(t);
+                    break;
+            }
+            pop();
+        }
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/SourcePrinter.java b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/SourcePrinter.java
new file mode 100644
index 0000000..3456488
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/SourcePrinter.java
@@ -0,0 +1,1059 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr.treewalker;
+
+import java.io.PrintStream;
+import java.util.Stack;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+
+/**
+ * An antlr AST visitor that prints groovy source code for each visited node
+ * to the supplied PrintStream.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+public class SourcePrinter extends VisitorAdapter {
+    private String[] tokenNames;
+    private int tabLevel;
+    private int lastLinePrinted;
+    private boolean newLines;
+    protected PrintStream out;
+    private String className;
+    private Stack stack;
+    private int stringConstructorCounter;
+
+    /**
+     * A visitor that prints groovy source code for each node visited.
+     * @param out where to print the source code to
+     * @param tokenNames an array of token names from antlr
+     */
+    public SourcePrinter(PrintStream out,String[] tokenNames) {
+        this(out,tokenNames,true);
+    }
+
+    /**
+     * A visitor that prints groovy source code for each node visited.
+     * @param out where to print the source code to
+     * @param tokenNames an array of token names from antlr
+     * @param newLines output newline character
+     */
+    public SourcePrinter(PrintStream out,String[] tokenNames, boolean newLines) {
+        this.tokenNames = tokenNames;
+        tabLevel = 0;
+        lastLinePrinted = 0;
+        this.out = out;
+        this.newLines = newLines;
+        this.stack = new Stack();
+    }
+    
+
+	public void visitAbstract(GroovySourceAST t, int visit) {
+		print(t,visit,"abstract ",null,null);
+	}
+
+	public void visitAnnotation(GroovySourceAST t, int visit) {
+		if (visit == OPENING_VISIT) {
+			print(t,visit,"@");
+		}
+		if (visit == SECOND_VISIT) {
+			print(t,visit,"(");
+		}
+		if (visit == SUBSEQUENT_VISIT) {
+			print(t,visit,", ");
+		}
+		if (visit == CLOSING_VISIT) {
+			if (t.getNumberOfChildren() > 1) {
+				print(t,visit,") ");
+			} else {
+				print(t,visit," ");
+			}
+		}
+
+    }
+
+    public void visitAnnotations(GroovySourceAST t, int visit) {
+    	// do nothing
+    }
+
+    public void visitAnnotationDef(GroovySourceAST t,int visit) {
+        print(t,visit,"@interface ",null,null);
+    }
+
+	public void visitAnnotationFieldDef(GroovySourceAST t, int visit) {
+    	print(t,visit,"() ","default ",null);
+	}
+
+	public void visitAnnotationMemberValuePair(GroovySourceAST t, int visit) {
+		print(t,visit," = ",null,null);
+	}
+
+	public void visitArrayDeclarator(GroovySourceAST t, int visit) {
+		//<ARRAY_DECLARATOR>int</ARRAY_DECLARATOR> primes = new int(<ARRAY_DECLARATOR>5</ARRAY_DECLARATOR>)
+		if (getParentNode().getType() == GroovyTokenTypes.TYPE ||
+				getParentNode().getType() == GroovyTokenTypes.TYPECAST) { // ugly hack
+			// type defintion, i.e.   int[] x;
+			print(t,visit,null,null,"[]");
+		} else {
+			// usually in new, i.e.   def y = new int[5];
+			print(t,visit,"[",null,"]");
+		}
+	}
+
+	public void visitAssign(GroovySourceAST t,int visit) {
+        print(t,visit," = ",null,null);
+    }
+	
+    // visitAt() ...
+    //   token type 'AT' should never be visited, as annotation definitions and usage, and
+    //   direct field access should have all moved this token out of the way. No test needed.
+
+	//   one of the BAND tokens is actually replaced by TYPE_UPPER_BOUNDS (e.g. class Foo<T extends C & I> {T t} )
+    public void visitBand(GroovySourceAST t, int visit) {
+        print(t,visit," & ",null,null);
+    }
+
+	public void visitBandAssign(GroovySourceAST t,int visit) {
+        print(t,visit," &= ",null,null);
+    }
+	
+    // visitBigSuffix() ...
+	//   token type BIG_SUFFIX never created/visited, NUM_BIG_INT, NUM_BIG_DECIMAL instead...    
+    
+	// visitBlock() ...
+	//   token type BLOCK never created/visited, see CLOSABLE_BLOCK etc...
+	
+	public void visitBnot(GroovySourceAST t, int visit) {
+		print(t,visit,"~",null,null);
+	}
+	
+	// Note: old closure syntax using BOR is deprecated, and also never creates/visits a BOR node
+    public void visitBor(GroovySourceAST t, int visit) {
+        print(t,visit," | ",null,null);
+    }
+	
+	public void visitBorAssign(GroovySourceAST t,int visit) {
+        print(t,visit," |= ",null,null);
+    }
+	
+    public void visitBsr(GroovySourceAST t, int visit) {
+        print(t,visit," >>> ",null,null);
+    }
+	
+	public void visitBsrAssign(GroovySourceAST t,int visit) {
+        print(t,visit," >>>= ",null,null);
+    }
+	
+    public void visitBxor(GroovySourceAST t, int visit) {
+        print(t,visit," ^ ",null,null);
+    }
+	
+	public void visitBxorAssign(GroovySourceAST t,int visit) {
+        print(t,visit," ^= ",null,null);
+    }
+	
+    public void visitCaseGroup(GroovySourceAST t, int visit) {
+        if (visit == OPENING_VISIT) {
+            tabLevel++;
+        }
+        if (visit == CLOSING_VISIT) {
+            tabLevel--;
+        }
+    }
+
+    public void visitClassDef(GroovySourceAST t,int visit) {
+        print(t,visit,"class ",null,null);
+
+        if (visit == OPENING_VISIT) {
+            // store name of class away for use in constructor ident
+            className = t.childOfType(GroovyTokenTypes.IDENT).getText();
+        }
+    }
+
+    public void visitClosedBlock(GroovySourceAST t, int visit) {
+        printUpdatingTabLevel(t,visit,"{","-> ","}");
+    }
+    
+    // visitClosureOp ...
+	//   token type CLOSABLE_BLOCK_OP never created/visited, see CLOSABLE_BLOCK...
+	
+
+    // visitColon ...
+    //   token type COLON never created/visited, see LABELED_STAT, FOR_IN_ITERABLE, 
+    //   ASSERT, CASE, QUESTION, MAP_CONSTRUCTOR, LABELED_ARG, SPREAD_MAP_ARG
+
+    // visitComma ...
+    //   token type COMMA never created/visited,
+    //   see TYPE_ARGUMENTS, ANNOTATION, many others ...
+    
+    public void visitCompareTo(GroovySourceAST t,int visit) {
+        print(t,visit," <=> ",null,null);
+    }
+
+    public void visitCtorCall(GroovySourceAST t,int visit) {
+        printUpdatingTabLevel(t,visit,"this("," ",")");
+    }
+
+    public void visitCtorIdent(GroovySourceAST t, int visit) {
+        // use name of class for constructor from the class definition
+        print(t,visit,className,null,null);
+    }
+
+    public void visitDec(GroovySourceAST t, int visit) {
+    	print(t,visit,"--",null,null);
+    }
+    
+    // visitDigit ...
+    //    never created/visited
+    
+    public void visitDiv(GroovySourceAST t, int visit) {
+        print(t,visit," / ",null,null);
+    }
+
+	public void visitDivAssign(GroovySourceAST t,int visit) {
+        print(t,visit," /= ",null,null);
+    }
+	
+    // visitDollar ...
+    //   token type DOLLAR never created/visited, see SCOPE_ESCAPE instead
+    
+    public void visitDot(GroovySourceAST t,int visit) {
+        print(t,visit,".",null,null);
+    }
+    
+    public void visitDynamicMember(GroovySourceAST t, int visit) {
+    	if (t.childOfType(GroovyTokenTypes.STRING_CONSTRUCTOR) == null) {
+    		printUpdatingTabLevel(t,visit,"(",null,")");
+    	}
+    }
+    
+    public void visitElist(GroovySourceAST t,int visit) {
+    	if (getParentNode().getType() == GroovyTokenTypes.ENUM_CONSTANT_DEF) {
+    		print(t,visit,"(",", ",")");
+    	} else {
+    		print(t,visit,null,", ",null);
+    	}
+    }
+
+    // visitEmptyStat ...
+    //   token type EMPTY_STAT obsolete and should be removed, never visited/created
+    
+    public void visitEnumConstantDef(GroovySourceAST t,int visit) {
+    	GroovySourceAST sibling = (GroovySourceAST)t.getNextSibling();
+    	if (sibling != null && sibling.getType() == GroovyTokenTypes.ENUM_CONSTANT_DEF) {
+    		print(t,visit,null,null,", ");
+    	}
+    }
+
+    public void visitEnumDef(GroovySourceAST t,int visit) {
+        print(t,visit,"enum ",null,null);
+    }
+
+    // visitEof ...
+    //   token type EOF never visited/created
+
+    public void visitEqual(GroovySourceAST t,int visit) {
+        print(t,visit," == ",null,null);
+    }
+
+    // visitExponent ...
+    //   token type EXPONENT only used by lexer, never visited/created
+    
+    public void visitExpr(GroovySourceAST t,int visit) {
+    	// do nothing
+    }
+
+    public void visitExtendsClause(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            if (t.getNumberOfChildren() != 0) {
+                print(t,visit," extends ");
+            }
+        }
+    }
+    
+	public void visitFinal(GroovySourceAST t, int visit) {
+        print(t,visit,"final ",null,null);
+	}
+
+	// visitFloatSuffix ... never visited/created see NUM_DOUBLE or NUM_FLOAT instead
+	
+	public void visitForCondition(GroovySourceAST t, int visit) {
+    	print(t,visit," ; ",null,null);
+    }
+	
+	// visitForEachClause ... 
+	//   FOR_EACH_CLAUSE obsolete and should be removed, never visited/created
+
+    public void visitForInit(GroovySourceAST t, int visit) {
+    	print(t,visit,"(",null,null);
+    }
+    
+    public void visitForInIterable(GroovySourceAST t, int visit) {
+        printUpdatingTabLevel(t,visit,"("," in ",") ");
+    }
+
+    public void visitForIterator(GroovySourceAST t, int visit) {
+    	print(t,visit," ; ",null,")");
+    }
+    
+    public void visitGe(GroovySourceAST t, int visit) {
+    	print(t,visit," >= ",null,null);
+    }
+    
+    public void visitGt(GroovySourceAST t, int visit) {
+        print(t,visit," > ",null,null);
+    }
+
+    public void visitIdent(GroovySourceAST t,int visit) {
+        print(t,visit,t.getText(),null,null);
+    }
+    public void visitImplementsClause(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            if (t.getNumberOfChildren() != 0) {
+                print(t,visit," implements ");
+            }
+        }
+        if (visit == CLOSING_VISIT) {
+            //space between classdef and objblock
+            print(t,visit," ");
+        }
+    }
+
+    public void visitImplicitParameters(GroovySourceAST t, int visit) {
+    	// do nothing
+    }
+
+    public void visitImport(GroovySourceAST t,int visit) {
+        print(t,visit,"import ",null,null);
+    }
+
+    public void visitInc(GroovySourceAST t, int visit) {
+    	print(t,visit,"++",null,null);
+    }
+
+    public void visitIndexOp(GroovySourceAST t, int visit) {
+        printUpdatingTabLevel(t,visit,"[",null,"]");
+    }
+
+    public void visitInterfaceDef(GroovySourceAST t,int visit) {
+        print(t,visit,"interface ",null,null);
+    }
+
+    public void visitInstanceInit(GroovySourceAST t, int visit) {
+    	// do nothing
+	}
+
+	public void visitLabeledArg(GroovySourceAST t, int visit) {
+        print(t,visit,":",null,null);
+    }
+
+	public void visitLabeledStat(GroovySourceAST t, int visit) {
+        print(t,visit,":",null,null);
+    }
+
+    public void visitLand(GroovySourceAST t, int visit) {
+        print(t,visit," && ",null,null);
+    }
+
+    // visit lbrack()
+    //   token type LBRACK only used inside parser, never visited/created
+
+    // visit lcurly()
+    //   token type LCURLY only used inside parser, never visited/created
+    
+    public void visitLe(GroovySourceAST t, int visit) {
+    	print(t,visit," <= ",null,null);
+    }
+
+    // visitLetter ...
+    //   token type LETTER only used by lexer, never visited/created
+
+    public void visitListConstructor(GroovySourceAST t, int visit) {
+        printUpdatingTabLevel(t,visit,"[",null,"]");
+    }
+
+    public void visitLiteralAny(GroovySourceAST t,int visit) {
+        print(t,visit,"any",null,null);
+    }
+
+    public void visitLiteralAs(GroovySourceAST t,int visit) {
+        print(t,visit," as ",null,null);
+    }
+
+    public void visitLiteralAssert(GroovySourceAST t,int visit) {
+    	if (t.getNumberOfChildren() > 1) {
+    		print(t,visit,"assert ",null," : ");
+    	} else {
+    		print(t,visit,"assert ",null,null);
+    	}
+    }
+
+    public void visitLiteralBoolean(GroovySourceAST t, int visit) {
+        print(t,visit,"boolean",null,null);
+    }
+
+    public void visitLiteralBreak(GroovySourceAST t, int visit) {
+        print(t,visit,"break ",null,null);
+    }
+
+    public void visitLiteralByte(GroovySourceAST t, int visit) {
+        print(t,visit,"byte",null,null);
+    }
+
+    public void visitLiteralCase(GroovySourceAST t, int visit) {
+        print(t,visit,"case ",null,":");
+    }
+
+    public void visitLiteralCatch(GroovySourceAST t,int visit) {
+        printUpdatingTabLevel(t,visit," catch (",null,") ");
+    }
+
+    public void visitLiteralChar(GroovySourceAST t, int visit) {
+        print(t,visit,"char",null,null);
+    }
+
+    // visitLiteralClass ...
+    //   token type "class" only used by parser, never visited/created directly
+
+    public void visitLiteralContinue(GroovySourceAST t, int visit) {
+        print(t,visit,"continue ",null,null);
+    }
+
+    // visitLiteralDef ...
+    //   token type "def" only used by parser, never visited/created directly
+
+    public void visitLiteralDefault(GroovySourceAST t,int visit) {
+        print(t,visit,"default",null,":");
+    }
+
+    public void visitLiteralDouble(GroovySourceAST t, int visit) {
+        print(t,visit,"double",null,null);
+    }
+
+    // visitLiteralElse ...
+    //   token type "else" only used by parser, never visited/created directly
+
+    // visitLiteralEnum ...
+    //   token type "enum" only used by parser, never visited/created directly
+
+    // visitLiteralExtends
+    //   token type "extends" only used by parser, never visited/created directly
+    
+    public void visitLiteralFalse(GroovySourceAST t,int visit) {
+        print(t,visit,"false",null,null);
+    }
+
+    public void visitLiteralFinally(GroovySourceAST t,int visit) {
+        print(t,visit,"finally ",null,null);
+    }
+    public void visitLiteralFloat(GroovySourceAST t,int visit) {
+        print(t,visit,"float",null,null);
+    }
+
+    public void visitLiteralFor(GroovySourceAST t,int visit) {
+        print(t,visit,"for ",null,null);
+    }
+
+    public void visitLiteralIf(GroovySourceAST t,int visit) {
+        // slightly strange as subsequent visit is done after closing visit
+        printUpdatingTabLevel(t,visit,"if ("," else ",") ");
+    }
+
+    // visitLiteralImplements
+    //   token type "implements" only used by parser, never visited/created directly
+
+    // visitLiteralImport
+    //   token type "import" only used by parser, never visited/created directly
+
+    public void visitLiteralIn(GroovySourceAST t, int visit) {
+        print(t,visit," in ",null,null);
+    }
+
+    public void visitLiteralInstanceof(GroovySourceAST t, int visit) {
+        print(t,visit," instanceof ",null,null);
+    }
+
+    public void visitLiteralInt(GroovySourceAST t,int visit) {
+        print(t,visit,"int",null,null);
+    }
+
+    // visitLiteralInterface
+    //   token type "interface" only used by parser, never visited/created directly
+
+    public void visitLiteralLong(GroovySourceAST t,int visit) {
+        print(t,visit,"long",null,null);
+    }
+
+    public void visitLiteralNative(GroovySourceAST t,int visit) {
+        print(t,visit,"native ",null,null);
+    }
+    public void visitLiteralNew(GroovySourceAST t,int visit) {
+    	if (t.childOfType(GroovyTokenTypes.ARRAY_DECLARATOR) == null) {
+    		// only print parenthesis if is not of form def x = new int[5]
+    		print(t,visit,"new ","(",")");
+    	} else {
+    		print(t,visit,"new ",null,null);
+    	}
+    }
+
+    public void visitLiteralNull(GroovySourceAST t, int visit) {
+        print(t,visit,"null",null,null);
+    }
+
+    // visitLiteralPackage
+    //   token type "package" only used by parser, never visited/created directly
+
+    public void visitLiteralPrivate(GroovySourceAST t,int visit) {
+        print(t,visit,"private ",null,null);
+    }
+
+    public void visitLiteralProtected(GroovySourceAST t,int visit) {
+        print(t,visit,"protected ",null,null);
+    }
+
+    public void visitLiteralPublic(GroovySourceAST t,int visit) {
+        print(t,visit,"public ",null,null);
+    }
+
+    public void visitLiteralReturn(GroovySourceAST t, int visit) {
+        print(t,visit,"return ",null,null);
+    }
+
+    public void visitLiteralShort(GroovySourceAST t,int visit) {
+        print(t,visit,"short",null,null);
+    }
+
+    public void visitLiteralStatic(GroovySourceAST t, int visit) {
+        print(t,visit,"static ",null,null);
+    }
+
+    public void visitLiteralSuper(GroovySourceAST t, int visit) {
+    	// only visited when calling super() without parentheses, i.e. "super 99" is equivalent to "super(99)"
+    	print(t,visit,"super",null,null);
+    }
+
+    public void visitLiteralSwitch(GroovySourceAST t, int visit) {
+        if (visit == OPENING_VISIT) {
+            print(t,visit,"switch (");
+            tabLevel++;
+        }
+        if (visit == SUBSEQUENT_VISIT) {
+            print(t,visit,") {");
+        }
+        if (visit == CLOSING_VISIT) {
+            tabLevel--;
+            print(t,visit,"}");
+        }
+    }
+
+    public void visitLiteralSynchronized(GroovySourceAST t,int visit) {
+    	if (t.getNumberOfChildren() > 0) {
+    		print(t,visit,"synchronized (",null,") ");
+    	} else {
+    		print(t,visit,"synchronized ",null,null);    		
+    	}
+	}
+
+    public void visitLiteralThis(GroovySourceAST t, int visit) {
+        print(t,visit,"this",null,null);
+    }
+
+    public void visitLiteralThreadsafe(GroovySourceAST t,int visit) {
+        print(t,visit,"threadsafe ",null,null);
+    }
+
+    public void visitLiteralThrow(GroovySourceAST t, int visit) {
+        print(t,visit,"throw ",null,null);
+    }
+
+    public void visitLiteralThrows(GroovySourceAST t, int visit) {
+        print(t,visit,"throws ",null,null);
+    }
+
+    public void visitLiteralTransient(GroovySourceAST t,int visit) {
+        print(t,visit,"transient ",null,null);
+    }
+
+    public void visitLiteralTrue(GroovySourceAST t,int visit) {
+        print(t,visit,"true",null,null);
+    }
+    public void visitLiteralTry(GroovySourceAST t,int visit) {
+        print(t,visit,"try ",null,null);
+    }
+    public void visitLiteralVoid(GroovySourceAST t,int visit) {
+        print(t,visit,"void",null,null);
+    }
+    public void visitLiteralVolatile(GroovySourceAST t,int visit) {
+        print(t,visit,"volatile ",null,null);
+    }
+    public void visitLiteralWhile(GroovySourceAST t,int visit) {
+        printUpdatingTabLevel(t,visit,"while (",null,") ");
+    }
+
+    public void visitLiteralWith(GroovySourceAST t,int visit) {
+        printUpdatingTabLevel(t,visit,"with (",null,") ");
+    }
+    
+    public void visitLnot(GroovySourceAST t, int visit) {
+        print(t,visit,"!",null,null);
+    }
+
+	// Note: old closure syntax using LOR is deprecated, and also never creates/visits a LOR node
+    public void visitLor(GroovySourceAST t, int visit) {
+        print(t,visit," || ",null,null);
+    }
+
+    public void visitLt(GroovySourceAST t, int visit) {
+        print(t,visit," < ",null,null);
+    }
+
+    public void visitMapConstructor(GroovySourceAST t, int visit) {
+        if (t.getNumberOfChildren() == 0) {
+            print(t,visit,"[:]",null,null);
+        } else {
+            printUpdatingTabLevel(t,visit,"[",null,"]");
+        }
+    }
+
+    public void visitMemberPointer(GroovySourceAST t, int visit) {
+        print(t,visit,".&",null,null);
+    }
+
+    public void visitMethodCall(GroovySourceAST t,int visit) {
+    	if ("<command>".equals(t.getText())) {
+    		printUpdatingTabLevel(t,visit," "," ",null);
+    	} else {
+    		printUpdatingTabLevel(t,visit,"("," ",")");
+    	}
+    }
+    public void visitMethodDef(GroovySourceAST t,int visit) {
+        //do nothing
+    }
+    public void visitMinus(GroovySourceAST t,int visit) {
+        print(t,visit," - ",null,null);
+    }
+    public void visitMinusAssign(GroovySourceAST t, int visit) {
+        print(t,visit," -= ",null,null);
+    }
+
+    // visitMlComment
+    //   multi-line comments are not created on the AST currently.
+
+    public void visitMod(GroovySourceAST t, int visit) {
+        print(t,visit," % ",null,null);
+    }
+
+    public void visitModifiers(GroovySourceAST t,int visit) {
+        //do nothing
+    }
+    public void visitModAssign(GroovySourceAST t, int visit) {
+        print(t,visit," %= ",null,null);
+    }
+
+    // visitNls
+    //   new lines are used by parser, but are not created on the AST,
+    //   they can be implied by the source code line/column information
+
+    // visitNullTreeLookahead
+    //   not used explicitly by parser.
+    
+    
+    public void visitNotEqual(GroovySourceAST t, int visit) {
+        print(t,visit," != ",null,null);
+    }
+
+    public void visitNumBigDecimal(GroovySourceAST t,int visit) {
+        print(t,visit,t.getText(),null,null);
+    }
+    public void visitNumBigInt(GroovySourceAST t,int visit) {
+        print(t,visit,t.getText(),null,null);
+    }
+    public void visitNumDouble(GroovySourceAST t,int visit) {
+        print(t,visit,t.getText(),null,null);
+    }
+    public void visitNumInt(GroovySourceAST t,int visit) {
+        print(t,visit,t.getText(),null,null);
+    }
+    public void visitNumFloat(GroovySourceAST t,int visit) {
+        print(t,visit,t.getText(),null,null);
+    }
+    public void visitNumLong(GroovySourceAST t,int visit) {
+        print(t,visit,t.getText(),null,null);
+    }
+    public void visitObjblock(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            tabLevel++;
+            print(t,visit,"{");
+        } else {
+            tabLevel--;
+            print(t,visit,"}");
+        }
+    }
+
+    // visitOneNl
+    //   new lines are used by parser, but are not created on the AST,
+    //   they can be implied by the source code line/column information
+
+    public void visitOptionalDot(GroovySourceAST t,int visit) {
+        print(t,visit,"?.",null,null);
+    }
+    
+    public void visitPackageDef(GroovySourceAST t, int visit) {
+        print(t,visit,"package ",null,null);
+    }
+
+    public void visitParameterDef(GroovySourceAST t,int visit) {
+        //do nothing
+    }
+
+    public void visitParameters(GroovySourceAST t,int visit) {
+    	if (getParentNode().getType() == GroovyTokenTypes.CLOSABLE_BLOCK) {
+    		printUpdatingTabLevel(t,visit,null,","," ");
+    	} else {
+    		printUpdatingTabLevel(t,visit,"(",", ",") ");
+    	}
+    }
+
+    public void visitPlus(GroovySourceAST t, int visit) {
+        print(t,visit," + ",null,null);
+    }
+    
+    public void visitPlusAssign(GroovySourceAST t, int visit) {
+        print(t,visit," += ",null,null);
+    }
+    public void visitPostDec(GroovySourceAST t, int visit) {
+    	print(t,visit,null,null,"--");
+    }
+
+    public void visitPostInc(GroovySourceAST t, int visit) {
+    	print(t,visit,null,null,"++");
+    }
+
+    public void visitQuestion(GroovySourceAST t, int visit) {
+        // ternary operator
+        print(t,visit,"?",":",null);
+    }
+
+    public void visitRangeExclusive(GroovySourceAST t, int visit) {
+        print(t,visit,"..<",null,null);
+    }
+
+    public void visitRangeInclusive(GroovySourceAST t, int visit) {
+        print(t,visit,"..",null,null);
+    }
+
+    // visit rbrack()
+    //   token type RBRACK only used inside parser, never visited/created
+
+    // visit rcurly()
+    //   token type RCURLY only used inside parser, never visited/created
+
+    // visit RegexpCtorEnd
+    // visit RegexpLiteral
+    // visit RegexpSymbol
+    //    token types REGEXP_CTOR_END, REGEXP_LITERAL, REGEXP_SYMBOL only used inside lexer
+    
+    public void visitRegexFind(GroovySourceAST t, int visit) {
+    	print(t,visit," =~ ",null,null);
+    }
+    public void visitRegexMatch(GroovySourceAST t, int visit) {
+    	print(t,visit," ==~ ",null,null);
+    }
+    // visit rparen()
+    //   token type RPAREN only used inside parser, never visited/created
+
+    public void visitScopeEscape(GroovySourceAST t, int visit) {
+    	print(t,visit,"$",null,null);
+    }
+    public void visitSelectSlot(GroovySourceAST t, int visit) {
+    	print(t,visit,"@",null,null);
+    }
+    
+    // visit semi()
+    //  SEMI only used inside parser, never visited/created (see visitForCondition(), visitForIterator())
+    
+    // visit ShComment()
+    //  never visited/created by parser
+    
+    public void visitSl(GroovySourceAST t, int visit) {
+    	print(t,visit," << ",null,null);
+    }
+    public void visitSlAssign(GroovySourceAST t, int visit) {
+    	print(t,visit," <<= ",null,null);
+    }
+    public void visitSlist(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            tabLevel++;
+            print(t,visit,"{");
+        } else {
+            tabLevel--;
+            print(t,visit,"}");
+        }
+    }
+
+    // visit SlComment()
+    //   never visited/created by parser
+    
+    public void visitSpreadArg(GroovySourceAST t,int visit) {
+    	print(t,visit,"*",null,null);
+    }
+    
+    public void visitSpreadMapArg(GroovySourceAST t,int visit) {
+    	print(t,visit,"*:",null,null);
+    }
+    
+    public void visitSr(GroovySourceAST t, int visit) {
+    	print(t,visit," >> ",null,null);
+    }
+    public void visitSrAssign(GroovySourceAST t, int visit) {
+    	print(t,visit," >>= ",null,null);
+    }
+
+    public void visitStar(GroovySourceAST t,int visit) {
+        print(t,visit,"*",null,null);
+    }
+    public void visitStarAssign(GroovySourceAST t, int visit) {
+    	print(t,visit," *= ",null,null);
+    }
+    public void visitStarStar(GroovySourceAST t,int visit) {
+        print(t,visit,"**",null,null);
+    }
+    public void visitStarStarAssign(GroovySourceAST t, int visit) {
+    	print(t,visit," **= ",null,null);
+    }
+    
+    public void visitStaticInit(GroovySourceAST t, int visit) {
+    	print(t,visit,"static ",null,null);
+    }
+    public void visitStaticImport(GroovySourceAST t,int visit) {
+        print(t,visit,"import static ",null,null);
+    }
+    public void visitStrictfp(GroovySourceAST t,int visit) {
+    	print(t,visit,"strictfp ",null,null);
+    }
+
+    // visitStringch
+    //   String characters only used by lexer, never visited/created directly
+
+
+    public void visitStringConstructor(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            stringConstructorCounter = 0;
+            print(t,visit,"\"");
+        }
+        if (visit == SUBSEQUENT_VISIT) {
+            // every other subsequent visit use an escaping $
+            if (stringConstructorCounter % 2 == 0) {
+               print(t,visit,"$");
+            }
+            stringConstructorCounter++;
+        }
+        if (visit == CLOSING_VISIT) {
+            print(t,visit,"\"");
+        }
+    }
+
+    public void visitStringLiteral(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            String theString = escape(t.getText());
+        if (getParentNode().getType() != GroovyTokenTypes.LABELED_ARG &&
+            getParentNode().getType() != GroovyTokenTypes.STRING_CONSTRUCTOR) {
+                theString = "\"" + theString + "\"";
+            }
+            print(t,visit,theString);
+        }
+    }
+
+    private String escape(String literal) {
+        literal = literal.replaceAll("\n","\\\\<<REMOVE>>n"); // can't seem to do \n in one go with Java regex
+        literal = literal.replaceAll("<<REMOVE>>","");
+        return literal;
+    }
+
+    public void visitSuperCtorCall(GroovySourceAST t,int visit) {
+		printUpdatingTabLevel(t,visit,"super("," ",")");
+    }
+    
+    // visit TripleDot, not used in the AST
+    
+    public void visitType(GroovySourceAST t,int visit) {
+        GroovySourceAST parent = getParentNode();
+        GroovySourceAST modifiers = parent.childOfType(GroovyTokenTypes.MODIFIERS);
+
+        // No need to print 'def' if we already have some modifiers
+        if (modifiers == null || modifiers.getNumberOfChildren() == 0) {
+
+            if (visit == OPENING_VISIT) {
+                if (t.getNumberOfChildren() == 0 && 
+                		parent.getType() != GroovyTokenTypes.PARAMETER_DEF) { // no need for 'def' if in a parameter list
+                    print(t,visit,"def");
+                }
+            }
+        	if (visit == CLOSING_VISIT) {
+        		print(t,visit," ");
+            }
+        } else {
+        	if (visit == CLOSING_VISIT) {
+        		if (t.getNumberOfChildren() != 0) {
+        			print(t,visit," ");
+        		}
+        	}
+        }
+    }
+    public void visitTypeArgument(GroovySourceAST t, int visit) {
+    	// print nothing
+    }
+
+    public void visitTypeArguments(GroovySourceAST t, int visit) {
+    	print(t,visit,"<",", ",">");
+    }
+
+    public void visitTypecast(GroovySourceAST t,int visit) {
+        print(t,visit,"(",null,")");
+    }
+    public void visitTypeLowerBounds(GroovySourceAST t,int visit) {
+        print(t,visit," super "," & ",null);
+    }
+    public void visitTypeParameter(GroovySourceAST t, int visit) {
+    	// print nothing
+    }
+
+    public void visitTypeParameters(GroovySourceAST t, int visit) {
+    	print(t,visit,"<",", ",">");
+    }
+
+    public void visitTypeUpperBounds(GroovySourceAST t,int visit) {
+        print(t,visit," extends "," & ",null);
+    }
+    public void visitUnaryMinus(GroovySourceAST t, int visit) {
+    	print(t,visit,"-",null,null);
+    }
+    public void visitUnaryPlus(GroovySourceAST t, int visit) {
+    	print(t,visit,"+",null,null);
+    }
+
+    // visit Unused "const", "do", "goto" - unsurprisingly these are unused by the AST.
+    
+    public void visitVariableDef(GroovySourceAST t,int visit) {
+        // do nothing
+    }
+
+    // a.k.a. "variable arity parameter" in the JLS
+    public void visitVariableParameterDef(GroovySourceAST t,int visit) {
+        print(t,visit,null,"... ",null);
+    }
+    
+    // visit Vocab - only used by Lexer
+    
+    public void visitWildcardType(GroovySourceAST t, int visit) {
+    	print(t,visit,"?",null,null);
+    }
+
+    // visit WS - only used by lexer
+    
+    
+    
+    public void visitDefault(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            print(t,visit,"<" + tokenNames[t.getType()] + ">");
+            //out.print("<" + t.getType() + ">");
+        } else {
+            print(t,visit,"</" + tokenNames[t.getType()] + ">");
+            //out.print("</" + t.getType() + ">");
+        }
+    }
+
+    protected void printUpdatingTabLevel(GroovySourceAST t,int visit,String opening, String subsequent, String closing) {
+        if (visit == OPENING_VISIT && opening != null) {
+            print(t,visit,opening);
+            tabLevel++;
+        }
+        if (visit == SUBSEQUENT_VISIT && subsequent != null) {
+            print(t,visit,subsequent);
+        }
+        if (visit == CLOSING_VISIT && closing != null) {
+            tabLevel--;
+            print(t,visit,closing);
+        }
+    }
+
+    protected void print(GroovySourceAST t,int visit,String opening, String subsequent, String closing) {
+        if (visit == OPENING_VISIT && opening != null) {
+            print(t,visit,opening);
+        }
+        if (visit == SUBSEQUENT_VISIT && subsequent != null) {
+            print(t,visit,subsequent);
+        }
+        if (visit == CLOSING_VISIT && closing != null) {
+            print(t,visit,closing);
+        }
+    }
+    protected void print(GroovySourceAST t,int visit,String value) {
+        if(visit == OPENING_VISIT) {
+            printNewlineAndIndent(t, visit);
+        }
+        if (visit == CLOSING_VISIT) {
+            printNewlineAndIndent(t, visit);
+        }
+        out.print(value);
+    }
+
+    protected void printNewlineAndIndent(GroovySourceAST t, int visit) {
+        int currentLine = t.getLine();
+        if (lastLinePrinted == 0) { lastLinePrinted = currentLine; }
+        if (lastLinePrinted != currentLine) {
+            if (newLines) {
+                if (!(visit == OPENING_VISIT && t.getType() == GroovyTokenTypes.SLIST)) {
+                    for (int i=lastLinePrinted;i<currentLine;i++) {
+                        out.println();
+                    }
+                    if (lastLinePrinted > currentLine) {
+                        out.println();
+                    }
+                    if (visit == OPENING_VISIT || (visit == CLOSING_VISIT && lastLinePrinted > currentLine)) {
+                        for (int i=0;i<tabLevel;i++) {
+                            out.print("    ");
+                        }
+                    }
+                }
+            }
+            lastLinePrinted = Math.max(currentLine,lastLinePrinted);
+        }
+    }
+
+    public void push(GroovySourceAST t) {
+        stack.push(t);
+    }
+    public GroovySourceAST pop() {
+        if (!stack.empty()) {
+            return (GroovySourceAST) stack.pop();
+        }
+        return null;
+    }
+
+    private GroovySourceAST getParentNode() {
+        Object currentNode = stack.pop();
+        Object parentNode = stack.peek();
+        stack.push(currentNode);
+        return (GroovySourceAST) parentNode;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/SummaryCollector.java b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/SummaryCollector.java
new file mode 100644
index 0000000..6a0a752
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/SummaryCollector.java
@@ -0,0 +1,120 @@
+/*
+ $Id$
+
+ Copyright 2005 (C) Jeremy Rayner. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.antlr.treewalker;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.AntlrSourceSummary;
+import org.codehaus.groovy.antlr.syntax.AntlrClassSource;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+import org.codehaus.groovy.syntax.ClassSource;
+import org.codehaus.groovy.syntax.SourceSummary;
+
+import java.util.Stack;
+
+/**
+ * A visitor for the antlr ast that creates a summary of the parsed source unit
+ *
+ * @author Jeremy Rayner
+ */
+public class SummaryCollector extends VisitorAdapter {
+    private SourceSummary sourceSummary;
+    private Stack stack;
+
+    public SourceSummary getSourceSummary() {
+        return sourceSummary;
+    }
+
+    public SummaryCollector() {
+        sourceSummary = new AntlrSourceSummary();
+        stack = new Stack();
+    }
+
+    public void setUp() {
+    }
+
+    public void visitClassDef(GroovySourceAST t, int visit) {
+        if (visit == OPENING_VISIT) {
+            ClassSource classSource = new AntlrClassSource(
+                    t.childOfType(GroovyTokenTypes.IDENT).getText(),t
+            );
+            // Here we assume that the optional restrictions (JLS$7.6)
+            // on compilation units in file-based implementations apply
+            // http://java.sun.com/docs/books/jls/second_edition/html/packages.doc.html#26783
+            GroovySourceAST modifiers = t.childOfType(GroovyTokenTypes.MODIFIERS);
+
+            if (isPublic(modifiers)) {
+                sourceSummary.addPublic(classSource);
+            }
+        }
+    }
+
+    /* figue out if this modifier node represents a public entity */
+    private boolean isPublic(GroovySourceAST modifiers) {
+        boolean isPublic = true;
+        if (modifiers != null) {
+            GroovySourceAST modprot = modifiers.childOfType(GroovyTokenTypes.LITERAL_protected);
+            GroovySourceAST modpriv = modifiers.childOfType(GroovyTokenTypes.LITERAL_private);
+            if (modpriv != null || modprot != null) {
+                isPublic = false;
+            }
+        }
+        return isPublic;
+    }
+
+    public void tearDown() {
+    }
+
+    public void push(GroovySourceAST t) {
+        stack.push(t);
+    }
+    public GroovySourceAST pop() {
+        if (!stack.empty()) {
+            return (GroovySourceAST) stack.pop();
+        }
+        return null;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/TraversalHelper.java b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/TraversalHelper.java
new file mode 100644
index 0000000..357b841
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/TraversalHelper.java
@@ -0,0 +1,533 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr.treewalker;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.AntlrASTProcessor;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+
+import antlr.collections.AST;
+
+/**                                                  
+ * Helper Class for Antlr AST traversal and visitation.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+public abstract class TraversalHelper implements AntlrASTProcessor {
+    protected List unvisitedNodes;
+    private Visitor v;
+
+    public TraversalHelper(Visitor visitor) {
+        this.unvisitedNodes = new ArrayList();
+        this.v = visitor;
+    }
+
+    protected void setUp(GroovySourceAST ast) {
+        v.setUp();
+    }
+    protected void tearDown(GroovySourceAST ast) {
+        v.tearDown();
+    }
+
+    protected void push(GroovySourceAST ast) {
+        v.push(ast);
+    }
+    protected GroovySourceAST pop() {
+        return v.pop();
+    }
+
+    protected void visitNode(GroovySourceAST ast, int n) {
+        if (ast != null) {
+            switch (ast.getType()) {
+                case GroovyTokenTypes.ABSTRACT                      :   v.visitAbstract(ast,n);                     break;
+                case GroovyTokenTypes.ANNOTATION                    :   v.visitAnnotation(ast,n);                   break;
+                case GroovyTokenTypes.ANNOTATIONS                   :   v.visitAnnotations(ast,n);                  break;
+                case GroovyTokenTypes.ANNOTATION_ARRAY_INIT         :   v.visitAnnotationArrayInit(ast,n);          break; // obsolete?
+                case GroovyTokenTypes.ANNOTATION_DEF                :   v.visitAnnotationDef(ast,n);                break;
+                case GroovyTokenTypes.ANNOTATION_FIELD_DEF          :   v.visitAnnotationFieldDef(ast,n);           break;
+                case GroovyTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR  :   v.visitAnnotationMemberValuePair(ast,n);    break;
+                case GroovyTokenTypes.ARRAY_DECLARATOR              :   v.visitArrayDeclarator(ast,n);              break;
+                case GroovyTokenTypes.ASSIGN                        :   v.visitAssign(ast,n);                       break;
+                case GroovyTokenTypes.AT                            :   v.visitAt(ast,n);                           break;
+                case GroovyTokenTypes.BAND                          :   v.visitBand(ast,n);                         break;
+                case GroovyTokenTypes.BAND_ASSIGN                   :   v.visitBandAssign(ast,n);                   break;
+                case GroovyTokenTypes.BIG_SUFFIX                    :   v.visitBigSuffix(ast,n);                    break;
+                case GroovyTokenTypes.BLOCK                         :   v.visitBlock(ast,n);                        break;
+                case GroovyTokenTypes.BNOT                          :   v.visitBnot(ast,n);                         break;
+                case GroovyTokenTypes.BOR                           :   v.visitBor(ast,n);                          break;
+                case GroovyTokenTypes.BOR_ASSIGN                    :   v.visitBorAssign(ast,n);                    break;
+                case GroovyTokenTypes.BSR                           :   v.visitBsr(ast,n);                          break;
+                case GroovyTokenTypes.BSR_ASSIGN                    :   v.visitBsrAssign(ast,n);                    break;
+                case GroovyTokenTypes.BXOR                          :   v.visitBxor(ast,n);                         break;
+                case GroovyTokenTypes.BXOR_ASSIGN                   :   v.visitBxorAssign(ast,n);                   break;
+                case GroovyTokenTypes.CASE_GROUP                    :   v.visitCaseGroup(ast,n);                    break;
+                case GroovyTokenTypes.CLASS_DEF                     :   v.visitClassDef(ast,n);                     break;
+                case GroovyTokenTypes.CLOSABLE_BLOCK                :   v.visitClosedBlock(ast,n);                  break;
+                case GroovyTokenTypes.CLOSABLE_BLOCK_OP             :   v.visitClosureOp(ast,n);                    break;
+                case GroovyTokenTypes.COLON                         :   v.visitColon(ast,n);                        break;
+                case GroovyTokenTypes.COMMA                         :   v.visitComma(ast,n);                        break;
+                case GroovyTokenTypes.COMPARE_TO                    :   v.visitCompareTo(ast,n);                    break;
+                case GroovyTokenTypes.CTOR_CALL                     :   v.visitCtorCall(ast,n);                     break;
+                case GroovyTokenTypes.CTOR_IDENT                    :   v.visitCtorIdent(ast,n);                    break;
+                case GroovyTokenTypes.DEC                           :   v.visitDec(ast,n);                          break;
+                case GroovyTokenTypes.DIGIT                         :   v.visitDigit(ast,n);                        break;
+                case GroovyTokenTypes.DIV                           :   v.visitDiv(ast,n);                          break;
+                case GroovyTokenTypes.DIV_ASSIGN                    :   v.visitDivAssign(ast,n);                    break;
+                case GroovyTokenTypes.DOLLAR                        :   v.visitDollar(ast,n);                       break;
+                case GroovyTokenTypes.DOT                           :   v.visitDot(ast,n);                          break;
+                case GroovyTokenTypes.DYNAMIC_MEMBER                :   v.visitDynamicMember(ast,n);                break;
+                case GroovyTokenTypes.ELIST                         :   v.visitElist(ast,n);                        break;
+                case GroovyTokenTypes.EMPTY_STAT                    :   v.visitEmptyStat(ast,n);                    break;
+                case GroovyTokenTypes.ENUM_CONSTANT_DEF             :   v.visitEnumConstantDef(ast,n);              break;
+                case GroovyTokenTypes.ENUM_DEF                      :   v.visitEnumDef(ast,n);                      break;
+                case GroovyTokenTypes.EOF                           :   v.visitEof(ast,n);                          break;
+                case GroovyTokenTypes.EQUAL                         :   v.visitEqual(ast,n);                        break;
+                case GroovyTokenTypes.ESC                           :   v.visitEsc(ast,n);                          break;
+                case GroovyTokenTypes.EXPONENT                      :   v.visitExponent(ast,n);                     break;
+                case GroovyTokenTypes.EXPR                          :   v.visitExpr(ast,n);                         break;
+                case GroovyTokenTypes.EXTENDS_CLAUSE                :   v.visitExtendsClause(ast,n);                break;
+                case GroovyTokenTypes.FINAL                         :   v.visitFinal(ast,n);                        break;
+                case GroovyTokenTypes.FLOAT_SUFFIX                  :   v.visitFloatSuffix(ast,n);                  break;
+                case GroovyTokenTypes.FOR_CONDITION                 :   v.visitForCondition(ast,n);                 break;
+                case GroovyTokenTypes.FOR_EACH_CLAUSE               :   v.visitForEachClause(ast,n);                break;
+                case GroovyTokenTypes.FOR_INIT                      :   v.visitForInit(ast,n);                      break;
+                case GroovyTokenTypes.FOR_IN_ITERABLE               :   v.visitForInIterable(ast,n);                break;
+                case GroovyTokenTypes.FOR_ITERATOR                  :   v.visitForIterator(ast,n);                  break;
+                case GroovyTokenTypes.GE                            :   v.visitGe(ast,n);                           break;
+                case GroovyTokenTypes.GT                            :   v.visitGt(ast,n);                           break;
+                case GroovyTokenTypes.HEX_DIGIT                     :   v.visitHexDigit(ast,n);                     break;
+                case GroovyTokenTypes.IDENT                         :   v.visitIdent(ast,n);                        break;
+                case GroovyTokenTypes.IMPLEMENTS_CLAUSE             :   v.visitImplementsClause(ast,n);             break;
+                case GroovyTokenTypes.IMPLICIT_PARAMETERS           :   v.visitImplicitParameters(ast,n);           break;
+                case GroovyTokenTypes.IMPORT                        :   v.visitImport(ast,n);                       break;
+                case GroovyTokenTypes.INC                           :   v.visitInc(ast,n);                          break;
+                case GroovyTokenTypes.INDEX_OP                      :   v.visitIndexOp(ast,n);                      break;
+                case GroovyTokenTypes.INSTANCE_INIT                 :   v.visitInstanceInit(ast,n);                 break;
+                case GroovyTokenTypes.INTERFACE_DEF                 :   v.visitInterfaceDef(ast,n);                 break;
+                case GroovyTokenTypes.LABELED_ARG                   :   v.visitLabeledArg(ast,n);                   break;
+                case GroovyTokenTypes.LABELED_STAT                  :   v.visitLabeledStat(ast,n);                  break;
+                case GroovyTokenTypes.LAND                          :   v.visitLand(ast,n);                         break;
+                case GroovyTokenTypes.LBRACK                        :   v.visitLbrack(ast,n);                       break;
+                case GroovyTokenTypes.LCURLY                        :   v.visitLcurly(ast,n);                       break;
+                case GroovyTokenTypes.LE                            :   v.visitLe(ast,n);                           break;
+                case GroovyTokenTypes.LETTER                        :   v.visitLetter(ast,n);                       break;
+                case GroovyTokenTypes.LIST_CONSTRUCTOR              :   v.visitListConstructor(ast,n);              break;
+                case GroovyTokenTypes.LITERAL_any                   :   v.visitLiteralAny(ast,n);                   break;
+                case GroovyTokenTypes.LITERAL_as                    :   v.visitLiteralAs(ast,n);                    break;
+                case GroovyTokenTypes.LITERAL_assert                :   v.visitLiteralAssert(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_boolean               :   v.visitLiteralBoolean(ast,n);               break;
+                case GroovyTokenTypes.LITERAL_break                 :   v.visitLiteralBreak(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_byte                  :   v.visitLiteralByte(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_case                  :   v.visitLiteralCase(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_catch                 :   v.visitLiteralCatch(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_char                  :   v.visitLiteralChar(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_class                 :   v.visitLiteralClass(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_continue              :   v.visitLiteralContinue(ast,n);              break;
+                case GroovyTokenTypes.LITERAL_def                   :   v.visitLiteralDef(ast,n);                   break;
+                case GroovyTokenTypes.LITERAL_default               :   v.visitLiteralDefault(ast,n);               break;
+                case GroovyTokenTypes.LITERAL_double                :   v.visitLiteralDouble(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_else                  :   v.visitLiteralElse(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_enum                  :   v.visitLiteralEnum(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_extends               :   v.visitLiteralExtends(ast,n);               break;
+                case GroovyTokenTypes.LITERAL_false                 :   v.visitLiteralFalse(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_finally               :   v.visitLiteralFinally(ast,n);               break;
+                case GroovyTokenTypes.LITERAL_float                 :   v.visitLiteralFloat(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_for                   :   v.visitLiteralFor(ast,n);                   break;
+                case GroovyTokenTypes.LITERAL_if                    :   v.visitLiteralIf(ast,n);                    break;
+                case GroovyTokenTypes.LITERAL_implements            :   v.visitLiteralImplements(ast,n);            break;
+                case GroovyTokenTypes.LITERAL_import                :   v.visitLiteralImport(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_in                    :   v.visitLiteralIn(ast,n);                    break;
+                case GroovyTokenTypes.LITERAL_instanceof            :   v.visitLiteralInstanceof(ast,n);            break;
+                case GroovyTokenTypes.LITERAL_int                   :   v.visitLiteralInt(ast,n);                   break;
+                case GroovyTokenTypes.LITERAL_interface             :   v.visitLiteralInterface(ast,n);             break;
+                case GroovyTokenTypes.LITERAL_long                  :   v.visitLiteralLong(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_native                :   v.visitLiteralNative(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_new                   :   v.visitLiteralNew(ast,n);                   break;
+                case GroovyTokenTypes.LITERAL_null                  :   v.visitLiteralNull(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_package               :   v.visitLiteralPackage(ast,n);               break;
+                case GroovyTokenTypes.LITERAL_private               :   v.visitLiteralPrivate(ast,n);               break;
+                case GroovyTokenTypes.LITERAL_protected             :   v.visitLiteralProtected(ast,n);             break;
+                case GroovyTokenTypes.LITERAL_public                :   v.visitLiteralPublic(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_return                :   v.visitLiteralReturn(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_short                 :   v.visitLiteralShort(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_static                :   v.visitLiteralStatic(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_super                 :   v.visitLiteralSuper(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_switch                :   v.visitLiteralSwitch(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_synchronized          :   v.visitLiteralSynchronized(ast,n);          break;
+                case GroovyTokenTypes.LITERAL_this                  :   v.visitLiteralThis(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_threadsafe            :   v.visitLiteralThreadsafe(ast,n);            break;
+                case GroovyTokenTypes.LITERAL_throw                 :   v.visitLiteralThrow(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_throws                :   v.visitLiteralThrows(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_transient             :   v.visitLiteralTransient(ast,n);             break;
+                case GroovyTokenTypes.LITERAL_true                  :   v.visitLiteralTrue(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_try                   :   v.visitLiteralTry(ast,n);                   break;
+                case GroovyTokenTypes.LITERAL_void                  :   v.visitLiteralVoid(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_volatile              :   v.visitLiteralVolatile(ast,n);              break;
+                case GroovyTokenTypes.LITERAL_while                 :   v.visitLiteralWhile(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_with                  :   v.visitLiteralWith(ast,n);                  break;
+                case GroovyTokenTypes.LNOT                          :   v.visitLnot(ast,n);                         break;
+                case GroovyTokenTypes.LOR                           :   v.visitLor(ast,n);                          break;
+                case GroovyTokenTypes.LPAREN                        :   v.visitLparen(ast,n);                       break;
+                case GroovyTokenTypes.LT                            :   v.visitLt(ast,n);                           break;
+                case GroovyTokenTypes.MAP_CONSTRUCTOR               :   v.visitMapConstructor(ast,n);               break;
+                case GroovyTokenTypes.MEMBER_POINTER                :   v.visitMemberPointer(ast,n);                break;
+                case GroovyTokenTypes.METHOD_CALL                   :   v.visitMethodCall(ast,n);                   break;
+                case GroovyTokenTypes.METHOD_DEF                    :   v.visitMethodDef(ast,n);                    break;
+                case GroovyTokenTypes.MINUS                         :   v.visitMinus(ast,n);                        break;
+                case GroovyTokenTypes.MINUS_ASSIGN                  :   v.visitMinusAssign(ast,n);                  break;
+                case GroovyTokenTypes.ML_COMMENT                    :   v.visitMlComment(ast,n);                    break;
+                case GroovyTokenTypes.MOD                           :   v.visitMod(ast,n);                          break;
+                case GroovyTokenTypes.MODIFIERS                     :   v.visitModifiers(ast,n);                    break;
+                case GroovyTokenTypes.MOD_ASSIGN                    :   v.visitModAssign(ast,n);                    break;
+                case GroovyTokenTypes.NLS                           :   v.visitNls(ast,n);                          break;
+                case GroovyTokenTypes.NOT_EQUAL                     :   v.visitNotEqual(ast,n);                     break;
+                case GroovyTokenTypes.NULL_TREE_LOOKAHEAD           :   v.visitNullTreeLookahead(ast,n);            break;
+                case GroovyTokenTypes.NUM_BIG_DECIMAL               :   v.visitNumBigDecimal(ast,n);                break;
+                case GroovyTokenTypes.NUM_BIG_INT                   :   v.visitNumBigInt(ast,n);                    break;
+                case GroovyTokenTypes.NUM_DOUBLE                    :   v.visitNumDouble(ast,n);                    break;
+                case GroovyTokenTypes.NUM_FLOAT                     :   v.visitNumFloat(ast,n);                     break;
+                case GroovyTokenTypes.NUM_INT                       :   v.visitNumInt(ast,n);                       break;
+                case GroovyTokenTypes.NUM_LONG                      :   v.visitNumLong(ast,n);                      break;
+                case GroovyTokenTypes.OBJBLOCK                      :   v.visitObjblock(ast,n);                     break;
+                case GroovyTokenTypes.ONE_NL                        :   v.visitOneNl(ast,n);                        break;
+                case GroovyTokenTypes.OPTIONAL_DOT                  :   v.visitOptionalDot(ast,n);                  break;
+                case GroovyTokenTypes.PACKAGE_DEF                   :   v.visitPackageDef(ast,n);                   break;
+                case GroovyTokenTypes.PARAMETERS                    :   v.visitParameters(ast,n);                   break;
+                case GroovyTokenTypes.PARAMETER_DEF                 :   v.visitParameterDef(ast,n);                 break;
+                case GroovyTokenTypes.PLUS                          :   v.visitPlus(ast,n);                         break;
+                case GroovyTokenTypes.PLUS_ASSIGN                   :   v.visitPlusAssign(ast,n);                   break;
+                case GroovyTokenTypes.POST_DEC                      :   v.visitPostDec(ast,n);                      break;
+                case GroovyTokenTypes.POST_INC                      :   v.visitPostInc(ast,n);                      break;
+                case GroovyTokenTypes.QUESTION                      :   v.visitQuestion(ast,n);                     break;
+                case GroovyTokenTypes.RANGE_EXCLUSIVE               :   v.visitRangeExclusive(ast,n);               break;
+                case GroovyTokenTypes.RANGE_INCLUSIVE               :   v.visitRangeInclusive(ast,n);               break;
+                case GroovyTokenTypes.RBRACK                        :   v.visitRbrack(ast,n);                       break;
+                case GroovyTokenTypes.RCURLY                        :   v.visitRcurly(ast,n);                       break;
+                case GroovyTokenTypes.REGEXP_CTOR_END               :   v.visitRegexpCtorEnd(ast,n);                break;
+                case GroovyTokenTypes.REGEXP_LITERAL                :   v.visitRegexpLiteral(ast,n);                break;
+                case GroovyTokenTypes.REGEXP_SYMBOL                 :   v.visitRegexpSymbol(ast,n);                 break;
+                case GroovyTokenTypes.REGEX_FIND                    :   v.visitRegexFind(ast,n);                    break;
+                case GroovyTokenTypes.REGEX_MATCH                   :   v.visitRegexMatch(ast,n);                   break;
+                case GroovyTokenTypes.RPAREN                        :   v.visitRparen(ast,n);                       break;
+                case GroovyTokenTypes.SCOPE_ESCAPE                  :   v.visitScopeEscape(ast,n);                  break;
+                case GroovyTokenTypes.SELECT_SLOT                   :   v.visitSelectSlot(ast,n);                   break;
+                case GroovyTokenTypes.SEMI                          :   v.visitSemi(ast,n);                         break;
+                case GroovyTokenTypes.SH_COMMENT                    :   v.visitShComment(ast,n);                    break;
+                case GroovyTokenTypes.SL                            :   v.visitSl(ast,n);                           break;
+                case GroovyTokenTypes.SLIST                         :   v.visitSlist(ast,n);                        break;
+                case GroovyTokenTypes.SL_ASSIGN                     :   v.visitSlAssign(ast,n);                     break;
+                case GroovyTokenTypes.SL_COMMENT                    :   v.visitSlComment(ast,n);                    break;
+                case GroovyTokenTypes.SPREAD_ARG                    :   v.visitSpreadArg(ast,n);                    break;
+                case GroovyTokenTypes.SPREAD_DOT                    :   v.visitSpreadDot(ast,n);                    break;
+                case GroovyTokenTypes.SPREAD_MAP_ARG                :   v.visitSpreadMapArg(ast,n);                 break;
+                case GroovyTokenTypes.SR                            :   v.visitSr(ast,n);                           break;
+                case GroovyTokenTypes.SR_ASSIGN                     :   v.visitSrAssign(ast,n);                     break;
+                case GroovyTokenTypes.STAR                          :   v.visitStar(ast,n);                         break;
+                case GroovyTokenTypes.STAR_ASSIGN                   :   v.visitStarAssign(ast,n);                   break;
+                case GroovyTokenTypes.STAR_STAR                     :   v.visitStarStar(ast,n);                     break;
+                case GroovyTokenTypes.STAR_STAR_ASSIGN              :   v.visitStarStarAssign(ast,n);               break;
+                case GroovyTokenTypes.STATIC_IMPORT                 :   v.visitStaticImport(ast,n);                 break;
+                case GroovyTokenTypes.STATIC_INIT                   :   v.visitStaticInit(ast,n);                   break;
+                case GroovyTokenTypes.STRICTFP                      :   v.visitStrictfp(ast,n);                     break;
+                case GroovyTokenTypes.STRING_CH                     :   v.visitStringCh(ast,n);                     break;
+                case GroovyTokenTypes.STRING_CONSTRUCTOR            :   v.visitStringConstructor(ast,n);            break;
+                case GroovyTokenTypes.STRING_CTOR_END               :   v.visitStringCtorEnd(ast,n);                break;
+                case GroovyTokenTypes.STRING_CTOR_MIDDLE            :   v.visitStringCtorMiddle(ast,n);             break;
+                case GroovyTokenTypes.STRING_CTOR_START             :   v.visitStringCtorStart(ast,n);              break;
+                case GroovyTokenTypes.STRING_LITERAL                :   v.visitStringLiteral(ast,n);                break;
+                case GroovyTokenTypes.STRING_NL                     :   v.visitStringNl(ast,n);                     break;
+                case GroovyTokenTypes.SUPER_CTOR_CALL               :   v.visitSuperCtorCall(ast,n);                break;
+                case GroovyTokenTypes.TRIPLE_DOT                    :   v.visitTripleDot(ast,n);                    break;
+                case GroovyTokenTypes.TYPE                          :   v.visitType(ast,n);                         break;
+                case GroovyTokenTypes.TYPECAST                      :   v.visitTypecast(ast,n);                     break;
+                case GroovyTokenTypes.TYPE_ARGUMENT                 :   v.visitTypeArgument(ast,n);                 break;
+                case GroovyTokenTypes.TYPE_ARGUMENTS                :   v.visitTypeArguments(ast,n);                break;
+                case GroovyTokenTypes.TYPE_LOWER_BOUNDS             :   v.visitTypeLowerBounds(ast,n);              break;
+                case GroovyTokenTypes.TYPE_PARAMETER                :   v.visitTypeParameter(ast,n);                break;
+                case GroovyTokenTypes.TYPE_PARAMETERS               :   v.visitTypeParameters(ast,n);               break;
+                case GroovyTokenTypes.TYPE_UPPER_BOUNDS             :   v.visitTypeUpperBounds(ast,n);              break;
+                case GroovyTokenTypes.UNARY_MINUS                   :   v.visitUnaryMinus(ast,n);                   break;
+                case GroovyTokenTypes.UNARY_PLUS                    :   v.visitUnaryPlus(ast,n);                    break;
+                case GroovyTokenTypes.UNUSED_CONST                  :   v.visitUnusedConst(ast,n);                  break;
+                case GroovyTokenTypes.UNUSED_DO                     :   v.visitUnusedDo(ast,n);                     break;
+                case GroovyTokenTypes.UNUSED_GOTO                   :   v.visitUnusedGoto(ast,n);                   break;
+                case GroovyTokenTypes.VARIABLE_DEF                  :   v.visitVariableDef(ast,n);                  break;
+                case GroovyTokenTypes.VARIABLE_PARAMETER_DEF        :   v.visitVariableParameterDef(ast,n);         break;
+                case GroovyTokenTypes.VOCAB                         :   v.visitVocab(ast,n);                        break;
+                case GroovyTokenTypes.WILDCARD_TYPE                 :   v.visitWildcardType(ast,n);                 break;
+                case GroovyTokenTypes.WS                            :   v.visitWs(ast,n);                           break;
+
+
+                default                                             :   v.visitDefault(ast,n);                      break;
+            }
+        } else {
+            // the supplied AST was null
+            v.visitDefault(null,n);
+        }
+    }
+    protected abstract void accept(GroovySourceAST currentNode);
+
+    protected void accept_v_FirstChildsFirstChild_v_Child2_Child3_v_Child4_v___v_LastChild(GroovySourceAST t) {
+        openingVisit(t);
+        GroovySourceAST expr2 = t.childAt(0);
+        skip(expr2);
+        accept(expr2.childAt(0));
+        closingVisit(t);
+
+        GroovySourceAST sibling = (GroovySourceAST)expr2.getNextSibling();
+        boolean firstSList = true;
+        while (sibling != null) {
+            if (!firstSList) {
+                subsequentVisit(t);
+            }
+            firstSList = false;
+            accept(sibling);
+            sibling = (GroovySourceAST)sibling.getNextSibling();
+        }
+    }
+
+    protected void accept_v_FirstChildsFirstChild_v_RestOfTheChildren(GroovySourceAST t) {
+        openingVisit(t);
+        GroovySourceAST expr = t.childAt(0);
+        skip(expr);
+        accept(expr.childAt(0));
+        closingVisit(t);
+        acceptSiblings(expr);
+    }
+
+    protected void accept_FirstChild_v_SecondChild(GroovySourceAST t) {
+        accept(t.childAt(0));
+        subsequentVisit(t);
+        accept(t.childAt(1));
+    }
+    protected void accept_FirstChild_v_SecondChild_v(GroovySourceAST t) {
+        accept(t.childAt(0));
+        openingVisit(t);
+        accept(t.childAt(1));
+        closingVisit(t);
+    }
+
+    protected void accept_FirstChild_v_SecondChildsChildren_v(GroovySourceAST t) {
+        accept(t.childAt(0));
+
+        openingVisit(t);
+        GroovySourceAST secondChild = t.childAt(1);
+        if (secondChild != null) {
+            acceptChildren(secondChild);
+        }
+        closingVisit(t);
+    }
+
+    
+    protected void accept_v_FirstChild_SecondChild_v_ThirdChild_v(GroovySourceAST t) {
+        openingVisit(t);
+        accept(t.childAt(0));
+        accept(t.childAt(1));
+        subsequentVisit(t);
+        accept(t.childAt(2));
+        closingVisit(t);
+    }
+
+    protected void accept_FirstChild_v_SecondChild_v_ThirdChild_v(GroovySourceAST t) {
+        accept(t.childAt(0));
+        openingVisit(t);
+        accept(t.childAt(1));
+        subsequentVisit(t);
+        accept(t.childAt(2));
+        closingVisit(t);
+    }
+	
+    protected void accept_FirstSecondAndThirdChild_v_v_ForthChild(GroovySourceAST t) {
+        GroovySourceAST child1 = (GroovySourceAST)t.getFirstChild();
+        if (child1 != null){
+        	accept(child1);
+            GroovySourceAST child2 = (GroovySourceAST)child1.getNextSibling();
+            if (child2 != null) {
+            	accept(child2);
+                GroovySourceAST child3 = (GroovySourceAST)child2.getNextSibling();
+                if (child3 != null) {
+                	accept(child3);
+                	openingVisit(t);
+                	GroovySourceAST child4 = (GroovySourceAST)child3.getNextSibling();
+                    if (child4 != null) {
+                    	subsequentVisit(t);
+                    	accept(child4);
+                    }
+                }
+            }
+        }
+	}
+
+	protected void accept_v_FirstChild_2ndv_SecondChild_v___LastChild_v(GroovySourceAST t) {
+        openingVisit(t);
+        GroovySourceAST child = (GroovySourceAST)t.getFirstChild();
+        if (child != null){
+            accept(child);
+            GroovySourceAST sibling = (GroovySourceAST)child.getNextSibling();
+            if (sibling != null) {
+            	secondVisit(t);
+            	accept(sibling);
+                sibling = (GroovySourceAST)sibling.getNextSibling();
+                while (sibling != null) {
+                    subsequentVisit(t);
+                    accept(sibling);
+                    sibling = (GroovySourceAST)sibling.getNextSibling();
+                }
+            }
+        }
+        closingVisit(t);
+    }
+
+	protected void accept_v_FirstChild_v_SecondChild_v___LastChild_v(GroovySourceAST t) {
+        openingVisit(t);
+        GroovySourceAST child = (GroovySourceAST)t.getFirstChild();
+        if (child != null){
+            accept(child);
+            GroovySourceAST sibling = (GroovySourceAST)child.getNextSibling();
+            while (sibling != null) {
+                subsequentVisit(t);
+                accept(sibling);
+                sibling = (GroovySourceAST)sibling.getNextSibling();
+            }
+        }
+        closingVisit(t);
+    }
+
+    protected void accept_v_FirstChild_v(GroovySourceAST t) {
+        openingVisit(t);
+        accept(t.childAt(0));
+        closingVisit(t);
+    }
+
+    protected void accept_v_AllChildren_v_Siblings(GroovySourceAST t) {
+        openingVisit(t);
+        acceptChildren(t);
+        closingVisit(t);
+        acceptSiblings(t);
+    }
+
+    protected void accept_v_AllChildren_v(GroovySourceAST t) {
+        openingVisit(t);
+        acceptChildren(t);
+        closingVisit(t);
+    }
+
+    protected void accept_FirstChild_v_RestOfTheChildren(GroovySourceAST t) {
+        accept(t.childAt(0));
+        openingVisit(t);
+        closingVisit(t);
+        acceptSiblings(t.childAt(0));
+    }
+    protected void accept_FirstChild_v_RestOfTheChildren_v_LastChild(GroovySourceAST t) {
+        int count = 0;
+        accept(t.childAt(0));
+        count++;
+        openingVisit(t);
+        if (t.childAt(0) != null) {
+            GroovySourceAST sibling = (GroovySourceAST)t.childAt(0).getNextSibling();
+            while (sibling != null) {
+                if (count == t.getNumberOfChildren() - 1) {closingVisit(t);}
+                accept(sibling);
+                count++;
+                sibling = (GroovySourceAST)sibling.getNextSibling();
+            }
+        }
+
+
+    }
+    protected void accept_FirstChild_v_RestOfTheChildren_v(GroovySourceAST t) {
+        accept(t.childAt(0));
+        openingVisit(t);
+        acceptSiblings(t.childAt(0));
+        closingVisit(t);
+    }
+    protected void accept_v_FirstChild_v_RestOfTheChildren(GroovySourceAST t) {
+        accept_v_FirstChild_v(t);
+        acceptSiblings(t.childAt(0));
+    }
+
+    protected void accept_v_FirstChild_v_RestOfTheChildren_v(GroovySourceAST t) {
+        openingVisit(t);
+        accept(t.childAt(0));
+        subsequentVisit(t);
+        acceptSiblings(t.childAt(0));
+        closingVisit(t);
+    }
+
+    protected void acceptSiblings(GroovySourceAST t) {
+        if (t != null) {
+            GroovySourceAST sibling = (GroovySourceAST)t.getNextSibling();
+            while (sibling != null) {
+                accept(sibling);
+                sibling = (GroovySourceAST)sibling.getNextSibling();
+            }
+        }
+    }
+
+    protected void acceptChildren(GroovySourceAST t) {
+        if (t != null) {
+            GroovySourceAST child = (GroovySourceAST)t.getFirstChild();
+            if (child != null){
+                accept(child);
+                acceptSiblings(child);
+            }
+        }
+    }
+
+    protected void skip(GroovySourceAST expr) {
+        unvisitedNodes.remove(expr);
+    }
+
+    protected void openingVisit(GroovySourceAST t) {
+        unvisitedNodes.remove(t);
+
+        int n = Visitor.OPENING_VISIT;
+        visitNode(t, n);
+    }
+
+    protected void secondVisit(GroovySourceAST t) {
+        int n = Visitor.SECOND_VISIT;
+        visitNode(t, n);
+    }
+
+    protected void subsequentVisit(GroovySourceAST t) {
+        int n = Visitor.SUBSEQUENT_VISIT;
+        visitNode(t, n);
+    }
+
+    protected void closingVisit(GroovySourceAST t) {
+        int n = Visitor.CLOSING_VISIT;
+        visitNode(t, n);
+    }
+    
+    public AST process(AST t) {
+        GroovySourceAST node = (GroovySourceAST) t;
+        
+        // process each node in turn
+        setUp(node);
+        accept(node);
+        acceptSiblings(node);
+        tearDown(node);
+        return null;
+    }    
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/Visitor.java b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/Visitor.java
new file mode 100644
index 0000000..ef78830
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/Visitor.java
@@ -0,0 +1,259 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr.treewalker;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+
+/**
+ * An interface for visiting a GroovySourceAST node.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+public interface Visitor {
+    final int OPENING_VISIT = 1;
+    final int SECOND_VISIT = 2; // only used on rare occasions, e.g. the '(' in this snippet...   @Foo  (  a=1, b=2, c=3)
+    final int SUBSEQUENT_VISIT = 3;
+    final int CLOSING_VISIT = 4;
+
+    void setUp();
+    void visitAbstract(GroovySourceAST t, int visit);
+    void visitAnnotation(GroovySourceAST t, int visit);
+    void visitAnnotations(GroovySourceAST t, int visit);
+    void visitAnnotationArrayInit(GroovySourceAST t, int visit);
+    void visitAnnotationDef(GroovySourceAST t, int visit);
+    void visitAnnotationFieldDef(GroovySourceAST t, int visit);
+    void visitAnnotationMemberValuePair(GroovySourceAST t, int visit);
+    void visitArrayDeclarator(GroovySourceAST t, int visit);
+    void visitAssign(GroovySourceAST t, int visit);
+    void visitAt(GroovySourceAST t, int visit);
+    void visitBand(GroovySourceAST t, int visit);
+    void visitBandAssign(GroovySourceAST t, int visit);
+    void visitBigSuffix(GroovySourceAST t, int visit);
+    void visitBlock(GroovySourceAST t, int visit);
+    void visitBnot(GroovySourceAST t, int visit);
+    void visitBor(GroovySourceAST t, int visit);
+    void visitBorAssign(GroovySourceAST t, int visit);
+    void visitBsr(GroovySourceAST t, int visit);
+    void visitBsrAssign(GroovySourceAST t, int visit);
+    void visitBxor(GroovySourceAST t, int visit);
+    void visitBxorAssign(GroovySourceAST t, int visit);
+    void visitCaseGroup(GroovySourceAST t, int visit);
+    void visitClassDef(GroovySourceAST t, int visit);
+    void visitClosedBlock(GroovySourceAST t, int visit);
+    void visitClosureOp(GroovySourceAST t, int visit);
+    void visitColon(GroovySourceAST t, int visit);
+    void visitComma(GroovySourceAST t, int visit);
+    void visitCompareTo(GroovySourceAST t, int visit);
+    void visitCtorCall(GroovySourceAST t, int visit);
+    void visitCtorIdent(GroovySourceAST t, int visit);
+    void visitDec(GroovySourceAST t, int visit);
+    void visitDigit(GroovySourceAST t, int visit);
+    void visitDiv(GroovySourceAST t, int visit);
+    void visitDivAssign(GroovySourceAST t, int visit);
+    void visitDollar(GroovySourceAST t, int visit);
+    void visitDot(GroovySourceAST t, int visit);
+    void visitDynamicMember(GroovySourceAST t, int visit);
+    void visitElist(GroovySourceAST t, int visit);
+    void visitEmptyStat(GroovySourceAST t, int visit);
+    void visitEnumConstantDef(GroovySourceAST t, int visit);
+    void visitEnumDef(GroovySourceAST t, int visit);
+    void visitEof(GroovySourceAST t, int visit);
+    void visitEqual(GroovySourceAST t, int visit);
+    void visitEsc(GroovySourceAST t, int visit);
+    void visitExponent(GroovySourceAST t, int visit);
+    void visitExpr(GroovySourceAST t, int visit);
+    void visitExtendsClause(GroovySourceAST t, int visit);
+    void visitFinal(GroovySourceAST t, int visit);
+    void visitFloatSuffix(GroovySourceAST t, int visit);
+    void visitForCondition(GroovySourceAST t, int visit);
+    void visitForEachClause(GroovySourceAST t, int visit);
+    void visitForInit(GroovySourceAST t, int visit);
+    void visitForInIterable(GroovySourceAST t, int visit);
+    void visitForIterator(GroovySourceAST t, int visit);
+    void visitGe(GroovySourceAST t, int visit);
+    void visitGt(GroovySourceAST t, int visit);
+    void visitHexDigit(GroovySourceAST t, int visit);
+    void visitIdent(GroovySourceAST t, int visit);
+    void visitImplementsClause(GroovySourceAST t, int visit);
+    void visitImplicitParameters(GroovySourceAST t, int visit);
+    void visitImport(GroovySourceAST t, int visit);
+    void visitInc(GroovySourceAST t, int visit);
+    void visitIndexOp(GroovySourceAST t, int visit);
+    void visitInstanceInit(GroovySourceAST t, int visit);
+    void visitInterfaceDef(GroovySourceAST t, int visit);
+    void visitLabeledArg(GroovySourceAST t, int visit);
+    void visitLabeledStat(GroovySourceAST t, int visit);
+    void visitLand(GroovySourceAST t, int visit);
+    void visitLbrack(GroovySourceAST t, int visit);
+    void visitLcurly(GroovySourceAST t, int visit);
+    void visitLe(GroovySourceAST t, int visit);
+    void visitLetter(GroovySourceAST t, int visit);
+    void visitListConstructor(GroovySourceAST t, int visit);
+    void visitLiteralAny(GroovySourceAST t, int visit);
+    void visitLiteralAs(GroovySourceAST t, int visit);
+    void visitLiteralAssert(GroovySourceAST t, int visit);
+    void visitLiteralBoolean(GroovySourceAST t, int visit);
+    void visitLiteralBreak(GroovySourceAST t, int visit);
+    void visitLiteralByte(GroovySourceAST t, int visit);
+    void visitLiteralCase(GroovySourceAST t, int visit);
+    void visitLiteralCatch(GroovySourceAST t, int visit);
+    void visitLiteralChar(GroovySourceAST t, int visit);
+    void visitLiteralClass(GroovySourceAST t, int visit);
+    void visitLiteralContinue(GroovySourceAST t, int visit);
+    void visitLiteralDef(GroovySourceAST t, int visit);
+    void visitLiteralDefault(GroovySourceAST t, int visit);
+    void visitLiteralDouble(GroovySourceAST t, int visit);
+    void visitLiteralElse(GroovySourceAST t, int visit);
+    void visitLiteralEnum(GroovySourceAST t, int visit);
+    void visitLiteralExtends(GroovySourceAST t, int visit);
+    void visitLiteralFalse(GroovySourceAST t, int visit);
+    void visitLiteralFinally(GroovySourceAST t, int visit);
+    void visitLiteralFloat(GroovySourceAST t, int visit);
+    void visitLiteralFor(GroovySourceAST t, int visit);
+    void visitLiteralIf(GroovySourceAST t, int visit);
+    void visitLiteralImplements(GroovySourceAST t, int visit);
+    void visitLiteralImport(GroovySourceAST t, int visit);
+    void visitLiteralIn(GroovySourceAST t, int visit);
+    void visitLiteralInstanceof(GroovySourceAST t, int visit);
+    void visitLiteralInt(GroovySourceAST t, int visit);
+    void visitLiteralInterface(GroovySourceAST t, int visit);
+    void visitLiteralLong(GroovySourceAST t, int visit);
+    void visitLiteralNative(GroovySourceAST t, int visit);
+    void visitLiteralNew(GroovySourceAST t, int visit);
+    void visitLiteralNull(GroovySourceAST t, int visit);
+    void visitLiteralPackage(GroovySourceAST t, int visit);
+    void visitLiteralPrivate(GroovySourceAST t, int visit);
+    void visitLiteralProtected(GroovySourceAST t, int visit);
+    void visitLiteralPublic(GroovySourceAST t, int visit);
+    void visitLiteralReturn(GroovySourceAST t, int visit);
+    void visitLiteralShort(GroovySourceAST t, int visit);
+    void visitLiteralStatic(GroovySourceAST t, int visit);
+    void visitLiteralSuper(GroovySourceAST t, int visit);
+    void visitLiteralSwitch(GroovySourceAST t, int visit);
+    void visitLiteralSynchronized(GroovySourceAST t, int visit);
+    void visitLiteralThis(GroovySourceAST t, int visit);
+    void visitLiteralThreadsafe(GroovySourceAST t, int visit);
+    void visitLiteralThrow(GroovySourceAST t, int visit);
+    void visitLiteralThrows(GroovySourceAST t, int visit);
+    void visitLiteralTransient(GroovySourceAST t, int visit);
+    void visitLiteralTrue(GroovySourceAST t, int visit);
+    void visitLiteralTry(GroovySourceAST t, int visit);
+    void visitLiteralVoid(GroovySourceAST t, int visit);
+    void visitLiteralVolatile(GroovySourceAST t, int visit);
+    void visitLiteralWhile(GroovySourceAST t, int visit);
+    void visitLiteralWith(GroovySourceAST t, int visit);
+    void visitLnot(GroovySourceAST t, int visit);
+    void visitLor(GroovySourceAST t, int visit);
+    void visitLparen(GroovySourceAST t, int visit);
+    void visitLt(GroovySourceAST t, int visit);
+    void visitMapConstructor(GroovySourceAST t, int visit);
+    void visitMemberPointer(GroovySourceAST t, int visit);
+    void visitMethodCall(GroovySourceAST t, int visit);
+    void visitMethodDef(GroovySourceAST t, int visit);
+    void visitMinus(GroovySourceAST t, int visit);
+    void visitMinusAssign(GroovySourceAST t, int visit);
+    void visitMlComment(GroovySourceAST t, int visit);
+    void visitMod(GroovySourceAST t, int visit);
+    void visitModifiers(GroovySourceAST t, int visit);
+    void visitModAssign(GroovySourceAST t, int visit);
+    void visitNls(GroovySourceAST t, int visit);
+    void visitNotEqual(GroovySourceAST t, int visit);
+    void visitNullTreeLookahead(GroovySourceAST t, int visit);
+    void visitNumBigDecimal(GroovySourceAST t, int visit);
+    void visitNumBigInt(GroovySourceAST t, int visit);
+    void visitNumDouble(GroovySourceAST t, int visit);
+    void visitNumFloat(GroovySourceAST t, int visit);
+    void visitNumInt(GroovySourceAST t, int visit);
+    void visitNumLong(GroovySourceAST t, int visit);
+    void visitObjblock(GroovySourceAST t, int visit);
+    void visitOneNl(GroovySourceAST t, int visit);
+    void visitOptionalDot(GroovySourceAST t, int visit);
+    void visitPackageDef(GroovySourceAST t, int visit);
+    void visitParameters(GroovySourceAST t, int visit);
+    void visitParameterDef(GroovySourceAST t, int visit);
+    void visitPlus(GroovySourceAST t, int visit);
+    void visitPlusAssign(GroovySourceAST t, int visit);
+    void visitPostDec(GroovySourceAST t, int visit);
+    void visitPostInc(GroovySourceAST t, int visit);
+    void visitQuestion(GroovySourceAST t, int visit);
+    void visitRangeExclusive(GroovySourceAST t, int visit);
+    void visitRangeInclusive(GroovySourceAST t, int visit);
+    void visitRbrack(GroovySourceAST t, int visit);
+    void visitRcurly(GroovySourceAST t, int visit);
+    void visitRegexpCtorEnd(GroovySourceAST t, int visit);
+    void visitRegexpLiteral(GroovySourceAST t, int visit);
+    void visitRegexpSymbol(GroovySourceAST t, int visit);
+    void visitRegexFind(GroovySourceAST t, int visit);
+    void visitRegexMatch(GroovySourceAST t, int visit);
+    void visitRparen(GroovySourceAST t, int visit);
+    void visitScopeEscape(GroovySourceAST t, int visit);
+    void visitSelectSlot(GroovySourceAST t, int visit);
+    void visitSemi(GroovySourceAST t, int visit);
+    void visitShComment(GroovySourceAST t, int visit);
+    void visitSl(GroovySourceAST t, int visit);
+    void visitSlist(GroovySourceAST t, int visit);
+    void visitSlAssign(GroovySourceAST t, int visit);
+    void visitSlComment(GroovySourceAST t, int visit);
+    void visitSpreadArg(GroovySourceAST t, int visit);
+    void visitSpreadDot(GroovySourceAST t, int visit);
+    void visitSpreadMapArg(GroovySourceAST t, int visit);
+    void visitSr(GroovySourceAST t, int visit);
+    void visitSrAssign(GroovySourceAST t, int visit);
+    void visitStar(GroovySourceAST t, int visit);
+    void visitStarAssign(GroovySourceAST t, int visit);
+    void visitStarStar(GroovySourceAST t, int visit);
+    void visitStarStarAssign(GroovySourceAST t, int visit);
+    void visitStaticImport(GroovySourceAST t, int visit);
+    void visitStaticInit(GroovySourceAST t, int visit);
+    void visitStrictfp(GroovySourceAST t, int visit);
+    void visitStringCh(GroovySourceAST t, int visit);
+    void visitStringConstructor(GroovySourceAST t, int visit);
+    void visitStringCtorEnd(GroovySourceAST t, int visit);
+    void visitStringCtorMiddle(GroovySourceAST t, int visit);
+    void visitStringCtorStart(GroovySourceAST t, int visit);
+    void visitStringLiteral(GroovySourceAST t, int visit);
+    void visitStringNl(GroovySourceAST t, int visit);
+    void visitSuperCtorCall(GroovySourceAST t, int visit);
+    void visitTripleDot(GroovySourceAST t, int visit);
+    void visitType(GroovySourceAST t, int visit);
+    void visitTypecast(GroovySourceAST t, int visit);
+    void visitTypeArgument(GroovySourceAST t, int visit);
+    void visitTypeArguments(GroovySourceAST t, int visit);
+    void visitTypeLowerBounds(GroovySourceAST t, int visit);
+    void visitTypeParameter(GroovySourceAST t, int visit);
+    void visitTypeParameters(GroovySourceAST t, int visit);
+    void visitTypeUpperBounds(GroovySourceAST t, int visit);
+    void visitUnaryMinus(GroovySourceAST t, int visit);
+    void visitUnaryPlus(GroovySourceAST t, int visit);
+    void visitUnusedConst(GroovySourceAST t, int visit);
+    void visitUnusedDo(GroovySourceAST t, int visit);
+    void visitUnusedGoto(GroovySourceAST t, int visit);
+    void visitVariableDef(GroovySourceAST t, int visit);
+    void visitVariableParameterDef(GroovySourceAST t, int visit);
+    void visitVocab(GroovySourceAST t, int visit);
+    void visitWildcardType(GroovySourceAST t, int visit);
+    void visitWs(GroovySourceAST t, int visit);
+
+    void visitDefault(GroovySourceAST t,int visit);
+    void tearDown();
+
+    void push(GroovySourceAST t);
+    GroovySourceAST pop();
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/VisitorAdapter.java b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/VisitorAdapter.java
new file mode 100644
index 0000000..6282842
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/antlr/treewalker/VisitorAdapter.java
@@ -0,0 +1,272 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr.treewalker;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+
+
+/**
+ * A default implementation of all visitor methods.
+ * If you extend this class, any un-overriden visit methods will
+ * call visitDefault.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+public class VisitorAdapter implements Visitor {
+    public void setUp() {}
+    public void visitAbstract(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAnnotation(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAnnotations(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAnnotationArrayInit(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAnnotationDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAnnotationFieldDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAnnotationMemberValuePair(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitArrayDeclarator(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAt(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBand(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBandAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBigSuffix(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBlock(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBnot(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBor(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBorAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBsr(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBsrAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBxor(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBxorAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitCaseGroup(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitClassDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitClosedBlock(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitClosureOp(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitColon(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitComma(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitCompareTo(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitCtorCall(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitCtorIdent(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitDec(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitDigit(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitDiv(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitDivAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitDollar(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitDot(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitDynamicMember(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitElist(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitEmptyStat(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitEnumConstantDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitEnumDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitEof(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitEqual(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitEsc(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitExponent(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitExpr(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitExtendsClause(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitFinal(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitFloatSuffix(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitForCondition(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitForEachClause(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitForInit(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitForInIterable(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitForIterator(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitGe(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitGt(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitHexDigit(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitIdent(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitImplementsClause(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitImplicitParameters(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitImport(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitInc(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitIndexOp(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitInstanceInit(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitInterfaceDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLabeledArg(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLabeledStat(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLand(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLbrack(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLcurly(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLe(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLetter(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitListConstructor(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralAny(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralAs(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralAssert(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralBoolean(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralBreak(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralByte(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralCase(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralCatch(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralChar(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralClass(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralContinue(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralDefault(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralDouble(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralElse(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralEnum(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralExtends(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralFalse(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralFinally(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralFloat(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralFor(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralIf(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralImplements(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralImport(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralIn(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralInstanceof(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralInt(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralInterface(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralLong(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralNative(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralNew(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralNull(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralPackage(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralPrivate(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralProtected(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralPublic(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralReturn(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralShort(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralStatic(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralSuper(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralSwitch(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralSynchronized(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralThis(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralThreadsafe(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralThrow(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralThrows(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralTransient(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralTrue(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralTry(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralVoid(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralVolatile(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralWhile(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralWith(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLnot(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLor(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLparen(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLt(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMapConstructor(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMemberPointer(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMethodCall(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMethodDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMinus(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMinusAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMlComment(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMod(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitModifiers(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitModAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNls(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNotEqual(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNullTreeLookahead(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNumBigDecimal(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNumBigInt(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNumDouble(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNumFloat(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNumInt(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNumLong(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitObjblock(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitOneNl(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitOptionalDot(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitPackageDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitParameters(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitParameterDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitPlus(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitPlusAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitPostDec(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitPostInc(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitQuestion(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRangeExclusive(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRangeInclusive(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRbrack(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRcurly(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRegexpCtorEnd(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRegexpLiteral(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRegexpSymbol(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRegexFind(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRegexMatch(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRparen(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitScopeEscape(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSelectSlot(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSemi(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitShComment(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSl(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSlist(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSlAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSlComment(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSpreadArg(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSpreadDot(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSpreadMapArg(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSr(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSrAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStar(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStarAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStarStar(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStarStarAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStaticImport(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStaticInit(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStrictfp(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStringCh(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStringConstructor(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStringCtorEnd(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStringCtorMiddle(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStringCtorStart(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStringLiteral(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStringNl(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSuperCtorCall(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTripleDot(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitType(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTypecast(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTypeArgument(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTypeArguments(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTypeLowerBounds(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTypeParameter(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTypeParameters(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTypeUpperBounds(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitUnaryMinus(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitUnaryPlus(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitUnusedConst(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitUnusedDo(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitUnusedGoto(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitVariableDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitVariableParameterDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitVocab(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitWildcardType(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitWs(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+
+    public void visitDefault(GroovySourceAST t,int visit) {}
+    public void tearDown() {}
+
+    public void push(GroovySourceAST t) {}
+    public GroovySourceAST pop() {return null;}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/ASTNode.java b/groovy-core/src/main/org/codehaus/groovy/ast/ASTNode.java
new file mode 100644
index 0000000..9afbf19
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/ASTNode.java
@@ -0,0 +1,115 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+
+/**
+ * Base class for any AST node
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ASTNode {
+
+    private int lineNumber = -1;
+    private int columnNumber = -1;
+    private int lastLineNumber = -1;
+    private int lastColumnNumber = -1;
+
+    public void visit(GroovyCodeVisitor visitor) {
+        throw new RuntimeException("No visit() method implemented for class: " + getClass().getName());
+    }
+
+    public String getText() {
+        return "<not implemented yet for class: " + getClass().getName() + ">";
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public void setLineNumber(int lineNumber) {
+        this.lineNumber = lineNumber;
+    }
+
+    public int getColumnNumber() {
+        return columnNumber;
+    }
+
+    public void setColumnNumber(int columnNumber) {
+        this.columnNumber = columnNumber;
+    }
+
+    public int getLastLineNumber() {
+        return lastLineNumber;
+    }
+
+    public void setLastLineNumber(int lastLineNumber) {
+        this.lastLineNumber = lastLineNumber;
+    }
+
+    public int getLastColumnNumber() {
+        return lastColumnNumber;
+    }
+
+    public void setLastColumnNumber(int lastColumnNumber) {
+        this.lastColumnNumber = lastColumnNumber;
+    }
+    
+    /**
+     * Sets the source position using another ASTNode.
+     * The sourcePosition consists of a line/column pair for
+     * the start and a line/column pair for the end of the
+     * expression or statement 
+     * 
+     */
+    public void setSourcePosition(ASTNode node) {
+        this.columnNumber = node.getColumnNumber();
+        this.lastLineNumber = node.getLastLineNumber();
+        this.lastColumnNumber = node.getLastColumnNumber();
+        this.lineNumber = node.getLineNumber();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/AnnotatedNode.java b/groovy-core/src/main/org/codehaus/groovy/ast/AnnotatedNode.java
new file mode 100644
index 0000000..bcc18dc
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/AnnotatedNode.java
@@ -0,0 +1,130 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Base class for any AST node which is capable of being annotationed
+ *
+ * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
+ * @version $Revision$
+ */
+public class AnnotatedNode extends ASTNode {
+    private Map annotations = new HashMap();
+    private Map annotationClasses = new HashMap();
+    private boolean synthetic;
+    ClassNode declaringClass;
+
+    public AnnotatedNode() {
+    }
+
+    public Map getAnnotations() {
+        return annotations;
+    }
+
+    public AnnotationNode getAnnotations(String name) {
+        return (AnnotationNode) annotations.get(name);
+    }
+    
+    public ClassNode getAnnotationClass(String name) {
+        return (ClassNode) annotationClasses.get(name);
+    }
+
+    public void addAnnotation(String name, AnnotationNode value) {
+        annotationClasses.put(name,value.getClassNode());
+        AnnotationNode oldValue = (AnnotationNode) annotations.get(name);
+
+        // TODO can we support many annotations of the same name?
+        if (oldValue == null) {
+            annotations.put(name, value);
+        }
+        else {
+            List list = null;
+            if (oldValue instanceof List) {
+                list = (List) oldValue;
+            }
+            else {
+                list = new ArrayList();
+                list.add(oldValue);
+                annotations.put(name, list);
+            }
+            list.add(value);
+        }
+    }
+
+    public void addAnnotations(List annotations) {
+        for (Iterator iter = annotations.iterator(); iter.hasNext();) {
+            AnnotationNode node = (AnnotationNode) iter.next();
+            addAnnotation(node.getClassNode().getName(), node);
+        }
+
+    }
+
+    public boolean isSynthetic() {
+        return synthetic;
+    }
+
+    public void setSynthetic(boolean synthetic) {
+        this.synthetic = synthetic;
+    }
+
+    public ClassNode getDeclaringClass() {
+        return declaringClass;
+    }
+
+    /**
+     * @param declaringClass The declaringClass to set.
+     */
+    public void setDeclaringClass(ClassNode declaringClass) {
+        this.declaringClass = declaringClass;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/AnnotationNode.java b/groovy-core/src/main/org/codehaus/groovy/ast/AnnotationNode.java
new file mode 100644
index 0000000..de2e9bd
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/AnnotationNode.java
@@ -0,0 +1,109 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+import org.codehaus.groovy.ast.expr.Expression;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Represents an annotation which can be attached to interfaces, classes, methods and fields.
+ * 
+ * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
+ * @version $Revision$
+ */
+public class AnnotationNode extends ASTNode {
+    private ClassNode classNode;
+    private Map members = new HashMap();
+
+    public AnnotationNode(ClassNode classNode) {
+        this.classNode = classNode;
+    }
+
+    public ClassNode getClassNode() {
+        return classNode;
+    }
+
+    public Map getMembers() {
+        return members;
+    }
+    
+    public Expression getMember(String name) {
+        return (Expression) members.get(name);
+    }
+    
+    public void addMember(String name, Expression value) {
+        Expression oldValue = (Expression) members.get(name);
+        if (oldValue == null) {
+            members.put(name, value);
+        }
+        else {
+            List list = null;
+            if (oldValue instanceof List) {
+                list = (List) oldValue;
+            }
+            else {
+                list = new ArrayList();
+                list.add(oldValue);
+                members.put(name, list);
+            }
+            list.add(value);
+        }
+    }
+
+    public void setMember(String name, Expression value) {
+        members.put(name, value);
+    }
+    
+    public boolean isBuiltIn(){
+        return false;
+    }
+    
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java b/groovy-core/src/main/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java
new file mode 100644
index 0000000..b95af4d
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java
@@ -0,0 +1,174 @@
+/*
+ * ClassCodeVisitorSupport.java created on 14.12.2005
+ *
+ */
+package org.codehaus.groovy.ast;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.stmt.AssertStatement;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.BreakStatement;
+import org.codehaus.groovy.ast.stmt.CaseStatement;
+import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.stmt.ContinueStatement;
+import org.codehaus.groovy.ast.stmt.DoWhileStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.stmt.SwitchStatement;
+import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
+import org.codehaus.groovy.ast.stmt.ThrowStatement;
+import org.codehaus.groovy.ast.stmt.TryCatchStatement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.syntax.SyntaxException;
+
+public abstract class ClassCodeVisitorSupport extends CodeVisitorSupport implements GroovyClassVisitor {
+    
+    public void visitClass(ClassNode node) {
+        visitAnnotations(node);
+        node.visitContents(this);
+        List list = node.getObjectInitializerStatements();
+        for (Iterator iter = list.iterator(); iter.hasNext();) {
+            Statement element = (Statement) iter.next();
+            element.visit(this);
+        }
+    }
+    
+    public void visitAnnotations(AnnotatedNode node) {
+        
+    }
+    
+    protected void visitClassCodeContainer(Statement code) {
+        if (code != null) code.visit(this);
+    }
+
+    protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
+        Statement code = node.getCode();
+        visitClassCodeContainer(code);
+    }
+    
+    public void visitConstructor(ConstructorNode node) {
+        visitConstructorOrMethod(node,true);        
+    }
+
+    public void visitMethod(MethodNode node) {
+        visitConstructorOrMethod(node,false);
+    }
+
+    public void visitField(FieldNode node) {
+        visitAnnotations(node);
+        Expression init = node.getInitialExpression();
+        if (init != null) init.visit(this);
+    }
+    
+    public void visitProperty(PropertyNode node) {
+        Statement statement = node.getGetterBlock();
+        visitClassCodeContainer(statement);
+        
+        statement = node.getSetterBlock();
+        visitClassCodeContainer(statement);
+        
+        Expression init = node.getInitialExpression();
+        if (init != null) init.visit(this);
+    }
+
+    protected void addError(String msg, ASTNode expr) {
+        int line = expr.getLineNumber();
+        int col = expr.getColumnNumber();
+        SourceUnit source = getSourceUnit();
+        source.getErrorCollector().addErrorAndContinue(
+          new SyntaxErrorMessage(new SyntaxException(msg + '\n', line, col), source)
+        );
+    }
+    
+    abstract protected SourceUnit getSourceUnit();
+    
+    protected void visitStatement(Statement statement) {}
+    
+    public void visitAssertStatement(AssertStatement statement) {
+        visitStatement(statement);
+        super.visitAssertStatement(statement);
+    }
+    
+    public void visitBlockStatement(BlockStatement block) {
+        visitStatement(block);
+        super.visitBlockStatement(block);
+    }
+    
+    public void visitBreakStatement(BreakStatement statement) {
+        visitStatement(statement);
+        super.visitBreakStatement(statement);
+    }
+    
+    public void visitCaseStatement(CaseStatement statement) {
+        visitStatement(statement);
+        super.visitCaseStatement(statement);
+    }
+    
+    public void visitCatchStatement(CatchStatement statement) {
+        visitStatement(statement);
+        super.visitCatchStatement(statement);
+    }
+    
+    public void visitContinueStatement(ContinueStatement statement) {
+        visitStatement(statement);
+        super.visitContinueStatement(statement);
+    }
+    
+    public void visitDoWhileLoop(DoWhileStatement loop) {
+        visitStatement(loop);
+        super.visitDoWhileLoop(loop);
+    }
+    
+    public void visitExpressionStatement(ExpressionStatement statement) {
+        visitStatement(statement);
+        super.visitExpressionStatement(statement);
+    }
+    
+    public void visitForLoop(ForStatement forLoop) {
+        visitStatement(forLoop);
+        super.visitForLoop(forLoop);
+    }
+    
+    public void visitIfElse(IfStatement ifElse) {
+        visitStatement(ifElse);
+        super.visitIfElse(ifElse);
+    }
+    
+    public void visitReturnStatement(ReturnStatement statement) {
+        visitStatement(statement);
+        super.visitReturnStatement(statement);
+    }
+    
+    public void visitSwitch(SwitchStatement statement) {
+        visitStatement(statement);
+        super.visitSwitch(statement);
+    }
+    
+    public void visitSynchronizedStatement(SynchronizedStatement statement) {
+        visitStatement(statement);
+        super.visitSynchronizedStatement(statement);
+    }
+    
+    public void visitThrowStatement(ThrowStatement statement) {
+        visitStatement(statement);
+        super.visitThrowStatement(statement);
+    }
+    
+    public void visitTryCatchFinally(TryCatchStatement statement) {
+        visitStatement(statement);
+        super.visitTryCatchFinally(statement);
+    }
+    
+    public void visitWhileLoop(WhileStatement loop) {
+        visitStatement(loop);
+        super.visitWhileLoop(loop);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/ClassHelper.java b/groovy-core/src/main/org/codehaus/groovy/ast/ClassHelper.java
new file mode 100644
index 0000000..b38a3ef
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/ClassHelper.java
@@ -0,0 +1,292 @@
+/*
+$Id$ created on 25.10.2005
+
+Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package org.codehaus.groovy.ast;
+
+import groovy.lang.Closure;
+import groovy.lang.GString;
+import groovy.lang.MetaClass;
+import groovy.lang.Range;
+import groovy.lang.Reference;
+import groovy.lang.Script;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.objectweb.asm.Opcodes;
+
+/**
+ * This class is a Helper for ClassNode and classes handling ClassNodes.
+ * It does contain a set of predefined ClassNodes for the most used 
+ * types and some code for cached ClassNode creation and basic 
+ * ClassNode handling 
+ * 
+ * @author Jochen Theodorou
+ */
+public class ClassHelper {
+    
+
+    private static String[] names = new String[] {
+        boolean.class.getName(),    char.class.getName(), 
+        byte.class.getName(),       short.class.getName(),
+        int.class.getName(),        long.class.getName(),
+        double.class.getName(),     float.class.getName(),
+        Object.class.getName(),     Void.TYPE.getName(),
+        Closure.class.getName(),    GString.class.getName(),
+        List.class.getName(),       Map.class.getName(),
+        Range.class.getName(),      Pattern.class.getName(),
+        Script.class.getName(),     String.class.getName(),
+        Boolean.class.getName(),    Character.class.getName(),
+        Byte.class.getName(),       Short.class.getName(),
+        Integer.class.getName(),    Long.class.getName(),
+        Double.class.getName(),     Float.class.getName(),
+        BigDecimal.class.getName(), BigInteger.class.getName(),
+        Void.class.getName(),       Reference.class.getName(),
+        Class.class.getName(),      MetaClass.class.getName()
+    };
+    
+    private static Class[] classes = new Class[] {
+        Object.class, Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE,
+        Integer.TYPE, Long.TYPE, Double.TYPE, Float.TYPE, Void.TYPE,
+        Closure.class, GString.class, List.class, Map.class, Range.class,
+        Pattern.class, Script.class, String.class,  Boolean.class, 
+        Character.class, Byte.class, Short.class, Integer.class, Long.class,
+        Double.class, Float.class, BigDecimal.class, BigInteger.class, Void.class,
+        Reference.class, Class.class, MetaClass.class
+    };
+    
+    public static final ClassNode 
+        DYNAMIC_TYPE = new ClassNode(Object.class),  OBJECT_TYPE = DYNAMIC_TYPE,
+        VOID_TYPE = new ClassNode(Void.TYPE),        CLOSURE_TYPE = new ClassNode(Closure.class),
+        GSTRING_TYPE = new ClassNode(GString.class), LIST_TYPE = new ClassNode(List.class),
+        MAP_TYPE = new ClassNode(Map.class),         RANGE_TYPE = new ClassNode(Range.class),
+        PATTERN_TYPE = new ClassNode(Pattern.class), STRING_TYPE = new ClassNode(String.class),
+        SCRIPT_TYPE = new ClassNode(Script.class),   REFERENCE_TYPE = new ClassNode(Reference.class),
+        
+        boolean_TYPE = new ClassNode(boolean.class),     char_TYPE = new ClassNode(char.class),
+        byte_TYPE = new ClassNode(byte.class),           int_TYPE = new ClassNode(int.class),
+        long_TYPE = new ClassNode(long.class),           short_TYPE = new ClassNode(short.class),
+        double_TYPE = new ClassNode(double.class),       float_TYPE = new ClassNode(float.class),
+        Byte_TYPE = new ClassNode(Byte.class),           Short_TYPE = new ClassNode(Short.class),
+        Integer_TYPE = new ClassNode(Integer.class),     Long_TYPE = new ClassNode(Long.class),
+        Character_TYPE = new ClassNode(Character.class), Float_TYPE = new ClassNode(Float.class),
+        Double_TYPE = new ClassNode(Double.class),       Boolean_TYPE = new ClassNode(Boolean.class),
+        BigInteger_TYPE =  new ClassNode(java.math.BigInteger.class),
+        BigDecimal_TYPE = new ClassNode(java.math.BigDecimal.class),
+        void_WRAPPER_TYPE = new ClassNode(Void.class),   
+        
+        CLASS_Type = new ClassNode(Class.class),        METACLASS_TYPE = new ClassNode(MetaClass.class);
+        
+    
+    private static ClassNode[] types = new ClassNode[] {
+        OBJECT_TYPE,
+        boolean_TYPE, char_TYPE, byte_TYPE, short_TYPE,
+        int_TYPE, long_TYPE, double_TYPE, float_TYPE,
+        VOID_TYPE, CLOSURE_TYPE, GSTRING_TYPE,
+        LIST_TYPE, MAP_TYPE, RANGE_TYPE, PATTERN_TYPE,
+        SCRIPT_TYPE, STRING_TYPE, Boolean_TYPE, Character_TYPE,
+        Byte_TYPE, Short_TYPE, Integer_TYPE, Long_TYPE,
+        Double_TYPE, Float_TYPE, BigDecimal_TYPE, BigInteger_TYPE, 
+        void_WRAPPER_TYPE, REFERENCE_TYPE, CLASS_Type, METACLASS_TYPE
+    };
+
+    
+    private static ClassNode[] numbers = new ClassNode[] {
+        char_TYPE, byte_TYPE, short_TYPE, int_TYPE, long_TYPE, 
+        double_TYPE, float_TYPE, Short_TYPE, Byte_TYPE, Character_TYPE,
+        Integer_TYPE, Float_TYPE, Long_TYPE, Double_TYPE, BigInteger_TYPE,
+        BigDecimal_TYPE
+    };
+
+    protected static final ClassNode[] EMPTY_TYPE_ARRAY = {};
+    
+    public static final String OBJECT = "java.lang.Object";    
+    
+    
+    /**
+     * Creates an array of ClassNodes using an array of classes.
+     * For each of the given classes a new ClassNode will be 
+     * created
+     * @see #make(Class)
+     * @param classes an array of classes used to create the ClassNodes
+     * @return an array of ClassNodes
+     */
+    public static ClassNode[] make(Class[] classes) {
+    	ClassNode[] cns = new ClassNode[classes.length];
+    	for (int i=0; i<cns.length; i++) {
+    		cns[i] = make(classes[i]);
+    	}
+    	
+    	return cns;
+    }
+    
+    /**
+     * Creates a ClassNode using a given class.
+     * A new ClassNode object is only created if the class
+     * is not one of the predefined ones
+     * 
+     * @param c class used to created the ClassNode
+     * @return ClassNode instance created from the given class
+     */
+    public static ClassNode make(Class c) {
+        for (int i=0; i<classes.length; i++) {
+            if (c==classes[i]) return types[i];
+        }
+        if (c.isArray()) {
+            ClassNode cn = make(c.getComponentType());
+            return cn.makeArray();
+        }
+        ClassNode t = new ClassNode(c);
+        return t;
+    }
+    
+    /**
+     * Creates a ClassNode using a given class.
+     * Unlike make(String) this method will not use the cache
+     * to create the ClassNode. This means the ClassNode created
+     * from this method using the same name will have a different
+     * references
+     * 
+     * @see #make(String)
+     * @param name of the class the ClassNode is representing
+     */
+    public static ClassNode makeWithoutCaching(String name) { 
+        ClassNode cn = new ClassNode(name,Opcodes.ACC_PUBLIC,OBJECT_TYPE);
+        cn.isPrimaryNode = false;
+        return cn;
+    }
+    
+    /**
+     * Creates a ClassNode using a given class.
+     * If the name is one of the predefined ClassNodes then the 
+     * corresponding ClassNode instance will be returned. If the
+     * is null of of length 0 the dynamic type is returned
+     * 
+     * @param name of the class the ClassNode is representing
+     */
+    public static ClassNode make(String name) {
+        if (name == null || name.length() == 0) return DYNAMIC_TYPE;
+        
+        for (int i=0; i<classes.length; i++) {
+            String cname = classes[i].getName();
+            if (name.equals(cname)) return types[i];
+        }        
+        return makeWithoutCaching(name);
+    }
+    
+    /**
+     * Creates a ClassNode containing the wrapper of a ClassNode 
+     * of primitive type. Any ClassNode representing a primitive
+     * type should be created using the predefined types used in
+     * class. The method will check the parameter for known 
+     * references of ClassNode representing a primitive type. If
+     * Reference is found, then a ClassNode will be contained that
+     * represents the wrapper class. For exmaple for boolean, the 
+     * wrapper class is java.lang.Boolean.
+     * 
+     * If the parameter is no primitve type, the redirected 
+     * ClassNode will be returned 
+     *   
+     * @see #make(Class)
+     * @see #make(String)
+     * @param cn the ClassNode containing a possible primitive type
+     */
+    public static ClassNode getWrapper(ClassNode cn) {
+        cn = cn.redirect();
+        if (!isPrimitiveType(cn)) return cn;
+        if (cn==boolean_TYPE) {
+            return Boolean_TYPE;
+        } else if (cn==byte_TYPE) {
+            return Byte_TYPE;
+        } else if (cn==char_TYPE) {
+            return Character_TYPE;
+        } else if (cn==short_TYPE) {
+            return Short_TYPE;
+        } else if (cn==int_TYPE) {
+            return Integer_TYPE;
+        } else if (cn==long_TYPE) {
+            return Long_TYPE;
+        } else if (cn==float_TYPE) {
+            return Float_TYPE;
+        } else if (cn==double_TYPE) {
+            return Double_TYPE;
+        } else if (cn==VOID_TYPE) {
+        	return void_WRAPPER_TYPE;
+        }
+        else {
+            return cn;
+        }
+    }
+    
+    /**
+     * Test to determine if a ClasNode is a primitve type. 
+     * Note: this only works for ClassNodes created using a
+     * predefined ClassNode
+     * 
+     * @see #make(Class)
+     * @see #make(String)
+     * @param cn the ClassNode containing a possible primitive type
+     * @return true if the ClassNode is a primitve type
+     */
+    public static boolean isPrimitiveType(ClassNode cn) {
+        return  cn == boolean_TYPE ||
+                cn == char_TYPE ||
+                cn == byte_TYPE ||
+                cn == short_TYPE ||
+                cn == int_TYPE ||
+                cn == long_TYPE ||
+                cn == float_TYPE ||
+                cn == double_TYPE ||
+                cn == VOID_TYPE;
+    }
+
+    public static ClassNode makeReference() {
+        return make(Reference.class);
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/ClassNode.java b/groovy-core/src/main/org/codehaus/groovy/ast/ClassNode.java
new file mode 100644
index 0000000..cfb46ce
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/ClassNode.java
@@ -0,0 +1,956 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package org.codehaus.groovy.ast;
+
+import groovy.lang.GroovyObject;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.EmptyStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.objectweb.asm.Opcodes;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents a class in the AST.<br/>
+ * A ClassNode should be created using the methods in ClassHelper. 
+ * This ClassNode may be used to represent a class declaration or
+ * any other type. This class uses a proxy meschanism allowing to
+ * create a class for a plain name at ast creation time. In another 
+ * phase of the compiler the real ClassNode for the plain name may be
+ * found. To avoid the need of exchanging this ClassNode with an 
+ * instance of the correct ClassNode the correct ClassNode is set as 
+ * redirect. All method calls are then redirected to that ClassNode.
+ * <br>
+ * Note: the proxy mechanism is only allowed for classes being marked
+ * as primary ClassNode which means they represent no actual class. 
+ * The redirect itself can be any type of ClassNode
+ *
+ * @see org.codehaus.groovy.ast.ClassHelper
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Jochen Theodorou
+ * @version $Revision$
+ */
+public class ClassNode extends AnnotatedNode implements Opcodes {
+
+	public static ClassNode[] EMPTY_ARRAY = new ClassNode[0];
+    
+    public static ClassNode THIS = new ClassNode(Object.class);
+    public static ClassNode SUPER = new ClassNode(Object.class);
+    
+    private String name;
+    private int modifiers;
+    private ClassNode[] interfaces;
+    private MixinNode[] mixins;
+    private List constructors = new ArrayList();
+    private List  objectInitializers = new ArrayList();
+    private List methods = new ArrayList();
+    private List fields = new ArrayList();
+    private List properties = new ArrayList();
+    private Map fieldIndex = new HashMap();
+    private ModuleNode module;
+    private CompileUnit compileUnit;
+    private boolean staticClass = false;
+    private boolean scriptBody = false;
+    private boolean script;
+    private ClassNode superClass;
+    boolean isPrimaryNode;
+    
+    // use this to synchronize access for the lazy intit
+    protected Object lazyInitLock = new Object();
+
+    // clazz!=null when resolved
+    protected Class clazz;
+    // only false when this classNode is constructed from a class 
+    private boolean lazyInitDone=true;
+    // not null if if the ClassNode is an array 
+    private ClassNode componentType = null;
+    // if not null this instance is handled as proxy 
+    // for the redirect
+    private ClassNode redirect=null; 
+    
+    /**
+     * Returns the ClassNode this ClassNode is redirecting to.
+     */
+    protected ClassNode redirect(){
+        if (redirect==null) return this;
+        return redirect.redirect();
+    }
+    
+    /**
+     * Sets this instance as proxy for the given ClassNode. 
+     * @param cn the class to redirect to. If set to null the redirect will be removed
+     */
+    public void setRedirect(ClassNode cn) {
+        if (isPrimaryNode) throw new GroovyBugError("tried to set a redirect for a primary ClassNode ("+getName()+"->"+cn.getName()+").");
+        if (cn!=null) cn = cn.redirect();
+        redirect = cn;
+    }
+    
+    /**
+     * Returns a ClassNode representing an array of the class
+     * represented by this ClassNode
+     */
+    public ClassNode makeArray() {
+        if (redirect!=null) return redirect().makeArray();
+        ClassNode cn;
+        if (clazz!=null) {
+            Class ret = Array.newInstance(clazz,0).getClass();
+            // don't use the ClassHelper here!
+            cn = new ClassNode(ret,this);
+        } else {
+            cn = new ClassNode(this);
+        }
+        return cn;
+    }
+    
+    /**
+     * Returns if this instance is a primary ClassNode
+     */
+    public boolean isPrimaryClassNode(){
+    	return redirect().isPrimaryNode || (componentType!= null && componentType.isPrimaryClassNode());
+    }
+    
+    /**
+     * Constructor used by makeArray() if no real class is available
+     */
+    private ClassNode(ClassNode componentType) {
+        this(componentType.getName()+"[]", ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
+        this.componentType = componentType.redirect();
+        isPrimaryNode=false;
+    }
+    
+    /**
+     * Constructor used by makeArray() if a real class is available
+     */
+    private ClassNode(Class c, ClassNode componentType) {
+        this(c);
+        this.componentType = componentType;
+        isPrimaryNode=false;
+    }
+    
+    /**
+     * Creates a ClassNode from a real class. The resulting 
+     * ClassNode will be no primary ClassNode.
+     */
+    public ClassNode(Class c) {
+        this(c.getName(), c.getModifiers(), null, null ,MixinNode.EMPTY_ARRAY);
+        clazz=c;
+        lazyInitDone=false;
+        CompileUnit cu = getCompileUnit();
+        if (cu!=null) cu.addClass(this);
+        isPrimaryNode=false;
+    }    
+    
+    /**
+     * The complete class structure will be initialized only when really
+     * needed to avoid having too much objects during compilation
+     */
+    private void lazyClassInit() {       
+        synchronized (lazyInitLock) {
+            if (lazyInitDone) return;
+            
+            Field[] fields = clazz.getDeclaredFields();
+            for (int i=0;i<fields.length;i++){
+                addField(fields[i].getName(),fields[i].getModifiers(),this,null);
+            }
+            Method[] methods = clazz.getDeclaredMethods();
+            for (int i=0;i<methods.length;i++){
+                Method m = methods[i];
+                MethodNode mn = new MethodNode(m.getName(), m.getModifiers(), ClassHelper.make(m.getReturnType()), createParameters(m.getParameterTypes()), ClassHelper.make(m.getExceptionTypes()), null);
+                addMethod(mn);
+            }
+            Constructor[] constructors = clazz.getDeclaredConstructors();
+            for (int i=0;i<constructors.length;i++){
+                Constructor ctor = constructors[i];
+                addConstructor(ctor.getModifiers(),createParameters(ctor.getParameterTypes()),ClassHelper.make(ctor.getExceptionTypes()),null);
+            }
+            Class sc = clazz.getSuperclass();
+            if (sc!=null) superClass = ClassHelper.make(sc);
+            buildInterfaceTypes(clazz);       
+            lazyInitDone=true;
+        }
+    }
+    
+    private void buildInterfaceTypes(Class c) {
+        Class[] interfaces = c.getInterfaces();
+        ClassNode[] ret = new ClassNode[interfaces.length];
+        for (int i=0;i<interfaces.length;i++){
+            ret[i] = ClassHelper.make(interfaces[i]);
+        }
+        this.interfaces = ret;
+    }
+    
+    
+    // added to track the enclosing method for local inner classes
+    private MethodNode enclosingMethod = null;
+
+    public MethodNode getEnclosingMethod() {
+        return redirect().enclosingMethod;
+    }
+
+    public void setEnclosingMethod(MethodNode enclosingMethod) {
+        redirect().enclosingMethod = enclosingMethod;
+    }
+
+
+    /**
+     * @param name       is the full name of the class
+     * @param modifiers  the modifiers,
+     * @param superClass the base class name - use "java.lang.Object" if no direct
+     *                   base class
+     * @see org.objectweb.asm.Opcodes
+     */
+    public ClassNode(String name, int modifiers, ClassNode superClass) {
+        this(name, modifiers, superClass, ClassHelper.EMPTY_TYPE_ARRAY, MixinNode.EMPTY_ARRAY);
+    }
+
+    /**
+     * @param name       is the full name of the class
+     * @param modifiers  the modifiers,
+     * @param superClass the base class name - use "java.lang.Object" if no direct
+     *                   base class
+     * @see org.objectweb.asm.Opcodes
+     */
+    public ClassNode(String name, int modifiers, ClassNode superClass, ClassNode[] interfaces, MixinNode[] mixins) {
+        this.name = name;
+        this.modifiers = modifiers;
+        this.superClass = superClass;
+        this.interfaces = interfaces;
+        this.mixins = mixins;
+        isPrimaryNode = true;
+    }
+
+    
+    /**
+     * Sets the superclass of this ClassNode
+     */
+    public void setSuperClass(ClassNode superClass) {
+        redirect().superClass = superClass;
+    }
+
+    /**
+     * Returns a list containing FieldNode objects for
+     * each field in the class represented by this ClassNode
+     */
+    public List getFields() {
+        if (!lazyInitDone) {
+            lazyClassInit();
+        }
+        if (redirect!=null) return redirect().getFields();
+        return fields;
+    }
+
+    /**
+     * Returns an array of ClassNodes representing the
+     * interfaces the class implements
+     */
+    public ClassNode[] getInterfaces() {
+        if (!lazyInitDone) {
+            lazyClassInit();
+        }
+        if (redirect!=null) return redirect().getInterfaces();
+        return interfaces;
+    }
+
+    public MixinNode[] getMixins() {
+        return redirect().mixins;
+    }
+
+    /**
+     * Returns a list containing MethodNode objects for
+     * each method in the class represented by this ClassNode
+     */    
+    public List getMethods() {
+        if (!lazyInitDone) {
+            lazyClassInit();
+        }
+        if (redirect!=null) return redirect().getMethods();
+        return methods;
+    }
+
+    /**
+     * Returns a list containing MethodNode objects for
+     * each abstract method in the class represented by 
+     * this ClassNode
+     */   
+    public List getAbstractMethods() {
+        
+        HashSet abstractNodes = new HashSet();
+        // let us collect the abstract super classes and stop at the
+        // first non abstract super class. If such a class still 
+        // contains abstract methods, then loading that class will fail.
+        // No need to be extra carefull here for that.
+        ClassNode parent = this.redirect();
+        do {
+        	abstractNodes.add(parent);
+            ClassNode[] interfaces = parent.getInterfaces();
+            for (int i = 0; i < interfaces.length; i++) {
+                abstractNodes.add(interfaces[i].redirect());
+            }
+            parent = parent.getSuperClass().redirect();
+        } while (parent!=null && ((parent.getModifiers() & Opcodes.ACC_ABSTRACT) != 0));
+        
+        List result = new ArrayList();
+        for (Iterator methIt = getAllDeclaredMethods().iterator(); methIt.hasNext();) {
+            MethodNode method = (MethodNode) methIt.next();
+            // add only abstract methods from abtract classes that
+            // are not overwritten
+            if ( abstractNodes.contains(method.getDeclaringClass().redirect()) && 
+                 (method.getModifiers() & Opcodes.ACC_ABSTRACT) != 0
+               ) {
+                result.add(method);
+            }
+        }
+        if (result.size() == 0) {
+            return null;
+        }
+        else {
+            return result;
+        }
+    }
+
+    public List getAllDeclaredMethods() {
+        return new ArrayList(getDeclaredMethodsMap().values());
+    }
+
+
+    protected Map getDeclaredMethodsMap() {
+        // Start off with the methods from the superclass.
+        ClassNode parent = getSuperClass();
+        Map result = null;
+        if (parent != null) {
+            result = parent.getDeclaredMethodsMap();
+        }
+        else {
+            result = new HashMap();
+        }
+
+        // add in unimplemented abstract methods from the interfaces
+        ClassNode[] interfaces = getInterfaces();
+        for (int i = 0; i < interfaces.length; i++) {
+            ClassNode iface = interfaces[i];
+            Map ifaceMethodsMap = iface.getDeclaredMethodsMap();
+            for (Iterator iter = ifaceMethodsMap.keySet().iterator(); iter.hasNext();) {
+                String methSig = (String) iter.next();
+                if (!result.containsKey(methSig)) {
+                    MethodNode methNode = (MethodNode) ifaceMethodsMap.get(methSig);
+                    result.put(methSig, methNode);
+                }
+            }
+        }
+
+        // And add in the methods implemented in this class.
+        for (Iterator iter = getMethods().iterator(); iter.hasNext();) {
+            MethodNode method = (MethodNode) iter.next();
+            String sig = method.getTypeDescriptor();
+            result.put(sig, method);
+        }
+        return result;
+    }
+
+    public String getName() {
+        return redirect().name;
+    }
+    
+    public String setName(String name) {
+        return redirect().name=name;
+    }
+
+    public int getModifiers() {
+        return redirect().modifiers;
+    }
+
+    public List getProperties() {
+        return redirect().properties;
+    }
+
+    public List getDeclaredConstructors() {
+        if (!lazyInitDone) {
+            lazyClassInit();
+        }
+        return redirect().constructors;
+    }
+
+    public ModuleNode getModule() {
+        return redirect().module;
+    }
+
+    public void setModule(ModuleNode module) {
+        redirect().module = module;
+        if (module != null) {
+            redirect().compileUnit = module.getUnit();
+        }
+    }
+
+    public void addField(FieldNode node) {
+        node.setDeclaringClass(redirect());
+        node.setOwner(redirect());
+        redirect().fields.add(node);
+        redirect().fieldIndex.put(node.getName(), node);
+    }
+
+    public void addProperty(PropertyNode node) {
+        node.setDeclaringClass(redirect());
+        FieldNode field = node.getField();
+        addField(field);
+
+        redirect().properties.add(node);
+    }
+
+    public PropertyNode addProperty(String name,
+                                    int modifiers,
+                                    ClassNode type,
+                                    Expression initialValueExpression,
+                                    Statement getterBlock,
+                                    Statement setterBlock) {
+    	for (Iterator iter = getProperties().iterator(); iter.hasNext();) {
+			PropertyNode pn = (PropertyNode) iter.next();
+			if (pn.getName().equals(name)) return pn;
+		}
+        PropertyNode node =
+                new PropertyNode(name, modifiers, type, redirect(), initialValueExpression, getterBlock, setterBlock);
+        addProperty(node);
+        return node;
+    }
+
+    public void addConstructor(ConstructorNode node) {
+        node.setDeclaringClass(this);
+        redirect().constructors.add(node);
+    }
+
+    public ConstructorNode addConstructor(int modifiers, Parameter[] parameters, ClassNode[] exceptions, Statement code) {
+        ConstructorNode node = new ConstructorNode(modifiers, parameters, exceptions, code);
+        addConstructor(node);
+        return node;
+    }
+
+    public void addMethod(MethodNode node) {
+        node.setDeclaringClass(this);
+        redirect().methods.add(node);
+    }
+
+    /**
+     * IF a method with the given name and parameters is already defined then it is returned
+     * otherwise the given method is added to this node. This method is useful for
+     * default method adding like getProperty() or invokeMethod() where there may already
+     * be a method defined in a class and  so the default implementations should not be added
+     * if already present.
+     */
+    public MethodNode addMethod(String name,
+                                int modifiers,
+                                ClassNode returnType,
+                                Parameter[] parameters,
+                                ClassNode[] exceptions,
+                                Statement code) {
+        MethodNode other = getDeclaredMethod(name, parameters);
+        // lets not add duplicate methods
+        if (other != null) {
+            return other;
+        }
+        MethodNode node = new MethodNode(name, modifiers, returnType, parameters, exceptions, code);
+        addMethod(node);
+        return node;
+    }
+
+    /**
+     * Adds a synthetic method as part of the compilation process
+     */
+    public MethodNode addSyntheticMethod(String name,
+                                         int modifiers,
+                                         ClassNode returnType,
+                                         Parameter[] parameters,
+                                         ClassNode[] exceptions,
+                                         Statement code) {
+        MethodNode answer = addMethod(name, modifiers, returnType, parameters, exceptions, code);
+        answer.setSynthetic(true);
+        return answer;
+    }
+
+    public FieldNode addField(String name, int modifiers, ClassNode type, Expression initialValue) {
+        FieldNode node = new FieldNode(name, modifiers, type, redirect(), initialValue);
+        addField(node);
+        return node;
+    }
+
+    public void addInterface(ClassNode type) {
+        // lets check if it already implements an interface
+        boolean skip = false;
+        ClassNode[] interfaces = redirect().interfaces;
+        for (int i = 0; i < interfaces.length; i++) {
+            if (type.equals(interfaces[i])) {
+                skip = true;
+            }
+        }
+        if (!skip) {
+            ClassNode[] newInterfaces = new ClassNode[interfaces.length + 1];
+            System.arraycopy(interfaces, 0, newInterfaces, 0, interfaces.length);
+            newInterfaces[interfaces.length] = type;
+            redirect().interfaces = newInterfaces;
+        }
+    }
+    
+    public boolean equals(Object o) {
+        if (redirect!=null) return redirect().equals(o);
+        ClassNode cn = (ClassNode) o;        
+        return (cn.getName().equals(getName()));
+    }
+
+    public void addMixin(MixinNode mixin) {
+        // lets check if it already uses a mixin
+        MixinNode[] mixins = redirect().mixins;
+        boolean skip = false;
+        for (int i = 0; i < mixins.length; i++) {
+            if (mixin.equals(mixins[i])) {
+                skip = true;
+            }
+        }
+        if (!skip) {
+            MixinNode[] newMixins = new MixinNode[mixins.length + 1];
+            System.arraycopy(mixins, 0, newMixins, 0, mixins.length);
+            newMixins[mixins.length] = mixin;
+            redirect().mixins = newMixins;
+        }
+    }
+
+    public FieldNode getField(String name) {
+        return (FieldNode) redirect().fieldIndex.get(name);
+    }
+
+    /**
+     * @return the field node on the outer class or null if this is not an
+     *         inner class
+     */
+    public FieldNode getOuterField(String name) {
+        return null;
+    }
+
+    /**
+     * Helper method to avoid casting to inner class
+     */
+    public ClassNode getOuterClass() {
+        return null;
+    }
+    
+    public void addObjectInitializerStatements(Statement statements) {
+        objectInitializers.add(statements);
+    }
+    
+    public List getObjectInitializerStatements() {
+        return objectInitializers;
+    }
+
+    public void addStaticInitializerStatements(List staticStatements, boolean fieldInit) {
+        MethodNode method = null;
+        List declaredMethods = getDeclaredMethods("<clinit>");
+        if (declaredMethods.isEmpty()) {
+            method =
+                    addMethod("<clinit>", ACC_PUBLIC | ACC_STATIC, ClassHelper.VOID_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new BlockStatement());
+            method.setSynthetic(true);
+        }
+        else {
+            method = (MethodNode) declaredMethods.get(0);
+        }
+        BlockStatement block = null;
+        Statement statement = method.getCode();
+        if (statement == null) {
+            block = new BlockStatement();
+        }
+        else if (statement instanceof BlockStatement) {
+            block = (BlockStatement) statement;
+        }
+        else {
+            block = new BlockStatement();
+            block.addStatement(statement);
+        }
+        
+        // while anything inside a static initializer block is appended 
+        // we don't want to append in the case we have a initialization
+        // expression of a static field. In that case we want to add
+        // before the other statements
+        if (!fieldInit) {
+            block.addStatements(staticStatements);
+        } else {
+            List blockStatements = block.getStatements();
+            staticStatements.addAll(blockStatements);
+            blockStatements.clear();
+            blockStatements.addAll(staticStatements);
+        }
+    }
+
+    /**
+     * @return a list of methods which match the given name
+     */
+    public List getDeclaredMethods(String name) {
+        List answer = new ArrayList();
+        for (Iterator iter = getMethods().iterator(); iter.hasNext();) {
+            MethodNode method = (MethodNode) iter.next();
+            if (name.equals(method.getName())) {
+                answer.add(method);
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * @return a list of methods which match the given name
+     */
+    public List getMethods(String name) {
+        List answer = new ArrayList();
+        ClassNode node = this;
+        do {
+            for (Iterator iter = node.getMethods().iterator(); iter.hasNext();) {
+                MethodNode method = (MethodNode) iter.next();
+                if (name.equals(method.getName())) {
+                    answer.add(method);
+                }
+            }
+            node = node.getSuperClass();
+        }
+        while (node != null);
+        return answer;
+    }
+
+    /**
+     * @return the method matching the given name and parameters or null
+     */
+    public MethodNode getDeclaredMethod(String name, Parameter[] parameters) {
+        for (Iterator iter = getMethods().iterator(); iter.hasNext();) {
+            MethodNode method = (MethodNode) iter.next();
+            if (name.equals(method.getName()) && parametersEqual(method.getParameters(), parameters)) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @return true if this node is derived from the given class node
+     */
+    public boolean isDerivedFrom(ClassNode type) {
+        ClassNode node = this;
+        while (node != null) {
+            if (type.equals(node)) {
+                return true;
+            }
+            node = node.getSuperClass();
+        }
+        return false;
+    }
+
+    /**
+     * @return true if this class is derived from a groovy object
+     *         i.e. it implements GroovyObject
+     */
+    public boolean isDerivedFromGroovyObject() {
+        return implementsInterface(GroovyObject.class.getName());
+    }
+
+    /**
+     * @param name the fully qualified name of the interface
+     * @return true if this class or any base class implements the given interface
+     */
+    public boolean implementsInterface(String name) {
+        ClassNode node = redirect();
+        do {
+            if (node.declaresInterface(name)) {
+                return true;
+            }
+            node = node.getSuperClass();
+        }
+        while (node != null);
+        return false;
+    }
+
+    /**
+     * @param name the fully qualified name of the interface
+     * @return true if this class declares that it implements the given interface
+     */
+    public boolean declaresInterface(String name) {
+        ClassNode[] interfaces = redirect().getInterfaces();
+        int size = interfaces.length;
+        for (int i = 0; i < size; i++) {
+            if (interfaces[i].getName().equals(name)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @return the ClassNode of the super class of this type
+     */
+    public ClassNode getSuperClass() {
+        if (!lazyInitDone && !isResolved()) {
+            throw new GroovyBugError("Classnode#getSuperClass for "+getName()+" called before class resolving");
+        }
+        return redirect().getUnresolvedSuperClass();
+    }
+    
+    public ClassNode getUnresolvedSuperClass() {
+        if (!lazyInitDone) {
+            lazyClassInit();
+        }
+        return redirect().superClass;
+    }
+
+    /**
+     * Factory method to create a new MethodNode via reflection
+     */
+    protected MethodNode createMethodNode(Method method) {
+        Parameter[] parameters = createParameters(method.getParameterTypes());
+        return new MethodNode(method.getName(), method.getModifiers(), ClassHelper.make(method.getReturnType()), parameters, ClassHelper.make(method.getExceptionTypes()), EmptyStatement.INSTANCE);
+    }
+
+    /**
+     * @param types
+     */
+    protected Parameter[] createParameters(Class[] types) {
+        Parameter[] parameters = Parameter.EMPTY_ARRAY;
+        int size = types.length;
+        if (size > 0) {
+            parameters = new Parameter[size];
+            for (int i = 0; i < size; i++) {
+                parameters[i] = createParameter(types[i], i);
+            }
+        }
+        return parameters;
+    }
+
+    protected Parameter createParameter(Class parameterType, int idx) {
+        return new Parameter(ClassHelper.make(parameterType), "param" + idx);
+    }
+
+    public CompileUnit getCompileUnit() {
+        if (redirect!=null) return redirect().getCompileUnit();
+        if (compileUnit == null && module != null) {
+            compileUnit = module.getUnit();
+        }
+        return compileUnit;
+    }
+    
+    protected void setCompileUnit(CompileUnit cu) {
+        if (redirect!=null) redirect().setCompileUnit(cu);
+        if (compileUnit!= null) compileUnit = cu;
+    }
+
+    /**
+     * @return true if the two arrays are of the same size and have the same contents
+     */
+    protected boolean parametersEqual(Parameter[] a, Parameter[] b) {
+        if (a.length == b.length) {
+            boolean answer = true;
+            for (int i = 0; i < a.length; i++) {
+                if (!a[i].getType().equals(b[i].getType())) {
+                    answer = false;
+                    break;
+                }
+            }
+            return answer;
+        }
+        return false;
+    }
+
+    /**
+     * @return the package name of this class
+     */
+    public String getPackageName() {
+        int idx = getName().lastIndexOf('.');
+        if (idx > 0) {
+            return getName().substring(0, idx);
+        }
+        return null;
+    }
+
+    public String getNameWithoutPackage() {
+        int idx = getName().lastIndexOf('.');
+        if (idx > 0) {
+            return getName().substring(idx + 1);
+        }
+        return getName();
+    }
+
+    public void visitContents(GroovyClassVisitor visitor) {
+        
+        // now lets visit the contents of the class
+        for (Iterator iter = getProperties().iterator(); iter.hasNext();) {
+            PropertyNode pn = (PropertyNode) iter.next();
+            visitor.visitProperty(pn);
+        }
+
+        for (Iterator iter = getFields().iterator(); iter.hasNext();) {
+            FieldNode fn = (FieldNode) iter.next();
+            visitor.visitField(fn);
+        }
+
+        for (Iterator iter = getDeclaredConstructors().iterator(); iter.hasNext();) {
+            ConstructorNode cn = (ConstructorNode) iter.next();
+            visitor.visitConstructor(cn);
+        }
+
+        for (Iterator iter = getMethods().iterator(); iter.hasNext();) {
+            MethodNode mn = (MethodNode) iter.next();
+            visitor.visitMethod(mn);
+        }
+    }
+
+    public MethodNode getGetterMethod(String getterName) {
+        for (Iterator iter = getMethods().iterator(); iter.hasNext();) {
+            MethodNode method = (MethodNode) iter.next();
+            if (getterName.equals(method.getName())
+                    && ClassHelper.VOID_TYPE!=method.getReturnType()
+                    && method.getParameters().length == 0) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    public MethodNode getSetterMethod(String getterName) {
+        for (Iterator iter = getMethods().iterator(); iter.hasNext();) {
+            MethodNode method = (MethodNode) iter.next();
+            if (getterName.equals(method.getName())
+                    && ClassHelper.VOID_TYPE==method.getReturnType()
+                    && method.getParameters().length == 1) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Is this class delcared in a static method (such as a closure / inner class declared in a static method)
+     */
+    public boolean isStaticClass() {
+        return redirect().staticClass;
+    }
+
+    public void setStaticClass(boolean staticClass) {
+        redirect().staticClass = staticClass;
+    }
+
+    /**
+     * @return Returns true if this inner class or closure was declared inside a script body
+     */
+    public boolean isScriptBody() {
+        return redirect().scriptBody;
+    }
+
+    public void setScriptBody(boolean scriptBody) {
+        redirect().scriptBody = scriptBody;
+    }
+
+    public boolean isScript() {
+        return redirect().script || isDerivedFrom(ClassHelper.SCRIPT_TYPE);
+    }
+
+    public void setScript(boolean script) {
+        redirect().script = script;
+    }
+
+    public String toString() {
+        return super.toString() + "[name: " + getName() + "]";
+    }
+
+    /**
+     * Returns true if the given method has a possibly matching method with the given name and arguments
+     */
+    public boolean hasPossibleMethod(String name, Expression arguments) {
+        int count = 0;
+
+        if (arguments instanceof TupleExpression) {
+            TupleExpression tuple = (TupleExpression) arguments;
+            // TODO this won't strictly be true when using list expension in argument calls
+            count = tuple.getExpressions().size();
+        }
+        ClassNode node = this;
+        do {
+            for (Iterator iter = getMethods().iterator(); iter.hasNext();) {
+                MethodNode method = (MethodNode) iter.next();
+                if (name.equals(method.getName()) && method.getParameters().length == count) {
+                    return true;
+                }
+            }
+            node = node.getSuperClass();
+        }
+        while (node != null);
+        return false;
+    }
+    
+    public boolean isInterface(){
+        return (getModifiers() & Opcodes.ACC_INTERFACE) > 0; 
+    }
+    
+    public boolean isResolved(){
+        return redirect().clazz!=null || (componentType != null && componentType.isResolved());
+    }
+    
+    public boolean isArray(){
+        return componentType!=null;
+    }
+    
+    public ClassNode getComponentType() {
+        return componentType;
+    }
+    
+    public Class getTypeClass(){
+        Class c = redirect().clazz;
+        if (c!=null) return c;
+        ClassNode component = redirect().componentType;
+        if (component!=null && component.isResolved()){
+            ClassNode cn = component.makeArray();
+            setRedirect(cn);
+            return redirect().clazz;
+        }
+        throw new GroovyBugError("ClassNode#getTypeClass for "+getName()+" is called before the type class is set ");
+    }
+    
+    public boolean hasPackageName(){
+        return redirect().name.indexOf('.')>0;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/CodeVisitorSupport.java b/groovy-core/src/main/org/codehaus/groovy/ast/CodeVisitorSupport.java
new file mode 100644
index 0000000..de6a552
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/CodeVisitorSupport.java
@@ -0,0 +1,312 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.codehaus.groovy.ast.expr.*;
+import org.codehaus.groovy.ast.stmt.AssertStatement;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.BreakStatement;
+import org.codehaus.groovy.ast.stmt.CaseStatement;
+import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.stmt.ContinueStatement;
+import org.codehaus.groovy.ast.stmt.DoWhileStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.stmt.SwitchStatement;
+import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
+import org.codehaus.groovy.ast.stmt.ThrowStatement;
+import org.codehaus.groovy.ast.stmt.TryCatchStatement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
+
+/**
+ * Abstract base class for any GroovyCodeVisitory which by default
+ * just walks the code and expression tree
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public abstract class CodeVisitorSupport implements GroovyCodeVisitor {
+
+    public void visitBlockStatement(BlockStatement block) {
+        List statements = block.getStatements();
+        for (Iterator iter = statements.iterator(); iter.hasNext(); ) {
+            Statement statement = (Statement) iter.next();
+            statement.visit(this);
+        }
+    }
+
+    public void visitForLoop(ForStatement forLoop) {
+        forLoop.getCollectionExpression().visit(this);
+        forLoop.getLoopBlock().visit(this);
+    }
+
+    public void visitWhileLoop(WhileStatement loop) {
+        loop.getBooleanExpression().visit(this);
+        loop.getLoopBlock().visit(this);
+    }
+
+    public void visitDoWhileLoop(DoWhileStatement loop) {
+        loop.getLoopBlock().visit(this);
+        loop.getBooleanExpression().visit(this);
+    }
+
+    public void visitIfElse(IfStatement ifElse) {
+        ifElse.getBooleanExpression().visit(this);
+        ifElse.getIfBlock().visit(this);
+        ifElse.getElseBlock().visit(this);
+    }
+
+    public void visitExpressionStatement(ExpressionStatement statement) {
+        statement.getExpression().visit(this);
+    }
+
+    public void visitReturnStatement(ReturnStatement statement) {
+        statement.getExpression().visit(this);
+    }
+
+    public void visitAssertStatement(AssertStatement statement) {
+        statement.getBooleanExpression().visit(this);
+        statement.getMessageExpression().visit(this);
+    }
+
+    public void visitTryCatchFinally(TryCatchStatement statement) {
+        statement.getTryStatement().visit(this);
+        List list = statement.getCatchStatements();
+        for (Iterator iter = list.iterator(); iter.hasNext(); ) {
+            CatchStatement catchStatement = (CatchStatement) iter.next();
+            catchStatement.visit(this);
+        }
+        statement.getFinallyStatement().visit(this);
+    }
+
+    public void visitSwitch(SwitchStatement statement) {
+        statement.getExpression().visit(this);
+        List list = statement.getCaseStatements();
+        for (Iterator iter = list.iterator(); iter.hasNext(); ) {
+            CaseStatement caseStatement = (CaseStatement) iter.next();
+            caseStatement.visit(this);
+        }
+        statement.getDefaultStatement().visit(this);
+    }
+
+    public void visitCaseStatement(CaseStatement statement) {
+        statement.getExpression().visit(this);
+        statement.getCode().visit(this);
+    }
+
+    public void visitBreakStatement(BreakStatement statement) {
+    }
+
+    public void visitContinueStatement(ContinueStatement statement) {
+    }
+
+    public void visitSynchronizedStatement(SynchronizedStatement statement) {
+        statement.getExpression().visit(this);
+        statement.getCode().visit(this);
+    }
+
+    public void visitThrowStatement(ThrowStatement statement) {
+        statement.getExpression().visit(this);
+    }
+
+    public void visitMethodCallExpression(MethodCallExpression call) {
+        call.getObjectExpression().visit(this);
+        call.getMethod().visit(this);
+        call.getArguments().visit(this);
+    }
+
+    public void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
+        call.getArguments().visit(this);
+    }
+
+    public void visitConstructorCallExpression(ConstructorCallExpression call) {
+        call.getArguments().visit(this);
+    }
+
+    public void visitBinaryExpression(BinaryExpression expression) {
+        expression.getLeftExpression().visit(this);
+        expression.getRightExpression().visit(this);
+    }
+
+    public void visitTernaryExpression(TernaryExpression expression) {
+        expression.getBooleanExpression().visit(this);
+        expression.getTrueExpression().visit(this);
+        expression.getFalseExpression().visit(this);
+    }
+
+    public void visitPostfixExpression(PostfixExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitPrefixExpression(PrefixExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitBooleanExpression(BooleanExpression expression) {
+		expression.getExpression().visit(this);
+	}
+
+	public void visitNotExpression(NotExpression expression) {
+		expression.getExpression().visit(this);
+	}
+
+    public void visitClosureExpression(ClosureExpression expression) {
+        expression.getCode().visit(this);
+    }
+    
+    public void visitTupleExpression(TupleExpression expression) {
+        visitListOfExpressions(expression.getExpressions());
+    }
+
+    public void visitListExpression(ListExpression expression) {
+        visitListOfExpressions(expression.getExpressions());
+    }
+
+    public void visitArrayExpression(ArrayExpression expression) {
+        visitListOfExpressions(expression.getExpressions());
+    }
+    
+    public void visitMapExpression(MapExpression expression) {
+        visitListOfExpressions(expression.getMapEntryExpressions());
+        
+    }
+
+    public void visitMapEntryExpression(MapEntryExpression expression) {
+        expression.getKeyExpression().visit(this);
+        expression.getValueExpression().visit(this);
+        
+    }
+
+    public void visitRangeExpression(RangeExpression expression) {
+        expression.getFrom().visit(this);
+        expression.getTo().visit(this);
+    }
+
+    public void visitSpreadExpression(SpreadExpression expression) {
+        expression.getExpression().visit(this);
+    }
+ 
+    public void visitSpreadMapExpression(SpreadMapExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitMethodPointerExpression(MethodPointerExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitNegationExpression(NegationExpression expression) {
+        expression.getExpression().visit(this);
+    }
+    
+    public void visitBitwiseNegExpression(BitwiseNegExpression expression) {
+        expression.getExpression().visit(this);
+    }
+    
+    public void visitCastExpression(CastExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitConstantExpression(ConstantExpression expression) {
+    }
+
+    public void visitClassExpression(ClassExpression expression) {
+    }
+
+    public void visitVariableExpression(VariableExpression expression) {
+    }
+
+    public void visitDeclarationExpression(DeclarationExpression expression) {
+        visitBinaryExpression(expression);
+    }
+    
+    public void visitPropertyExpression(PropertyExpression expression) {
+    	expression.getObjectExpression().visit(this);
+    	expression.getProperty().visit(this);
+    }
+
+    public void visitAttributeExpression(AttributeExpression expression) {
+    	expression.getObjectExpression().visit(this);
+    	expression.getProperty().visit(this);
+    }
+
+    public void visitFieldExpression(FieldExpression expression) {
+    }
+
+    public void visitRegexExpression(RegexExpression expression) {
+    }
+
+    public void visitGStringExpression(GStringExpression expression) {
+        visitListOfExpressions(expression.getStrings());
+        visitListOfExpressions(expression.getValues());
+    }
+
+    protected void visitListOfExpressions(List list) {
+        Expression expression, expr2, expr3;
+        for (Iterator iter = list.iterator(); iter.hasNext(); ) {
+            expression = (Expression) iter.next();
+            if (expression instanceof SpreadExpression) {
+                expr2 = ((SpreadExpression) expression).getExpression();
+                expr2.visit(this);
+            }
+            else {
+                expression.visit(this);
+            }
+        }
+    }
+    public void visitCatchStatement(CatchStatement statement) {
+    	statement.getCode().visit(this);
+    }
+    
+    public void visitArgumentlistExpression(ArgumentListExpression ale) {
+    	visitTupleExpression(ale);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/CompileUnit.java b/groovy-core/src/main/org/codehaus/groovy/ast/CompileUnit.java
new file mode 100644
index 0000000..22e4ca7
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/CompileUnit.java
@@ -0,0 +1,194 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package org.codehaus.groovy.ast;
+
+import groovy.lang.GroovyClassLoader;
+
+import java.security.CodeSource;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.syntax.SyntaxException;
+
+/**
+ * Represents the entire contents of a compilation step which consists of one
+ * or more {@link ModuleNode}instances
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan </a>
+ * @version $Revision$
+ */
+public class CompileUnit {
+
+    private List modules = new ArrayList();
+    private Map classes = new HashMap();
+    private CompilerConfiguration config;
+    private GroovyClassLoader classLoader;
+    private CodeSource codeSource;
+    private Map classesToCompile = new HashMap();
+    private Map classNameToSource = new HashMap();
+    
+    public CompileUnit(GroovyClassLoader classLoader, CompilerConfiguration config) {
+    	this(classLoader, null, config);
+    }
+    
+    public CompileUnit(GroovyClassLoader classLoader, CodeSource codeSource, CompilerConfiguration config) {
+        this.classLoader = classLoader;
+        this.config = config;
+        this.codeSource = codeSource;
+    }
+
+    public List getModules() {
+        return modules;
+    }
+
+    public void addModule(ModuleNode node) {
+        // node==null means a compilation error prevented
+        // groovy from building an ast
+        if (node==null) return;
+        modules.add(node);
+        node.setUnit(this);
+        addClasses(node.getClasses());
+    }
+
+    /**
+     * @return the ClassNode for the given qualified name or returns null if
+     *         the name does not exist in the current compilation unit
+     *         (ignoring the .class files on the classpath)
+     */
+    public ClassNode getClass(String name) {
+        ClassNode cn = (ClassNode) classes.get(name);
+        if (cn!=null) return cn;
+        return (ClassNode) classesToCompile.get(name);
+    }
+
+    /**
+     * @return a list of all the classes in each module in the compilation unit
+     */
+    public List getClasses() {
+        List answer = new ArrayList();
+        for (Iterator iter = modules.iterator(); iter.hasNext();) {
+            ModuleNode module = (ModuleNode) iter.next();
+            answer.addAll(module.getClasses());
+        }
+        return answer;
+    }
+
+    public CompilerConfiguration getConfig() {
+        return config;
+    }
+
+    public GroovyClassLoader getClassLoader() {
+        return classLoader;
+    }
+    
+    public CodeSource getCodeSource() {
+    	return codeSource;
+    }
+
+    /**
+     * Appends all of the fully qualified class names in this
+     * module into the given map
+     */
+    void addClasses(List classList) {
+        for (Iterator iter = classList.iterator(); iter.hasNext();) {
+            addClass((ClassNode) iter.next());
+        }
+    }
+    
+    /**
+     *  Adds a class to the unit.
+     */
+    public void addClass(ClassNode node) {
+    	node = node.redirect();
+        String name = node.getName();
+        ClassNode stored = (ClassNode) classes.get(name);
+        if (stored != null && stored != node) {
+            // we have a duplicate class!
+            // One possibility for this is, that we delcared a script and a 
+            // class in the same file and named the class like the file
+            SourceUnit nodeSource = node.getModule().getContext();
+            SourceUnit storedSource = stored.getModule().getContext();
+            String txt = "Invalid duplicate class definition of class "+node.getName()+" : ";
+            if (nodeSource==storedSource) {
+                // same class in same source
+                txt += "The source "+nodeSource.getName()+" contains at last two defintions of the class "+node.getName()+".\n";
+                if (node.isScriptBody() || stored.isScriptBody()) {
+                    txt += "One of the classes is a explicit generated class using the class statement, the other is a class generated from"+
+                           " the script body based on the file name. Solutions are to change the file name or to change the class name.\n";
+                }
+            } else {
+                txt += "The sources "+nodeSource.getName()+" and "+storedSource.getName()+" are containing both a class of the name "+node.getName()+".\n";
+            }
+            nodeSource.getErrorCollector().addErrorAndContinue(
+                    new SyntaxErrorMessage(new SyntaxException(txt, node.getLineNumber(), node.getColumnNumber()), nodeSource)
+            );
+        }
+        classes.put(name, node);
+        
+        if (classesToCompile.containsKey(name)) {
+            ClassNode cn = (ClassNode) classesToCompile.get(name);
+            cn.setRedirect(node);
+            classesToCompile.remove(name);
+        }        
+    }
+     
+    /**
+     * this emthod actually does not compile a class. It's only
+     * a marker that this type has to be compiled by the CompilationUnit
+     * at the end of a parse step no node should be be left.
+     */
+    public void addClassNodeToCompile(ClassNode node, SourceUnit location) {
+        classesToCompile.put(node.getName(),node);
+        classNameToSource.put(node.getName(),location);
+    }
+    
+    public SourceUnit getScriptSourceLocation(String className) {
+        return (SourceUnit) classNameToSource.get(className);
+    }
+
+    public boolean hasClassNodeToCompile(){
+        return classesToCompile.size()!=0;
+    }
+    
+    public Iterator iterateClassNodeToCompile(){
+        return classesToCompile.keySet().iterator();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/ConstructorNode.java b/groovy-core/src/main/org/codehaus/groovy/ast/ConstructorNode.java
new file mode 100644
index 0000000..6dff753
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/ConstructorNode.java
@@ -0,0 +1,76 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+import java.util.Map;
+
+import org.codehaus.groovy.ast.stmt.*;
+
+
+/**
+ * Represents a constructor declaration
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ConstructorNode extends MethodNode {
+    
+    public ConstructorNode(int modifiers, Statement code) {
+        this(modifiers, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, code);
+    }
+    
+    public ConstructorNode(int modifiers, Parameter[] parameters, ClassNode[] exceptions, Statement code) {
+        super("<init>",modifiers,ClassHelper.VOID_TYPE,parameters,exceptions,code);
+        
+        VariableScope scope = new VariableScope();
+        Map declares = scope.getDeclaredVariables(); 
+        for (int i = 0; i < parameters.length; i++) {
+            declares.put(parameters[i].getName(),parameters[i]);
+        }
+        this.setVariableScope(scope);
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/DynamicVariable.java b/groovy-core/src/main/org/codehaus/groovy/ast/DynamicVariable.java
new file mode 100644
index 0000000..f6a4e2c
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/DynamicVariable.java
@@ -0,0 +1,54 @@
+/*
+ * UnreferencedVariable.java created on 14.12.2005
+ *
+ * To change this generated comment go to 
+ * Window>Preferences>Java>Code Generation>Code and Comments
+ */
+package org.codehaus.groovy.ast;
+
+import org.codehaus.groovy.ast.expr.Expression;
+
+public class DynamicVariable implements Variable {
+
+    private String name;
+    private boolean closureShare = false;
+    private boolean staticContext = false;
+    
+    public DynamicVariable(String name, boolean context) {
+        this.name = name;
+        staticContext = context;
+    }
+    
+    public ClassNode getType() {
+        return ClassHelper.DYNAMIC_TYPE;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Expression getInitialExpression() {
+        return null;
+    }
+
+    public boolean hasInitialExpression() {
+        return false;
+    }
+
+    public boolean isInStaticContext() {
+        return staticContext;
+    }
+
+    public boolean isDynamicTyped() {
+        return true;
+    }
+
+    public boolean isClosureSharedVariable() {
+        return closureShare;
+    }
+
+    public void setClosureSharedVariable(boolean inClosure) {
+        closureShare = inClosure;        
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/FieldNode.java b/groovy-core/src/main/org/codehaus/groovy/ast/FieldNode.java
new file mode 100644
index 0000000..149b164
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/FieldNode.java
@@ -0,0 +1,161 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+import java.lang.reflect.Field;
+
+import org.codehaus.groovy.ast.expr.Expression;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Represents a field (member variable)
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class FieldNode extends AnnotatedNode implements Opcodes, Variable {
+
+    private String name;
+    private int modifiers;
+    private ClassNode type;
+    private ClassNode owner;
+    private Expression initialValueExpression;
+    private boolean dynamicTyped;
+    private boolean holder;
+    private boolean closureShare = false;
+
+    public static FieldNode newStatic(Class theClass, String name) throws SecurityException, NoSuchFieldException {
+        Field field = theClass.getField(name);
+        ClassNode fldType = ClassHelper.make(field.getType());
+        return new FieldNode(name, ACC_PUBLIC | ACC_STATIC, fldType, ClassHelper.make(theClass), null);
+    }
+
+    public FieldNode(String name, int modifiers, ClassNode type, ClassNode owner, Expression initialValueExpression) {
+        this.name = name;
+        this.modifiers = modifiers;
+        this.type = type;
+        if (this.type==ClassHelper.DYNAMIC_TYPE && initialValueExpression!=null) this.setType(initialValueExpression.getType());
+        this.setType(type);
+        this.owner = owner;
+        this.initialValueExpression = initialValueExpression;
+    }
+
+    public Expression getInitialExpression() {
+        return initialValueExpression;
+    }
+
+    public int getModifiers() {
+        return modifiers;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public ClassNode getType() {
+        return type;
+    }
+
+    public void setType(ClassNode type) {
+        this.type = type;
+        dynamicTyped |= type==ClassHelper.DYNAMIC_TYPE;
+    }
+    
+    public ClassNode getOwner() {
+        return owner;
+    }
+
+    public boolean isHolder() {
+        return holder;
+    }
+
+    public void setHolder(boolean holder) {
+        this.holder = holder;
+    }
+
+    public boolean isDynamicTyped() {
+        return dynamicTyped;
+    }
+
+    public void setModifiers(int modifiers) {
+        this.modifiers = modifiers;
+    }
+
+    /**
+     * @return true if the field is static
+     */
+    public boolean isStatic() {
+        return (modifiers & ACC_STATIC) != 0;
+    }
+	/**
+	 * @param owner The owner to set.
+	 */
+	public void setOwner(ClassNode owner) {
+		this.owner = owner;
+	}
+
+    public boolean hasInitialExpression() {
+        return initialValueExpression!=null;
+    }
+
+    public boolean isInStaticContext() {
+        return isStatic();
+    }
+    public Expression getInitialValueExpression() {
+        return initialValueExpression;
+    }
+    public void setInitialValueExpression(Expression initialValueExpression) {
+        this.initialValueExpression = initialValueExpression;
+    }
+
+    public boolean isClosureSharedVariable() {
+        return false;
+    }
+    
+    public void setClosureSharedVariable(boolean inClosure) {
+        closureShare = inClosure;        
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/GroovyClassVisitor.java b/groovy-core/src/main/org/codehaus/groovy/ast/GroovyClassVisitor.java
new file mode 100644
index 0000000..b1f299c
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/GroovyClassVisitor.java
@@ -0,0 +1,62 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+/**
+ * An implementation of the visitor pattern for working with ASTNodes
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public interface GroovyClassVisitor {
+
+    public void visitClass(ClassNode node);
+    public void visitConstructor(ConstructorNode node);
+    public void visitMethod(MethodNode node);
+    public void visitField(FieldNode node);
+    public void visitProperty(PropertyNode node);
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/GroovyCodeVisitor.java b/groovy-core/src/main/org/codehaus/groovy/ast/GroovyCodeVisitor.java
new file mode 100644
index 0000000..b03ec79
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/GroovyCodeVisitor.java
@@ -0,0 +1,231 @@
+/*
+
+ $Id$
+
+
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+
+
+ Redistribution and use of this software and associated documentation
+
+ ("Software"), with or without modification, are permitted provided
+
+ that the following conditions are met:
+
+
+
+ 1. Redistributions of source code must retain copyright
+
+    statements and notices.  Redistributions must also contain a
+
+    copy of this document.
+
+
+
+ 2. Redistributions in binary form must reproduce the
+
+    above copyright notice, this list of conditions and the
+
+    following disclaimer in the documentation and/or other
+
+    materials provided with the distribution.
+
+
+
+ 3. The name "groovy" must not be used to endorse or promote
+
+    products derived from this Software without prior written
+
+    permission of The Codehaus.  For written permission,
+
+    please contact info@codehaus.org.
+
+
+
+ 4. Products derived from this Software may not be called "groovy"
+
+    nor may "groovy" appear in their names without prior written
+
+    permission of The Codehaus. "groovy" is a registered
+
+    trademark of The Codehaus.
+
+
+
+ 5. Due credit should be given to The Codehaus -
+
+    http://groovy.codehaus.org/
+
+
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+ */
+
+package org.codehaus.groovy.ast;
+
+
+
+import org.codehaus.groovy.ast.expr.*;
+
+import org.codehaus.groovy.ast.stmt.*;
+
+
+
+/**
+
+ * An implementation of the visitor pattern for working with ASTNodes
+
+ * 
+
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+
+ * @version $Revision$
+
+ */
+
+public interface GroovyCodeVisitor {
+
+
+
+    // statements
+
+    //-------------------------------------------------------------------------
+
+    public void visitBlockStatement(BlockStatement statement);
+
+    public void visitForLoop(ForStatement forLoop);
+
+    public void visitWhileLoop(WhileStatement loop);
+
+    public void visitDoWhileLoop(DoWhileStatement loop);
+
+    public void visitIfElse(IfStatement ifElse);
+
+    public void visitExpressionStatement(ExpressionStatement statement);
+
+    public void visitReturnStatement(ReturnStatement statement);
+
+    public void visitAssertStatement(AssertStatement statement);
+
+    public void visitTryCatchFinally(TryCatchStatement finally1);
+
+    public void visitSwitch(SwitchStatement statement);
+
+    public void visitCaseStatement(CaseStatement statement);
+
+    public void visitBreakStatement(BreakStatement statement);
+
+    public void visitContinueStatement(ContinueStatement statement);
+
+    public void visitThrowStatement(ThrowStatement statement);
+
+    public void visitSynchronizedStatement(SynchronizedStatement statement);
+    
+    public void visitCatchStatement(CatchStatement statement);
+
+    
+
+    // expressions
+
+    //-------------------------------------------------------------------------
+
+    public void visitMethodCallExpression(MethodCallExpression call);
+
+    public void visitStaticMethodCallExpression(StaticMethodCallExpression expression);
+
+    public void visitConstructorCallExpression(ConstructorCallExpression expression);
+
+    public void visitTernaryExpression(TernaryExpression expression);
+
+    public void visitBinaryExpression(BinaryExpression expression);
+
+    public void visitPrefixExpression(PrefixExpression expression);
+
+    public void visitPostfixExpression(PostfixExpression expression);
+
+    public void visitBooleanExpression(BooleanExpression expression);
+
+    public void visitClosureExpression(ClosureExpression expression);
+
+    
+
+    public void visitTupleExpression(TupleExpression expression);
+
+    public void visitMapExpression(MapExpression expression);
+
+    public void visitMapEntryExpression(MapEntryExpression expression);
+
+    public void visitListExpression(ListExpression expression);
+
+    public void visitRangeExpression(RangeExpression expression);
+
+    
+
+    public void visitPropertyExpression(PropertyExpression expression);
+
+    public void visitAttributeExpression(AttributeExpression attributeExpression);
+
+    public void visitFieldExpression(FieldExpression expression);
+
+    public void visitMethodPointerExpression(MethodPointerExpression expression);
+
+
+
+    public void visitConstantExpression(ConstantExpression expression);
+
+    public void visitClassExpression(ClassExpression expression);
+
+    public void visitVariableExpression(VariableExpression expression);
+
+    public void visitDeclarationExpression(DeclarationExpression expression);
+
+    public void visitRegexExpression(RegexExpression expression);
+
+    public void visitGStringExpression(GStringExpression expression);
+
+    public void visitArrayExpression(ArrayExpression expression);
+
+
+
+    public void visitSpreadExpression(SpreadExpression expression);
+
+    public void visitSpreadMapExpression(SpreadMapExpression expression);
+    public void visitNotExpression(NotExpression expression);
+
+    public void visitNegationExpression(NegationExpression expression);
+
+    public void visitBitwiseNegExpression(BitwiseNegExpression expression);
+
+    public void visitCastExpression(CastExpression expression);
+
+
+    public void visitArgumentlistExpression(ArgumentListExpression expression);
+}
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/ImportNode.java b/groovy-core/src/main/org/codehaus/groovy/ast/ImportNode.java
new file mode 100644
index 0000000..81b0d81
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/ImportNode.java
@@ -0,0 +1,91 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Represents an import statement of a single class
+ * 
+ * author Jochen Theodorou
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ImportNode extends AnnotatedNode implements Opcodes {
+
+    private ClassNode type;
+    private String alias;
+    
+    public ImportNode(ClassNode type, String alias) {
+        this.type = type;
+        this.alias = alias;
+    }
+    
+    /**
+     * @return the text display of this import
+     */
+    public String getText() {
+        if (alias == null || alias.length() == 0) {
+            return "import " + type.getName();
+        }
+        else {
+            return "import " + type.getName() + " as " + alias;
+        }
+    }
+    
+    public String getAlias() {
+        return alias;
+    }
+
+    public ClassNode getType() {
+        return type;
+    }
+    
+    public String getClassName() {
+    	return type.getName();
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/InnerClassNode.java b/groovy-core/src/main/org/codehaus/groovy/ast/InnerClassNode.java
new file mode 100644
index 0000000..596c1e0
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/InnerClassNode.java
@@ -0,0 +1,87 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+/**
+ * Represents an inner class declaration
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class InnerClassNode extends ClassNode {
+
+    private ClassNode outerClass;
+
+    /**
+     * @param name is the full name of the class
+     * @param modifiers the modifiers, @see org.objectweb.asm.Opcodes
+     * @param superClass the base class name - use "java.lang.Object" if no direct base class
+     */
+    public InnerClassNode(ClassNode outerClass, String name, int modifiers, ClassNode superClass) {
+        this(outerClass, name, modifiers, superClass, ClassHelper.EMPTY_TYPE_ARRAY, MixinNode.EMPTY_ARRAY);
+    }
+
+    /**
+     * @param name is the full name of the class
+     * @param modifiers the modifiers, @see org.objectweb.asm.Opcodes
+     * @param superClass the base class name - use "java.lang.Object" if no direct base class
+     */
+    public InnerClassNode(ClassNode outerClass, String name, int modifiers, ClassNode superClass, ClassNode[] interfaces, MixinNode[] mixins) {
+        super(name, modifiers, superClass, interfaces, mixins);
+        this.outerClass = outerClass;
+    }
+
+    public ClassNode getOuterClass() {
+        return outerClass;
+    }
+
+    /**
+     * @return the field node on the outer class or null if this is not an inner class
+     */
+    public FieldNode getOuterField(String name) {
+        return outerClass.getField(name);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/MethodNode.java b/groovy-core/src/main/org/codehaus/groovy/ast/MethodNode.java
new file mode 100644
index 0000000..fcea887
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/MethodNode.java
@@ -0,0 +1,199 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+import java.util.List;
+
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Represents a method declaration
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MethodNode extends AnnotatedNode implements Opcodes {
+
+    private String name;
+    private int modifiers;
+    private ClassNode returnType;
+    private Parameter[] parameters;
+    private boolean hasDefaultValue = false;
+    private Statement code;
+    private boolean dynamicReturnType;
+    private VariableScope variableScope;
+    private ClassNode[] exceptions;
+    
+    public MethodNode(String name, int modifiers, ClassNode returnType, Parameter[] parameters, ClassNode[] exceptions, Statement code) {
+        this.name = name;
+        this.modifiers = modifiers;
+        this.parameters = parameters;
+        this.code = code;
+        this.returnType = returnType;
+        if (returnType==null) this.returnType = ClassHelper.OBJECT_TYPE; 
+
+        variableScope = new VariableScope();
+        if (parameters != null && parameters.length > 0) {
+            for (int i = 0; i < parameters.length; i++) {
+                Parameter para = parameters[i];
+                if (para.hasInitialExpression()) {
+                    this.hasDefaultValue = true;
+                }
+                para.setInStaticContext(isStatic());
+                variableScope.getDeclaredVariables().put(para.getName(),para);
+            }
+        }
+        variableScope.setInStaticContext(isStatic());
+        
+        this.exceptions = exceptions;
+    }
+
+    /**
+     * The type descriptor for a method node is a string containing the name of the method, its return type,
+     * and its parameter types in a canonical form. For simplicity, I'm using the format of a Java declaration
+     * without parameter names, and with $dynamic as the type for any dynamically typed values.
+     */
+    // TODO: add test case for type descriptor
+    public String getTypeDescriptor() {
+        StringBuffer buf = new StringBuffer();
+        // buf.append(dynamicReturnType ? "$dynamic" : cleanupTypeName(returnType));
+        //
+        buf.append(returnType.getName()); // br  to replace the above. Dynamic type returns Object.
+        //
+        buf.append(' ');
+        buf.append(name);
+        buf.append('(');
+        for (int i = 0; i < parameters.length; i++) {
+            if (i > 0) {
+                buf.append(',');
+            }
+            Parameter param = parameters[i];
+            buf.append(param.getType().getName());
+        }
+        buf.append(')');
+        return buf.toString();
+    }
+ 
+    public boolean isVoidMethod() {
+        return returnType==ClassHelper.VOID_TYPE;
+    }
+
+    public Statement getCode() {
+        return code;
+    }
+
+    public void setCode(Statement code) {
+        this.code = code;
+    }
+
+    public int getModifiers() {
+        return modifiers;
+    }
+
+    public void setModifiers(int modifiers) {
+        this.modifiers = modifiers;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Parameter[] getParameters() {
+        return parameters;
+    }
+
+    public ClassNode getReturnType() {
+        return returnType;
+    }
+
+    public VariableScope getVariableScope() {
+        return variableScope;
+    }
+
+    public void setVariableScope(VariableScope variableScope) {
+        this.variableScope = variableScope;
+    }
+
+    public boolean isDynamicReturnType() {
+        return dynamicReturnType;
+    }
+
+    public boolean isAbstract() {
+        return (modifiers & ACC_ABSTRACT) != 0;
+    }
+
+    public boolean isStatic() {
+        return (modifiers & ACC_STATIC) != 0;
+    }
+
+    public boolean hasDefaultValue() {
+        return this.hasDefaultValue;
+    }
+
+    public String toString() {
+        return super.toString() + "[name: " + name + "]";
+    }
+
+    public void setReturnType(ClassNode returnType) {
+        this.returnType = returnType;
+    }
+
+    public ClassNode[] getExceptions() {
+        return exceptions;
+    }
+    
+    public Statement getFirstStatement(){
+        if (code == null) return null;
+        if (code instanceof BlockStatement) {
+            List list = ((BlockStatement) code).getStatements();
+            if (list.size()>0) return (Statement) list.get(0);
+            return null;
+        }
+        return code;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/MixinNode.java b/groovy-core/src/main/org/codehaus/groovy/ast/MixinNode.java
new file mode 100644
index 0000000..f9956ac
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/MixinNode.java
@@ -0,0 +1,75 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+/**
+ * Represents a mixin which can be applied to any ClassNode to implement mixins
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MixinNode extends ClassNode {
+
+    public static final MixinNode[] EMPTY_ARRAY = {};
+    
+    /**
+     * @param name is the full name of the class
+     * @param modifiers the modifiers, @see org.objectweb.asm.Opcodes
+     * @param superType the base class name - use "java.lang.Object" if no direct base class
+     */
+    public MixinNode(String name, int modifiers, ClassNode superType) {
+        this(name, modifiers, superType, ClassHelper.EMPTY_TYPE_ARRAY);
+    }
+
+    /**
+     * @param name is the full name of the class
+     * @param modifiers the modifiers, @see org.objectweb.asm.Opcodes
+     * @param superType the base class name - use "java.lang.Object" if no direct base class
+     */
+    public MixinNode(String name, int modifiers, ClassNode superType, ClassNode[] interfaces) {
+        super(name, modifiers, superType, interfaces, MixinNode.EMPTY_ARRAY);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/ModuleNode.java b/groovy-core/src/main/org/codehaus/groovy/ast/ModuleNode.java
new file mode 100644
index 0000000..0927953
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/ModuleNode.java
@@ -0,0 +1,343 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+import groovy.lang.Binding;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Represents a module, which consists typically of a class declaration
+ * but could include some imports, some statements and multiple classes
+ * intermixed with statements like scripts in Python or Ruby
+ *
+ * @author Jochen Theodorou
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ModuleNode extends ASTNode implements Opcodes {
+
+    private BlockStatement statementBlock = new BlockStatement();
+    List classes = new LinkedList();
+    private List methods = new ArrayList();
+    private List imports = new ArrayList();
+    private List importPackages = new ArrayList();
+    private Map importIndex = new HashMap();
+    private CompileUnit unit;
+    private String packageName;
+    private String description;
+    private boolean createClassForStatements = true;
+    private transient SourceUnit context;
+    private boolean importsResolved = false;
+
+
+    public ModuleNode (SourceUnit context ) {
+        this.context = context;
+    }
+
+    public ModuleNode (CompileUnit unit) {
+        this.unit = unit;
+    }
+
+    public BlockStatement getStatementBlock() {
+        return statementBlock;
+    }
+
+    public List getMethods() {
+        return methods;
+    }
+
+    public List getClasses() {
+        if (createClassForStatements && (!statementBlock.isEmpty() || !methods.isEmpty())) {
+            ClassNode mainClass = createStatementsClass();
+            createClassForStatements = false;
+            classes.add(0, mainClass);
+            mainClass.setModule(this);
+            addToCompileUnit(mainClass);
+        }
+        return classes;
+    }
+
+    public List getImports() {
+        return imports;
+    }
+
+    public List getImportPackages() {
+        return importPackages;
+    }
+
+    /**
+     * @return the class name for the given alias or null if none is available
+     */
+    public ClassNode getImport(String alias) {
+        return (ClassNode) importIndex.get(alias);
+    }
+
+    public void addImport(String alias, ClassNode type) {
+        imports.add(new ImportNode(type, alias));
+        importIndex.put(alias, type);
+    }
+
+    public String[]  addImportPackage(String packageName) {
+        importPackages.add(packageName);
+        return new String[] { /* class names, not qualified */ };
+    }
+
+    public void addStatement(Statement node) {
+        statementBlock.addStatement(node);
+    }
+
+    public void addClass(ClassNode node) {
+        classes.add(node);
+        node.setModule(this);
+        addToCompileUnit(node);
+    }
+
+    /**
+     * @param node
+     */
+    private void addToCompileUnit(ClassNode node) {
+        // register the new class with the compile unit
+        if (unit != null) {
+            unit.addClass(node);
+        }
+    }
+
+    public void addMethod(MethodNode node) {
+        methods.add(node);
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+    }
+
+    public String getPackageName() {
+        return packageName;
+    }
+
+    public void setPackageName(String packageName) {
+        this.packageName = packageName;
+    }
+    
+    public boolean hasPackageName(){
+        return this.packageName != null;
+    }
+
+    public SourceUnit getContext() {
+        return context;
+    }
+
+    /**
+     * @return the underlying character stream description
+     */
+    public String getDescription() {
+        if( context != null )
+        {
+            return context.getName();
+        }
+        else
+        {
+            return this.description;
+        }
+    }
+
+    public void setDescription(String description) {
+        // DEPRECATED -- context.getName() is now sufficient
+        this.description = description;
+    }
+
+    public CompileUnit getUnit() {
+        return unit;
+    }
+
+    void setUnit(CompileUnit unit) {
+        this.unit = unit;
+    }
+
+    protected ClassNode createStatementsClass() {
+        String name = getPackageName();
+        if (name == null) {
+            name = "";
+        }
+        // now lets use the file name to determine the class name
+        if (getDescription() == null) {
+            throw new RuntimeException("Cannot generate main(String[]) class for statements when we have no file description");
+        }
+        name += extractClassFromFileDescription();
+
+        String baseClassName = null;
+        if (unit != null) baseClassName = unit.getConfig().getScriptBaseClass();
+        ClassNode baseClass = null;
+        if (baseClassName!=null) {
+            baseClass = ClassHelper.make(baseClassName);
+        }
+        if (baseClass == null) {
+            baseClass = ClassHelper.SCRIPT_TYPE;
+        }
+        ClassNode classNode = new ClassNode(name, ACC_PUBLIC, baseClass);
+        classNode.setScript(true);
+        classNode.setScriptBody(true);
+
+        // return new Foo(new ShellContext(args)).run()
+        classNode.addMethod(
+            new MethodNode(
+                "main",
+                ACC_PUBLIC | ACC_STATIC,
+                ClassHelper.VOID_TYPE,
+                new Parameter[] { new Parameter(ClassHelper.STRING_TYPE.makeArray(), "args")},
+                ClassNode.EMPTY_ARRAY,
+                new ExpressionStatement(
+                    new MethodCallExpression(
+                        new ClassExpression(ClassHelper.make(InvokerHelper.class)),
+                        "runScript",
+                        new ArgumentListExpression(
+                            new Expression[] {
+                                new ClassExpression(classNode),
+                                new VariableExpression("args")})))));
+
+        classNode.addMethod(
+            new MethodNode("run", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, statementBlock));
+
+        classNode.addConstructor(ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new BlockStatement());
+        Statement stmt = new ExpressionStatement(
+                        new MethodCallExpression(
+                            new VariableExpression("super"),
+            				"setBinding",
+            				new ArgumentListExpression(
+                                    new Expression[] {
+                                        new VariableExpression("context")})));
+
+        classNode.addConstructor(
+            ACC_PUBLIC,
+            new Parameter[] { new Parameter(ClassHelper.make(Binding.class), "context")},
+			ClassNode.EMPTY_ARRAY,
+            stmt);
+
+        for (Iterator iter = methods.iterator(); iter.hasNext();) {
+            MethodNode node = (MethodNode) iter.next();
+            int modifiers = node.getModifiers();
+            if ((modifiers & ACC_ABSTRACT) != 0) {
+                throw new RuntimeException(
+                    "Cannot use abstract methods in a script, they are only available inside classes. Method: "
+                        + node.getName());
+            }
+            // br: the old logic seems to add static to all def f().... in a script, which makes enclosing
+            // inner classes (including closures) in a def function difficult. Comment it out.
+            node.setModifiers(modifiers /*| ACC_STATIC*/);
+
+            classNode.addMethod(node);
+        }
+        return classNode;
+    }
+
+    protected String extractClassFromFileDescription() {
+        // lets strip off everything after the last .
+        String answer = getDescription();
+        int idx = answer.lastIndexOf('.');
+        if (idx > 0) {
+            answer = answer.substring(0, idx);
+        }
+        // new lets trip the path separators
+        idx = answer.lastIndexOf('/');
+        if (idx >= 0) {
+            answer = answer.substring(idx + 1);
+        }
+        idx = answer.lastIndexOf(File.separatorChar);
+        if (idx >= 0) {
+            answer = answer.substring(idx + 1);
+        }
+        return answer;
+    }
+
+    public boolean isEmpty() {
+        return classes.isEmpty() && statementBlock.getStatements().isEmpty();
+    }
+    
+    public void sortClasses(){
+    	if (isEmpty()) return;
+    	List classes = getClasses();
+    	LinkedList sorted = new LinkedList();
+    	int level=1;
+    	while (!classes.isEmpty()) {
+	    	for (Iterator cni = classes.iterator(); cni.hasNext();) {
+				ClassNode cn = (ClassNode) cni.next();
+				ClassNode sn = cn;
+				for (int i=0; sn!=null && i<level; i++) sn = sn.getSuperClass();
+				if (sn!=null && sn.isPrimaryClassNode()) continue;
+				cni.remove();
+				sorted.addLast(cn);
+			}
+	    	level++;
+    	}
+    	this.classes = sorted;
+    }
+
+    public boolean hasImportsResolved() {
+        return importsResolved;
+    }
+
+    public void setImportsResolved(boolean importsResolved) {
+        this.importsResolved = importsResolved;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/Parameter.java b/groovy-core/src/main/org/codehaus/groovy/ast/Parameter.java
new file mode 100644
index 0000000..40235b4
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/Parameter.java
@@ -0,0 +1,134 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+import org.codehaus.groovy.ast.expr.*;
+
+/**
+ * Represents a parameter on a constructor or method call. The type name is
+ * optional - it should be defaulted to java.lang.Object if unknown.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class Parameter implements Variable {
+
+    public static final Parameter[] EMPTY_ARRAY = {
+    };
+
+    private ClassNode type;
+    private String name;
+    private boolean dynamicTyped;
+    private Expression defaultValue;
+    private boolean hasDefaultValue;
+    private boolean inStaticContext;
+    private boolean closureShare=false;
+
+    public Parameter(ClassNode type, String name) {
+        this.name = name;
+        this.setType(type);
+        this.hasDefaultValue = false;
+    }
+    
+    public Parameter(ClassNode type, String name, Expression defaultValue) {
+        this(type,name);
+        this.defaultValue = defaultValue;
+        this.hasDefaultValue = true;
+    }
+
+    public String toString() {
+        return super.toString() + "[name:" + name + ((type == null) ? "" : " type: " + type.getName()) + ", hasDefaultValue: " + this.hasInitialExpression() + "]";
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public ClassNode getType() {
+        return type;
+    }
+
+    public void setType(ClassNode type) {
+        this.type = type;
+        dynamicTyped |= type==ClassHelper.DYNAMIC_TYPE;
+    }
+    
+    public boolean hasInitialExpression() {
+        return this.hasDefaultValue;
+    }
+    
+    /**
+     * @return the default value expression for this parameter or null if
+     * no default value is specified
+     */
+    public Expression getInitialExpression() {
+        return defaultValue;
+    }
+    
+    public void setInitialExpression(Expression init) {
+        defaultValue = init;
+    }
+    
+    public boolean isInStaticContext() {
+        return inStaticContext;
+    }
+    
+    public void setInStaticContext(boolean inStaticContext) {
+        this.inStaticContext = inStaticContext;
+    }
+
+    public boolean isDynamicTyped() {
+        return dynamicTyped;
+    }
+
+    public boolean isClosureSharedVariable() {
+        return closureShare;
+    }
+
+    public void setClosureSharedVariable(boolean inClosure) {
+        closureShare = inClosure;        
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/PropertyNode.java b/groovy-core/src/main/org/codehaus/groovy/ast/PropertyNode.java
new file mode 100644
index 0000000..5da4c8b
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/PropertyNode.java
@@ -0,0 +1,136 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+import org.codehaus.groovy.ast.expr.*;
+import org.codehaus.groovy.ast.stmt.*;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Represents a property (member variable, a getter and setter)
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class PropertyNode extends AnnotatedNode implements Opcodes,Variable {
+
+    private FieldNode field;
+    private Statement getterBlock;
+    private Statement setterBlock;
+    private int modifiers;
+    private boolean closureShare = false;
+
+    public PropertyNode(
+        String name, int modifiers, ClassNode type, ClassNode owner,
+        Expression initialValueExpression, Statement getterBlock,
+        Statement setterBlock)
+    {
+        this(new FieldNode(name, modifiers & ACC_STATIC, type, owner, initialValueExpression), modifiers, getterBlock, setterBlock);
+    }
+
+    public PropertyNode(FieldNode field, int modifiers, Statement getterBlock, Statement setterBlock) {
+        this.field = field;
+        this.modifiers = modifiers;
+        this.getterBlock = getterBlock;
+        this.setterBlock = setterBlock;
+    }
+
+    public Statement getGetterBlock() {
+        return getterBlock;
+    }
+
+    public Expression getInitialExpression() {
+        return field.getInitialExpression();
+    }
+
+    public int getModifiers() {
+        return modifiers;
+    }
+
+    public String getName() {
+        return field.getName();
+    }
+
+    public Statement getSetterBlock() {
+        return setterBlock;
+    }
+
+    public ClassNode getType() {
+        return field.getType();
+    }
+
+    public void setType(ClassNode t) {
+        field.setType(t);
+    }
+    
+    public FieldNode getField() {
+        return field;
+    }
+
+    public boolean isPrivate() {
+        return (modifiers & ACC_PRIVATE) != 0;
+    }
+
+    public boolean hasInitialExpression() {
+        return field.hasInitialExpression();
+    }
+
+    public boolean isInStaticContext() {
+        return field.isInStaticContext();
+    }
+
+    public boolean isDynamicTyped() {
+        return field.isDynamicTyped();
+    }
+
+    public boolean isClosureSharedVariable() {
+        return false;
+    }
+    
+    public void setClosureSharedVariable(boolean inClosure) {
+        closureShare = inClosure;        
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/Variable.java b/groovy-core/src/main/org/codehaus/groovy/ast/Variable.java
new file mode 100644
index 0000000..479c1db
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/Variable.java
@@ -0,0 +1,90 @@
+/*
+$Id$
+
+Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+package org.codehaus.groovy.ast;
+
+import org.codehaus.groovy.ast.expr.Expression;
+
+/**
+ * interface to mark a AstNode as Variable. Typically these are 
+ * VariableExpression, FieldNode, PropertyNode and Parameter
+ * 
+ * @author Jochen Theodorou
+ */
+public interface Variable {
+    
+    /**
+     * the type of the variable
+     */
+    public ClassNode getType();
+    
+    /**
+     * the name of the variable
+     */
+    public String getName();
+    
+    /**
+     * expression used to initialize the variable or null of there
+     * is no initialization.
+     */
+    public Expression getInitialExpression();
+    
+    /**
+     * returns true if there is an initialization expression
+     */
+    public boolean hasInitialExpression();
+    
+    /**
+     * returns true if this variable is used in a static context.
+     * A static context is any static initializer block, when this variable
+     * is declared as static or when this variable is used in a static method 
+     */
+    public boolean isInStaticContext();
+
+    public boolean isDynamicTyped();
+    public boolean isClosureSharedVariable();
+    public void setClosureSharedVariable(boolean inClosure);
+    
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/VariableScope.java b/groovy-core/src/main/org/codehaus/groovy/ast/VariableScope.java
new file mode 100644
index 0000000..ae230bf
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/VariableScope.java
@@ -0,0 +1,142 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents a variable scope. This is primarily used to determine variable sharing
+ * across method and closure boundaries.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Jochen Theodorou
+ * @version $Revision$
+ */
+public class VariableScope  {
+    private Map declaredVariables = new HashMap();
+    private Map referencedLocalVariables = new HashMap();
+    private Map referencedClassVariables = new HashMap();
+ 
+    private boolean inStaticContext = false;
+    private boolean resolvesDynamic = false; 
+    private ClassNode clazzScope;
+    private VariableScope parent;
+
+    public VariableScope() {
+    }
+    public VariableScope(VariableScope parent) {
+        this.parent = parent;
+    }
+    public Map getDeclaredVariables() {
+        return declaredVariables;
+    }
+    public Variable getDeclaredVariable(String name) {
+        return (Variable) declaredVariables.get(name);
+    }
+    public Map getReferencedLocalVariables() {
+        return referencedLocalVariables;
+    }
+    
+    public boolean isReferencedLocalVariable(String name) {
+        return referencedLocalVariables.containsKey(name);
+    }
+    
+    public Map getReferencedClassVariables() {
+        return referencedClassVariables;
+    }
+    
+    public boolean isReferencedClassVariable(String name) {
+        return referencedClassVariables.containsKey(name);
+    }
+    public VariableScope getParent() {
+        return parent;
+    }
+
+    public boolean isInStaticContext() {
+        return inStaticContext;
+    }
+
+    public void setInStaticContext(boolean inStaticContext) {
+        this.inStaticContext = inStaticContext;
+    }
+
+    public boolean isResolvingDynamic() {
+        return resolvesDynamic;
+    }
+
+    public void setDynamicResolving(boolean resolvesDynamic) {
+        this.resolvesDynamic = resolvesDynamic;
+    }
+
+    public void setClassScope(ClassNode node) {
+        this.clazzScope = node;
+    }
+    
+    public ClassNode getClassScope(){
+        return clazzScope;
+    }
+    
+    public boolean isClassScope(){
+        return clazzScope!=null;
+    }
+    
+    public boolean isRoot() {
+        return parent==null;
+    }
+    
+    public VariableScope copy() {
+        VariableScope copy = new VariableScope();
+        copy.clazzScope = clazzScope;
+        copy.declaredVariables.putAll(declaredVariables);
+        copy.inStaticContext = inStaticContext;
+        copy.parent = parent;
+        copy.referencedClassVariables.putAll(referencedClassVariables);
+        copy.referencedLocalVariables.putAll(referencedLocalVariables);
+        copy.resolvesDynamic = resolvesDynamic;
+        return copy;
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/ArgumentListExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ArgumentListExpression.java
new file mode 100644
index 0000000..8ff1410
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ArgumentListExpression.java
@@ -0,0 +1,93 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import java.util.List;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.Parameter;
+
+/**
+ * Represents one or more arguments being passed into a method
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ArgumentListExpression extends TupleExpression {
+
+    public static final Object[] EMPTY_ARRAY = {
+    };
+    
+    public static final ArgumentListExpression EMPTY_ARGUMENTS = new ArgumentListExpression();
+
+    public ArgumentListExpression() {
+    }
+
+    public ArgumentListExpression(List expressions) {
+        super(expressions);
+    }
+
+    public ArgumentListExpression(Expression[] expressions) {
+        super(expressions);
+    }
+
+    public ArgumentListExpression(Parameter[] parameters) {
+        for (int i = 0; i < parameters.length; i++) {
+            Parameter parameter = parameters[i];
+            addExpression(new VariableExpression(parameter.getName()));
+        }
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new ArgumentListExpression(transformExpressions(getExpressions(), transformer));
+        ret.setSourcePosition(this);
+        return ret;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitArgumentlistExpression(this);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/ArrayExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ArrayExpression.java
new file mode 100644
index 0000000..ea818c6
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ArrayExpression.java
@@ -0,0 +1,168 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents an array object construction either using a fixed size
+ * or an initializer expression
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ArrayExpression extends Expression {
+    private List expressions;
+    private List sizeExpression;
+
+    private ClassNode elementType;
+    
+    private static ClassNode makeArray(ClassNode base, List sizeExpression) {
+    	ClassNode ret = base.makeArray();
+    	if (sizeExpression==null) return ret;
+    	int size = sizeExpression.size();
+    	for (int i=1; i<size; i++) {
+    		ret = ret.makeArray();
+    	}
+    	return ret;
+    }
+    
+    public ArrayExpression(ClassNode elementType, List expressions, List sizeExpression) {
+        //expect to get the elementType
+        super.setType(makeArray(elementType,sizeExpression));
+        if (expressions==null) expressions=Collections.EMPTY_LIST;
+        this.elementType = elementType;
+        this.expressions = expressions;
+        this.sizeExpression = sizeExpression;
+        
+        for (Iterator iter = expressions.iterator(); iter.hasNext();) {
+            Object item = iter.next();
+            if (item!=null && !(item instanceof Expression)) {
+                throw new ClassCastException("Item: " + item + " is not an Expression");
+            }
+        }
+        if (sizeExpression!=null) {
+	        for (Iterator iter = sizeExpression.iterator(); iter.hasNext();) {
+	            Object item = iter.next();
+	            if (!(item instanceof Expression)) {
+	                throw new ClassCastException("Item: " + item + " is not an Expression");
+	            }
+	        }
+        }
+    }
+    
+    
+    /**
+     * Creates an array using an initializer expression
+     */
+    public ArrayExpression(ClassNode elementType, List expressions) {
+        this(elementType,expressions,null);
+    }
+
+    public void addExpression(Expression expression) {
+        expressions.add(expression);
+    }
+
+    public List getExpressions() {
+        return expressions;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitArrayExpression(this);
+    }
+
+    public boolean isDynamic() {
+        return false;
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+    	List exprList = transformExpressions(expressions, transformer);
+    	List sizes = null;
+    	if (sizeExpression!=null) sizes = transformExpressions(sizeExpression,transformer);
+        Expression ret = new ArrayExpression(elementType, exprList, sizes);
+        ret.setSourcePosition(this);
+        return ret;
+    }
+
+    public Expression getExpression(int i) {
+        Object object = expressions.get(i);
+        return (Expression) object;
+    }
+
+    public ClassNode getElementType() {
+        return elementType;
+    }
+    
+    public String getText() {
+        StringBuffer buffer = new StringBuffer("[");
+        boolean first = true;
+        for (Iterator iter = expressions.iterator(); iter.hasNext();) {
+            if (first) {
+                first = false;
+            }
+            else {
+                buffer.append(", ");
+            }
+
+            buffer.append(((Expression) iter.next()).getText());
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+
+    public List getSizeExpression() {
+        return sizeExpression;
+    }
+
+    public String toString() {
+        return super.toString() + expressions;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/AttributeExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/AttributeExpression.java
new file mode 100644
index 0000000..743f157
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/AttributeExpression.java
@@ -0,0 +1,76 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+
+/**
+ * Represents an attribute access (accessing the field of a class) such as the expression "foo.@bar".
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class AttributeExpression extends PropertyExpression {
+
+    public AttributeExpression(Expression objectExpression, Expression property) {
+        super(objectExpression, property, false);
+    }
+
+    public AttributeExpression(Expression objectExpression, Expression property, boolean safe) {
+        super(objectExpression, property, safe);
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitAttributeExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new AttributeExpression(transformer.transform(getObjectExpression()),transformer.transform(getProperty()),isSafe());
+        ret.setSourcePosition(this);
+        return ret;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/BinaryExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/BinaryExpression.java
new file mode 100644
index 0000000..3b84d62
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/BinaryExpression.java
@@ -0,0 +1,146 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
+
+/**
+ * Represents two expressions and an operation
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class BinaryExpression extends Expression {
+    
+    private Expression leftExpression;
+    private Expression rightExpression;
+    private Token operation;
+    
+    public BinaryExpression(Expression leftExpression,
+                            Token operation,
+                            Expression rightExpression) {
+        this.leftExpression = leftExpression;
+        this.operation = operation;
+        this.rightExpression = rightExpression;
+    }
+
+    public String toString() {
+        return super.toString() +"[" + leftExpression + operation + rightExpression + "]";
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitBinaryExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new BinaryExpression(transformer.transform(leftExpression), operation, transformer.transform(rightExpression));
+        ret.setSourcePosition(this);
+        return ret;
+    }
+
+    public Expression getLeftExpression() {
+        return leftExpression;
+    }
+
+    public void setLeftExpression(Expression leftExpression) {
+        this.leftExpression = leftExpression;
+    }
+
+    public void setRightExpression(Expression rightExpression) {
+        this.rightExpression = rightExpression;
+    }
+
+    public Token getOperation() {
+        return operation;
+    }
+
+    public Expression getRightExpression() {
+        return rightExpression;
+    }
+
+    public String getText() {
+        if (operation.getType() == Types.LEFT_SQUARE_BRACKET) {
+            return leftExpression.getText() + "[" + rightExpression.getText() + "]";
+        }
+        return "(" + leftExpression.getText() + " " + operation.getText() + " " + rightExpression.getText() + ")";
+    }
+    
+    
+   /**
+    *  Creates an assignment expression in which the specified expression
+    *  is written into the specified variable name.   
+    */
+    
+    public static BinaryExpression newAssignmentExpression( Variable variable, Expression rhs ) {
+    	VariableExpression lhs = new VariableExpression( variable );
+    	Token         operator = Token.newPlaceholder( Types.ASSIGN );
+    
+    	return new BinaryExpression( lhs, operator, rhs );
+    }
+
+
+    /**
+     *  Creates variable initialization expression in which the specified expression
+     *  is written into the specified variable name.   
+     */
+     
+     public static BinaryExpression newInitializationExpression( String variable, ClassNode type, Expression rhs ) {
+     	VariableExpression lhs = new VariableExpression( variable );
+     
+     	if( type != null ) {
+     	    lhs.setType(type);
+     	}
+     
+     	Token operator = Token.newPlaceholder( Types.ASSIGN );
+     
+        return new BinaryExpression( lhs, operator, rhs );
+     }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/BitwiseNegExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/BitwiseNegExpression.java
new file mode 100644
index 0000000..d3d120c
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/BitwiseNegExpression.java
@@ -0,0 +1,72 @@
+/*
+ * $Id: BitwiseNegExpression.java,v 1.0 2005/02/21 10:46:54 phk Exp
+ * 
+ * Copyright 2005 (C) Pilho Kim. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * @author phk
+ */
+public class BitwiseNegExpression extends Expression {
+
+    private Expression expression;
+	
+    public BitwiseNegExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitBitwiseNegExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new BitwiseNegExpression(transformer.transform(expression));
+        ret.setSourcePosition(this);
+        return ret;
+    }
+
+    public String getText() {
+		return expression.getText();
+	}
+
+    public ClassNode getType() {
+        return expression.getType();
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/BooleanExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/BooleanExpression.java
new file mode 100644
index 0000000..22c4a2f
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/BooleanExpression.java
@@ -0,0 +1,82 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a boolean expression
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class BooleanExpression extends Expression {
+    private Expression expression;
+
+    public BooleanExpression(Expression expression) {
+        this.expression = expression;
+        setType(ClassHelper.boolean_TYPE); // for consistancy with AsmClassGenerator. see AsmClassGenerator.visitBooleanExpression.  
+    }
+    
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitBooleanExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new BooleanExpression(transformer.transform(expression));
+        ret.setSourcePosition(this);
+        return ret;    }
+    
+    public String getText() {
+        return expression.getText();
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/CastExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/CastExpression.java
new file mode 100644
index 0000000..d1f1916
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/CastExpression.java
@@ -0,0 +1,118 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a type cast expression
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class CastExpression extends Expression {
+    
+    private Expression expression;
+    private boolean ignoreAutoboxing=false;
+    private boolean coerce = false;
+
+    public static CastExpression asExpression(ClassNode type, Expression expression) {
+        CastExpression answer = new CastExpression(type, expression);
+        answer.setCoerce(true);
+        return answer;
+    }
+
+    public CastExpression(ClassNode type, Expression expression) {
+        this(type,expression,false);
+    }
+
+    public CastExpression(ClassNode type, Expression expression, boolean ignoreAutoboxing) {
+        super.setType(type);
+        this.expression = expression;
+        this.ignoreAutoboxing = ignoreAutoboxing;
+    }
+    
+    public boolean isIgnoringAutoboxing(){
+        return ignoreAutoboxing;
+    }
+
+    public boolean isCoerce() {
+        return coerce;
+    }
+
+    public void setCoerce(boolean coerce) {
+        this.coerce = coerce;
+    }
+
+    public String toString() {
+        return super.toString() +"[(" + getType().getName() + ") " + expression + "]";
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitCastExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        CastExpression ret =  new CastExpression(getType(), transformer.transform(expression));
+        ret.setSourcePosition(this);
+        ret.setCoerce(this.isCoerce());
+        return ret;
+    }
+    
+    public String getText() {
+        return "(" + getType() + ") " + expression.getText();
+    }
+ 
+    public Expression getExpression() {
+        return expression;
+    }
+    
+    public void setType(ClassNode t) {
+        super.setType(t);
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/ClassExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ClassExpression.java
new file mode 100644
index 0000000..a238752
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ClassExpression.java
@@ -0,0 +1,79 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents access to a Java/Groovy class in an expression, such
+ * as when invoking a static method or accessing a static type
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ClassExpression extends Expression {
+
+    public ClassExpression(ClassNode type) {
+        super.setType(type);
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitClassExpression(this);
+    }
+    
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        return this;
+    }
+    
+    public String getText() {
+        return getType().getName();
+    }
+
+    public String toString() {
+       return super.toString() + "[type: " + getType().getName() + "]";
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/ClosureExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ClosureExpression.java
new file mode 100644
index 0000000..1a6ca23
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ClosureExpression.java
@@ -0,0 +1,107 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+
+/**
+ * Represents a closure creation expression such as { statement; } 
+ * or { i : statement; } or { i, x, String y: statement }
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ClosureExpression extends Expression {
+    
+    private Parameter[] parameters;
+    private Statement code;
+    private VariableScope variableScope;
+    
+    public ClosureExpression(Parameter[] parameters, Statement code) {
+        this.parameters = parameters;
+        this.code = code;
+        super.setType(ClassHelper.CLOSURE_TYPE);
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitClosureExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        return this;
+    }
+    
+    public String toString() {
+        return super.toString() + InvokerHelper.toString(parameters) + "{ " + code + " }";
+    }
+
+    public Statement getCode() {
+        return code;
+    }
+
+    public Parameter[] getParameters() {
+        return parameters;
+    }
+
+    public boolean isParameterSpecified() {
+        return parameters != null && parameters.length > 0;
+    }
+    
+    public VariableScope getVariableScope() {
+        return variableScope;
+    }
+
+    public void setVariableScope(VariableScope variableScope) {
+        this.variableScope = variableScope;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/ConstantExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ConstantExpression.java
new file mode 100644
index 0000000..1702e20
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ConstantExpression.java
@@ -0,0 +1,97 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a constant expression such as null, true, false
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ConstantExpression extends Expression {
+    public static final ConstantExpression VOID = new ConstantExpression(Void.class);
+    public static final ConstantExpression NULL = new ConstantExpression(null);
+    public static final ConstantExpression TRUE = new ConstantExpression(Boolean.TRUE);
+    public static final ConstantExpression FALSE = new ConstantExpression(Boolean.FALSE);
+    public static final ConstantExpression EMPTY_STRING = new ConstantExpression("");
+    //public static final Expression EMPTY_ARRAY = new PropertyExpression(new ClassExpression(ArgumentListExpression.class.getName()), "EMPTY_ARRAY");
+    public static final ConstantExpression EMTPY_EXPRESSION = new ConstantExpression(null);
+    
+    private Object value;
+    
+    public ConstantExpression(Object value) {
+        this.value = value;
+        if (this.value != null)
+            setType(ClassHelper.make(value.getClass()));
+    }
+
+    public String toString() {
+        return super.toString() +"[value=" + value + "]";
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitConstantExpression(this);
+    }
+
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        return this;
+    }
+
+    /**
+     * @return the value of this constant expression
+     */    
+    public Object getValue() {
+        return value;
+    }
+
+    public String getText() {
+        return (value == null) ? "null" : value.toString();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/ConstructorCallExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ConstructorCallExpression.java
new file mode 100644
index 0000000..7927367
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ConstructorCallExpression.java
@@ -0,0 +1,115 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * A constructor call
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Jochen Theodorou
+ * @version $Revision$
+ */
+public class ConstructorCallExpression extends Expression {
+
+    private Expression arguments;
+
+    public ConstructorCallExpression(ClassNode type, Expression arguments) {
+        super.setType(type);
+        if (!(arguments instanceof TupleExpression)){
+            TupleExpression tuple = new TupleExpression();
+            tuple.addExpression(arguments);
+            this.arguments = tuple;
+        } else {
+            this.arguments = arguments;
+        }
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitConstructorCallExpression(this);
+    }
+    
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression args = transformer.transform(arguments);
+        Expression ret = new ConstructorCallExpression(getType(), args);
+        ret.setSourcePosition(this);
+        return ret;
+    }
+
+    public Expression getArguments() {
+        return arguments;
+    }
+
+    public String getText() {
+        String text = null;
+        if (isSuperCall()) {
+            text = "super ";
+        } else if (isThisCall()) {
+            text = "this ";
+        } else {
+            text = "new "+ getType().getName();
+        }
+        return text + arguments.getText();
+    }
+
+    public String toString() {
+        return super.toString() + "[type: " + getType() + " arguments: " + arguments + "]";
+    }
+    
+    public boolean isSuperCall() {
+        return getType()==ClassNode.SUPER;
+    }
+    
+    public boolean isSpecialCall(){
+        return isThisCall() || isSuperCall();
+    }
+    
+    public boolean isThisCall() {
+        return getType()==ClassNode.THIS;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/DeclarationExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/DeclarationExpression.java
new file mode 100644
index 0000000..2a3fc16
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/DeclarationExpression.java
@@ -0,0 +1,82 @@
+/*
+$Id$
+
+Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.syntax.Token;
+
+/**
+ * Represents a local variable name declaration, an expression like 
+ * "def foo" or with type "String foo".
+ * 
+ * @author Jochen Theodorou
+ * @version $Revision$
+ */
+public class DeclarationExpression extends BinaryExpression {
+    
+    public DeclarationExpression(VariableExpression left, Token operation, Expression right) {
+        super(left,operation,right);
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitDeclarationExpression(this);
+    }
+    
+    public VariableExpression getVariableExpression() {
+        return (VariableExpression) this.getLeftExpression();
+    }
+    
+    public void setLeftExpression(Expression leftExpression) {
+        super.setLeftExpression((VariableExpression) leftExpression);
+    }
+    
+    
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret =  new DeclarationExpression((VariableExpression) transformer.transform(getLeftExpression()), getOperation(), transformer.transform(getRightExpression()));
+        ret.setSourcePosition(this);
+        return ret;        
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/Expression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/Expression.java
new file mode 100644
index 0000000..6e461ed
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/Expression.java
@@ -0,0 +1,91 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+
+/**
+ * Represents a base class for expressions which evaluate as an object
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public abstract class Expression extends ASTNode {
+
+    private ClassNode type=ClassHelper.DYNAMIC_TYPE;
+    
+    /**
+     * Return a copy of the expression calling the transformer on any nested expressions 
+     * @param transformer
+     */
+    public abstract Expression transformExpression(ExpressionTransformer transformer);
+
+    /**
+     * Transforms the list of expressions
+     * @return a new list of transformed expressions
+     */
+    protected List transformExpressions(List expressions, ExpressionTransformer transformer) {
+        List list = new ArrayList(expressions.size());
+        for (Iterator iter = expressions.iterator(); iter.hasNext(); ) {
+            list.add(transformer.transform((Expression) iter.next()));
+        }
+        return list;
+    }
+    
+    public ClassNode getType() {
+        return type;
+    }
+    
+    public void setType(ClassNode t) {
+        type=t;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/ExpressionTransformer.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ExpressionTransformer.java
new file mode 100644
index 0000000..ca1fbb8
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ExpressionTransformer.java
@@ -0,0 +1,61 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+
+/**
+ * Provides a way to transform expressions
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public interface ExpressionTransformer {
+    
+    /** 
+     * Transforms the given expression into another expression
+     */
+    public Expression transform(Expression expression);
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/FieldExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/FieldExpression.java
new file mode 100644
index 0000000..4b92aab
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/FieldExpression.java
@@ -0,0 +1,98 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a field access such as the expression "this.foo".
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class FieldExpression extends Expression {
+
+    private FieldNode field;
+    
+    public FieldExpression(FieldNode field) {
+        this.field = field;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitFieldExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        return this;
+    }
+    
+    public String getFieldName() {
+        return field.getName();
+    }
+
+    public FieldNode getField() {
+        return field;
+    }
+
+    public String getText() {
+        return "this." + field.getName();
+    }
+
+    public boolean isDynamicTyped() {
+        return field.isDynamicTyped();
+    }
+
+    public void setType(ClassNode type) {
+        super.setType(type);
+        field.setType(type);
+    }
+    
+    public ClassNode getType() {
+        return field.getType();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/GStringExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/GStringExpression.java
new file mode 100644
index 0000000..8ae980b
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/GStringExpression.java
@@ -0,0 +1,143 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a String expression which contains embedded values inside
+ * it such as "hello there ${user} how are you" which is expanded lazily
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class GStringExpression extends Expression {
+
+    private String verbatimText;
+    private List strings = new ArrayList();
+    private List values = new ArrayList();
+    
+    public GStringExpression(String verbatimText) {
+        this.verbatimText = verbatimText;
+        super.setType(ClassHelper.GSTRING_TYPE);
+    }
+
+    public GStringExpression(String verbatimText, List strings, List values) {
+        this.verbatimText = verbatimText;
+        this.strings = strings;
+        this.values = values;
+        super.setType(ClassHelper.GSTRING_TYPE);
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitGStringExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new GStringExpression(
+                verbatimText,
+                transformExpressions(strings, transformer),
+                transformExpressions(values, transformer));
+        ret.setSourcePosition(this);
+        return ret;        
+    }
+
+    public String toString() {
+        return super.toString() + "[strings: " + strings + " values: " + values + "]";
+    }
+
+    public String getText() {
+        return verbatimText;
+    }
+
+    public List getStrings() {
+        return strings;
+    }
+
+    public List getValues() {
+        return values;
+    }
+
+    public void addString(ConstantExpression text) {
+        if (text == null) {
+            throw new NullPointerException("Cannot add a null text expression");
+        }
+        strings.add(text);
+    }
+
+    public void addValue(Expression value) {
+        // If the first thing is an value, then we need a dummy empty string in front of it so that when we
+        // toString it they come out in the correct order.
+        if (strings.size() == 0)
+            strings.add(ConstantExpression.EMPTY_STRING);
+        values.add(value);
+    }
+
+    public Expression getValue(int idx) {
+        return (Expression) values.get(idx);
+    }
+
+    public boolean isConstantString() {
+        return values.isEmpty();
+    }
+
+    public Expression asConstantString() {
+        StringBuffer buffer = new StringBuffer();
+        for (Iterator iter = strings.iterator(); iter.hasNext();) {
+            ConstantExpression expression = (ConstantExpression) iter.next();
+            Object value = expression.getValue();
+            if (value != null) {
+                buffer.append(value);
+            }
+        }
+        return new ConstantExpression(buffer.toString());
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/ListExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ListExpression.java
new file mode 100644
index 0000000..798761a
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/ListExpression.java
@@ -0,0 +1,117 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a list expression [1, 2, 3] which creates a mutable List
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ListExpression extends Expression {
+    private List expressions;
+
+    public ListExpression() {
+        this(new ArrayList());
+    }
+    
+    public ListExpression(List expressions) {
+        this.expressions = expressions;
+        //TODO: get the type's of the expressions to specify the
+        // list type to List<X> if possible.
+        setType(ClassHelper.LIST_TYPE);
+    }
+    
+    public void addExpression(Expression expression) {
+        expressions.add(expression);
+    }
+    
+    public List getExpressions() {
+        return expressions;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitListExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new ListExpression(transformExpressions(getExpressions(), transformer));
+        ret.setSourcePosition(this);
+        return ret;       
+    }
+
+    public Expression getExpression(int i) {
+        return (Expression) expressions.get(i);
+    }
+
+    public String getText() {
+        StringBuffer buffer = new StringBuffer("[");
+        boolean first = true;
+        for (Iterator iter = expressions.iterator(); iter.hasNext(); ) {
+            if (first) {
+                first = false;
+            }
+            else {
+                buffer.append(", ");
+            }
+            
+            buffer.append(((Expression)iter.next()).getText());
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+
+    public String toString() {
+        return super.toString() + expressions;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/MapEntryExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/MapEntryExpression.java
new file mode 100644
index 0000000..d5b78fc
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/MapEntryExpression.java
@@ -0,0 +1,88 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+
+/**
+ * Represents an entry inside a map expression such as 1 : 2.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MapEntryExpression extends Expression {
+    private Expression keyExpression;
+    private Expression valueExpression;
+
+    public MapEntryExpression(Expression keyExpression, Expression valueExpression) {
+        this.keyExpression = keyExpression;
+        this.valueExpression = valueExpression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitMapEntryExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new MapEntryExpression(transformer.transform(keyExpression), transformer.transform(valueExpression));
+        ret.setSourcePosition(this);
+        return ret;        
+    }
+
+    public String toString() {
+        return super.toString() + "(key: " + keyExpression + ", value: " + valueExpression + ")";
+    }
+
+    public Expression getKeyExpression() {
+        return keyExpression;
+    }
+
+    public Expression getValueExpression() {
+        return valueExpression;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/MapExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/MapExpression.java
new file mode 100644
index 0000000..06251c9
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/MapExpression.java
@@ -0,0 +1,125 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a map expression [1 : 2, "a" : "b", x : y] which creates a mutable Map
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MapExpression extends Expression {
+    private List mapEntryExpressions;
+
+    public MapExpression() {
+        this(new ArrayList());
+    }
+    
+    public MapExpression(List mapEntryExpressions) {
+        this.mapEntryExpressions = mapEntryExpressions;
+        //TODO: get the type's of the expressions to specify the
+        // map type to Map<X> if possible.
+        setType(ClassHelper.MAP_TYPE);
+    }
+    
+    public void addMapEntryExpression(MapEntryExpression expression) {
+        mapEntryExpressions.add(expression);
+    }
+    
+    public List getMapEntryExpressions() {
+        return mapEntryExpressions;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitMapExpression(this);
+    }
+
+    public boolean isDynamic() {
+        return false;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new MapExpression(transformExpressions(getMapEntryExpressions(), transformer));
+        ret.setSourcePosition(this);
+        return ret;        
+    }
+    
+    public String toString() {
+        return super.toString() + mapEntryExpressions;
+    }
+
+    public String getText() {
+        StringBuffer sb = new StringBuffer(32);
+        sb.append("[");
+        int size = mapEntryExpressions.size();
+        MapEntryExpression mapEntryExpression = null;
+        if (size > 0) {
+            mapEntryExpression = (MapEntryExpression) mapEntryExpressions.get(0);
+            sb.append(mapEntryExpression.getKeyExpression().getText() + ":" + mapEntryExpression.getValueExpression().getText());
+            for (int i = 1; i < size; i++) {
+                mapEntryExpression = (MapEntryExpression) mapEntryExpressions.get(i);
+                sb.append(", " + mapEntryExpression.getKeyExpression().getText() + ":" + mapEntryExpression.getValueExpression().getText());
+                if (sb.length() > 120 && i < size - 1) {
+                    sb.append(", ... ");
+                    break;
+                }
+            }
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public void addMapEntryExpression(Expression keyExpression, Expression valueExpression) {
+        addMapEntryExpression(new MapEntryExpression(keyExpression, valueExpression));
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/MethodCallExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/MethodCallExpression.java
new file mode 100644
index 0000000..34e77e4
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/MethodCallExpression.java
@@ -0,0 +1,178 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import groovy.lang.MetaMethod;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * A method call on an object or class
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MethodCallExpression extends Expression {
+
+    private Expression objectExpression;
+    private Expression method;
+    private Expression arguments;
+    private boolean spreadSafe = false;
+    private boolean safe = false;
+    private boolean implicitThis;
+    
+    public static Expression NO_ARGUMENTS = new TupleExpression();
+
+    public MetaMethod getMetaMethod() {
+        return metaMethod;
+    }
+
+    private MetaMethod metaMethod = null;
+
+    public MethodCallExpression(Expression objectExpression, String method, Expression arguments) {
+        this(objectExpression,new ConstantExpression(method),arguments);
+    }
+    
+    public MethodCallExpression(Expression objectExpression, Expression method, Expression arguments) {
+        this.objectExpression = objectExpression;
+        this.method = method;
+        this.arguments = arguments;
+        //TODO: set correct type here
+        // if setting type and a methodcall is the last expresssion in a method,
+        // then the method will return null if the method itself is not void too!
+        // (in bytecode after call: aconst_null, areturn)
+        this.setType(ClassHelper.DYNAMIC_TYPE);
+        this.setImplicitThis(true);
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitMethodCallExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        MethodCallExpression answer =
+            new MethodCallExpression(transformer.transform(objectExpression), transformer.transform(method), transformer.transform(arguments));
+        answer.setSafe(safe);
+        answer.setSourcePosition(this);
+        return answer;
+    }
+
+    public Expression getArguments() {
+        return arguments;
+    }
+
+    public Expression getMethod() {
+        return method;
+    }
+    
+    /**
+     * This method returns the method name as String if it is no dynamic
+     * calculated method name, but an constant.
+     */
+    public String getMethodAsString() {
+        if (! (method instanceof ConstantExpression)) return null;
+        ConstantExpression constant = (ConstantExpression) method;
+        return constant.getText();
+    }
+
+    public Expression getObjectExpression() {
+        return objectExpression;
+    }
+
+    public String getText() {
+        return objectExpression.getText() + "." + method.getText() + arguments.getText();
+    }
+
+    /**
+     * @return is this a safe method call, i.e. if true then if the source object is null
+     * then this method call will return null rather than throwing a null pointer exception
+     */
+    public boolean isSafe() {
+        return safe;
+    }
+
+    public void setSafe(boolean safe) {
+        this.safe = safe;
+    }
+
+    public boolean isSpreadSafe() {
+        return spreadSafe;
+    }
+
+    public void setSpreadSafe(boolean value) {
+        spreadSafe = value;
+    }
+
+    /**
+     * @return true if no object expression was specified otherwise if 
+     * some expression was specified for the object on which to evaluate
+     * the method then return false
+     */
+    public boolean isImplicitThis() {
+        return implicitThis;
+    }
+
+    public void setImplicitThis(boolean implicitThis) {
+        this.implicitThis = implicitThis;
+    }
+
+    public String toString() {
+        return super.toString()
+            + "[object: "
+            + objectExpression
+            + " method: "
+            + method
+            + " arguments: "
+            + arguments
+            + "]";
+    }
+
+    public void setMethod(MetaMethod mmeth) {
+        this.metaMethod = mmeth;
+        super.setType(ClassHelper.make(mmeth.getReturnType()));
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/MethodPointerExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/MethodPointerExpression.java
new file mode 100644
index 0000000..2b22891
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/MethodPointerExpression.java
@@ -0,0 +1,118 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import groovy.lang.Closure;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a method pointer on an object such as
+ * foo.&bar which means find the method pointer on foo for the method called "bar"
+ * which is equivalent to
+ * <code>
+ * foo.metaClass.getMethodPointer(foo, "bar")
+ * 
+ * @version $Revision$
+ */
+public class MethodPointerExpression extends Expression {
+
+    private Expression expression;
+    private String methodName;
+
+    public MethodPointerExpression(Expression expression, String methodName) {
+        this.expression = expression;
+        this.methodName = methodName;
+    }
+
+    public Expression getExpression() {
+	if (expression == null)
+	    return VariableExpression.THIS_EXPRESSION;
+	else
+	    return expression;
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitMethodPointerExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret;
+        if (expression == null) {
+	        ret = new MethodPointerExpression(VariableExpression.THIS_EXPRESSION, methodName);
+        } else {
+	        ret = new MethodPointerExpression(transformer.transform(expression), methodName);
+        }
+        ret.setSourcePosition(this);
+        return ret;        
+    }
+
+    public String getText() {
+        if (expression == null) {
+            return "&" + methodName;
+        } else {
+            return expression.getText() + ".&" + methodName;
+        }
+    }
+
+    public ClassNode getType() {
+        return ClassHelper.CLOSURE_TYPE;
+    }
+
+    public boolean isDynamic() {
+        return false;
+    }
+
+    public Class getTypeClass() {
+        return Closure.class;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/NamedArgumentListExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/NamedArgumentListExpression.java
new file mode 100644
index 0000000..ab8f418
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/NamedArgumentListExpression.java
@@ -0,0 +1,71 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import java.util.List;
+
+/**
+ * Represents one or more arguments being passed into a method by name
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class NamedArgumentListExpression extends MapExpression {
+
+    public NamedArgumentListExpression() {
+    }
+    
+    public NamedArgumentListExpression(List mapEntryExpressions) {
+        super(mapEntryExpressions);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new NamedArgumentListExpression(transformExpressions(getMapEntryExpressions(), transformer)); 
+        ret.setSourcePosition(this);
+        return ret;        
+    }
+    
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/NegationExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/NegationExpression.java
new file mode 100644
index 0000000..a77ce7f
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/NegationExpression.java
@@ -0,0 +1,76 @@
+/*
+ * $Id$version Jan 6, 2004 11:04:16 PM $user Exp $
+ * 
+ * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * @author sam
+ */
+public class NegationExpression extends Expression {
+
+	private Expression expression;
+	
+	public NegationExpression(Expression expression) {
+		this.expression = expression;
+	}
+
+	public Expression getExpression() {
+		return expression;
+	}
+
+	public void visit(GroovyCodeVisitor visitor) {
+		visitor.visitNegationExpression(this);
+	}
+
+	public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new NegationExpression(transformer.transform(expression)); 
+        ret.setSourcePosition(this);
+        return ret;
+	}
+
+    public String getText() {
+		return expression.getText();
+	}
+
+    public ClassNode getType() {
+        return expression.getType();
+    }
+
+    public boolean isDynamic() {
+        return false;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/NotExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/NotExpression.java
new file mode 100644
index 0000000..6a8530e
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/NotExpression.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * @author sam
+ */
+public class NotExpression extends BooleanExpression {
+
+	public NotExpression(Expression expression) {
+		super(expression);
+	}
+
+	public void visit(GroovyCodeVisitor visitor) {
+		visitor.visitNotExpression(this);
+	}
+
+    public boolean isDynamic() {
+        return false;
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new NotExpression(transformer.transform(getExpression())); 
+        ret.setSourcePosition(this);
+        return ret;
+	}
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/PostfixExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/PostfixExpression.java
new file mode 100644
index 0000000..00d1e4f
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/PostfixExpression.java
@@ -0,0 +1,102 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.syntax.Token;
+
+/**
+ * Represents a postfix expression like foo++ or bar++
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class PostfixExpression extends Expression {
+
+    private Token operation;
+    private Expression expression;
+
+    public PostfixExpression(Expression expression, Token operation) {
+        this.operation = operation;
+        this.expression = expression;
+    }
+
+    public String toString() {
+        return super.toString() + "[" + expression + operation + "]";
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitPostfixExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new PostfixExpression(transformer.transform(expression), operation); 
+        ret.setSourcePosition(this);
+        return ret;
+    }
+
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public Token getOperation() {
+        return operation;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public String getText() {
+        return "(" + expression.getText() + operation.getText() + ")";
+    }
+
+    public ClassNode getType() {
+        return expression.getType();
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/PrefixExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/PrefixExpression.java
new file mode 100644
index 0000000..41ddf9e
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/PrefixExpression.java
@@ -0,0 +1,102 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.syntax.Token;
+
+/**
+ * Represents a prefix expression like ++foo or --bar
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class PrefixExpression extends Expression {
+
+    private Token operation;
+    private Expression expression;
+
+    public PrefixExpression(Token operation, Expression expression) {
+        this.operation = operation;
+        this.expression = expression;
+    }
+
+    public String toString() {
+        return super.toString() + "[" + operation + expression + "]";
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitPrefixExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new PrefixExpression(operation, transformer.transform(expression)); 
+        ret.setSourcePosition(this);
+        return ret;
+    }
+
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public Token getOperation() {
+        return operation;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public String getText() {
+        return "(" + operation.getText() + expression.getText() + ")";
+    }
+
+    public ClassNode getType() {
+        return expression.getType();
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/PropertyExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/PropertyExpression.java
new file mode 100644
index 0000000..ed59425
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/PropertyExpression.java
@@ -0,0 +1,186 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a property access such as the expression "foo.bar".
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class PropertyExpression extends Expression {
+
+    private Expression objectExpression;
+    private Expression property;
+    private boolean spreadSafe = false;
+    private boolean safe = false;
+    private boolean isStatic = false;
+
+    private Method getter = null;
+    private Method setter = null;
+
+    private Field field = null;
+    private int access = -1;
+    private boolean implicitThis = false;
+
+    public boolean isStatic() {
+        return isStatic;
+    }
+
+    public PropertyExpression(Expression objectExpression, String property) {
+        this(objectExpression, new ConstantExpression(property), false);
+    }
+    
+    public PropertyExpression(Expression objectExpression, Expression property) {
+        this(objectExpression, property, false);
+    }
+
+    public PropertyExpression(Expression objectExpression, Expression property, boolean safe) {
+        this.objectExpression = objectExpression;
+        this.property = property;
+        this.safe = safe;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitPropertyExpression(this);
+    }
+
+    public boolean isDynamic() {
+        return true;
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        return this;
+    }
+
+    public Expression getObjectExpression() {
+        return objectExpression;
+    }
+
+    public void setObjectExpression(Expression exp) {
+        objectExpression=exp;
+    }    
+    
+    public Expression getProperty() {
+        return property;
+    }
+    
+    public String getPropertyAsString() {
+        if (property==null) return null;
+        if (! (property instanceof ConstantExpression)) return null;
+        ConstantExpression constant = (ConstantExpression) property;
+        return constant.getText();
+    }
+
+    public String getText() {
+        return objectExpression.getText() + "." + property.getText();
+    }
+
+    /**
+     * @return is this a safe navigation, i.e. if true then if the source object is null
+     * then this navigation will return null
+     */
+    public boolean isSafe() {
+        return safe;
+    }
+
+    public boolean isSpreadSafe() {
+        return spreadSafe;
+    }
+
+    public void setSpreadSafe(boolean value) {
+        spreadSafe = value;
+    }
+
+    public String toString() {
+        return super.toString() + "[object: " + objectExpression + " property: " + property + "]";
+    }
+
+    public void setStatic(boolean aStatic) {
+        this.isStatic = aStatic;
+    }
+
+    public Method getGetter() {
+        return getter;
+    }
+
+    public Method getSetter() {
+        return setter;
+    }
+
+    public void setField(Field fld) {
+        field = fld;
+        setStatic(Modifier.isStatic(fld.getModifiers()));
+        setType(ClassHelper.make(fld.getType()));
+    }
+    
+    public Field getField() {
+        return field;
+    }
+
+    public void setAccess(int access) {
+        this.access = access;
+    }
+
+    public int getAccess() {
+        return access;
+    }
+    
+    public boolean isImplicitThis(){
+        return implicitThis;
+    }
+    
+    public void setImplicitThis(boolean it) {
+        implicitThis  = it;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/RangeExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/RangeExpression.java
new file mode 100644
index 0000000..5e1d4eb
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/RangeExpression.java
@@ -0,0 +1,97 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a range expression such as for iterating
+ * <pre>for i in 0..10 {...}
+ * </pre>
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class RangeExpression extends Expression {
+
+    private Expression from;
+    private Expression to;
+    private boolean inclusive;
+
+    public RangeExpression(Expression from, Expression to, boolean inclusive) {
+        this.from = from;
+        this.to = to;
+        this.inclusive = inclusive;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitRangeExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new RangeExpression(transformer.transform(from), transformer.transform(to), inclusive); 
+        ret.setSourcePosition(this);
+        return ret;
+    }
+
+    public Expression getFrom() {
+        return from;
+    }
+
+    public Expression getTo() {
+        return to;
+    }
+
+    public boolean isInclusive() {
+        return inclusive;
+    }
+
+    public String getText() {
+        return "(" + from.getText() +
+               (!isInclusive()? "..<" : ".." ) +
+               to.getText() + ")";
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/RegexExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/RegexExpression.java
new file mode 100644
index 0000000..55fd79d
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/RegexExpression.java
@@ -0,0 +1,81 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a regular expression of the form ~<double quoted string> which creates
+ * a regular expression. 
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class RegexExpression extends Expression {
+    
+    private Expression string;
+    
+    public RegexExpression(Expression string) {
+        this.string = string;
+        super.setType(ClassHelper.PATTERN_TYPE);
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitRegexExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new RegexExpression(transformer.transform(string)); 
+        ret.setSourcePosition(this);
+        return ret;       
+    }
+
+    public Expression getRegex() {
+        return string;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/SpreadExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/SpreadExpression.java
new file mode 100644
index 0000000..ead8723
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/SpreadExpression.java
@@ -0,0 +1,85 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a spread expression *x in the list expression [1, *x, 2].
+ * 
+ * @version $Revision$
+ */
+public class SpreadExpression extends Expression {
+
+    private Expression expression;
+	
+    public SpreadExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitSpreadExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new SpreadExpression(transformer.transform(expression)); 
+        ret.setSourcePosition(this);
+        return ret;
+    }
+
+    public String getText() {
+		return "*" + expression.getText();
+	}
+
+    public ClassNode getType() {
+        return expression.getType();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/SpreadMapExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/SpreadMapExpression.java
new file mode 100644
index 0000000..6820e4d
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/SpreadMapExpression.java
@@ -0,0 +1,87 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a spread map expression *:m
+ *         in the map expression [1, *:m, 2, "c":100]
+ *      or in the method invoke expression func(1, *:m, 2, "c":100).
+ * 
+ * @version $Revision$
+ */
+public class SpreadMapExpression extends Expression {
+
+    private Expression expression;
+	
+    public SpreadMapExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitSpreadMapExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new SpreadMapExpression(transformer.transform(expression)); 
+        ret.setSourcePosition(this);
+        return ret;
+    }
+
+    public String getText() {
+	return "*:" + expression.getText();
+    }
+
+    public ClassNode getType() {
+        return expression.getType();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/StaticMethodCallExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/StaticMethodCallExpression.java
new file mode 100644
index 0000000..0dc7125
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/StaticMethodCallExpression.java
@@ -0,0 +1,113 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import groovy.lang.MetaMethod;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * A static method call on a class
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class StaticMethodCallExpression extends Expression {
+
+    private ClassNode ownerType;
+    private String method;
+    private Expression arguments;
+    private MetaMethod metaMethod = null;
+
+    public StaticMethodCallExpression(ClassNode type, String method, Expression arguments) {
+        ownerType = type;
+        this.method = method;
+        this.arguments = arguments;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitStaticMethodCallExpression(this);
+    }
+    
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new StaticMethodCallExpression(getType(), method, transformer.transform(arguments)); 
+        ret.setSourcePosition(this);
+        return ret; 
+    }
+
+    public Expression getArguments() {
+        return arguments;
+    }
+
+    public String getMethod() {
+        return method;
+    }
+
+    public String getText() {
+        return getType().getName() + "." + method + arguments.getText();
+    }
+
+    public String toString() {
+        return super.toString() + "[" + getOwnerType().getName() + "#" + method + " arguments: " + arguments + "]";
+    }
+    public ClassNode getOwnerType() {
+        return ownerType;
+    }
+
+    public void setOwnerType(ClassNode ownerType) {
+        this.ownerType = ownerType;
+    }
+
+    public void setMetaMethod(MetaMethod metaMethod) {
+        this.metaMethod = metaMethod;
+    }
+
+    public MetaMethod getMetaMethod() {
+        return metaMethod;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/TernaryExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/TernaryExpression.java
new file mode 100644
index 0000000..e5e8c47
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/TernaryExpression.java
@@ -0,0 +1,112 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a ternary expression (booleanExpression) ? expression : expression
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class TernaryExpression extends Expression {
+
+    private BooleanExpression booleanExpression;
+    private Expression trueExpression;
+    private Expression falseExpression;
+
+    public TernaryExpression(
+        BooleanExpression booleanExpression,
+        Expression trueExpression,
+        Expression falseExpression) {
+        this.booleanExpression = booleanExpression;
+        this.trueExpression = trueExpression;
+        this.falseExpression = falseExpression;
+    }
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitTernaryExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new TernaryExpression(
+                (BooleanExpression) transformer.transform(booleanExpression),
+                transformer.transform(trueExpression),
+                transformer.transform(falseExpression)); 
+        ret.setSourcePosition(this);
+        return ret; 
+    }
+
+    public String toString() {
+        return super.toString() +"[" + booleanExpression + " ? " + trueExpression + " : " + falseExpression + "]";
+    }
+    
+    public BooleanExpression getBooleanExpression() {
+        return booleanExpression;
+    }
+
+    public Expression getFalseExpression() {
+        return falseExpression;
+    }
+
+    public Expression getTrueExpression() {
+        return trueExpression;
+    }
+
+    public String getText() {
+        return "("
+            + booleanExpression.getText()
+            + ") ? "
+            + trueExpression.getText()
+            + " : "
+            + falseExpression.getText();
+    }
+
+    public ClassNode getType() {
+        return trueExpression.getType();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/TupleExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/TupleExpression.java
new file mode 100644
index 0000000..6dfe157
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/TupleExpression.java
@@ -0,0 +1,120 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a tuple expression {1, 2, 3} which creates an immutable List
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class TupleExpression extends Expression {
+    private List expressions;
+
+    public TupleExpression() {
+        this(new ArrayList());
+    }
+    
+    public TupleExpression(List expressions) {
+        this.expressions = expressions;
+    }
+    
+    public TupleExpression(Expression[] expressionArray) {
+        this();
+        expressions.addAll(Arrays.asList(expressionArray));
+    }
+
+    public TupleExpression addExpression(Expression expression) {
+        expressions.add(expression);
+        return this;
+    }
+    
+    public List getExpressions() {
+        return expressions;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitTupleExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new TupleExpression(transformExpressions(getExpressions(), transformer)); 
+        ret.setSourcePosition(this);
+        return ret;
+    }
+
+    public Expression getExpression(int i) {
+        return (Expression) expressions.get(i);
+    }
+
+    public String getText() {
+        StringBuffer buffer = new StringBuffer("(");
+        boolean first = true;
+        for (Iterator iter = expressions.iterator(); iter.hasNext(); ) {
+            if (first) {
+                first = false;
+            }
+            else {
+                buffer.append(", ");
+            }
+            
+            buffer.append(((Expression)iter.next()).getText());
+        }
+        buffer.append(")");
+        return buffer.toString();
+    }
+
+    public String toString() {
+        return super.toString() + expressions;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/VariableExpression.java b/groovy-core/src/main/org/codehaus/groovy/ast/expr/VariableExpression.java
new file mode 100644
index 0000000..7c82503
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/VariableExpression.java
@@ -0,0 +1,154 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.Variable;
+
+/**
+ * Represents a local variable name, the simplest form of expression. e.g. "foo".
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class VariableExpression extends Expression implements Variable {
+
+    public static final VariableExpression THIS_EXPRESSION = new VariableExpression("this", ClassHelper.DYNAMIC_TYPE);
+    public static final VariableExpression SUPER_EXPRESSION = new VariableExpression("super", ClassHelper.DYNAMIC_TYPE);
+
+    private String variable;
+    private boolean inStaticContext;
+    private boolean isDynamicTyped=false;
+    private Variable accessedVariable;
+    boolean closureShare=false;
+
+    public Variable getAccessedVariable() {
+        return accessedVariable;
+    }
+
+    public void setAccessedVariable(Variable origin) {
+        this.accessedVariable = origin;
+    }
+
+    public VariableExpression(String variable, ClassNode type) {
+        this.variable = variable;
+        super.setType(ClassHelper.getWrapper(type));
+    }
+    
+    public VariableExpression(String variable) {
+        this(variable, ClassHelper.DYNAMIC_TYPE);
+    }
+    
+    public VariableExpression(Variable variable) {
+        this(variable.getName(), variable.getType());
+        setAccessedVariable(variable);
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitVariableExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        return this;
+    }
+
+    public String getText() {
+        return variable;
+    }
+    
+    public String getName() {
+        return variable;
+    }
+
+    /**
+     * @return true if this variable is dynamically typed
+     */
+    public String toString() {
+        return super.toString() + "[variable: " + variable + (this.isDynamicTyped() ? "" : " type: " + getType()) + "]";
+    }
+
+    public Expression getInitialExpression() {
+        return null;
+    }
+
+    public boolean hasInitialExpression() {
+        return false;
+    }
+    
+    public boolean isInStaticContext() {
+        if (accessedVariable!=null && accessedVariable!=this) return accessedVariable.isInStaticContext();
+        return inStaticContext;
+    }
+    
+    public void setInStaticContext(boolean inStaticContext) {
+        this.inStaticContext = inStaticContext;
+    }
+
+    public void setType(ClassNode cn){
+        super.setType(cn);
+        isDynamicTyped |= ClassHelper.DYNAMIC_TYPE==cn;
+    }
+    
+    public boolean isDynamicTyped() {
+        return isDynamicTyped;
+    }
+
+    public boolean isClosureSharedVariable() {
+        if (accessedVariable!=null && accessedVariable!=this) return accessedVariable.isClosureSharedVariable();
+        return closureShare;
+    }
+    
+    public void setClosureSharedVariable(boolean inClosure) {
+        closureShare = inClosure;        
+    }
+    
+    public ClassNode getType() {
+        if (accessedVariable!=null && accessedVariable!=this) return accessedVariable.getType();
+        return super.getType();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/expr/package.html b/groovy-core/src/main/org/codehaus/groovy/ast/expr/package.html
new file mode 100644
index 0000000..bac5071
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/expr/package.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>package org.codehaus.groovy.ast.expr.*</title>
+  </head>
+  <body>
+    <p>AST nodes for Groovy expressions</p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/package.html b/groovy-core/src/main/org/codehaus/groovy/ast/package.html
new file mode 100644
index 0000000..71d94b0
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/package.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>package org.codehaus.groovy.ast.*</title>
+  </head>
+  <body>
+    <p>Groovy AST nodes for the syntax of the language</p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/AssertStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/AssertStatement.java
new file mode 100644
index 0000000..9468c38
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/AssertStatement.java
@@ -0,0 +1,93 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+
+/**
+ * Represents an assert statement such as 
+ * <code>
+ * assert i != 0 : "should never be zero";
+ * </code>
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class AssertStatement extends Statement {
+
+    private BooleanExpression booleanExpression;
+    private Expression messageExpression;
+    
+    public AssertStatement(BooleanExpression booleanExpression) {
+        this(booleanExpression, ConstantExpression.NULL);
+    }
+    
+    public AssertStatement(BooleanExpression booleanExpression, Expression messageExpression) {
+        this.booleanExpression = booleanExpression;
+        this.messageExpression = messageExpression;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitAssertStatement(this);
+    }
+
+    public Expression getMessageExpression() {
+        return messageExpression;
+    }
+
+    public BooleanExpression getBooleanExpression() {
+        return booleanExpression;
+    }
+    public void setBooleanExpression(BooleanExpression booleanExpression) {
+        this.booleanExpression = booleanExpression;
+    }
+    public void setMessageExpression(Expression messageExpression) {
+        this.messageExpression = messageExpression;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/BlockStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/BlockStatement.java
new file mode 100644
index 0000000..7b7c5ba
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/BlockStatement.java
@@ -0,0 +1,129 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.VariableScope;
+
+/**
+ * A list of statements
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class BlockStatement extends Statement {
+
+    private List statements = new ArrayList();
+    private VariableScope scope;
+    
+    public BlockStatement() {
+        this(new ArrayList(), new VariableScope());
+    }
+    
+    public BlockStatement(List statements, VariableScope scope) {
+        this.statements = statements;
+        this.scope = scope;
+    }
+    
+    public BlockStatement(Statement[] statements, VariableScope scope) {
+        this.statements.addAll(Arrays.asList(statements));
+        this.scope = scope;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitBlockStatement(this);
+    }
+
+    public List getStatements() {
+        return statements;
+    }
+
+    public void addStatement(Statement statement) {
+        statements.add(statement);
+    }
+
+    public void addStatements(List listOfStatements) {
+        statements.addAll(listOfStatements);
+    }
+
+    public String toString() {
+        return super.toString() + statements;
+    }
+
+    public String getText() {
+        StringBuffer buffer = new StringBuffer("{ ");
+        boolean first = true;
+        for (Iterator iter = statements.iterator(); iter.hasNext(); ) {
+            if (first) {
+                first = false;
+            }
+            else {
+                buffer.append("; ");
+            }
+            Statement statement = (Statement) iter.next();
+            buffer.append(statement.getText());
+        }
+        buffer.append(" }");
+        return buffer.toString();
+    }
+
+    public boolean isEmpty() {
+        return statements.isEmpty();
+    }
+
+    public void setVariableScope(VariableScope scope) {
+        this.scope = scope;
+    }
+    
+    public VariableScope getVariableScope() {
+        return scope;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/BreakStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/BreakStatement.java
new file mode 100644
index 0000000..b8bb4ff
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/BreakStatement.java
@@ -0,0 +1,76 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+
+/**
+ * Represents a break statement in a switch or loop statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class BreakStatement extends Statement {
+
+    private String label;
+    
+    public BreakStatement() {
+        this(null);
+    }
+    
+    public BreakStatement(String label) {
+        this.label = label;
+    }
+    
+    public String getLabel() {
+        return label;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitBreakStatement(this);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/CaseStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/CaseStatement.java
new file mode 100644
index 0000000..7821624
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/CaseStatement.java
@@ -0,0 +1,87 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+
+/**
+ * Represents a case statement in a switch statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class CaseStatement extends Statement {
+
+    private Statement code;
+    private Expression expression;
+    
+    public CaseStatement(Expression expression, Statement code) {
+        this.expression = expression;
+        this.code = code;
+    }
+    
+    public Statement getCode() {
+        return code;
+    }
+    
+    public Expression getExpression() {
+        return expression;
+    }
+    
+    public void setExpression(Expression e) {
+        expression=e;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitCaseStatement(this);
+    }
+    
+    public String toString() {
+        return super.toString() + "[expression: " + expression + "; code: " + code + "]";
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/CatchStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/CatchStatement.java
new file mode 100644
index 0000000..2fb8680
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/CatchStatement.java
@@ -0,0 +1,84 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.Parameter;
+
+
+/**
+ * Represents a catch (Exception var) { } statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class CatchStatement extends Statement {
+
+    private Parameter variable;
+    private Statement code;
+    
+    public CatchStatement(Parameter variable, Statement code) {
+        this.variable = variable;
+        this.code = code;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitCatchStatement(this);
+    }
+    
+    public Statement getCode() {
+        return code;
+    }
+
+    public ClassNode getExceptionType() {
+        return variable.getType();
+    }
+
+    public Parameter getVariable() {
+        return variable;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/ContinueStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/ContinueStatement.java
new file mode 100644
index 0000000..f2aab41
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/ContinueStatement.java
@@ -0,0 +1,76 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+
+/**
+ * Represents a continue statement in a loop statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ContinueStatement extends Statement {
+
+    private String label;
+    
+    public ContinueStatement() {
+        this(null);
+    }
+    
+    public ContinueStatement(String label) {
+        this.label = label;
+    }
+    
+    public String getLabel() {
+        return label;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitContinueStatement(this);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/DoWhileStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/DoWhileStatement.java
new file mode 100644
index 0000000..f7b933e
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/DoWhileStatement.java
@@ -0,0 +1,82 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+
+/**
+ * Represents a do { ... } while (condition) loop in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class DoWhileStatement extends Statement {
+
+    private BooleanExpression booleanExpression;
+    private Statement loopBlock;
+    
+
+    public DoWhileStatement(BooleanExpression booleanExpression, Statement loopBlock) {
+        this.booleanExpression = booleanExpression;
+        this.loopBlock = loopBlock;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitDoWhileLoop(this);
+    }
+    
+    public BooleanExpression getBooleanExpression() {
+        return booleanExpression;
+    }
+
+    public Statement getLoopBlock() {
+        return loopBlock;
+    }
+    public void setBooleanExpression(BooleanExpression booleanExpression) {
+        this.booleanExpression = booleanExpression;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/EmptyStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/EmptyStatement.java
new file mode 100644
index 0000000..2647686
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/EmptyStatement.java
@@ -0,0 +1,67 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents an empty statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class EmptyStatement extends Statement {
+
+    public static final EmptyStatement INSTANCE = new EmptyStatement();
+    
+    public void visit(GroovyCodeVisitor visitor) {
+    }
+
+    public boolean isEmpty() {
+        return true;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/ExpressionStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/ExpressionStatement.java
new file mode 100644
index 0000000..af8d280
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/ExpressionStatement.java
@@ -0,0 +1,88 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+
+/**
+ * A simple statement such as a method call where the return value is ignored
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ExpressionStatement extends Statement {
+
+    private Expression expression;
+    
+    public ExpressionStatement(Expression expression) {
+        if (expression == null) {
+            throw new IllegalArgumentException("expression cannot be null");
+        }
+        this.expression = expression;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitExpressionStatement(this);
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public String getText() {
+    	return this.toString();
+    }
+    public String toString() {
+        return super.toString() + "[expression:" + expression + "]";
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/ForStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/ForStatement.java
new file mode 100644
index 0000000..9ad3231
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/ForStatement.java
@@ -0,0 +1,105 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.Expression;
+
+/**
+ * Represents a standard for loop in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ForStatement extends Statement {
+
+    private Parameter variable;
+    private Expression collectionExpression;
+    private Statement loopBlock;
+    private VariableScope scope;
+    
+
+    public ForStatement(Parameter variable, Expression collectionExpression, Statement loopBlock) {
+        this.variable = variable;
+        this.collectionExpression = collectionExpression;
+        this.loopBlock = loopBlock;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitForLoop(this);
+    }
+    
+    public Expression getCollectionExpression() {
+        return collectionExpression;
+    }
+
+    public Statement getLoopBlock() {
+        return loopBlock;
+    }
+
+    public Parameter getVariable() {
+        return variable;
+    }
+    
+    public ClassNode getVariableType() {
+        return variable.getType();
+    }
+    
+    public void setCollectionExpression(Expression collectionExpression) {
+        this.collectionExpression = collectionExpression;
+    }
+
+    public void setVariableScope(VariableScope variableScope) {
+       scope = variableScope;        
+    }
+
+    public VariableScope getVariableScope() {
+        return scope;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/IfStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/IfStatement.java
new file mode 100644
index 0000000..fdf480b
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/IfStatement.java
@@ -0,0 +1,89 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+
+/**
+ * Represents a do { ... } while (condition) loop in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class IfStatement extends Statement {
+
+    private BooleanExpression booleanExpression;
+    private Statement ifBlock;
+    private Statement elseBlock;
+    
+
+    public IfStatement(BooleanExpression booleanExpression, Statement ifBlock, Statement elseBlock) {
+        this.booleanExpression = booleanExpression;
+        this.ifBlock = ifBlock;
+        this.elseBlock = elseBlock;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitIfElse(this);
+    }
+    
+    public BooleanExpression getBooleanExpression() {
+        return booleanExpression;
+    }
+    
+    public Statement getIfBlock() {
+        return ifBlock;
+    }
+
+    public Statement getElseBlock() {
+        return elseBlock;
+    }
+
+    public void setBooleanExpression(BooleanExpression booleanExpression) {
+        this.booleanExpression = booleanExpression;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/ReturnStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/ReturnStatement.java
new file mode 100644
index 0000000..7ad82ef
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/ReturnStatement.java
@@ -0,0 +1,88 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+
+/**
+ * A return statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ReturnStatement extends Statement {
+
+    public static final ReturnStatement RETURN_NULL_OR_VOID = new ReturnStatement(ConstantExpression.NULL);
+
+    private Expression expression;
+    
+    public ReturnStatement(ExpressionStatement statement) {
+        this(statement.getExpression());
+        setStatementLabel(statement.getStatementLabel());
+    }
+    
+    public ReturnStatement(Expression expression) {
+        this.expression = expression;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitReturnStatement(this);
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public String getText() {
+        return "return " + expression.getText();
+    }
+
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/Statement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/Statement.java
new file mode 100644
index 0000000..8eb85f8
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/Statement.java
@@ -0,0 +1,76 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import org.codehaus.groovy.ast.ASTNode;
+
+/**
+ * Base class for any statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class Statement extends ASTNode {
+
+    private String statementLabel;
+
+    public Statement() {
+        statementLabel = null;
+    }
+
+    public String getStatementLabel() {
+        return statementLabel;
+    }
+
+    public void setStatementLabel( String label ) {
+        statementLabel = label;
+    }
+
+    public boolean isEmpty() {
+        return false;
+    }
+    
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/SwitchStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/SwitchStatement.java
new file mode 100644
index 0000000..e075719
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/SwitchStatement.java
@@ -0,0 +1,119 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+/**
+ * Represents a switch (object) { case value: ... case [1, 2, 3]: ...  default: ... } statement in Groovy.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class SwitchStatement extends Statement {
+
+    private Expression expression;
+    private List caseStatements = new ArrayList();
+    private Statement defaultStatement;
+    
+
+    public SwitchStatement(Expression expression) {
+        this(expression, EmptyStatement.INSTANCE);
+    }
+
+    public SwitchStatement(Expression expression, Statement defaultStatement) {
+        this.expression = expression;
+        this.defaultStatement = defaultStatement;
+    }
+
+    public SwitchStatement(Expression expression, List caseStatements, Statement defaultStatement) {
+        this.expression = expression;
+        this.caseStatements = caseStatements;
+        this.defaultStatement = defaultStatement;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitSwitch(this);
+    }
+    
+    public List getCaseStatements() {
+        return caseStatements;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void setExpression(Expression e) {
+        expression=e;
+    }
+    
+    public Statement getDefaultStatement() {
+        return defaultStatement;
+    }
+
+    public void setDefaultStatement(Statement defaultStatement) {
+        this.defaultStatement = defaultStatement;
+    }
+
+    public void addCase(CaseStatement caseStatement) {
+        caseStatements.add(caseStatement);
+    }
+
+    /**
+     * @return the case statement of the given index or null
+     */
+    public CaseStatement getCaseStatement(int idx) {
+        if (idx >= 0 && idx < caseStatements.size()) {
+            return (CaseStatement) caseStatements.get(idx);
+        }
+        return null;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/SynchronizedStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/SynchronizedStatement.java
new file mode 100644
index 0000000..e73cf19
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/SynchronizedStatement.java
@@ -0,0 +1,82 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+
+/**
+ * Represents a synchronized statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class SynchronizedStatement extends Statement {
+
+    private Statement code;
+    private Expression expression;
+    
+    public SynchronizedStatement(Expression expression, Statement code) {
+        this.expression = expression;
+        this.code = code;
+    }
+    
+    public Statement getCode() {
+        return code;
+    }
+    
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitSynchronizedStatement(this);
+    }
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/ThrowStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/ThrowStatement.java
new file mode 100644
index 0000000..c79354d
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/ThrowStatement.java
@@ -0,0 +1,76 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+
+/**
+ * Represents a throw statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ThrowStatement extends Statement {
+
+    private Expression expression;
+    
+    public ThrowStatement(Expression expression) {
+        this.expression = expression;
+    }
+    
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitThrowStatement(this);
+    }
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/TryCatchStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/TryCatchStatement.java
new file mode 100644
index 0000000..59bdd10
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/TryCatchStatement.java
@@ -0,0 +1,100 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a try { ... } catch () finally {} statement in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class TryCatchStatement extends Statement {
+
+    private Statement tryStatement;
+    private List catchStatements = new ArrayList();
+    private Statement finallyStatement;
+    
+
+    public TryCatchStatement(Statement tryStatement, Statement finallyStatement) {
+        this.tryStatement = tryStatement;
+        this.finallyStatement = finallyStatement;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitTryCatchFinally(this);
+    }
+    
+    public List getCatchStatements() {
+        return catchStatements;
+    }
+
+    public Statement getFinallyStatement() {
+        return finallyStatement;
+    }
+
+    public Statement getTryStatement() {
+        return tryStatement;
+    }
+
+    public void addCatch(CatchStatement catchStatement) {
+        catchStatements.add(catchStatement);
+    }
+
+    /**
+     * @return the catch statement of the given index or null
+     */
+    public CatchStatement getCatchStatement(int idx) {
+        if (idx >= 0 && idx < catchStatements.size()) {
+            return (CatchStatement) catchStatements.get(idx);
+        }
+        return null;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/WhileStatement.java b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/WhileStatement.java
new file mode 100644
index 0000000..deed866
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/WhileStatement.java
@@ -0,0 +1,83 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+
+/**
+ * Represents a while (condition) { ... } loop in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class WhileStatement extends Statement {
+
+    private BooleanExpression booleanExpression;
+    private Statement loopBlock;
+    
+
+    public WhileStatement(BooleanExpression booleanExpression, Statement loopBlock) {
+        this.booleanExpression = booleanExpression;
+        this.loopBlock = loopBlock;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitWhileLoop(this);
+    }
+    
+    public BooleanExpression getBooleanExpression() {
+        return booleanExpression;
+    }
+
+    public Statement getLoopBlock() {
+        return loopBlock;
+    }
+
+	public void setBooleanExpression(BooleanExpression booleanExpression) {
+		this.booleanExpression = booleanExpression;
+	}
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/ast/stmt/package.html b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/package.html
new file mode 100644
index 0000000..95a6e74
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/ast/stmt/package.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>package org.codehaus.groovy.ast.stmt.*</title>
+  </head>
+  <body>
+    <p>AST nodes for Groovy statements</p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/org/codehaus/groovy/bsf/CachingGroovyEngine.java b/groovy-core/src/main/org/codehaus/groovy/bsf/CachingGroovyEngine.java
new file mode 100644
index 0000000..a434f3a
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/bsf/CachingGroovyEngine.java
@@ -0,0 +1,140 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package org.codehaus.groovy.bsf;
+
+import groovy.lang.Binding;
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyShell;
+import groovy.lang.Script;
+import org.apache.bsf.BSFDeclaredBean;
+import org.apache.bsf.BSFException;
+import org.apache.bsf.BSFManager;
+import org.apache.bsf.util.BSFFunctions;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.io.ByteArrayInputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+import java.util.logging.Logger;
+import java.util.logging.Level;
+
+/**
+ * A Caching implementation of the GroovyEngine
+ *
+ * @author James Birchfield
+ */
+public class CachingGroovyEngine extends GroovyEngine {
+    private static final Logger LOG = Logger.getLogger(CachingGroovyEngine.class.getName());
+    private static final Object[] EMPTY_ARGS = new Object[]{new String[]{}};
+
+    private Map evalScripts;
+    private Map execScripts;
+    private Binding context;
+    private GroovyClassLoader loader;
+
+    /**
+     * Evaluate an expression.
+     */
+    public Object eval(String source, int lineNo, int columnNo, Object script) throws BSFException {
+        try {
+            Class scriptClass = (Class) evalScripts.get(script);
+            if (scriptClass == null) {
+                scriptClass = loader.parseClass(new ByteArrayInputStream(script.toString().getBytes()), source);
+                evalScripts.put(script, scriptClass);
+            } else {
+                LOG.fine("eval() - Using cached script...");
+            }
+            //can't cache the script because the context may be different.
+            //but don't bother loading parsing the class again
+            Script s = InvokerHelper.createScript(scriptClass, context);
+            return s.run();
+        } catch (Exception e) {
+            throw new BSFException(BSFException.REASON_EXECUTION_ERROR, "exception from Groovy: " + e, e);
+        }
+    }
+
+    /**
+     * Execute a script.
+     */
+    public void exec(String source, int lineNo, int columnNo, Object script) throws BSFException {
+        try {
+            //          shell.run(script.toString(), source, EMPTY_ARGS);
+
+            Class scriptClass = (Class) execScripts.get(script);
+            if (scriptClass == null) {
+                scriptClass = loader.parseClass(new ByteArrayInputStream(script.toString().getBytes()), source);
+                execScripts.put(script, scriptClass);
+            } else {
+                LOG.fine("exec() - Using cached version of class...");
+            }
+            InvokerHelper.invokeMethod(scriptClass, "main", EMPTY_ARGS);
+        } catch (Exception e) {
+            LOG.log(Level.WARNING, "BSF trace", e);
+            throw new BSFException(BSFException.REASON_EXECUTION_ERROR, "exception from Groovy: " + e, e);
+        }
+    }
+
+    /**
+     * Initialize the engine.
+     */
+    public void initialize(final BSFManager mgr, String lang, Vector declaredBeans) throws BSFException {
+        super.initialize(mgr, lang, declaredBeans);
+        ClassLoader parent = mgr.getClassLoader();
+        if (parent == null)
+            parent = GroovyShell.class.getClassLoader();
+        final ClassLoader finalParent = parent;
+        this.loader =
+                (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
+                    public Object run() {
+                        CompilerConfiguration configuration = new CompilerConfiguration();
+                        configuration.setClasspath(mgr.getClassPath());
+                        return new GroovyClassLoader(finalParent, configuration);
+                    }
+                });
+        execScripts = new HashMap();
+        evalScripts = new HashMap();
+        context = shell.getContext();
+        // create a shell
+        // register the mgr with object name "bsf"
+        context.setVariable("bsf", new BSFFunctions(mgr, this));
+        int size = declaredBeans.size();
+        for (int i = 0; i < size; i++) {
+            declareBean((BSFDeclaredBean) declaredBeans.elementAt(i));
+        }
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/bsf/GroovyEngine.java b/groovy-core/src/main/org/codehaus/groovy/bsf/GroovyEngine.java
new file mode 100644
index 0000000..780773a
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/bsf/GroovyEngine.java
@@ -0,0 +1,182 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.bsf;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyShell;
+import org.apache.bsf.BSFDeclaredBean;
+import org.apache.bsf.BSFException;
+import org.apache.bsf.BSFManager;
+import org.apache.bsf.util.BSFEngineImpl;
+import org.apache.bsf.util.BSFFunctions;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.util.Vector;
+
+/**
+ * A BSF Engine for the <a href="http://groovy.codehaus.org/">Groovy</a>
+ * scripting language.
+ * <p/>
+ * It's derived from the Jython / JPython engine
+ *
+ * @author James Strachan
+ */
+public class GroovyEngine extends BSFEngineImpl {
+    protected GroovyShell shell;
+
+    /*
+     * Convert a non java class name to a java classname
+     * This is used to convert a script name to a name
+     * that can be used as a classname with the script is
+     * loaded in GroovyClassloader#load()
+     * The method simply replaces any invalid characters
+     * with "_".
+     */
+    private String convertToValidJavaClassname(String inName) {
+        if (inName == null || inName.equals("")) {
+            return "_";
+        }
+        StringBuffer output = new StringBuffer(inName.length());
+        boolean firstChar = true;
+        for (int i = 0; i < inName.length(); ++i) {
+            char ch = inName.charAt(i);
+            if (firstChar && !Character.isJavaIdentifierStart(ch)) {
+                ch = '_';
+            } else if (!firstChar
+                    && !(Character.isJavaIdentifierPart(ch) || ch == '.')) {
+                ch = '_';
+            }
+            firstChar = (ch == '.');
+            output.append(ch);
+        }
+        return output.toString();
+    }
+
+    /**
+     * Allow an anonymous function to be declared and invoked
+     */
+    public Object apply(String source, int lineNo, int columnNo, Object funcBody, Vector paramNames,
+                        Vector arguments) throws BSFException {
+        Object object = eval(source, lineNo, columnNo, funcBody);
+        if (object instanceof Closure) {
+            // lets call the function
+            Closure closure = (Closure) object;
+            return closure.call(arguments.toArray());
+        }
+        return object;
+    }
+
+    /**
+     * Call the named method of the given object.
+     */
+    public Object call(Object object, String method, Object[] args) throws BSFException {
+        return InvokerHelper.invokeMethod(object, method, args);
+    }
+
+    /**
+     * Evaluate an expression.
+     */
+    public Object eval(String source, int lineNo, int columnNo, Object script) throws BSFException {
+        try {
+            source = convertToValidJavaClassname(source);
+            return getEvalShell().evaluate(script.toString(), source);
+        } catch (Exception e) {
+            throw new BSFException(BSFException.REASON_EXECUTION_ERROR, "exception from Groovy: " + e, e);
+        }
+    }
+
+    /**
+     * Execute a script.
+     */
+    public void exec(String source, int lineNo, int columnNo, Object script) throws BSFException {
+        try {
+            // use evaluate to pass in the BSF variables
+            source = convertToValidJavaClassname(source);
+            getEvalShell().evaluate(script.toString(), source);
+        } catch (Exception e) {
+            throw new BSFException(BSFException.REASON_EXECUTION_ERROR, "exception from Groovy: " + e, e);
+        }
+    }
+
+    /**
+     * Initialize the engine.
+     */
+    public void initialize(BSFManager mgr, String lang, Vector declaredBeans) throws BSFException {
+        super.initialize(mgr, lang, declaredBeans);
+
+        // create a shell
+        shell = new GroovyShell(mgr.getClassLoader());
+
+        // register the mgr with object name "bsf"
+        shell.setVariable("bsf", new BSFFunctions(mgr, this));
+
+        int size = declaredBeans.size();
+        for (int i = 0; i < size; i++) {
+            declareBean((BSFDeclaredBean) declaredBeans.elementAt(i));
+        }
+    }
+
+    /**
+     * Declare a bean
+     */
+    public void declareBean(BSFDeclaredBean bean) throws BSFException {
+        shell.setVariable(bean.name, bean.bean);
+    }
+
+    /**
+     * Undeclare a previously declared bean.
+     */
+    public void undeclareBean(BSFDeclaredBean bean) throws BSFException {
+        shell.setVariable(bean.name, null);
+    }
+
+    /**
+     * @return a newly created GroovyShell using the same variable scope but a new class loader
+     */
+    protected GroovyShell getEvalShell() {
+        return new GroovyShell(shell);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/bsf/package.html b/groovy-core/src/main/org/codehaus/groovy/bsf/package.html
new file mode 100644
index 0000000..feb0a25
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/bsf/package.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>package org.codehaus.groovy.bsf.*</title>
+  </head>
+  <body>
+    <p>Defines the BSF Engine for using Groovy inside any BSF application.</p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/AsmClassGenerator.java b/groovy-core/src/main/org/codehaus/groovy/classgen/AsmClassGenerator.java
new file mode 100644
index 0000000..e4b7fe0
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -0,0 +1,3280 @@
+/*
+$Id$
+
+Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package org.codehaus.groovy.classgen;
+
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.ArrayExpression;
+import org.codehaus.groovy.ast.expr.AttributeExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.BitwiseNegExpression;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ExpressionTransformer;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.GStringExpression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.MapEntryExpression;
+import org.codehaus.groovy.ast.expr.MapExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.MethodPointerExpression;
+import org.codehaus.groovy.ast.expr.NegationExpression;
+import org.codehaus.groovy.ast.expr.NotExpression;
+import org.codehaus.groovy.ast.expr.PostfixExpression;
+import org.codehaus.groovy.ast.expr.PrefixExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.RangeExpression;
+import org.codehaus.groovy.ast.expr.RegexExpression;
+import org.codehaus.groovy.ast.expr.SpreadExpression;
+import org.codehaus.groovy.ast.expr.SpreadMapExpression;
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
+import org.codehaus.groovy.ast.expr.TernaryExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.AssertStatement;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.BreakStatement;
+import org.codehaus.groovy.ast.stmt.CaseStatement;
+import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.stmt.ContinueStatement;
+import org.codehaus.groovy.ast.stmt.DoWhileStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.stmt.SwitchStatement;
+import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
+import org.codehaus.groovy.ast.stmt.ThrowStatement;
+import org.codehaus.groovy.ast.stmt.TryCatchStatement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
+import org.codehaus.groovy.syntax.RuntimeParserException;
+import org.codehaus.groovy.syntax.Types;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+
+/**
+ * Generates Java class versions of Groovy classes using ASM.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author <a href="mailto:b55r@sina.com">Bing Ran</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ *
+ * @version $Revision$
+ */
+public class AsmClassGenerator extends ClassGenerator {
+
+    private Logger log = Logger.getLogger(getClass().getName());
+
+    private ClassVisitor cw;
+    private MethodVisitor cv;
+    private GeneratorContext context;
+
+    private String sourceFile;
+
+    // current class details
+    private ClassNode classNode;
+    private ClassNode outermostClass;
+    private String internalClassName;
+    private String internalBaseClassName;
+
+    /** maps the variable names to the JVM indices */
+    private CompileStack compileStack;
+
+    /** have we output a return statement yet */
+    private boolean outputReturn;
+
+    /** are we on the left or right of an expression */
+    private boolean leftHandExpression=false;
+    /**
+     * Notes for leftHandExpression:
+     * The default is false, that menas the right side is default.
+     * The right side means that variables are read and not written.
+     * Any change of leftHandExpression to true, should be made carefully.
+     * If such a change is needed, then it should be set to false as soon as
+     * possible, but most important in the same method. Setting 
+     * leftHandExpression to false is needed for writing variables.
+     */
+
+    // method invocation
+    MethodCallerMultiAdapter invokeMethodOnCurrent = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"invokeMethodOnCurrent",true,false);
+    MethodCallerMultiAdapter invokeMethodOnSuper   = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"invokeMethodOnSuper",true,false);
+    MethodCallerMultiAdapter invokeMethod          = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"invokeMethod",true,false);
+    MethodCallerMultiAdapter invokeStaticMethod    = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"invokeStaticMethod",true,true);
+    MethodCallerMultiAdapter invokeNew             = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"invokeNew",true,true);
+    
+    // fields & properties
+    MethodCallerMultiAdapter setField             = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"setField",false,false);
+    MethodCallerMultiAdapter getField             = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"getField",false,false);
+    MethodCallerMultiAdapter setGroovyObjectField = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"setGroovyObjectField",false,false);
+    MethodCallerMultiAdapter getGroovyObjectField = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"getGroovyObjectField",false,false);
+    MethodCallerMultiAdapter setFieldOnSuper      = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"setFieldOnSuper",false,false);
+    MethodCallerMultiAdapter getFieldOnSuper      = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"getFieldOnSuper",false,false);
+    
+    MethodCallerMultiAdapter setProperty             = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"setProperty",false,false);
+    MethodCallerMultiAdapter getProperty             = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"getProperty",false,false);
+    MethodCallerMultiAdapter setGroovyObjectProperty = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"setGroovyObjectProperty",false,false);
+    MethodCallerMultiAdapter getGroovyObjectProperty = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"getGroovyObjectProperty",false,false);
+    MethodCallerMultiAdapter setPropertyOnSuper      = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"setPropertyOnSuper",false,false);
+    MethodCallerMultiAdapter getPropertyOnSuper      = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class,"getPropertyOnSuper",false,false);
+    
+    // iterator
+    MethodCaller iteratorNextMethod = MethodCaller.newInterface(Iterator.class, "next");
+    MethodCaller iteratorHasNextMethod = MethodCaller.newInterface(Iterator.class, "hasNext");
+    // assert
+    MethodCaller assertFailedMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "assertFailed");
+    // isCase
+    MethodCaller isCaseMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "isCase");
+    //compare
+    MethodCaller compareIdenticalMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareIdentical");
+    MethodCaller compareEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareEqual");
+    MethodCaller compareNotEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareNotEqual");
+    MethodCaller compareToMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareTo");
+    MethodCaller compareLessThanMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareLessThan");
+    MethodCaller compareLessThanEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareLessThanEqual");
+    MethodCaller compareGreaterThanMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareGreaterThan");
+    MethodCaller compareGreaterThanEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareGreaterThanEqual");
+    //regexpr
+    MethodCaller findRegexMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "findRegex");
+    MethodCaller matchRegexMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "matchRegex");
+    MethodCaller regexPattern = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "regexPattern");
+    // spread expressions
+    MethodCaller spreadMap = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "spreadMap");
+    MethodCaller despreadList = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "despreadList");
+    // Closure
+    MethodCaller getMethodPointer = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "getMethodPointer");
+    MethodCaller invokeClosureMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeClosure");
+    //negation
+    MethodCaller negation = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "negate");
+    MethodCaller bitNegation = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "bitNegate");
+
+    // type converions
+    MethodCaller asTypeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "asType");
+    MethodCaller castToTypeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "castToType");
+    MethodCaller createListMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createList");
+    MethodCaller createTupleMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createTuple");
+    MethodCaller createMapMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createMap");
+    MethodCaller createRangeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createRange");
+    
+    // wrapper creation methods
+    MethodCaller createPojoWrapperMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createPojoWrapper");
+    MethodCaller createGroovyObjectWrapperMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createGroovyObjectWrapper");
+
+    // constructor calls with this() and super()
+    MethodCaller selectConstructorAndTransformArguments = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "selectConstructorAndTransformArguments");
+ 
+    // exception blocks list
+    private List exceptionBlocks = new ArrayList();    
+    
+    private Set syntheticStaticFields = new HashSet();
+    private boolean passingClosureParams;
+
+    private ConstructorNode constructorNode;
+    private MethodNode methodNode;
+    private BytecodeHelper helper = new BytecodeHelper(null);
+
+    public static final boolean CREATE_DEBUG_INFO = true;
+    public static final boolean CREATE_LINE_NUMBER_INFO = true;
+    private static final boolean MARK_START = true;
+
+    public static final boolean ASM_DEBUG = false; // add marker in the bytecode to show source-byecode relationship
+    private int lineNumber = -1;
+    private int columnNumber = -1;
+    private ASTNode currentASTNode = null;
+
+    private DummyClassGenerator dummyGen = null;
+    private ClassWriter dummyClassWriter = null;
+    
+    private ClassNode interfaceClassLoadingClass;
+
+    private boolean implicitThis = false;
+
+    public AsmClassGenerator(
+            GeneratorContext context, ClassVisitor classVisitor,
+            ClassLoader classLoader, String sourceFile
+    ) {
+        super(classLoader);
+        this.context = context;
+        this.cw = classVisitor;
+        this.sourceFile = sourceFile;
+
+        this.dummyClassWriter = new ClassWriter(true);
+        dummyGen  = new DummyClassGenerator(context, dummyClassWriter, classLoader, sourceFile);
+        compileStack = new CompileStack();
+
+    }
+    
+    protected SourceUnit getSourceUnit() {
+        return null;
+    }
+
+    // GroovyClassVisitor interface
+    //-------------------------------------------------------------------------
+    public void visitClass(ClassNode classNode) {
+        // todo to be tested
+        // createDummyClass(classNode);
+
+        try {
+            syntheticStaticFields.clear();
+            this.classNode = classNode;
+            this.outermostClass = null;
+            this.internalClassName = BytecodeHelper.getClassInternalName(classNode);
+
+            this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass());
+
+            cw.visit(
+                asmJDKVersion,
+                classNode.getModifiers(),
+                internalClassName,
+                null,
+                internalBaseClassName,
+                BytecodeHelper.getClassInternalNames(classNode.getInterfaces())
+            );            
+            cw.visitSource(sourceFile,null);
+            
+            if (classNode.isInterface()) {
+                ClassNode owner = classNode;
+                if (owner instanceof InnerClassNode) {
+                    owner = owner.getOuterClass();
+                }
+                String outerClassName = owner.getName();
+                String name = outerClassName + "$" + context.getNextInnerClassIdx();
+                interfaceClassLoadingClass = new InnerClassNode(owner, name, 4128, ClassHelper.OBJECT_TYPE);
+                
+                super.visitClass(classNode);
+                createInterfaceSyntheticStaticFields();                
+            } else {
+                super.visitClass(classNode);
+                createMopMethods();
+                createSyntheticStaticFields();
+            }
+            
+            for (Iterator iter = innerClasses.iterator(); iter.hasNext();) {
+                ClassNode innerClass = (ClassNode) iter.next();
+                String innerClassName = innerClass.getName();
+                String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName);
+                {
+                    int index = innerClassName.lastIndexOf('$');
+                    if (index>=0) innerClassName = innerClassName.substring(index+1);
+                }
+                String outerClassName = internalClassName; // default for inner classes
+                MethodNode enclosingMethod = innerClass.getEnclosingMethod();
+                if (enclosingMethod != null) {
+                    // local inner classes do not specify the outer class name
+                    outerClassName = null;
+                    innerClassName = null;
+                }
+                cw.visitInnerClass(
+                    innerClassInternalName,
+                    outerClassName,
+                    innerClassName,
+                    innerClass.getModifiers());
+            }
+            //TODO: an inner class should have an entry of itself
+            cw.visitEnd();
+        }
+        catch (GroovyRuntimeException e) {
+            e.setModule(classNode.getModule());
+            throw e;
+        }
+    }
+   
+    private void createMopMethods() {
+        visitMopMethodList(classNode.getMethods(), true);
+        visitMopMethodList(classNode.getSuperClass().getAllDeclaredMethods(), false);
+    }
+
+    private String[] buildExceptions(ClassNode[] exceptions) {
+        if (exceptions==null) return null;
+        String[] ret = new String[exceptions.length];
+        for (int i = 0; i < exceptions.length; i++) {
+            ret[i] = BytecodeHelper.getClassInternalName(exceptions[i]);
+        }
+        return ret;
+    }
+    
+    /**
+     * filters a list of method for MOP methods. For all methods that are no 
+     * MOP methods a MOP method is created if the method is not public and the
+     * call would be a call on "this" (isThis == true). If the call is not on
+     * "this", then the call is a call on "super" and all methods are used, 
+     * unless they are already a MOP method
+     *  
+     * @see #generateMopCalls(LinkedList, boolean)
+     *  
+     * @param methods unfiltered list of methods for MOP 
+     * @param isThis  if true, then we are creating a MOP method on "this", "super" else 
+     */
+    private void visitMopMethodList(List methods, boolean isThis){
+        LinkedList mopCalls = new LinkedList();
+        for (Iterator iter = methods.iterator(); iter.hasNext();) {
+            MethodNode mn = (MethodNode) iter.next();
+            if ((mn.getModifiers() & ACC_ABSTRACT) !=0 ) continue;
+            // no this$ methods for protected/public isThis=true
+            // super$ method for protected/public isThis=false
+            // --> results in XOR
+            if (isThis ^ (mn.getModifiers() & (ACC_PUBLIC|ACC_PROTECTED)) == 0) continue; 
+            String methodName = mn.getName();
+            if (isMopMethod(methodName) || methodName.startsWith("<")) continue;
+            String name = getMopMethodName(mn,isThis);
+            if (containsMethod(methods,name,mn.getParameters())) continue;
+            mopCalls.add(mn);
+        }
+        generateMopCalls(mopCalls, isThis);
+        mopCalls.clear();
+    }
+    
+    private boolean containsMethod(List methods, String name, Parameter[] paras) {
+        for (Iterator iter = methods.iterator(); iter.hasNext();) {
+            MethodNode element = (MethodNode) iter.next();
+            if (element.getName().equals(name) && equalParameterTypes(paras,element.getParameters())) return true;
+        }
+        return false;
+    }
+    
+    private boolean equalParameterTypes(Parameter[] p1, Parameter[] p2) {
+        if (p1.length!=p2.length) return false;
+        for (int i=0; i<p1.length; i++) {
+            if (!p1[i].getType().equals(p2[i].getType())) return false;
+        }
+        return true;
+    }
+    
+    /**
+     * generates a Meta Object Protocoll method, that is used to call a non public
+     * method, or to make a call to super.
+     * @param mopCalls list of methods a mop call method should be generated for
+     * @param useThis true if "this" should be used for the naming
+     */
+    private void generateMopCalls(LinkedList mopCalls, boolean useThis) {
+        for (Iterator iter = mopCalls.iterator(); iter.hasNext();) {
+            MethodNode method = (MethodNode) iter.next();
+            String name = getMopMethodName(method,useThis);
+            Parameter[] parameters = method.getParameters();
+            String methodDescriptor = BytecodeHelper.getMethodDescriptor(method.getReturnType(), method.getParameters());
+            cv = cw.visitMethod(Opcodes.ACC_PUBLIC & Opcodes.ACC_SYNTHETIC, name, methodDescriptor, null, null);
+            cv.visitVarInsn(ALOAD,0);
+            BytecodeHelper helper = new BytecodeHelper(cv);
+            int newRegister = 1;
+            for (int i=0; i<parameters.length; i++) {
+                ClassNode type = parameters[i].getType();
+                helper.load(parameters[i].getType(),newRegister);
+                // increment to next register, double/long are using two places
+                newRegister++;
+                if (type == ClassHelper.double_TYPE || type == ClassHelper.long_TYPE) newRegister++;
+            }
+            cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(method.getDeclaringClass()), method.getName(), methodDescriptor); 
+            helper.doReturn(method.getReturnType());
+            cv.visitMaxs(0, 0);
+            cv.visitEnd();
+            classNode.addMethod(name,Opcodes.ACC_PUBLIC & Opcodes.ACC_SYNTHETIC,method.getReturnType(),parameters,null,null);
+        }
+    }
+
+    /**
+     * creates a MOP method name from a method
+     * @param method the method to be called by the mop method
+     * @param useThis if true, then it is a call on "this", "super" else
+     * @return the mop method name
+     */
+    public static String getMopMethodName(MethodNode method, boolean useThis) {
+        ClassNode declaringNode = method.getDeclaringClass();
+        int distance = 0;
+        for (;declaringNode!=null; declaringNode=declaringNode.getSuperClass()) {
+            distance++;
+        }
+        return (useThis?"this":"super")+"$"+distance+"$"+method.getName();
+    }
+   
+    /**
+     * method to determine if a method is a MOP method. This is done by the
+     * method name. If the name starts with "this$" or "super$", then it is
+     * a MOP method
+     * @param methodName name of the method to test
+     * @return true if the method is a MOP method
+     */
+    public static boolean isMopMethod(String methodName) {
+        return  methodName.startsWith("this$") || 
+                methodName.startsWith("super$");
+    }
+    
+    protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
+        String methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), node.getParameters());
+
+        cv = cw.visitMethod(node.getModifiers(), node.getName(), methodType, null, buildExceptions(node.getExceptions()));
+        helper = new BytecodeHelper(cv);
+        if (!node.isAbstract()) { 
+            Statement code = node.getCode();
+            if (isConstructor && (code == null || !firstStatementIsSpecialConstructorCall(node))) {
+                // invokes the super class constructor
+                cv.visitVarInsn(ALOAD, 0);
+                cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(classNode.getSuperClass()), "<init>", "()V");
+            }
+            
+            compileStack.init(node.getVariableScope(),node.getParameters(),cv, classNode);
+            
+            // ensure we save the current (meta) class in a register
+            (new ClassExpression(classNode)).visit(this);
+            cv.visitInsn(POP);
+            (new ClassExpression(ClassHelper.METACLASS_TYPE)).visit(this);
+            cv.visitInsn(POP);
+            
+            // handle body
+            super.visitConstructorOrMethod(node, isConstructor);
+            if (!outputReturn || node.isVoidMethod()) {
+                cv.visitInsn(RETURN);
+            }
+            compileStack.clear();
+            
+            // lets do all the exception blocks
+            for (Iterator iter = exceptionBlocks.iterator(); iter.hasNext();) {
+                Runnable runnable = (Runnable) iter.next();
+                runnable.run();
+            }
+            exceptionBlocks.clear();
+    
+            cv.visitMaxs(0, 0);
+        }
+    }
+
+    private boolean firstStatementIsSpecialConstructorCall(MethodNode node) {
+        Statement code = node.getFirstStatement();
+        if (code == null || !(code instanceof ExpressionStatement)) return false;
+
+        Expression expression = ((ExpressionStatement)code).getExpression();
+        if (!(expression instanceof ConstructorCallExpression)) return false;
+        ConstructorCallExpression cce = (ConstructorCallExpression) expression;
+        return cce.isSpecialCall();
+    }
+
+    public void visitConstructor(ConstructorNode node) {
+        this.constructorNode = node;
+        this.methodNode = null;
+        outputReturn = false;
+        super.visitConstructor(node);
+    }
+
+    public void visitMethod(MethodNode node) {
+        this.constructorNode = null;
+        this.methodNode = node;
+        outputReturn = false;
+        
+        super.visitMethod(node);
+    }
+
+    public void visitField(FieldNode fieldNode) {
+        onLineNumber(fieldNode, "visitField: " + fieldNode.getName());
+        ClassNode t = fieldNode.getType();
+        cw.visitField(
+            fieldNode.getModifiers(),
+            fieldNode.getName(),
+            BytecodeHelper.getTypeDescription(t),
+            null, //fieldValue,  //br  all the sudden that one cannot init the field here. init is done in static initilizer and instace intializer.
+            null);
+        visitAnnotations(fieldNode);
+    }
+
+    public void visitProperty(PropertyNode statement) {
+        // the verifyer created the field and the setter/getter methods, so here is
+        // not really something to do
+        onLineNumber(statement, "visitProperty:" + statement.getField().getName());
+        this.methodNode = null;
+    }
+
+    // GroovyCodeVisitor interface
+    //-------------------------------------------------------------------------
+
+    // Statements
+    //-------------------------------------------------------------------------
+
+    protected void visitStatement(Statement statement) {
+        String name = statement.getStatementLabel();
+        if (name!=null) {
+            Label label = compileStack.createLocalLabel(name);
+            cv.visitLabel(label);
+        }
+    }
+    
+    public void visitBlockStatement(BlockStatement block) {
+        onLineNumber(block, "visitBlockStatement");
+        visitStatement(block);
+        
+        compileStack.pushVariableScope(block.getVariableScope());
+        super.visitBlockStatement(block);
+        compileStack.pop();
+    }
+
+    public void visitForLoop(ForStatement loop) {
+        onLineNumber(loop, "visitForLoop");
+        visitStatement(loop);
+
+        compileStack.pushLoop(loop.getVariableScope(),loop.getStatementLabel());
+
+        //
+        // Declare the loop counter.
+        Variable variable = compileStack.defineVariable(loop.getVariable(),false);
+
+        //
+        // Then get the iterator and generate the loop control
+        MethodCallExpression iterator = new MethodCallExpression(loop.getCollectionExpression(),"iterator",new ArgumentListExpression());
+        iterator.visit(this);
+
+        final int iteratorIdx = compileStack.defineTemporaryVariable("iterator", ClassHelper.make(java.util.Iterator.class),true);
+
+        Label continueLabel = compileStack.getContinueLabel();
+        Label breakLabel = compileStack.getBreakLabel();
+        
+        cv.visitLabel(continueLabel);
+        cv.visitVarInsn(ALOAD, iteratorIdx);
+        iteratorHasNextMethod.call(cv);
+        // note: ifeq tests for ==0, a boolean is 0 if it is false
+        cv.visitJumpInsn(IFEQ, breakLabel);
+        
+        cv.visitVarInsn(ALOAD, iteratorIdx);
+        iteratorNextMethod.call(cv);
+        helper.storeVar(variable);
+
+        // Generate the loop body
+        loop.getLoopBlock().visit(this);
+
+        cv.visitJumpInsn(GOTO, continueLabel);        
+        cv.visitLabel(breakLabel);
+        
+        compileStack.pop();
+    }
+
+    public void visitWhileLoop(WhileStatement loop) {
+        onLineNumber(loop, "visitWhileLoop");
+        visitStatement(loop);
+
+        compileStack.pushLoop(loop.getStatementLabel());
+        Label continueLabel = compileStack.getContinueLabel();
+        Label breakLabel = compileStack.getBreakLabel();
+        
+        cv.visitLabel(continueLabel);
+        loop.getBooleanExpression().visit(this);
+        cv.visitJumpInsn(IFEQ, breakLabel);
+        
+        loop.getLoopBlock().visit(this);
+        
+        cv.visitJumpInsn(GOTO, continueLabel);
+        cv.visitLabel(breakLabel);
+        
+        compileStack.pop();
+    }
+
+    public void visitDoWhileLoop(DoWhileStatement loop) {
+        onLineNumber(loop, "visitDoWhileLoop");
+        visitStatement(loop);
+
+        compileStack.pushLoop(loop.getStatementLabel());
+        Label breakLabel = compileStack.getBreakLabel();
+        Label continueLabel = compileStack.getContinueLabel();
+        cv.visitLabel(continueLabel);
+
+        loop.getLoopBlock().visit(this);
+
+        loop.getBooleanExpression().visit(this);
+        cv.visitJumpInsn(IFEQ, continueLabel);
+        cv.visitLabel(breakLabel);
+        
+        compileStack.pop();
+    }
+
+    public void visitIfElse(IfStatement ifElse) {
+        onLineNumber(ifElse, "visitIfElse");
+        visitStatement(ifElse);
+        ifElse.getBooleanExpression().visit(this);
+        
+        Label l0 = new Label();
+        cv.visitJumpInsn(IFEQ, l0);
+
+        ifElse.getIfBlock().visit(this);
+
+        Label l1 = new Label();
+        cv.visitJumpInsn(GOTO, l1);
+        cv.visitLabel(l0);
+
+        ifElse.getElseBlock().visit(this);
+        cv.visitLabel(l1);
+    }
+
+    public void visitTernaryExpression(TernaryExpression expression) {
+        onLineNumber(expression, "visitTernaryExpression");
+
+        expression.getBooleanExpression().visit(this);
+
+        Label l0 = new Label();
+        cv.visitJumpInsn(IFEQ, l0);
+        visitAndAutoboxBoolean(expression.getTrueExpression());
+
+        Label l1 = new Label();
+        cv.visitJumpInsn(GOTO, l1);
+        cv.visitLabel(l0);
+
+        visitAndAutoboxBoolean(expression.getFalseExpression());
+        cv.visitLabel(l1);
+    }
+
+    public void visitAssertStatement(AssertStatement statement) {
+        onLineNumber(statement, "visitAssertStatement");
+        visitStatement(statement);
+
+        BooleanExpression booleanExpression = statement.getBooleanExpression();
+        booleanExpression.visit(this);
+
+        Label l0 = new Label();
+        cv.visitJumpInsn(IFEQ, l0);
+
+        // do nothing
+
+        Label l1 = new Label();
+        cv.visitJumpInsn(GOTO, l1);
+        cv.visitLabel(l0);
+
+        // push expression string onto stack
+        String expressionText = booleanExpression.getText();
+        List list = new ArrayList();
+        addVariableNames(booleanExpression, list);
+        if (list.isEmpty()) {
+            cv.visitLdcInsn(expressionText);
+        }
+        else {
+            boolean first = true;
+
+            // lets create a new expression
+            cv.visitTypeInsn(NEW, "java/lang/StringBuffer");
+            cv.visitInsn(DUP);
+            cv.visitLdcInsn(expressionText + ". Values: ");
+
+            cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "(Ljava/lang/String;)V");
+
+            int tempIndex = compileStack.defineTemporaryVariable("assert",true);
+
+            for (Iterator iter = list.iterator(); iter.hasNext();) {
+                String name = (String) iter.next();
+                String text = name + " = ";
+                if (first) {
+                    first = false;
+                }
+                else {
+                    text = ", " + text;
+                }
+
+                cv.visitVarInsn(ALOAD, tempIndex);
+                cv.visitLdcInsn(text);
+                cv.visitMethodInsn(
+                    INVOKEVIRTUAL,
+                    "java/lang/StringBuffer",
+                    "append",
+                    "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
+                cv.visitInsn(POP);
+
+                cv.visitVarInsn(ALOAD, tempIndex);
+                new VariableExpression(name).visit(this);
+                cv.visitMethodInsn(
+                    INVOKEVIRTUAL,
+                    "java/lang/StringBuffer",
+                    "append",
+                    "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
+                cv.visitInsn(POP);
+
+            }
+            cv.visitVarInsn(ALOAD, tempIndex);
+            compileStack.removeVar(tempIndex);
+        }
+        // now the optional exception expression
+        statement.getMessageExpression().visit(this);
+
+        assertFailedMethod.call(cv);
+        cv.visitLabel(l1);
+    }
+
+    private void addVariableNames(Expression expression, List list) {
+        if (expression instanceof BooleanExpression) {
+            BooleanExpression boolExp = (BooleanExpression) expression;
+            addVariableNames(boolExp.getExpression(), list);
+        }
+        else if (expression instanceof BinaryExpression) {
+            BinaryExpression binExp = (BinaryExpression) expression;
+            addVariableNames(binExp.getLeftExpression(), list);
+            addVariableNames(binExp.getRightExpression(), list);
+        }
+        else if (expression instanceof VariableExpression) {
+            VariableExpression varExp = (VariableExpression) expression;
+            list.add(varExp.getName());
+        }
+    }
+
+    public void visitTryCatchFinally(TryCatchStatement statement) {
+        onLineNumber(statement, "visitTryCatchFinally");
+        visitStatement(statement);
+        
+        CatchStatement catchStatement = statement.getCatchStatement(0);
+        Statement tryStatement = statement.getTryStatement();
+        final Statement finallyStatement = statement.getFinallyStatement();
+
+        int anyExceptionIndex = compileStack.defineTemporaryVariable("exception",false);
+        if (!finallyStatement.isEmpty()) {
+            compileStack.pushFinallyBlock(
+                new Runnable(){
+                    public void run(){finallyStatement.visit(AsmClassGenerator.this);}
+                }
+            );
+        }
+        
+        // start try block, label needed for exception table
+        final Label tryStart = new Label();
+        cv.visitLabel(tryStart);
+        tryStatement.visit(this);
+        // goto finally part
+        final Label finallyStart = new Label();
+        cv.visitJumpInsn(GOTO, finallyStart);
+        // marker needed for Exception table
+        final Label tryEnd = new Label();
+        cv.visitLabel(tryEnd);
+        
+        for (Iterator it=statement.getCatchStatements().iterator(); it.hasNext();) {
+            catchStatement = (CatchStatement) it.next();
+            ClassNode exceptionType = catchStatement.getExceptionType();
+            // start catch block, label needed for exception table
+            final Label catchStart = new Label();
+            cv.visitLabel(catchStart);
+            // create exception variable and store the exception 
+            compileStack.defineVariable(catchStatement.getVariable(),true);
+            // handle catch body
+            catchStatement.visit(this);
+            // goto finally start
+            cv.visitJumpInsn(GOTO, finallyStart);
+            // add exception to table
+            final String exceptionTypeInternalName = BytecodeHelper.getClassInternalName(exceptionType);
+            exceptionBlocks.add(new Runnable() {
+                public void run() {
+                    cv.visitTryCatchBlock(tryStart, tryEnd, catchStart, exceptionTypeInternalName);
+                }
+            });
+        }
+        
+        // marker needed for the exception table
+        final Label endOfAllCatches = new Label();
+        cv.visitLabel(endOfAllCatches);
+        
+        // remove the finally, don't let it visit itself
+        if (!finallyStatement.isEmpty()) compileStack.popFinallyBlock();
+        
+        // start finally
+        cv.visitLabel(finallyStart);
+        finallyStatement.visit(this);
+        // goto end of finally
+        Label afterFinally = new Label();
+        cv.visitJumpInsn(GOTO, afterFinally);
+        
+        // start a block catching any Exception
+        final Label catchAny = new Label();
+        cv.visitLabel(catchAny);
+        //store exception
+        cv.visitVarInsn(ASTORE, anyExceptionIndex);
+        finallyStatement.visit(this);
+        // load the exception and rethrow it
+        cv.visitVarInsn(ALOAD, anyExceptionIndex);
+        cv.visitInsn(ATHROW);
+        
+        // end of all catches and finally parts
+        cv.visitLabel(afterFinally);
+        
+        // add catch any block to exception table
+        exceptionBlocks.add(new Runnable() {
+            public void run() {
+                cv.visitTryCatchBlock(tryStart, endOfAllCatches, catchAny, null);
+            }
+        });
+    }
+
+    public void visitSwitch(SwitchStatement statement) {
+        onLineNumber(statement, "visitSwitch");
+        visitStatement(statement);
+
+        statement.getExpression().visit(this);
+
+        // switch does not have a continue label. use its parent's for continue
+        Label breakLabel = compileStack.pushSwitch();
+        
+        int switchVariableIndex = compileStack.defineTemporaryVariable("switch",true);
+
+        List caseStatements = statement.getCaseStatements();
+        int caseCount = caseStatements.size();
+        Label[] labels = new Label[caseCount + 1];
+        for (int i = 0; i < caseCount; i++) {
+            labels[i] = new Label();
+        }
+
+        int i = 0;
+        for (Iterator iter = caseStatements.iterator(); iter.hasNext(); i++) {
+            CaseStatement caseStatement = (CaseStatement) iter.next();
+            visitCaseStatement(caseStatement, switchVariableIndex, labels[i], labels[i + 1]);
+        }
+
+        statement.getDefaultStatement().visit(this);
+
+        cv.visitLabel(breakLabel);
+
+        compileStack.pop();
+    }
+
+    public void visitCaseStatement(CaseStatement statement) {
+    }
+
+    public void visitCaseStatement(
+        CaseStatement statement,
+        int switchVariableIndex,
+        Label thisLabel,
+        Label nextLabel) {
+
+        onLineNumber(statement, "visitCaseStatement");
+
+        cv.visitVarInsn(ALOAD, switchVariableIndex);
+        statement.getExpression().visit(this);
+
+        isCaseMethod.call(cv);
+
+        Label l0 = new Label();
+        cv.visitJumpInsn(IFEQ, l0);
+
+        cv.visitLabel(thisLabel);
+
+        statement.getCode().visit(this);
+
+        // now if we don't finish with a break we need to jump past
+        // the next comparison
+        if (nextLabel != null) {
+            cv.visitJumpInsn(GOTO, nextLabel);
+        }
+
+        cv.visitLabel(l0);
+    }
+
+    public void visitBreakStatement(BreakStatement statement) {
+        onLineNumber(statement, "visitBreakStatement");
+        visitStatement(statement);
+        
+        String name = statement.getLabel();
+        Label breakLabel = compileStack.getNamedBreakLabel(name);
+        compileStack.applyFinallyBlocks(breakLabel, true);
+        
+        cv.visitJumpInsn(GOTO, breakLabel);
+    }
+
+    public void visitContinueStatement(ContinueStatement statement) {
+        onLineNumber(statement, "visitContinueStatement");
+        visitStatement(statement);
+        
+        String name = statement.getLabel();
+        Label continueLabel = compileStack.getContinueLabel();
+        if (name!=null) continueLabel = compileStack.getNamedContinueLabel(name);
+        compileStack.applyFinallyBlocks(continueLabel, false);
+        cv.visitJumpInsn(GOTO, continueLabel);
+    }
+
+    public void visitSynchronizedStatement(SynchronizedStatement statement) {
+        onLineNumber(statement, "visitSynchronizedStatement");
+        visitStatement(statement);
+        
+        statement.getExpression().visit(this);
+        final int index = compileStack.defineTemporaryVariable("synchronized", ClassHelper.Integer_TYPE,true);
+
+        final Label synchronizedStart = new Label();
+        final Label synchronizedEnd = new Label();
+        final Label catchAll = new Label();
+        
+        cv.visitVarInsn(ALOAD, index);
+        cv.visitInsn(MONITORENTER);
+        cv.visitLabel(synchronizedStart);
+
+        Runnable finallyPart = new Runnable(){
+            public void run(){
+                cv.visitVarInsn(ALOAD, index);
+                cv.visitInsn(MONITOREXIT);
+            }
+        };
+        compileStack.pushFinallyBlock(finallyPart);
+        statement.getCode().visit(this);
+
+        finallyPart.run();
+        cv.visitJumpInsn(GOTO, synchronizedEnd);
+        cv.visitLabel(catchAll);
+        finallyPart.run();
+        cv.visitInsn(ATHROW);
+        cv.visitLabel(synchronizedEnd);
+
+        compileStack.popFinallyBlock();
+        exceptionBlocks.add(new Runnable() {
+            public void run() {
+                cv.visitTryCatchBlock(synchronizedStart, catchAll, catchAll, null);
+            }
+        });
+    }
+
+    public void visitThrowStatement(ThrowStatement statement) {
+        onLineNumber(statement, "visitThrowStatement");
+        visitStatement(statement);
+        
+        statement.getExpression().visit(this);
+
+        // we should infer the type of the exception from the expression
+        cv.visitTypeInsn(CHECKCAST, "java/lang/Throwable");
+
+        cv.visitInsn(ATHROW);
+    }
+
+    public void visitReturnStatement(ReturnStatement statement) {
+        onLineNumber(statement, "visitReturnStatement");
+        visitStatement(statement);
+        
+        ClassNode returnType = methodNode.getReturnType();
+        if (returnType==ClassHelper.VOID_TYPE) {
+        	if (!(statement == ReturnStatement.RETURN_NULL_OR_VOID)) {
+                throwException("Cannot use return statement with an expression on a method that returns void");
+        	}
+            compileStack.applyFinallyBlocks();
+            cv.visitInsn(RETURN);
+            outputReturn = true;
+            return;
+        }
+
+        Expression expression = statement.getExpression();
+        evaluateExpression(expression);
+        if (returnType==ClassHelper.OBJECT_TYPE && expression.getType() != null && expression.getType()==ClassHelper.VOID_TYPE) {
+            cv.visitInsn(ACONST_NULL); // cheat the caller
+        } else {
+            // return is based on class type
+            // we may need to cast
+            doConvertAndCast(returnType, expression, false, true, false);
+            helper.unbox(returnType);
+        }
+        if (compileStack.hasFinallyBlocks()) {
+            int returnValueIdx = compileStack.defineTemporaryVariable("returnValue",returnType,true);
+            compileStack.applyFinallyBlocks();
+            helper.load(returnType,returnValueIdx);
+        }        
+        helper.doReturn(returnType);
+        outputReturn = true;
+    }
+
+    /**
+     * Casts to the given type unless it can be determined that the cast is unnecessary
+     */
+    protected void doConvertAndCast(ClassNode type, Expression expression, boolean ignoreAutoboxing, boolean forceCast, boolean coerce) {
+        ClassNode expType = getExpressionType(expression);
+        // temp resolution: convert all primitive casting to corresponsing Object type
+        if (!ignoreAutoboxing && ClassHelper.isPrimitiveType(type)) {
+            type = ClassHelper.getWrapper(type);
+        }
+        if (forceCast || (type!=null && !type.equals(expType))) {
+            doConvertAndCast(type,coerce);
+        }
+    }    
+
+    /**
+     * @param expression
+     */
+    protected void evaluateExpression(Expression expression) {
+        visitAndAutoboxBoolean(expression);
+
+        Expression assignExpr = createReturnLHSExpression(expression);
+        if (assignExpr != null) {
+            leftHandExpression = false;
+            assignExpr.visit(this);
+        }
+    }
+
+    public void visitExpressionStatement(ExpressionStatement statement) {
+        onLineNumber(statement, "visitExpressionStatement: " + statement.getExpression().getClass().getName());
+        visitStatement(statement);
+        
+        Expression expression = statement.getExpression();
+
+        visitAndAutoboxBoolean(expression);
+
+        if (isPopRequired(expression)) {
+            cv.visitInsn(POP);
+        }
+    }
+
+    // Expressions
+    //-------------------------------------------------------------------------
+
+    public void visitDeclarationExpression(DeclarationExpression expression) {
+        onLineNumber(expression, "visitDeclarationExpression: \""+expression.getVariableExpression().getName()+"\"");
+
+        Expression rightExpression = expression.getRightExpression();
+        // no need to visit left side, just get the variable name
+        VariableExpression vex = expression.getVariableExpression();
+        ClassNode type = vex.getType();
+
+        // lets not cast for primitive types as we handle these in field setting etc
+        if (ClassHelper.isPrimitiveType(type)) {
+            rightExpression.visit(this);
+        } else {
+            if (type!=ClassHelper.OBJECT_TYPE){
+                visitCastExpression(new CastExpression(type, rightExpression));
+            } else {
+                visitAndAutoboxBoolean(rightExpression);
+            }
+        }
+        compileStack.defineVariable(vex,true);
+    }
+    
+    public void visitBinaryExpression(BinaryExpression expression) {
+        onLineNumber(expression, "visitBinaryExpression: \"" + expression.getOperation().getText() + "\" ");
+        switch (expression.getOperation().getType()) {
+            case Types.EQUAL : // = assignment
+                evaluateEqual(expression);
+                break;
+
+            case Types.COMPARE_IDENTICAL : // ===
+                evaluateBinaryExpression(compareIdenticalMethod, expression);
+                break;
+
+            case Types.COMPARE_EQUAL : // ==
+                evaluateBinaryExpression(compareEqualMethod, expression);
+                break;
+
+            case Types.COMPARE_NOT_EQUAL :
+                evaluateBinaryExpression(compareNotEqualMethod, expression);
+                break;
+
+            case Types.COMPARE_TO :
+                evaluateCompareTo(expression);
+                break;
+
+            case Types.COMPARE_GREATER_THAN :
+                evaluateBinaryExpression(compareGreaterThanMethod, expression);
+                break;
+
+            case Types.COMPARE_GREATER_THAN_EQUAL :
+                evaluateBinaryExpression(compareGreaterThanEqualMethod, expression);
+                break;
+
+            case Types.COMPARE_LESS_THAN :
+                evaluateBinaryExpression(compareLessThanMethod, expression);
+                break;
+
+            case Types.COMPARE_LESS_THAN_EQUAL :
+                evaluateBinaryExpression(compareLessThanEqualMethod, expression);
+                break;
+
+            case Types.LOGICAL_AND :
+                evaluateLogicalAndExpression(expression);
+                break;
+
+            case Types.LOGICAL_OR :
+                evaluateLogicalOrExpression(expression);
+                break;
+
+            case Types.BITWISE_AND :
+                evaluateBinaryExpression("and", expression);
+                break;
+
+            case Types.BITWISE_AND_EQUAL :
+                evaluateBinaryExpressionWithAsignment("and", expression);
+                break;
+
+            case Types.BITWISE_OR :
+                evaluateBinaryExpression("or", expression);
+                break;
+
+            case Types.BITWISE_OR_EQUAL :
+                evaluateBinaryExpressionWithAsignment("or", expression);
+                break;
+
+            case Types.BITWISE_XOR :
+                evaluateBinaryExpression("xor", expression);
+                break;
+
+            case Types.BITWISE_XOR_EQUAL :
+                evaluateBinaryExpressionWithAsignment("xor", expression);
+                break;
+
+            case Types.PLUS :
+                evaluateBinaryExpression("plus", expression);
+                break;
+
+            case Types.PLUS_EQUAL :
+                evaluateBinaryExpressionWithAsignment("plus", expression);
+                break;
+                
+            case Types.MINUS :
+                evaluateBinaryExpression("minus", expression);
+                break;
+                
+            case Types.MINUS_EQUAL :
+                evaluateBinaryExpressionWithAsignment("minus", expression);
+                break;
+
+            case Types.MULTIPLY :
+                evaluateBinaryExpression("multiply", expression);
+                break;
+
+            case Types.MULTIPLY_EQUAL :
+                evaluateBinaryExpressionWithAsignment("multiply", expression);
+                break;
+
+            case Types.DIVIDE :
+                evaluateBinaryExpression("div", expression);
+                break;
+
+            case Types.DIVIDE_EQUAL :
+                //SPG don't use divide since BigInteger implements directly
+                //and we want to dispatch through DefaultGroovyMethods to get a BigDecimal result
+                evaluateBinaryExpressionWithAsignment("div", expression);
+                break;
+
+            case Types.INTDIV :
+                evaluateBinaryExpression("intdiv", expression);
+                break;
+
+            case Types.INTDIV_EQUAL :
+                evaluateBinaryExpressionWithAsignment("intdiv", expression);
+                break;
+
+            case Types.MOD :
+                evaluateBinaryExpression("mod", expression);
+                break;
+
+            case Types.MOD_EQUAL :
+                evaluateBinaryExpressionWithAsignment("mod", expression);
+                break;
+
+            case Types.POWER :
+                evaluateBinaryExpression("power", expression);
+                break;
+
+            case Types.POWER_EQUAL :
+                evaluateBinaryExpressionWithAsignment("power", expression);
+                break;
+
+            case Types.LEFT_SHIFT :
+                evaluateBinaryExpression("leftShift", expression);
+                break;
+
+            case Types.LEFT_SHIFT_EQUAL :
+                evaluateBinaryExpressionWithAsignment("leftShift", expression);
+                break;
+
+            case Types.RIGHT_SHIFT :
+                evaluateBinaryExpression("rightShift", expression);
+                break;
+
+            case Types.RIGHT_SHIFT_EQUAL :
+                evaluateBinaryExpressionWithAsignment("rightShift", expression);
+                break;
+
+            case Types.RIGHT_SHIFT_UNSIGNED :
+                evaluateBinaryExpression("rightShiftUnsigned", expression);
+                break;
+
+            case Types.RIGHT_SHIFT_UNSIGNED_EQUAL :
+                evaluateBinaryExpressionWithAsignment("rightShiftUnsigned", expression);
+                break;
+
+            case Types.KEYWORD_INSTANCEOF :
+                evaluateInstanceof(expression);
+                break;
+
+            case Types.FIND_REGEX :
+                evaluateBinaryExpression(findRegexMethod, expression);
+                break;
+
+            case Types.MATCH_REGEX :
+                evaluateBinaryExpression(matchRegexMethod, expression);
+                break;
+
+            case Types.LEFT_SQUARE_BRACKET :
+                if (leftHandExpression) {
+                    throwException("Should not be called here. Possible reason: postfix operation on array.");
+                    // This is handled right now in the evaluateEqual()
+                    // should support this here later
+                    //evaluateBinaryExpression("putAt", expression);
+                } else {
+                    evaluateBinaryExpression("getAt", expression);
+                }
+                break;
+             
+            case Types.KEYWORD_IN :
+                evaluateBinaryExpression(isCaseMethod, expression);
+                break;
+
+            default :
+                throwException("Operation: " + expression.getOperation() + " not supported");
+        }
+    }
+
+    private void load(Expression exp) {
+
+        boolean wasLeft = leftHandExpression;
+        leftHandExpression = false;
+//        if (CREATE_DEBUG_INFO)
+//            helper.mark("-- loading expression: " + exp.getClass().getName() +
+//                    " at [" + exp.getLineNumber() + ":" + exp.getColumnNumber() + "]");
+        //exp.visit(this);
+        visitAndAutoboxBoolean(exp);
+//        if (CREATE_DEBUG_INFO)
+//            helper.mark(" -- end of loading --");
+
+        leftHandExpression  = wasLeft;
+    }
+
+    public void visitPostfixExpression(PostfixExpression expression) {
+        switch (expression.getOperation().getType()) {
+            case Types.PLUS_PLUS :
+                evaluatePostfixMethod("next", expression.getExpression());
+                break;
+            case Types.MINUS_MINUS :
+                evaluatePostfixMethod("previous", expression.getExpression());
+                break;
+        }
+    }
+
+    private void throwException(String s) {
+        throw new RuntimeParserException(s, currentASTNode);
+    }
+
+    public void visitPrefixExpression(PrefixExpression expression) {
+        switch (expression.getOperation().getType()) {
+            case Types.PLUS_PLUS :
+                evaluatePrefixMethod("next", expression.getExpression());
+                break;
+            case Types.MINUS_MINUS :
+                evaluatePrefixMethod("previous", expression.getExpression());
+                break;
+        }
+    }
+
+    public void visitClosureExpression(ClosureExpression expression) {
+        ClassNode innerClass = createClosureClass(expression);
+        addInnerClass(innerClass);
+        String innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass);
+
+        passingClosureParams = true;
+        List constructors = innerClass.getDeclaredConstructors();
+        ConstructorNode node = (ConstructorNode) constructors.get(0);
+        
+        Parameter[] localVariableParams = node.getParameters();
+
+        cv.visitTypeInsn(NEW, innerClassinternalName);
+        cv.visitInsn(DUP);
+        if (isStaticMethod() || classNode.isStaticClass()) {
+            visitClassExpression(new ClassExpression(classNode));
+            visitClassExpression(new ClassExpression(getOutermostClass()));
+        } else {
+            cv.visitVarInsn(ALOAD, 0);
+            loadThis();
+        }
+
+        // now lets load the various parameters we're passing
+        // we start at index 1 because the first variable we pass
+        // is the owner instance and at this point it is already 
+        // on the stack
+        for (int i = 2; i < localVariableParams.length; i++) {
+            Parameter param = localVariableParams[i];
+            String name = param.getName();
+
+            // compileStack.containsVariable(name) means to ask if the variable is already declared
+            // compileStack.getScope().isReferencedClassVariable(name) means to ask if the variable is a field
+            // If it is no field and is not yet declared, then it is either a closure shared variable or 
+            // an already declared variable. 
+            if (!compileStack.containsVariable(name) && compileStack.getScope().isReferencedClassVariable(name)) {
+                visitFieldExpression(new FieldExpression(classNode.getField(name)));
+            } else { 
+                Variable v = compileStack.getVariable(name,classNode.getSuperClass()!=ClassHelper.CLOSURE_TYPE);
+                if (v==null) {
+                    // variable is not on stack because we are
+                    // inside a nested Closure and this variable
+                    // was not used before
+                    // then load it from the Closure field
+                    FieldNode field = classNode.getField(name);
+                    cv.visitVarInsn(ALOAD, 0);
+                    cv.visitFieldInsn(GETFIELD, internalClassName, name, BytecodeHelper.getTypeDescription(field.getType()));
+                    // and define it
+                    // Note:
+                    // we can simply define it here and don't have to
+                    // be afraid about name problems because a second
+                    // variable with that name is not allowed inside the closure
+                    param.setClosureSharedVariable(false);
+                    v = compileStack.defineVariable(param,true);
+                    param.setClosureSharedVariable(true);
+                    v.setHolder(true);
+                }
+                cv.visitVarInsn(ALOAD, v.getIndex());
+            }
+        }
+        passingClosureParams = false;
+
+        // we may need to pass in some other constructors
+        //cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", prototype + ")V");
+        cv.visitMethodInsn(
+            INVOKESPECIAL,
+            innerClassinternalName,
+            "<init>",
+            BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, localVariableParams));
+    }
+
+    /**
+     * Loads either this object or if we're inside a closure then load the top level owner
+     */
+    protected void loadThisOrOwner() {
+        if (isInnerClass()) {
+            visitFieldExpression(new FieldExpression(classNode.getField("owner")));
+        } else {
+            loadThis();
+        }
+    }
+
+    public void visitRegexExpression(RegexExpression expression) {
+        expression.getRegex().visit(this);
+        regexPattern.call(cv);
+    }
+
+    /**
+     * Generate byte code for constants
+     * @see <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#14152">Class field types</a>
+     */
+    public void visitConstantExpression(ConstantExpression expression) {
+        Object value = expression.getValue();
+        helper.loadConstant(value);
+    }
+
+    public void visitSpreadExpression(SpreadExpression expression) {
+        throw new GroovyBugError("SpreadExpression should not be visited here");
+    }
+
+    public void visitSpreadMapExpression(SpreadMapExpression expression) {
+        Expression subExpression = expression.getExpression();
+        subExpression.visit(this);
+        spreadMap.call(cv);
+    }
+
+    public void visitMethodPointerExpression(MethodPointerExpression expression) {
+        Expression subExpression = expression.getExpression();
+        subExpression.visit(this);
+        helper.loadConstant(expression.getMethodName());
+        getMethodPointer.call(cv);
+    }
+
+    public void visitNegationExpression(NegationExpression expression) {
+        Expression subExpression = expression.getExpression();
+        subExpression.visit(this);
+        negation.call(cv);
+    }
+
+    public void visitBitwiseNegExpression(BitwiseNegExpression expression) {
+        Expression subExpression = expression.getExpression();
+        subExpression.visit(this);
+        bitNegation.call(cv);
+    }
+
+    public void visitCastExpression(CastExpression expression) {
+        ClassNode type = expression.getType();
+        visitAndAutoboxBoolean(expression.getExpression());
+        doConvertAndCast(type, expression.getExpression(), expression.isIgnoringAutoboxing(),false,expression.isCoerce());
+    }
+
+    public void visitNotExpression(NotExpression expression) {
+        Expression subExpression = expression.getExpression();
+        subExpression.visit(this);
+        // if we do !object, then the cast to boolean will
+        // do the conversion of Object to boolean. so a simple
+        // call to unbox is enough here.
+        if (
+                !isComparisonExpression(subExpression) && 
+                !(subExpression instanceof BooleanExpression))
+        {
+            helper.unbox(boolean.class);
+        }
+        helper.negateBoolean();
+    }
+
+    /**
+     * return a primitive boolean value of the BooleanExpresion.
+     * @param expression
+     */
+    public void visitBooleanExpression(BooleanExpression expression) {
+        compileStack.pushBooleanExpression();
+        expression.getExpression().visit(this);
+
+        if (!isComparisonExpression(expression.getExpression())) {
+// comment out for optimization when boolean values are not autoboxed for eg. function calls.
+//           Class typeClass = expression.getExpression().getTypeClass();
+//           if (typeClass != null && typeClass != boolean.class) {
+                helper.unbox(boolean.class); // to return a primitive boolean
+//            }
+        }
+        compileStack.pop();
+    }
+    
+    private void makeInvokeMethodCall(MethodCallExpression call, boolean useSuper, MethodCallerMultiAdapter adapter) {
+        // receiver
+        // we operate on GroovyObject if possible
+        Expression objectExpression = call.getObjectExpression();
+        if (!isStaticMethod() && !isStaticContext() && isThisExpression(call.getObjectExpression())) 
+        {
+            objectExpression = new CastExpression(ClassHelper.make(GroovyObject.class),objectExpression);
+        }
+        // message name
+        Expression messageName = new CastExpression(ClassHelper.STRING_TYPE,call.getMethod());
+        if (useSuper) {
+            makeCall(new ClassExpression(getOutermostClass().getSuperClass()),
+                    objectExpression, messageName,
+                    call.getArguments(), adapter,
+                    call.isSafe(), call.isSpreadSafe(), 
+                    false
+            );
+        } else {
+            makeCall(objectExpression, messageName,
+                    call.getArguments(), adapter,
+                    call.isSafe(), call.isSpreadSafe(), 
+                    call.isImplicitThis()
+            );
+        }
+    }
+    
+    private void makeCall( 
+            Expression receiver, Expression message, Expression arguments, 
+            MethodCallerMultiAdapter adapter, 
+            boolean safe, boolean spreadSafe, boolean implicitThis
+    ) {
+        ClassNode cn = classNode;
+        if (isInClosure() && !implicitThis) {
+            cn = getOutermostClass();
+        }
+        makeCall(new ClassExpression(cn), receiver, message, arguments,
+                adapter, safe, spreadSafe, implicitThis);
+    }
+    
+    private void makeCall( 
+            ClassExpression sender,
+            Expression receiver, Expression message, Expression arguments, 
+            MethodCallerMultiAdapter adapter, 
+            boolean safe, boolean spreadSafe, boolean implicitThis
+    ) {
+        // ensure VariableArguments are read, not stored
+        boolean lhs = leftHandExpression;
+        leftHandExpression = false;
+        
+        // sender
+        sender.visit(this);
+        // receiver
+        boolean oldVal = this.implicitThis;
+        this.implicitThis = implicitThis;
+        receiver.visit(this);
+        this.implicitThis = oldVal;
+        // message
+        if (message!=null) message.visit(this);
+
+        // arguments
+        boolean containsSpreadExpression = containsSpreadExpression(arguments);
+        int numberOfArguments = containsSpreadExpression?-1:argumentSize(arguments);
+        if (numberOfArguments > adapter.maxArgs || containsSpreadExpression) {
+            ArgumentListExpression ae;
+            if (arguments instanceof ArgumentListExpression) {
+                ae = (ArgumentListExpression) arguments;
+            } else if (arguments instanceof TupleExpression){
+                TupleExpression te = (TupleExpression) arguments;
+                ae = new ArgumentListExpression(te.getExpressions());
+            } else {
+                ae = new ArgumentListExpression();
+                ae.addExpression(arguments);
+            }
+            if (containsSpreadExpression){
+                despreadList(ae.getExpressions(),true);
+            } else {
+                ae.visit(this);
+            }
+        } else if (numberOfArguments > 0) {
+            TupleExpression te = (TupleExpression) arguments;
+            for (int i = 0; i < numberOfArguments; i++) {
+                Expression argument = te.getExpression(i);
+                visitAndAutoboxBoolean(argument);
+                if (argument instanceof CastExpression) loadWrapper(argument);
+            }
+        }
+                
+        adapter.call(cv,numberOfArguments,safe,spreadSafe);
+        
+        leftHandExpression = lhs;
+    }
+
+    private void despreadList(List expressions, boolean wrap) {
+        
+        ArrayList spreadIndexes = new ArrayList();
+        ArrayList spreadExpressions = new ArrayList();
+        ArrayList normalArguments = new ArrayList();
+        for (int i=0; i<expressions.size(); i++) {
+            Object expr = expressions.get(i);
+            if ( !(expr instanceof SpreadExpression) ) {
+                normalArguments.add(expr);
+            } else {
+                spreadIndexes.add(new ConstantExpression(new Integer(i-spreadExpressions.size())));
+                spreadExpressions.add(((SpreadExpression)expr).getExpression());                
+            }
+        }
+
+        //load normal arguments as array
+        visitTupleExpression(new ArgumentListExpression(normalArguments),wrap);
+        //load spread expressions as array
+        (new TupleExpression(spreadExpressions)).visit(this);
+        //load insertion index
+        (new ArrayExpression(ClassHelper.int_TYPE,spreadIndexes,null)).visit(this);
+        despreadList.call(cv);
+    }
+
+    public void visitMethodCallExpression(MethodCallExpression call) {
+        onLineNumber(call, "visitMethodCallExpression: \"" + call.getMethod() + "\":");
+
+        Expression arguments = call.getArguments();
+        String methodName = call.getMethodAsString();
+        boolean isSuperMethodCall = usesSuper(call);
+        boolean isThisExpression = isThisExpression(call.getObjectExpression());
+        
+        // are we a local variable
+        if (methodName!=null && isThisExpression && isFieldOrVariable(methodName) && ! classNode.hasPossibleMethod(methodName, arguments)) {
+            // lets invoke the closure method
+            visitVariableExpression(new VariableExpression(methodName));
+            arguments.visit(this);
+            invokeClosureMethod.call(cv);
+        } else {
+            MethodCallerMultiAdapter adapter = invokeMethod;
+            if (isThisExpression) adapter = invokeMethodOnCurrent;
+            if (isSuperMethodCall) adapter = invokeMethodOnSuper;
+            if (isStaticInvocation(call)) adapter = invokeStaticMethod;
+            makeInvokeMethodCall(call,isSuperMethodCall,adapter);
+        }
+    }
+
+    private boolean isStaticInvocation(MethodCallExpression call) {
+        if (!isThisExpression(call.getObjectExpression())) return false;
+        if (isStaticMethod()) return true;
+        return isStaticContext() && !call.isImplicitThis();
+    }
+
+    protected boolean emptyArguments(Expression arguments) {
+        return argumentSize(arguments) == 0;
+    }
+    
+    protected static boolean containsSpreadExpression(Expression arguments) {
+        List args = null;
+        if (arguments instanceof TupleExpression) {
+            TupleExpression tupleExpression = (TupleExpression) arguments;
+            args = tupleExpression.getExpressions();
+        } else if (arguments instanceof ListExpression) {
+            ListExpression le = (ListExpression) arguments;
+            args = le.getExpressions();
+        } else {
+            return arguments instanceof SpreadExpression;
+        }
+        for (Iterator iter = args.iterator(); iter.hasNext();) {
+            if (iter.next() instanceof SpreadExpression) return true;
+        }
+        return false;
+    }
+    
+    protected static int argumentSize(Expression arguments) {
+        if (arguments instanceof TupleExpression) {
+            TupleExpression tupleExpression = (TupleExpression) arguments;
+            int size = tupleExpression.getExpressions().size();
+            return size;
+        }
+        return 1;
+    }
+
+    public void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
+        onLineNumber(call, "visitStaticMethodCallExpression: \"" + call.getMethod() + "\":");
+
+        makeCall(
+                new ClassExpression(call.getOwnerType()),
+                new ConstantExpression(call.getMethod()),
+                call.getArguments(),
+                invokeStaticMethod,
+                false,false,false);
+    }
+    
+    private void visitSpecialConstructorCall(ConstructorCallExpression call) {
+        ClassNode callNode = classNode;
+        if (call.isSuperCall()) callNode = callNode.getSuperClass();
+        List constructors = sortConstructors(call, callNode);
+        call.getArguments().visit(this);
+        // keep Objet[] on stack
+        cv.visitInsn(DUP);
+        // to select the constructor we need also the number of
+        // available constructors and the class we want to make
+        // the call on
+        helper.pushConstant(constructors.size());
+        visitClassExpression(new ClassExpression(callNode));
+        // removes one Object[] leaves the int containing the 
+        // call flags and the construtcor number
+        selectConstructorAndTransformArguments.call(cv);
+        // Object[],int -> int,Object[],int
+        // we need to examine the flags and maybe change the 
+        // Object[] later, so this reordering will do the job
+        cv.visitInsn(DUP_X1);
+        // test if rewrap flag is set
+        cv.visitInsn(ICONST_1);
+        cv.visitInsn(IAND);
+        Label afterIf = new Label();
+        cv.visitJumpInsn(IFEQ, afterIf);
+        // true part, so rewrap using the first argument
+        cv.visitInsn(ICONST_0);
+        cv.visitInsn(AALOAD);
+        cv.visitTypeInsn(CHECKCAST, "[Ljava/lang/Object;");
+        cv.visitLabel(afterIf);
+        // here the stack is int,Object[], but we need the
+        // the int for our table, so swap it
+        cv.visitInsn(SWAP);
+        //load "this"
+        cv.visitVarInsn(ALOAD, 0);
+        cv.visitInsn(SWAP);
+        //prepare switch with >>8        
+        cv.visitIntInsn(BIPUSH,8);
+        cv.visitInsn(ISHR);
+        Label[] targets = new Label[constructors.size()];
+        int[] indices = new int[constructors.size()];
+        for (int i=0; i<targets.length; i++) {
+            targets[i] = new Label();
+            indices[i] = i;
+        }
+        // create switch targets
+        Label defaultLabel = new Label();
+        Label afterSwitch = new Label();
+        cv.visitLookupSwitchInsn(defaultLabel, indices, targets);
+        for (int i=0; i<targets.length; i++) {
+            cv.visitLabel(targets[i]);
+            // to keep the stack height, we need to leave
+            // one Object[] on the stack as last element. At the 
+            // same time, we need the Object[] on top of the stack
+            // to extract the parameters. So a SWAP will exchange 
+            // "this" and Object[], a DUP_X1 will then copy the Object[]
+            /// to the last place in the stack: 
+            //     Object[],this -SWAP-> this,Object[]
+            //     this,Object[] -DUP_X1-> Object[],this,Object[] 
+            cv.visitInsn(SWAP);
+            cv.visitInsn(DUP_X1);
+            
+            ConstructorNode cn = (ConstructorNode) constructors.get(i);
+            String descriptor = helper.getMethodDescriptor(ClassHelper.VOID_TYPE, cn.getParameters());
+            // unwrap the Object[] and make transformations if needed
+            // that means, to duplicate the Object[], make a cast with possible
+            // unboxing and then swap it with the Object[] for each parameter
+            Parameter[] parameters = cn.getParameters();
+            for (int p=0; p<parameters.length; p++) {
+                cv.visitInsn(DUP);
+                helper.pushConstant(p);
+                cv.visitInsn(AALOAD);
+                ClassNode type = parameters[p].getType();
+                if (ClassHelper.isPrimitiveType(type)) {
+                    helper.unbox(type);
+                } else {
+                    helper.doCast(type);
+                }
+                helper.swapWithObject(type);
+            }
+            // at the end we remove the Object[]
+            cv.visitInsn(POP);
+            // make the constructor call
+            cv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(callNode), "<init>", descriptor);
+            cv.visitJumpInsn(GOTO, afterSwitch);
+        }
+        cv.visitLabel(defaultLabel);
+        // this part should never be reached!
+        cv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
+        cv.visitInsn(DUP);
+        cv.visitLdcInsn("illegal constructor number");
+        cv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "(Ljava/lang/String;)V");
+        cv.visitInsn(ATHROW);
+        cv.visitLabel(afterSwitch);
+    }
+
+    private List sortConstructors(ConstructorCallExpression call, ClassNode callNode) {
+        // sort in a new list to prevent side effects
+        List constructors = new ArrayList(callNode.getDeclaredConstructors());
+        Comparator comp = new Comparator() {
+            public int compare(Object arg0, Object arg1) {
+                ConstructorNode c0 = (ConstructorNode) arg0;
+                ConstructorNode c1 = (ConstructorNode) arg1;
+                String descriptor0 = helper.getMethodDescriptor(ClassHelper.VOID_TYPE, c0.getParameters()); 
+                String descriptor1 = helper.getMethodDescriptor(ClassHelper.VOID_TYPE, c1.getParameters());
+                return descriptor0.compareTo(descriptor1);
+            }            
+        };
+        Collections.sort(constructors,comp);
+        return constructors;
+    }
+
+    public void visitConstructorCallExpression(ConstructorCallExpression call) {
+        onLineNumber(call, "visitConstructorCallExpression: \"" + call.getType().getName() + "\":");
+
+        if (call.isSpecialCall()){
+            visitSpecialConstructorCall(call);
+            return;
+        }
+        
+        Expression arguments = call.getArguments();
+        if (arguments instanceof TupleExpression) {
+            TupleExpression tupleExpression = (TupleExpression) arguments;
+            int size = tupleExpression.getExpressions().size();
+            if (size == 0) {
+                arguments = MethodCallExpression.NO_ARGUMENTS;
+            }
+        }
+        
+        Expression receiverClass = new ClassExpression(call.getType());
+        makeCall(
+                receiverClass, null,
+                arguments,
+                invokeNew, false, false, false
+        );
+    }
+    
+    private static String makeFieldClassName(ClassNode type) {
+        String internalName = BytecodeHelper.getClassInternalName(type);
+        StringBuffer ret = new StringBuffer(internalName.length());
+        for (int i=0; i<internalName.length(); i++) {
+            char c = internalName.charAt(i);
+            if (c=='/') {
+                ret.append('$');
+            } else if (c==';') {
+                //append nothing -> delete ';'
+            } else {
+                ret.append(c);
+            }
+        }
+        return ret.toString();
+    }
+    
+    private static String getStaticFieldName(ClassNode type) {
+        ClassNode componentType = type;
+        String prefix = "";
+        for (; componentType.isArray(); componentType=componentType.getComponentType()){
+            prefix+="$";
+        }
+        if (prefix.length()!=0) prefix = "array"+prefix;
+        String name = prefix+"class$" + makeFieldClassName(componentType);
+        return name;
+    }
+    
+    private void visitAttributeOrProperty(PropertyExpression expression, MethodCallerMultiAdapter adapter) {
+        Expression objectExpression = expression.getObjectExpression();
+        if (isThisExpression(objectExpression)) {
+            // lets use the field expression if its available
+            String name = expression.getPropertyAsString();
+            if (name!=null) {
+                FieldNode field = classNode.getField(name);
+                if (field != null) {
+                    visitFieldExpression(new FieldExpression(field));
+                    return;
+                }
+            }
+        }  
+
+        // arguments already on stack if any
+        makeCall( 
+                objectExpression, // receiver
+                new CastExpression(ClassHelper.STRING_TYPE, expression.getProperty()), // messageName
+                MethodCallExpression.NO_ARGUMENTS,
+                adapter,
+                expression.isSafe(), expression.isSpreadSafe(), expression.isImplicitThis()
+        );
+    }
+    
+    private boolean isStaticContext(){
+        if (!isInClosure()) return false;
+        if (constructorNode != null) return false;
+        return classNode.isStaticClass() || methodNode.isStatic();
+    }
+
+    public void visitPropertyExpression(PropertyExpression expression) {
+        Expression objectExpression = expression.getObjectExpression();
+        MethodCallerMultiAdapter adapter;
+        if (leftHandExpression) {
+            adapter = setProperty;
+            if (isGroovyObject(objectExpression)) adapter = setGroovyObjectProperty;
+            if (isStaticContext() && isThisOrSuper(objectExpression)) adapter = setProperty;
+        } else {
+            adapter = getProperty;
+            if (isGroovyObject(objectExpression)) adapter = getGroovyObjectProperty;
+            if (isStaticContext() && isThisOrSuper(objectExpression)) adapter = getProperty;
+        }
+        visitAttributeOrProperty(expression,adapter);
+    }        
+    
+    public void visitAttributeExpression(AttributeExpression expression) {
+        Expression objectExpression = expression.getObjectExpression();
+        MethodCallerMultiAdapter adapter;
+        if (leftHandExpression) {
+            adapter = setField;
+            if (isGroovyObject(objectExpression)) adapter = setGroovyObjectField;
+            if (usesSuper(expression)) adapter = getFieldOnSuper;
+        } else {
+            adapter = getField;
+            if (isGroovyObject(objectExpression)) adapter = getGroovyObjectField;
+            if (usesSuper(expression)) adapter = getFieldOnSuper;
+        }
+        visitAttributeOrProperty(expression,adapter);
+    }
+
+    protected boolean isGroovyObject(Expression objectExpression) {
+        return isThisExpression(objectExpression);
+    }
+
+    public void visitFieldExpression(FieldExpression expression) {
+        FieldNode field = expression.getField();
+
+	    if (field.isStatic()) {
+        	if (leftHandExpression) {
+        		storeStaticField(expression);
+        	}else {
+        		loadStaticField(expression);
+        	}
+        } else {
+        	if (leftHandExpression) {
+        		storeThisInstanceField(expression);
+        	} else {
+        		loadInstanceField(expression);
+        	}
+		}
+    }
+
+    /**
+     *
+     * @param fldExp
+     */
+    public void loadStaticField(FieldExpression fldExp) {
+        FieldNode field = fldExp.getField();
+        boolean holder = field.isHolder() && !isInClosureConstructor();
+        ClassNode type = field.getType();
+
+        String ownerName = (field.getOwner().equals(classNode))
+                ? internalClassName
+                : BytecodeHelper.getClassInternalName(field.getOwner());
+        if (holder) {
+            cv.visitFieldInsn(GETSTATIC, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
+            cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
+        }
+        else {
+            cv.visitFieldInsn(GETSTATIC, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
+            if (ClassHelper.isPrimitiveType(type)) {
+                helper.box(type);
+			} else {
+			}
+        }
+    }
+
+	/**
+	 * RHS instance field. should move most of the code in the BytecodeHelper
+	 * @param fldExp
+	 */
+    public void loadInstanceField(FieldExpression fldExp) {
+    	FieldNode field = fldExp.getField();
+        boolean holder = field.isHolder() && !isInClosureConstructor();
+        ClassNode type = field.getType();
+        String ownerName = (field.getOwner().equals(classNode))
+				? internalClassName
+				: helper.getClassInternalName(field.getOwner());
+
+        cv.visitVarInsn(ALOAD, 0);
+		cv.visitFieldInsn(GETFIELD, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
+
+		if (holder) {
+			cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
+		} else {
+			if (ClassHelper.isPrimitiveType(type)) {
+				helper.box(type);
+			} else {
+			}
+		}
+    }
+
+    public void storeThisInstanceField(FieldExpression expression) {
+        FieldNode field = expression.getField();
+
+        boolean holder = field.isHolder() && !isInClosureConstructor();
+        ClassNode type = field.getType();
+
+        String ownerName =  (field.getOwner().equals(classNode)) ?
+        		internalClassName : BytecodeHelper.getClassInternalName(field.getOwner());
+        if (holder) {
+            cv.visitVarInsn(ALOAD, 0);
+            cv.visitFieldInsn(GETFIELD, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
+            cv.visitInsn(SWAP);
+            cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
+        }
+        else {
+            if (isInClosureConstructor()) {
+                helper.doCast(type);
+            } else if (!ClassHelper.isPrimitiveType(type)){
+                doConvertAndCast(type);
+            }
+            cv.visitVarInsn(ALOAD, 0);
+            //helper.swapObjectWith(type);
+            cv.visitInsn(SWAP);
+            helper.unbox(type);
+            helper.putField(field, ownerName);
+        }
+    }
+
+
+    public void storeStaticField(FieldExpression expression) {
+    	FieldNode field = expression.getField();
+
+        boolean holder = field.isHolder() && !isInClosureConstructor();
+
+        ClassNode type = field.getType();
+
+        String ownerName = (field.getOwner().equals(classNode))
+                ? internalClassName
+                : helper.getClassInternalName(field.getOwner());
+        if (holder) {
+            cv.visitFieldInsn(GETSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
+            cv.visitInsn(SWAP);
+            cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
+        } else {
+            helper.doCast(type);
+            cv.visitFieldInsn(PUTSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(type));
+        }
+    }
+
+    protected void visitOuterFieldExpression(FieldExpression expression, ClassNode outerClassNode, int steps, boolean first ) {
+        FieldNode field = expression.getField();
+        boolean isStatic = field.isStatic();
+
+        int tempIdx = compileStack.defineTemporaryVariable(field, leftHandExpression && first);
+
+        if (steps > 1 || !isStatic) {
+            cv.visitVarInsn(ALOAD, 0);
+            cv.visitFieldInsn(
+                GETFIELD,
+                internalClassName,
+                "owner",
+                BytecodeHelper.getTypeDescription(outerClassNode));
+        }
+
+        if( steps == 1 ) {
+            int opcode = (leftHandExpression) ? ((isStatic) ? PUTSTATIC : PUTFIELD) : ((isStatic) ? GETSTATIC : GETFIELD);
+            String ownerName = BytecodeHelper.getClassInternalName(outerClassNode);
+
+            if (leftHandExpression) {
+                cv.visitVarInsn(ALOAD, tempIdx);
+                boolean holder = field.isHolder() && !isInClosureConstructor();
+                if ( !holder) {
+                    doConvertAndCast(field.getType());
+                }
+            }
+            cv.visitFieldInsn(opcode, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(field.getType()));
+            if (!leftHandExpression) {
+                if (ClassHelper.isPrimitiveType(field.getType())) {
+                    helper.box(field.getType());
+                }
+            }
+        }
+
+        else {
+            visitOuterFieldExpression( expression, outerClassNode.getOuterClass(), steps - 1, false );
+        }
+    }
+
+
+
+    /**
+     *  Visits a bare (unqualified) variable expression.
+     */
+
+    public void visitVariableExpression(VariableExpression expression) {
+
+        String variableName = expression.getName();
+
+      //-----------------------------------------------------------------------
+      // SPECIAL CASES
+
+        //
+        // "this" for static methods is the Class instance
+
+        ClassNode classNode = this.classNode;
+        if (isInClosure()) classNode = getOutermostClass();
+        
+        if (variableName.equals("this")) {
+            if (isStaticMethod() || (!implicitThis && isStaticContext())) {
+                visitClassExpression(new ClassExpression(classNode));
+            } else {
+                loadThis();
+            }
+            return;
+        }
+
+        //
+        // "super" also requires special handling
+
+        if (variableName.equals("super")) {
+            if (isStaticMethod()) {
+                visitClassExpression(new ClassExpression(classNode.getSuperClass()));
+            } else {
+                loadThis();
+            }
+            return;                                               // <<< FLOW CONTROL <<<<<<<<<
+        }
+
+        Variable variable = compileStack.getVariable(variableName, false);
+
+        VariableScope scope = compileStack.getScope();
+        if (variable==null) {
+            processClassVariable(variableName);
+        } else {
+            processStackVariable(variable);
+        }
+    }
+
+    private void loadThis() {
+        cv.visitVarInsn(ALOAD, 0);
+        if (!implicitThis  && isInClosure()) {
+            cv.visitMethodInsn(
+                    INVOKEVIRTUAL,
+                    "groovy/lang/Closure",
+                    "getThisObject",
+                    "()Ljava/lang/Object;"
+            );
+        }
+    }
+
+    protected void processStackVariable(Variable variable) {
+        if( leftHandExpression ) {
+            helper.storeVar(variable);
+        } else {
+        	helper.loadVar(variable);
+        }
+        if (ASM_DEBUG) {
+            helper.mark("var: " + variable.getName());
+        }
+    }
+
+    protected void processClassVariable(String name) {
+        if (passingClosureParams && isInScriptBody() ) {
+            // lets create a ScriptReference to pass into the closure
+            cv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/ScriptReference");
+            cv.visitInsn(DUP);
+
+            loadThisOrOwner();
+            cv.visitLdcInsn(name);
+
+            cv.visitMethodInsn(
+                INVOKESPECIAL,
+                "org/codehaus/groovy/runtime/ScriptReference",
+                "<init>",
+                "(Lgroovy/lang/Script;Ljava/lang/String;)V");
+        }
+        else {
+            PropertyExpression pexp = new PropertyExpression(VariableExpression.THIS_EXPRESSION, name);
+            pexp.setImplicitThis(true);
+            visitPropertyExpression(pexp);
+        }
+    }
+
+
+    protected void processFieldAccess( String name, FieldNode field, int steps ) {
+        FieldExpression expression = new FieldExpression(field);
+
+        if( steps == 0 ) {
+            visitFieldExpression( expression );
+        }
+        else {
+            visitOuterFieldExpression( expression, classNode.getOuterClass(), steps, true );
+        }
+    }
+
+
+
+    /**
+     * @return true if we are in a script body, where all variables declared are no longer
+     * local variables but are properties
+     */
+    protected boolean isInScriptBody() {
+        if (classNode.isScriptBody()) {
+            return true;
+        }
+        else {
+            return classNode.isScript() && methodNode != null && methodNode.getName().equals("run");
+        }
+    }
+
+    /**
+     * @return true if this expression will have left a value on the stack
+     * that must be popped
+     */
+    protected boolean isPopRequired(Expression expression) {
+        if (expression instanceof MethodCallExpression) {
+            if (expression.getType()==ClassHelper.VOID_TYPE) { // nothing on the stack
+                return false;
+            } else {
+                return !usesSuper((MethodCallExpression) expression);
+            }
+        }
+        if (expression instanceof DeclarationExpression) {
+            return false;
+        }
+        if (expression instanceof BinaryExpression) {
+            BinaryExpression binExp = (BinaryExpression) expression;
+            switch (binExp.getOperation().getType()) {   // br todo should leave a copy of the value on the stack for all the assignemnt.
+//                case Types.EQUAL :   // br a copy of the right value is left on the stack (see evaluateEqual()) so a pop is required for a standalone assignment
+//                case Types.PLUS_EQUAL : // this and the following are related to evaluateBinaryExpressionWithAsignment()
+//                case Types.MINUS_EQUAL :
+//                case Types.MULTIPLY_EQUAL :
+//                case Types.DIVIDE_EQUAL :
+//                case Types.INTDIV_EQUAL :
+//                case Types.MOD_EQUAL :
+//                    return false;
+            }
+        }
+        if (expression instanceof ConstructorCallExpression) {
+            ConstructorCallExpression cce = (ConstructorCallExpression) expression;
+            return !cce.isSpecialCall();
+        }
+        return true;
+    }
+    
+    protected void createInterfaceSyntheticStaticFields() {
+        if (syntheticStaticFields.isEmpty()) return;
+
+        addInnerClass(interfaceClassLoadingClass);
+        
+        for (Iterator iter = syntheticStaticFields.iterator(); iter.hasNext();) {
+            String staticFieldName = (String) iter.next();
+            // generate a field node
+            interfaceClassLoadingClass.addField(staticFieldName,ACC_STATIC + ACC_SYNTHETIC,ClassHelper.CLASS_Type,null);
+        }
+    }
+    
+    protected void createSyntheticStaticFields() {
+        for (Iterator iter = syntheticStaticFields.iterator(); iter.hasNext();) {
+            String staticFieldName = (String) iter.next();
+            // generate a field node
+            FieldNode fn = classNode.getField(staticFieldName);
+            if (fn!=null) {
+                boolean type = fn.getType()==ClassHelper.CLASS_Type;
+                boolean modifiers = fn.getModifiers() == ACC_STATIC + ACC_SYNTHETIC;
+                if (type && modifiers) continue;
+                String text = "";
+                if (!type) text = " with wrong type: "+fn.getType()+" (java.lang.Class needed)";
+                if (!modifiers) text = " with wrong modifiers: "+fn.getModifiers()+" ("+(ACC_STATIC + ACC_SYNTHETIC)+" needed)";
+                throwException(
+                        "tried to set a static syntethic field "+staticFieldName+" in "+classNode.getName()+
+                        " for class resolving, but found alreeady a node of that"+
+                        " name "+text);
+            } else {
+                cw.visitField(ACC_STATIC + ACC_SYNTHETIC, staticFieldName, "Ljava/lang/Class;", null, null);
+            }
+        }
+
+        cv =
+            cw.visitMethod(
+                    ACC_STATIC + ACC_SYNTHETIC,
+                    "class$",
+                    "(Ljava/lang/String;)Ljava/lang/Class;",
+                    null,
+                    null);
+        Label l0 = new Label();
+        cv.visitLabel(l0);
+        cv.visitVarInsn(ALOAD, 0);
+        cv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
+        Label l1 = new Label();
+        cv.visitLabel(l1);
+        cv.visitInsn(ARETURN);
+        Label l2 = new Label();
+        cv.visitLabel(l2);
+        cv.visitVarInsn(ASTORE, 1);
+        cv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
+        cv.visitInsn(DUP);
+        cv.visitVarInsn(ALOAD, 1);
+        cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassNotFoundException", "getMessage", "()Ljava/lang/String;");
+        cv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoClassDefFoundError", "<init>", "(Ljava/lang/String;)V");
+        cv.visitInsn(ATHROW);
+        cv.visitTryCatchBlock(l0, l2, l2, "java/lang/ClassNotFoundException"); // br using l2 as the 2nd param seems create the right table entry
+        cv.visitMaxs(3, 2);
+    }
+
+    /** load class object on stack */
+    public void visitClassExpression(ClassExpression expression) {
+        ClassNode type = expression.getType();
+
+        if (ClassHelper.isPrimitiveType(type)) {
+            ClassNode objectType = ClassHelper.getWrapper(type);
+            cv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(objectType), "TYPE", "Ljava/lang/Class;");          
+        } else {
+            String staticFieldName;
+            if (type.equals(classNode)) {
+                staticFieldName = "class$0";
+                if (compileStack.getCurrentClassIndex()!=-1) {
+                    cv.visitVarInsn(ALOAD,compileStack.getCurrentClassIndex());
+                    return;
+                } 
+            } else if (type.equals(ClassHelper.METACLASS_TYPE)) {
+                staticFieldName = getStaticFieldName(type);
+                if (compileStack.getCurrentMetaClassIndex()!=-1) {
+                    cv.visitVarInsn(ALOAD,compileStack.getCurrentMetaClassIndex());
+                    return;
+                }
+            } else {
+                staticFieldName = getStaticFieldName(type);
+            }
+            
+            syntheticStaticFields.add(staticFieldName);
+
+            String internalClassName = this.internalClassName;
+            if (classNode.isInterface()) {
+                internalClassName = BytecodeHelper.getClassInternalName(interfaceClassLoadingClass);
+            }
+            
+            cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
+            
+            Label l0 = new Label();
+            cv.visitJumpInsn(IFNONNULL, l0);
+            cv.visitLdcInsn(BytecodeHelper.getClassLoadingTypeDescription(type));
+            cv.visitMethodInsn(INVOKESTATIC, internalClassName, "class$", "(Ljava/lang/String;)Ljava/lang/Class;");
+            cv.visitInsn(DUP);
+            cv.visitFieldInsn(PUTSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
+            Label l1 = new Label();
+            cv.visitJumpInsn(GOTO, l1);
+            cv.visitLabel(l0);
+            cv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
+            cv.visitLabel(l1);
+            
+            if (type.equals(classNode)) {
+                cv.visitInsn(DUP);
+                int index = compileStack.defineTemporaryVariable("class$0",ClassHelper.CLASS_Type,true);
+                compileStack.setCurrentClassIndex(index);
+            } else if (type.equals(ClassHelper.METACLASS_TYPE)) {
+                cv.visitInsn(DUP);
+                int index = compileStack.defineTemporaryVariable("meta$class$0",ClassHelper.CLASS_Type,true);
+                compileStack.setCurrentMetaClassIndex(index);
+            }
+        }
+    }
+
+    public void visitRangeExpression(RangeExpression expression) {
+        expression.getFrom().visit(this);
+        expression.getTo().visit(this);
+
+        helper.pushConstant(expression.isInclusive());
+
+        createRangeMethod.call(cv);
+    }
+
+    public void visitMapEntryExpression(MapEntryExpression expression) {
+        throw new GroovyBugError("MapEntryExpression should not be visited here");
+    }
+
+    public void visitMapExpression(MapExpression expression) {
+        List entries = expression.getMapEntryExpressions();
+        int size = entries.size();
+        helper.pushConstant(size * 2);
+
+        cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
+
+        int i = 0;
+        for (Iterator iter = entries.iterator(); iter.hasNext();) {
+            Object object = iter.next();
+            MapEntryExpression entry = (MapEntryExpression) object;
+
+            cv.visitInsn(DUP);
+            helper.pushConstant(i++);
+            visitAndAutoboxBoolean(entry.getKeyExpression());
+            cv.visitInsn(AASTORE);
+
+            cv.visitInsn(DUP);
+            helper.pushConstant(i++);
+            visitAndAutoboxBoolean(entry.getValueExpression());
+            cv.visitInsn(AASTORE);
+        }
+        createMapMethod.call(cv);
+    }
+    
+    public void visitArgumentlistExpression(ArgumentListExpression ale) {
+        if (containsSpreadExpression(ale)) {
+            despreadList(ale.getExpressions(),true);
+        } else {
+            visitTupleExpression(ale,true);
+        }
+    }
+    
+    public void visitTupleExpression(TupleExpression expression) {
+        visitTupleExpression(expression,false);
+    }
+
+    private void visitTupleExpression(TupleExpression expression,boolean useWrapper) {
+        int size = expression.getExpressions().size();
+
+        helper.pushConstant(size);
+
+        cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
+
+        for (int i = 0; i < size; i++) {
+            cv.visitInsn(DUP);
+            helper.pushConstant(i);
+            Expression argument = expression.getExpression(i);
+            visitAndAutoboxBoolean(argument);
+            if (useWrapper && argument instanceof CastExpression) loadWrapper(argument);
+            
+            cv.visitInsn(AASTORE);
+        }
+    }
+    
+    private void loadWrapper(Expression argument) {
+        ClassNode goalClass = argument.getType();
+        visitClassExpression(new ClassExpression(goalClass));
+        if (goalClass.isDerivedFromGroovyObject()) {
+            createGroovyObjectWrapperMethod.call(cv);
+        } else {
+            createPojoWrapperMethod.call(cv);
+        }
+    }
+
+    public void visitArrayExpression(ArrayExpression expression) {
+        ClassNode elementType = expression.getElementType();
+        String arrayTypeName = BytecodeHelper.getClassInternalName(elementType);        
+        List sizeExpression = expression.getSizeExpression();
+
+        int size=0;
+        int dimensions=0;
+        if (sizeExpression!=null) {
+        	for (Iterator iter = sizeExpression.iterator(); iter.hasNext();) {
+				Expression element = (Expression) iter.next();
+				if (element==ConstantExpression.EMTPY_EXPRESSION) break;
+				dimensions++;
+	            // lets convert to an int
+	            visitAndAutoboxBoolean(element);
+                helper.unbox(int.class);
+			}
+        } else {
+            size = expression.getExpressions().size();
+            helper.pushConstant(size);
+        }
+
+        int storeIns=AASTORE;
+        if (sizeExpression!=null) {
+            arrayTypeName = BytecodeHelper.getTypeDescription(expression.getType());
+        	cv.visitMultiANewArrayInsn(arrayTypeName, dimensions);
+        } else if (ClassHelper.isPrimitiveType(elementType)) {
+            int primType=0;
+            if (elementType==ClassHelper.boolean_TYPE) {
+                primType = T_BOOLEAN;
+                storeIns = BASTORE;
+            } else if (elementType==ClassHelper.char_TYPE) {
+                primType = T_CHAR;
+                storeIns = CASTORE;
+            } else if (elementType==ClassHelper.float_TYPE) {
+                primType = T_FLOAT;
+                storeIns = FASTORE;
+            } else if (elementType==ClassHelper.double_TYPE) {
+                primType = T_DOUBLE;
+                storeIns = DASTORE;
+            } else if (elementType==ClassHelper.byte_TYPE) {
+                primType = T_BYTE;
+                storeIns = BASTORE;
+            } else if (elementType==ClassHelper.short_TYPE) {
+                primType = T_SHORT;
+                storeIns = SASTORE;
+            } else if (elementType==ClassHelper.int_TYPE) {
+                primType = T_INT;
+                storeIns=IASTORE;
+            } else if (elementType==ClassHelper.long_TYPE) {
+                primType = T_LONG;
+                storeIns = LASTORE;
+            } 
+            cv.visitIntInsn(NEWARRAY, primType);
+        } else {
+            cv.visitTypeInsn(ANEWARRAY, arrayTypeName);
+        } 
+
+        for (int i = 0; i < size; i++) {
+            cv.visitInsn(DUP);
+            helper.pushConstant(i);
+            Expression elementExpression = expression.getExpression(i);
+            if (elementExpression == null) {
+                ConstantExpression.NULL.visit(this);
+            } else {
+                if (!elementType.equals(elementExpression.getType())) {
+                    visitCastExpression(new CastExpression(elementType, elementExpression, true));
+                } else {
+                    visitAndAutoboxBoolean(elementExpression);
+                }
+            }
+            cv.visitInsn(storeIns);            
+        }
+        
+        if (sizeExpression==null && ClassHelper.isPrimitiveType(elementType)) {
+            int par = compileStack.defineTemporaryVariable("par",true);
+            cv.visitVarInsn(ALOAD, par);
+        }
+    }
+
+    public void visitListExpression(ListExpression expression) {
+        int size = expression.getExpressions().size();
+        boolean containsSpreadExpression = containsSpreadExpression(expression);
+        if (!containsSpreadExpression) {
+            helper.pushConstant(size);
+    
+            cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
+    
+            for (int i = 0; i < size; i++) {
+                cv.visitInsn(DUP);
+                helper.pushConstant(i);
+                visitAndAutoboxBoolean(expression.getExpression(i));
+                cv.visitInsn(AASTORE);
+            }
+        } else {
+            despreadList(expression.getExpressions(),false);
+        }
+        createListMethod.call(cv);
+    }
+
+    public void visitGStringExpression(GStringExpression expression) {
+        int size = expression.getValues().size();
+        helper.pushConstant(size);
+
+        cv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
+
+        for (int i = 0; i < size; i++) {
+            cv.visitInsn(DUP);
+            helper.pushConstant(i);
+            visitAndAutoboxBoolean(expression.getValue(i));
+            cv.visitInsn(AASTORE);
+        }
+
+        int paramIdx = compileStack.defineTemporaryVariable("iterator",true);
+
+        ClassNode innerClass = createGStringClass(expression);
+        addInnerClass(innerClass);
+        String innerClassinternalName = BytecodeHelper.getClassInternalName(innerClass);
+
+        cv.visitTypeInsn(NEW, innerClassinternalName);
+        cv.visitInsn(DUP);
+        cv.visitVarInsn(ALOAD, paramIdx);
+
+        cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", "([Ljava/lang/Object;)V");
+        compileStack.removeVar(paramIdx);
+    }
+    
+    public void visitAnnotations(AnnotatedNode node) {
+        Map annotionMap = node.getAnnotations();
+        if (annotionMap.isEmpty()) return;
+        Iterator it = annotionMap.values().iterator(); 
+        while (it.hasNext()) {
+            AnnotationNode an = (AnnotationNode) it.next();
+            //skip builtin properties
+            if (an.isBuiltIn()) continue;
+            ClassNode type = an.getClassNode();
+
+            String clazz = type.getName();
+            AnnotationVisitor av = cw.visitAnnotation(BytecodeHelper.formatNameForClassLoading(clazz),false);
+
+            Iterator mIt = an.getMembers().keySet().iterator();
+            while (mIt.hasNext()) {
+                String name = (String) mIt.next();
+                ConstantExpression exp = (ConstantExpression) an.getMember(name);
+                av.visit(name,exp.getValue());
+            }
+            av.visitEnd();
+        }
+    }
+    
+    
+    // Implementation methods
+    //-------------------------------------------------------------------------
+    protected boolean addInnerClass(ClassNode innerClass) {
+        innerClass.setModule(classNode.getModule());
+        return innerClasses.add(innerClass);
+    }
+
+    protected ClassNode createClosureClass(ClosureExpression expression) {
+        ClassNode outerClass = getOutermostClass();
+        String name = outerClass.getName() + "$"
+                + context.getNextClosureInnerName(outerClass, classNode, methodNode); // br added a more infomative name
+        boolean staticMethodOrInStaticClass = isStaticMethod() || classNode.isStaticClass();
+
+        Parameter[] parameters = expression.getParameters();
+        if (parameters==null){
+            parameters = new Parameter[0];
+        } else if (parameters.length == 0) {
+            // lets create a default 'it' parameter
+            parameters = new Parameter[] { new Parameter(ClassHelper.OBJECT_TYPE, "it", ConstantExpression.NULL)};
+        } 
+
+        Parameter[] localVariableParams = getClosureSharedVariables(expression);
+
+        InnerClassNode answer = new InnerClassNode(outerClass, name, 0, ClassHelper.CLOSURE_TYPE); // closures are local inners and not public
+        answer.setEnclosingMethod(this.methodNode);
+        answer.setSynthetic(true);
+        
+        if (staticMethodOrInStaticClass) {
+            answer.setStaticClass(true);
+        }
+        if (isInScriptBody()) {
+            answer.setScriptBody(true);
+        }
+        MethodNode method =
+            answer.addMethod("doCall", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, expression.getCode());
+        method.setSourcePosition(expression);
+
+        VariableScope varScope = expression.getVariableScope();
+        if (varScope == null) {
+            throw new RuntimeException(
+                "Must have a VariableScope by now! for expression: " + expression + " class: " + name);
+        } else {
+            method.setVariableScope(varScope.copy());
+        }
+        if (parameters.length > 1
+            || (parameters.length == 1
+                && parameters[0].getType() != null
+                && parameters[0].getType() != ClassHelper.OBJECT_TYPE)) {
+
+            // lets add a typesafe call method
+            MethodNode call = answer.addMethod(
+                "call",
+                ACC_PUBLIC,
+                ClassHelper.OBJECT_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                new ReturnStatement(
+                    new MethodCallExpression(
+                        VariableExpression.THIS_EXPRESSION,
+                        "doCall",
+                        new ArgumentListExpression(parameters))));
+            call.setSourcePosition(expression);
+        }
+
+        // lets make the constructor
+        BlockStatement block = new BlockStatement();
+        block.setSourcePosition(expression);
+        VariableExpression outer = new VariableExpression("_outerInstance");
+        outer.setSourcePosition(expression);
+        block.getVariableScope().getReferencedLocalVariables().put("_outerInstance",outer);
+        VariableExpression thisObject = new VariableExpression("_thisObject");
+        thisObject.setSourcePosition(expression);
+        block.getVariableScope().getReferencedLocalVariables().put("_thisObject",thisObject);
+        TupleExpression conArgs = new TupleExpression();
+        conArgs.addExpression(outer);
+        conArgs.addExpression(thisObject);
+        block.addStatement(
+            new ExpressionStatement(
+                new ConstructorCallExpression(
+                    ClassNode.SUPER,
+                    conArgs)));
+
+        // lets assign all the parameter fields from the outer context
+        for (int i = 0; i < localVariableParams.length; i++) {
+            Parameter param = localVariableParams[i];
+            String paramName = param.getName();
+            Expression initialValue = null;
+            ClassNode type = param.getType();
+            FieldNode paramField = null;
+            if (true) {
+            	initialValue = new VariableExpression(paramName);
+                ClassNode realType = type;
+                type = ClassHelper.makeReference();
+                param.setType(type);
+                paramField = answer.addField(paramName, ACC_PRIVATE, type, initialValue);
+                paramField.setHolder(true);
+                String methodName = Verifier.capitalize(paramName);
+
+                // lets add a getter & setter
+                Expression fieldExp = new FieldExpression(paramField);
+                answer.addMethod(
+                    "get" + methodName,
+                    ACC_PUBLIC,
+                    realType,
+                    Parameter.EMPTY_ARRAY,
+                    ClassNode.EMPTY_ARRAY,
+                    new ReturnStatement(fieldExp));
+
+                /*
+                answer.addMethod(
+                    "set" + methodName,
+                    ACC_PUBLIC,
+                    "void",
+                    new Parameter[] { new Parameter(realType, "__value") },
+                    new ExpressionStatement(
+                        new BinaryExpression(expression, Token.newSymbol(Types.EQUAL, 0, 0), new VariableExpression("__value"))));
+                        */
+            }
+        }
+
+        Parameter[] params = new Parameter[2 + localVariableParams.length];
+        params[0] = new Parameter(ClassHelper.OBJECT_TYPE, "_outerInstance");
+        params[1] = new Parameter(ClassHelper.OBJECT_TYPE, "_thisObject");
+        System.arraycopy(localVariableParams, 0, params, 2, localVariableParams.length);
+
+        ASTNode sn = answer.addConstructor(ACC_PUBLIC, params, ClassNode.EMPTY_ARRAY, block);
+        sn.setSourcePosition(expression);
+        return answer;
+    }
+    
+    protected Parameter[] getClosureSharedVariables(ClosureExpression ce){
+        VariableScope scope =  ce.getVariableScope();
+        Map references = scope.getReferencedLocalVariables();
+        Parameter[] ret = new Parameter[references.size()];
+        int index = 0;
+        for (Iterator iter = references.values().iterator(); iter.hasNext();) {
+            org.codehaus.groovy.ast.Variable element = (org.codehaus.groovy.ast.Variable) iter.next();
+            if (element instanceof Parameter) {
+                ret[index] = (Parameter) element;
+            } else {
+                Parameter p = new Parameter(element.getType(),element.getName());
+                ret[index] = p;
+            }
+            index++;
+        }
+        return ret;
+    }
+
+    protected ClassNode getOutermostClass() {
+        if (outermostClass == null) {
+            outermostClass = classNode;
+            while (outermostClass instanceof InnerClassNode) {
+                outermostClass = outermostClass.getOuterClass();
+            }
+        }
+        return outermostClass;
+    }
+
+    protected ClassNode createGStringClass(GStringExpression expression) {
+        ClassNode owner = classNode;
+        if (owner instanceof InnerClassNode) {
+            owner = owner.getOuterClass();
+        }
+        String outerClassName = owner.getName();
+        String name = outerClassName + "$" + context.getNextInnerClassIdx();
+        InnerClassNode answer = new InnerClassNode(owner, name, 0, ClassHelper.GSTRING_TYPE);
+        answer.setEnclosingMethod(this.methodNode);
+        FieldNode stringsField =
+            answer.addField(
+                "strings",
+                ACC_PRIVATE /*| ACC_STATIC*/,
+                ClassHelper.STRING_TYPE.makeArray(),
+                new ArrayExpression(ClassHelper.STRING_TYPE, expression.getStrings()));
+        answer.addMethod(
+            "getStrings",
+            ACC_PUBLIC,
+            ClassHelper.STRING_TYPE.makeArray(),
+            Parameter.EMPTY_ARRAY,
+            ClassNode.EMPTY_ARRAY,
+            new ReturnStatement(new FieldExpression(stringsField)));
+        // lets make the constructor
+        BlockStatement block = new BlockStatement();
+        block.addStatement(
+            new ExpressionStatement(
+                new ConstructorCallExpression(ClassNode.SUPER, new VariableExpression("values"))));
+        Parameter[] contructorParams = new Parameter[] { new Parameter(ClassHelper.OBJECT_TYPE.makeArray(), "values")};
+        answer.addConstructor(ACC_PUBLIC, contructorParams, ClassNode.EMPTY_ARRAY, block);
+        return answer;
+    }
+
+    protected void doConvertAndCast(ClassNode type){
+        doConvertAndCast(type,false);
+    }
+    
+    protected void doConvertAndCast(ClassNode type, boolean coerce) {
+        if (type==ClassHelper.OBJECT_TYPE) return;
+        if (isValidTypeForCast(type)) {
+            visitClassExpression(new ClassExpression(type));
+            if (coerce) {
+                asTypeMethod.call(cv);
+            } else {
+                castToTypeMethod.call(cv);
+            }
+        } 
+        helper.doCast(type);
+    }
+
+    protected void evaluateLogicalOrExpression(BinaryExpression expression) {
+        visitBooleanExpression(new BooleanExpression(expression.getLeftExpression()));
+        Label l0 = new Label();
+        Label l2 = new Label();
+        cv.visitJumpInsn(IFEQ, l0);
+
+        cv.visitLabel(l2);
+
+        visitConstantExpression(ConstantExpression.TRUE);
+
+        Label l1 = new Label();
+        cv.visitJumpInsn(GOTO, l1);
+        cv.visitLabel(l0);
+
+        visitBooleanExpression(new BooleanExpression(expression.getRightExpression()));
+
+        cv.visitJumpInsn(IFNE, l2);
+
+        visitConstantExpression(ConstantExpression.FALSE);
+        cv.visitLabel(l1);
+    }
+
+    // todo: optimization: change to return primitive boolean. need to adjust the BinaryExpression and isComparisonExpression for
+    // consistancy.
+    protected void evaluateLogicalAndExpression(BinaryExpression expression) {
+        visitBooleanExpression(new BooleanExpression(expression.getLeftExpression()));
+        Label l0 = new Label();
+        cv.visitJumpInsn(IFEQ, l0);
+
+        visitBooleanExpression(new BooleanExpression(expression.getRightExpression()));
+
+        cv.visitJumpInsn(IFEQ, l0);
+
+        visitConstantExpression(ConstantExpression.TRUE);
+
+        Label l1 = new Label();
+        cv.visitJumpInsn(GOTO, l1);
+        cv.visitLabel(l0);
+
+        visitConstantExpression(ConstantExpression.FALSE);
+
+        cv.visitLabel(l1);
+    }
+    
+    protected void evaluateBinaryExpression(String method, BinaryExpression expression) {
+        makeCall(
+                expression.getLeftExpression(),
+                new ConstantExpression(method),
+                new ArgumentListExpression().addExpression(expression.getRightExpression()),
+                invokeMethod, false, false, false
+        );
+    }
+
+    protected void evaluateCompareTo(BinaryExpression expression) {
+        Expression leftExpression = expression.getLeftExpression();
+        leftExpression.visit(this);
+        if (isComparisonExpression(leftExpression)) {
+            helper.boxBoolean();
+        }
+
+        // if the right hand side is a boolean expression, we need to autobox
+        Expression rightExpression = expression.getRightExpression();
+        rightExpression.visit(this);
+        if (isComparisonExpression(rightExpression)) {
+            helper.boxBoolean();
+        }
+        compareToMethod.call(cv);
+    }
+
+    protected void evaluateBinaryExpressionWithAsignment(String method, BinaryExpression expression) {
+        Expression leftExpression = expression.getLeftExpression();
+        if (leftExpression instanceof BinaryExpression) {
+            BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
+            if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
+                // lets replace this assignment to a subscript operator with a
+                // method call
+                // e.g. x[5] += 10
+                // -> (x, [], 5), =, x[5] + 10
+                // -> methodCall(x, "putAt", [5, methodCall(x[5], "plus", 10)])
+
+                MethodCallExpression methodCall =
+                    new MethodCallExpression(
+                        expression.getLeftExpression(),
+                        method,
+                        new ArgumentListExpression(new Expression[] { expression.getRightExpression()}));
+
+                Expression safeIndexExpr = createReusableExpression(leftBinExpr.getRightExpression());
+
+                visitMethodCallExpression(
+                    new MethodCallExpression(
+                        leftBinExpr.getLeftExpression(),
+                        "putAt",
+                        new ArgumentListExpression(new Expression[] { safeIndexExpr, methodCall })));
+                //cv.visitInsn(POP);
+                return;
+            }
+        }
+
+        evaluateBinaryExpression(method, expression);
+
+        // br to leave a copy of rvalue on the stack. see also isPopRequired()
+        cv.visitInsn(DUP);
+
+        leftHandExpression = true;
+        evaluateExpression(leftExpression);
+        leftHandExpression = false;
+    }
+
+    private void evaluateBinaryExpression(MethodCaller compareMethod, BinaryExpression expression) {
+        Expression leftExp = expression.getLeftExpression();
+        Expression rightExp = expression.getRightExpression();
+        load(leftExp);
+        load(rightExp);
+        compareMethod.call(cv);
+    }
+
+    protected void evaluateEqual(BinaryExpression expression) {
+        Expression leftExpression = expression.getLeftExpression();
+        if (leftExpression instanceof BinaryExpression) {
+            BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
+            if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
+                // lets replace this assignment to a subscript operator with a
+                // method call
+                // e.g. x[5] = 10
+                // -> (x, [], 5), =, 10
+                // -> methodCall(x, "putAt", [5, 10])
+                
+                visitMethodCallExpression(
+                    new MethodCallExpression(
+                        leftBinExpr.getLeftExpression(),
+                        "putAt",
+                        new ArgumentListExpression(
+                            new Expression[] { leftBinExpr.getRightExpression(), expression.getRightExpression()})));
+                 // cv.visitInsn(POP); //this is realted to isPopRequired()
+                return;
+            }
+        }
+
+        // lets evaluate the RHS then hopefully the LHS will be a field
+        Expression rightExpression = expression.getRightExpression();
+        ClassNode type = getLHSType(leftExpression);
+        // lets not cast for primitive types as we handle these in field setting etc
+        if (ClassHelper.isPrimitiveType(type)) {
+            visitAndAutoboxBoolean(rightExpression);
+        } else if (type!=ClassHelper.OBJECT_TYPE){
+            visitCastExpression(new CastExpression(type, rightExpression));
+        } else {
+            visitAndAutoboxBoolean(rightExpression);
+        }
+
+        cv.visitInsn(DUP);  // to leave a copy of the rightexpression value on the stack after the assignment.
+        leftHandExpression = true;
+        leftExpression.visit(this);
+        leftHandExpression = false;
+    }
+    
+    /**
+     * Deduces the type name required for some casting
+     *
+     * @return the type of the given (LHS) expression or null if it is java.lang.Object or it cannot be deduced
+     */
+    protected ClassNode getLHSType(Expression leftExpression) {
+        if (leftExpression instanceof VariableExpression) {
+            VariableExpression varExp = (VariableExpression) leftExpression; 
+            ClassNode type = varExp.getType();
+            if (isValidTypeForCast(type)) {
+                return type;
+            }
+            String variableName = varExp.getName();
+            Variable variable = compileStack.getVariable(variableName,false);
+            if (variable != null) {
+                if (variable.isHolder()) {
+                    return type;
+                }
+                if (variable.isProperty()) return variable.getType();
+                type = variable.getType();
+                if (isValidTypeForCast(type)) {
+                    return type;
+                }
+            }
+            else {
+                FieldNode field = classNode.getField(variableName);
+                if (field == null) {
+                    field = classNode.getOuterField(variableName);
+                }
+                if (field != null) {
+                    type = field.getType();
+                    if (!field.isHolder() && isValidTypeForCast(type)) {
+                        return type;
+                    }
+                }
+            }
+        }
+        else if (leftExpression instanceof FieldExpression) {
+            FieldExpression fieldExp = (FieldExpression) leftExpression;
+            ClassNode type = fieldExp.getType();
+            if (isValidTypeForCast(type)) {
+                return type;
+            }
+        }
+        return ClassHelper.DYNAMIC_TYPE;
+    }
+
+    protected boolean isValidTypeForCast(ClassNode type) {
+        return type!=ClassHelper.DYNAMIC_TYPE && 
+               type!=ClassHelper.REFERENCE_TYPE;
+    }
+
+    protected void visitAndAutoboxBoolean(Expression expression) {
+        expression.visit(this);
+
+        if (isComparisonExpression(expression)) {
+            helper.boxBoolean(); // convert boolean to Boolean
+        }
+    }
+
+    protected void evaluatePrefixMethod(String method, Expression expression) {
+        // execute method
+        makeCall(
+                expression, 
+                new ConstantExpression(method),
+                MethodCallExpression.NO_ARGUMENTS,invokeMethod,
+                false,false,false);
+        
+        // store 
+        leftHandExpression = true;
+        expression.visit(this);
+        
+        // reload new value
+        leftHandExpression = false;
+        expression.visit(this);
+    }
+
+    protected void evaluatePostfixMethod(String method, Expression expression) {
+        // load 
+        expression.visit(this);
+
+        // save value for later
+        int tempIdx = compileStack.defineTemporaryVariable("postfix_" + method, true);
+        
+        //execute method
+        makeCall(
+                expression, new ConstantExpression(method),
+                MethodCallExpression.NO_ARGUMENTS,
+                invokeMethod,false,false, false);
+
+        // store
+        leftHandExpression = true;
+        expression.visit(this);
+        leftHandExpression = false;
+        
+        //reload saved value
+        cv.visitVarInsn(ALOAD, tempIdx);
+        compileStack.removeVar(tempIdx);
+    }
+
+    protected void evaluateInstanceof(BinaryExpression expression) {
+        visitAndAutoboxBoolean(expression.getLeftExpression());
+        Expression rightExp = expression.getRightExpression();
+        ClassNode classType = ClassHelper.DYNAMIC_TYPE;
+        if (rightExp instanceof ClassExpression) {
+            ClassExpression classExp = (ClassExpression) rightExp;
+            classType = classExp.getType();
+        }
+        else {
+            throw new RuntimeException(
+                "Right hand side of the instanceof keyword must be a class name, not: " + rightExp);
+        }
+        String classInternalName = BytecodeHelper.getClassInternalName(classType);
+        cv.visitTypeInsn(INSTANCEOF, classInternalName);
+    }
+
+    /**
+     * @return true if the given argument expression requires the stack, in
+     *         which case the arguments are evaluated first, stored in the
+     *         variable stack and then reloaded to make a method call
+     */
+    protected boolean argumentsUseStack(Expression arguments) {
+        return arguments instanceof TupleExpression || arguments instanceof ClosureExpression;
+    }
+
+    /**
+     * @return true if the given expression represents a non-static field
+     */
+    protected boolean isNonStaticField(Expression expression) {
+        FieldNode field = null;
+        if (expression instanceof VariableExpression) {
+            VariableExpression varExp = (VariableExpression) expression;
+            field = classNode.getField(varExp.getName());
+        }
+        else if (expression instanceof FieldExpression) {
+            FieldExpression fieldExp = (FieldExpression) expression;
+            field = classNode.getField(fieldExp.getFieldName());
+        }
+        else if (expression.getClass()==PropertyExpression.class) {
+            PropertyExpression fieldExp = (PropertyExpression) expression;
+            String possibleField = fieldExp.getPropertyAsString();
+            if (possibleField!=null) field = classNode.getField(possibleField);
+        }
+        if (field != null) {
+            return !field.isStatic();
+        }
+        return false;
+    }
+
+    private static boolean isThisExpression(Expression expression) {
+        if (expression instanceof VariableExpression) {
+            VariableExpression varExp = (VariableExpression) expression;
+            return varExp.getName().equals("this");
+        }
+        return false;
+    }
+    
+    private static boolean isSuperExpression(Expression expression) {
+        if (expression instanceof VariableExpression) {
+            VariableExpression varExp = (VariableExpression) expression;
+            return varExp.getName().equals("super");
+        }
+        return false;
+    }
+    
+    private static boolean isThisOrSuper(Expression expression) {
+        return isThisExpression(expression) || isSuperExpression(expression);
+    }
+    
+
+    /**
+     * For assignment expressions, return a safe expression for the LHS we can use
+     * to return the value
+     */
+    protected Expression createReturnLHSExpression(Expression expression) {
+        if (expression instanceof BinaryExpression) {
+            BinaryExpression binExpr = (BinaryExpression) expression;
+            if (binExpr.getOperation().isA(Types.ASSIGNMENT_OPERATOR)) {
+                return createReusableExpression(binExpr.getLeftExpression());
+            }
+        }
+        return null;
+    }
+
+    protected Expression createReusableExpression(Expression expression) {
+        ExpressionTransformer transformer = new ExpressionTransformer() {
+            public Expression transform(Expression expression) {
+                if (expression instanceof PostfixExpression) {
+                    PostfixExpression postfixExp = (PostfixExpression) expression;
+                    return postfixExp.getExpression();
+                }
+                else if (expression instanceof PrefixExpression) {
+                    PrefixExpression prefixExp = (PrefixExpression) expression;
+                    return prefixExp.getExpression();
+                }
+                return expression;
+            }
+        };
+
+        // could just be a postfix / prefix expression or nested inside some other expression
+        return transformer.transform(expression.transformExpression(transformer));
+    }
+
+    protected boolean isComparisonExpression(Expression expression) {
+        if (expression instanceof BinaryExpression) {
+            BinaryExpression binExpr = (BinaryExpression) expression;
+            switch (binExpr.getOperation().getType()) {
+                case Types.COMPARE_EQUAL :
+                case Types.MATCH_REGEX :
+                case Types.COMPARE_GREATER_THAN :
+                case Types.COMPARE_GREATER_THAN_EQUAL :
+                case Types.COMPARE_LESS_THAN :
+                case Types.COMPARE_LESS_THAN_EQUAL :
+                case Types.COMPARE_IDENTICAL :
+                case Types.COMPARE_NOT_EQUAL :
+                case Types.KEYWORD_INSTANCEOF :
+                case Types.KEYWORD_IN :
+                    return true;
+            }
+        }
+        else if (expression instanceof BooleanExpression) {
+            return true;
+        }
+        return false;
+    }
+
+    protected void onLineNumber(ASTNode statement, String message) {
+        int line = statement.getLineNumber();
+        int col = statement.getColumnNumber();
+        this.currentASTNode = statement;
+
+        if (line >=0) {
+            lineNumber = line;
+            columnNumber = col;
+        }
+        if (CREATE_LINE_NUMBER_INFO && line >= 0 && cv != null) {
+            Label l = new Label();
+            cv.visitLabel(l);
+            cv.visitLineNumber(line, l);
+            if (ASM_DEBUG) {
+                helper.mark(message + "[" + statement.getLineNumber() + ":" + statement.getColumnNumber() + "]");
+            }
+        }
+    }
+    
+    private boolean isInnerClass() {
+        return classNode instanceof InnerClassNode;
+    }
+
+    /** @return true if the given name is a local variable or a field */
+    protected boolean isFieldOrVariable(String name) {
+        return compileStack.containsVariable(name) || classNode.getField(name) != null;
+    }
+
+    /**
+     * @return if the type of the expression can be determined at compile time
+     *         then this method returns the type - otherwise null
+     */
+    protected ClassNode getExpressionType(Expression expression) {
+        if (isComparisonExpression(expression)) {
+            return ClassHelper.boolean_TYPE;
+        }
+        if (expression instanceof VariableExpression) {
+        	if (expression == VariableExpression.THIS_EXPRESSION) {
+        		return classNode;
+        	}else  if (expression==VariableExpression.SUPER_EXPRESSION) {
+        		return classNode.getSuperClass();
+        	}
+        	
+            VariableExpression varExpr = (VariableExpression) expression;
+            Variable variable = compileStack.getVariable(varExpr.getName(),false);
+            if (variable != null && !variable.isHolder()) {
+                ClassNode type = variable.getType();
+                if (! variable.isDynamicTyped()) return type;
+            }
+            if (variable == null) {
+                org.codehaus.groovy.ast.Variable var = (org.codehaus.groovy.ast.Variable) compileStack.getScope().getReferencedClassVariables().get(varExpr.getName());
+                if (var!=null && !var.isDynamicTyped()) return var.getType();
+            }
+        }
+        return expression.getType();
+    }
+
+    protected boolean isInClosureConstructor() {
+        return constructorNode != null
+            && classNode.getOuterClass() != null
+            && classNode.getSuperClass()==ClassHelper.CLOSURE_TYPE;
+    }
+
+    protected boolean isInClosure() {
+        return classNode.getOuterClass() != null
+            && classNode.getSuperClass()==ClassHelper.CLOSURE_TYPE;
+    }
+    
+    protected boolean isStaticMethod() {
+        if (methodNode == null) { // we're in a constructor
+            return false;
+        }
+        return methodNode.isStatic();
+    }
+
+    protected CompileUnit getCompileUnit() {
+        CompileUnit answer = classNode.getCompileUnit();
+        if (answer == null) {
+            answer = context.getCompileUnit();
+        }
+        return answer;
+    }
+
+    protected boolean isHolderVariable(Expression expression) {
+        if (expression instanceof FieldExpression) {
+            FieldExpression fieldExp = (FieldExpression) expression;
+            return fieldExp.getField().isHolder();
+        }
+        if (expression instanceof VariableExpression) {
+            VariableExpression varExp = (VariableExpression) expression;
+            Variable variable = compileStack.getVariable(varExp.getName(),false);
+            if (variable != null) {
+                return variable.isHolder();
+            }
+            FieldNode field = classNode.getField(varExp.getName());
+            if (field != null) {
+                return field.isHolder();
+            }
+        }
+        return false;
+    }
+    
+    public static boolean usesSuper(MethodCallExpression call) {
+        Expression expression = call.getObjectExpression();
+        if (expression instanceof VariableExpression) {
+            VariableExpression varExp = (VariableExpression) expression;
+            String variable = varExp.getName();
+            return variable.equals("super");
+        }
+        return false;
+    }
+    
+    public static boolean usesSuper(PropertyExpression pe) {
+        Expression expression = pe.getObjectExpression();
+        if (expression instanceof VariableExpression) {
+            VariableExpression varExp = (VariableExpression) expression;
+            String variable = varExp.getName();
+            return variable.equals("super");
+        }
+        return false;
+    }    
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/BytecodeExpression.java b/groovy-core/src/main/org/codehaus/groovy/classgen/BytecodeExpression.java
new file mode 100644
index 0000000..a25851e
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/BytecodeExpression.java
@@ -0,0 +1,67 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ExpressionTransformer;
+
+/**
+ * Represents some custom bytecode generation by the compiler
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public abstract class BytecodeExpression extends Expression {
+    public BytecodeExpression() {
+    }
+    
+    public abstract void visit(GroovyCodeVisitor visitor);
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        return this;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/BytecodeHelper.java b/groovy-core/src/main/org/codehaus/groovy/classgen/BytecodeHelper.java
new file mode 100644
index 0000000..af5be65
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/BytecodeHelper.java
@@ -0,0 +1,708 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.classgen;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Label;
+
+/**
+ * A helper class for bytecode generation with AsmClassGenerator.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author <a href="mailto:b55r@sina.com">Bing Ran</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * @version $Revision$
+ */
+public class BytecodeHelper implements Opcodes {
+
+    private MethodVisitor cv;
+
+    public MethodVisitor getMethodVisitor() {
+        return cv;
+    }
+
+    public BytecodeHelper(MethodVisitor cv) {
+        this.cv = cv;
+    }
+    
+    /**
+     * box the primitive value on the stack
+     * @param type
+     */
+    public void quickBoxIfNecessary(ClassNode type) {
+        String descr = getTypeDescription(type);
+        if (type == ClassHelper.boolean_TYPE) {
+            boxBoolean();
+        }
+        else if (ClassHelper.isPrimitiveType(type) && type != ClassHelper.VOID_TYPE) {
+            ClassNode wrapper = ClassHelper.getWrapper(type);
+            String internName = getClassInternalName(wrapper);
+            cv.visitTypeInsn(NEW, internName);
+            cv.visitInsn(DUP);
+            if (type==ClassHelper.double_TYPE || type==ClassHelper.long_TYPE) {
+                cv.visitInsn(DUP2_X2);
+                cv.visitInsn(POP2);
+            } else {
+                cv.visitInsn(DUP2_X1);
+                cv.visitInsn(POP2);
+            }
+            cv.visitMethodInsn(INVOKESPECIAL, internName, "<init>", "(" + descr + ")V");
+        }
+    }
+    
+    public void quickUnboxIfNecessary(ClassNode type){
+        if (ClassHelper.isPrimitiveType(type) && type != ClassHelper.VOID_TYPE) { // todo care when BigDecimal or BigIneteger on stack
+            ClassNode wrapper = ClassHelper.getWrapper(type);
+            String internName = getClassInternalName(wrapper);
+            if (type == ClassHelper.boolean_TYPE) {
+                cv.visitTypeInsn(CHECKCAST, internName);
+                cv.visitMethodInsn(INVOKEVIRTUAL, internName, type.getName() + "Value", "()" + getTypeDescription(type));
+            } else { // numbers
+                cv.visitTypeInsn(CHECKCAST, "java/lang/Number");
+                cv.visitMethodInsn(INVOKEVIRTUAL, /*internName*/"java/lang/Number", type.getName() + "Value", "()" + getTypeDescription(type));
+            }
+        }
+    }
+    
+    /**
+     * Generates the bytecode to autobox the current value on the stack
+     */
+    public void box(Class type) {
+        if (type.isPrimitive() && type != void.class) {
+            String returnString = "(" + getTypeDescription(type) + ")Ljava/lang/Object;";
+            cv.visitMethodInsn(INVOKESTATIC, getClassInternalName(DefaultTypeTransformation.class.getName()), "box", returnString);
+        }
+    }
+
+    public void box(ClassNode type) {
+        if (type.isPrimaryClassNode()) return;
+        box(type.getTypeClass());
+    }
+
+    /**
+     * Generates the bytecode to unbox the current value on the stack
+     */
+    public void unbox(Class type) {
+        if (type.isPrimitive() && type != Void.TYPE) {
+            String returnString = "(Ljava/lang/Object;)" + getTypeDescription(type);
+            cv.visitMethodInsn(
+                INVOKESTATIC,
+                getClassInternalName(DefaultTypeTransformation.class.getName()),
+                type.getName() + "Unbox",
+                returnString);
+        }
+    }
+    
+    public void unbox(ClassNode type) {
+        if (type.isPrimaryClassNode()) return;
+        unbox(type.getTypeClass());
+    }
+
+    public static String getClassInternalName(ClassNode t){
+    	if (t.isPrimaryClassNode()){
+    		return getClassInternalName(t.getName());
+    	}
+        return getClassInternalName(t.getTypeClass());
+    }
+    
+    public static String getClassInternalName(Class t) {
+        return org.objectweb.asm.Type.getInternalName(t);
+    }
+    
+    /**
+     * @return the ASM internal name of the type
+     */
+    public static String getClassInternalName(String name) {
+        return name.replace('.', '/');
+    }
+    
+    /**
+     * @return the ASM method type descriptor
+     */
+    public static String getMethodDescriptor(ClassNode returnType, Parameter[] parameters) {
+        StringBuffer buffer = new StringBuffer("(");
+        for (int i = 0; i < parameters.length; i++) {
+            buffer.append(getTypeDescription(parameters[i].getType()));
+        }
+        buffer.append(")");
+        buffer.append(getTypeDescription(returnType));
+        return buffer.toString();
+    }
+
+    /**
+     * @return the ASM method type descriptor
+     */
+    public static String getMethodDescriptor(Class returnType, Class[] paramTypes) {
+        // lets avoid class loading
+        StringBuffer buffer = new StringBuffer("(");
+        for (int i = 0; i < paramTypes.length; i++) {
+            buffer.append(getTypeDescription(paramTypes[i]));
+        }
+        buffer.append(")");
+        buffer.append(getTypeDescription(returnType));
+        return buffer.toString();
+    }
+
+    public static String getTypeDescription(Class c) {
+        return org.objectweb.asm.Type.getDescriptor(c);
+    }
+    
+    /**
+     * array types are special:
+     * eg.: String[]: classname: [Ljava.lang.String;
+     *      Object:   classname: java.lang.Object
+     *      int[] :   classname: [I
+     * unlike getTypeDescription '.' is not replaces by '/'. 
+     * it seems that makes problems for
+     * the class loading if '.' is replaced by '/'
+     * @return the ASM type description for class loading
+     */
+    public static String getClassLoadingTypeDescription(ClassNode c) {
+        StringBuffer buf = new StringBuffer();
+        boolean array = false;
+        while (true) {
+            if (c.isArray()) {
+                buf.append('[');
+                c = c.getComponentType();
+                array = true;
+            } else {
+                if (ClassHelper.isPrimitiveType(c)) {
+                    buf.append(getTypeDescription(c));
+                } else {
+                    if (array) buf.append('L');
+                    buf.append(c.getName());
+                    if(array) buf.append(';');
+                }
+                return buf.toString();
+            }
+        }
+    }
+    
+    /**
+     * array types are special:
+     * eg.: String[]: classname: [Ljava/lang/String;
+     *      int[]: [I
+     * @return the ASM type description
+     */
+    public static String getTypeDescription(ClassNode c) {
+        StringBuffer buf = new StringBuffer();
+        ClassNode d = c;
+        while (true) {
+            if (ClassHelper.isPrimitiveType(d)) {
+                char car;
+                if (d == ClassHelper.int_TYPE) {
+                    car = 'I';
+                } else if (d == ClassHelper.VOID_TYPE) {
+                    car = 'V';
+                } else if (d == ClassHelper.boolean_TYPE) {
+                    car = 'Z';
+                } else if (d == ClassHelper.byte_TYPE) {
+                    car = 'B';
+                } else if (d == ClassHelper.char_TYPE) {
+                    car = 'C';
+                } else if (d == ClassHelper.short_TYPE) {
+                    car = 'S';
+                } else if (d == ClassHelper.double_TYPE) {
+                    car = 'D';
+                } else if (d == ClassHelper.float_TYPE) {
+                    car = 'F';
+                } else /* long */{
+                    car = 'J';
+                }
+                buf.append(car);
+                return buf.toString();
+            } else if (d.isArray()) {
+                buf.append('[');
+                d = d.getComponentType();
+            } else {
+                buf.append('L');
+                String name = d.getName();
+                int len = name.length();
+                for (int i = 0; i < len; ++i) {
+                    char car = name.charAt(i);
+                    buf.append(car == '.' ? '/' : car);
+                }
+                buf.append(';');
+                return buf.toString();
+            }
+        }
+    }
+
+    /**
+     * @return an array of ASM internal names of the type
+     */
+    public static String[] getClassInternalNames(ClassNode[] names) {
+        int size = names.length;
+        String[] answer = new String[size];
+        for (int i = 0; i < size; i++) {
+            answer[i] = getClassInternalName(names[i]);
+        }
+        return answer;
+    }
+
+    protected void pushConstant(boolean value) {
+        if (value) {
+            cv.visitInsn(ICONST_1);
+        }
+        else {
+            cv.visitInsn(ICONST_0);
+        }
+    }
+
+    protected void pushConstant(int value) {
+        switch (value) {
+            case 0 :
+                cv.visitInsn(ICONST_0);
+                break;
+            case 1 :
+                cv.visitInsn(ICONST_1);
+                break;
+            case 2 :
+                cv.visitInsn(ICONST_2);
+                break;
+            case 3 :
+                cv.visitInsn(ICONST_3);
+                break;
+            case 4 :
+                cv.visitInsn(ICONST_4);
+                break;
+            case 5 :
+                cv.visitInsn(ICONST_5);
+                break;
+            default :
+                if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
+                    cv.visitIntInsn(BIPUSH, value);
+                }
+                else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
+                    cv.visitIntInsn(SIPUSH, value);
+                }
+                else {
+                    cv.visitLdcInsn(new Integer(value));
+                }
+        }
+    }
+
+    public void doCast(Class type) {
+        if (type!=Object.class) {
+            if (type.isPrimitive() && type!=Void.TYPE) {
+                unbox(type);
+            }
+            else {
+                cv.visitTypeInsn(
+                    CHECKCAST,
+                    type.isArray() ? getTypeDescription(type) : getClassInternalName(type.getName()));
+            }
+        }
+    }
+    
+    public void doCast(ClassNode type) {
+        if (type==ClassHelper.OBJECT_TYPE) return;
+        if (ClassHelper.isPrimitiveType(type) && type!=ClassHelper.VOID_TYPE) {
+            unbox(type);
+        }
+        else {
+            cv.visitTypeInsn(
+                    CHECKCAST,
+                    type.isArray() ? getTypeDescription(type) : getClassInternalName(type));
+        }
+    }
+
+    public void load(ClassNode type, int idx) {
+        if (type==ClassHelper.double_TYPE) {
+            cv.visitVarInsn(DLOAD, idx);
+        }
+        else if (type==ClassHelper.float_TYPE) {
+            cv.visitVarInsn(FLOAD, idx);
+        }
+        else if (type==ClassHelper.long_TYPE) {
+            cv.visitVarInsn(LLOAD, idx);
+        }
+        else if (
+            type==ClassHelper.boolean_TYPE
+                || type==ClassHelper.char_TYPE
+                || type==ClassHelper.byte_TYPE
+                || type==ClassHelper.int_TYPE
+                || type==ClassHelper.short_TYPE)
+        {    
+            cv.visitVarInsn(ILOAD, idx);
+        }
+        else {
+            cv.visitVarInsn(ALOAD, idx);
+        }
+    }
+
+    public void load(Variable v) {
+    	load(v.getType(), v.getIndex());
+    }
+
+    public void store(Variable v, boolean markStart) {
+        ClassNode type = v.getType();
+        unbox(type);
+        int idx = v.getIndex();
+
+        if (type==ClassHelper.double_TYPE) {
+            cv.visitVarInsn(DSTORE, idx);
+        }
+        else if (type==ClassHelper.float_TYPE) {
+            cv.visitVarInsn(FSTORE, idx);
+        }
+        else if (type==ClassHelper.long_TYPE) {
+            cv.visitVarInsn(LSTORE, idx);
+        }
+        else if (
+                type==ClassHelper.boolean_TYPE
+                || type==ClassHelper.char_TYPE
+                || type==ClassHelper.byte_TYPE
+                || type==ClassHelper.int_TYPE
+                || type==ClassHelper.short_TYPE) {
+            cv.visitVarInsn(ISTORE, idx);
+        }
+        else {
+            cv.visitVarInsn(ASTORE, idx);
+        }
+    }
+
+    public void store(Variable v) {
+        store(v, false);
+    }
+
+    /**
+     * load the constant on the operand stack. primitives auto-boxed.
+     */
+    void loadConstant (Object value) {
+        if (value == null) {
+            cv.visitInsn(ACONST_NULL);
+        }
+        else if (value instanceof String) {
+            cv.visitLdcInsn(value);
+        }
+        else if (value instanceof Character) {
+            String className = "java/lang/Character";
+            cv.visitTypeInsn(NEW, className);
+            cv.visitInsn(DUP);
+            cv.visitLdcInsn(value);
+            String methodType = "(C)V";
+            cv.visitMethodInsn(INVOKESPECIAL, className, "<init>", methodType);
+        }
+        else if (value instanceof Number) {
+            /** todo it would be more efficient to generate class constants */
+            Number n = (Number) value;
+            String className = BytecodeHelper.getClassInternalName(value.getClass().getName());
+            cv.visitTypeInsn(NEW, className);
+            cv.visitInsn(DUP);
+            String methodType;
+            if (n instanceof Integer) {
+            	//pushConstant(n.intValue());
+            	cv.visitLdcInsn(n);
+            	methodType = "(I)V";
+        	}
+            else if (n instanceof Double) {
+            	cv.visitLdcInsn(n);
+            	methodType = "(D)V";
+            }
+            else if (n instanceof Float) {
+            	cv.visitLdcInsn(n);
+            	methodType = "(F)V";
+            }
+            else if (n instanceof Long) {
+            	cv.visitLdcInsn(n);
+            	methodType = "(J)V";
+            }
+            else if (n instanceof BigDecimal) {
+            	cv.visitLdcInsn(n.toString());
+            	methodType = "(Ljava/lang/String;)V";
+            }
+            else if (n instanceof BigInteger) {
+            	cv.visitLdcInsn(n.toString());
+            	methodType = "(Ljava/lang/String;)V";
+            }
+            else if (n instanceof Short) {
+            	cv.visitLdcInsn(n);
+            	methodType = "(S)V";
+            }
+            else if (n instanceof Byte) {
+            	cv.visitLdcInsn(n);
+            	methodType = "(B)V";
+            }
+            else {
+        	throw new ClassGeneratorException(
+                               "Cannot generate bytecode for constant: " + value
+                             + " of type: " + value.getClass().getName()
+                             + ".  Numeric constant type not supported.");
+            }
+            cv.visitMethodInsn(INVOKESPECIAL, className, "<init>", methodType);
+        }
+        else if (value instanceof Boolean) {
+            Boolean bool = (Boolean) value;
+            String text = (bool.booleanValue()) ? "TRUE" : "FALSE";
+            cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", text, "Ljava/lang/Boolean;");
+        }
+        else if (value instanceof Class) {
+            Class vc = (Class) value;
+            if (vc.getName().equals("java.lang.Void")) {
+                // load nothing here for void
+            } else {
+                throw new ClassGeneratorException(
+                "Cannot generate bytecode for constant: " + value + " of type: " + value.getClass().getName());
+            }
+        }
+        else {
+            throw new ClassGeneratorException(
+                "Cannot generate bytecode for constant: " + value + " of type: " + value.getClass().getName());
+        }
+    }
+
+
+    /**
+     * load the value of the variable on the operand stack. unbox it if it's a reference
+     * @param variable
+     */
+    public void loadVar(Variable variable) {
+		int index = variable.getIndex();
+		if (variable.isHolder()) {
+			cv.visitVarInsn(ALOAD, index);
+			cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;");
+		} else {
+            load(variable);
+            if (variable!=Variable.THIS_VARIABLE && variable!=Variable.SUPER_VARIABLE) {
+                box(variable.getType());
+            }
+		}
+	}
+    
+    public void storeVar(Variable variable) {
+        String  type   = variable.getTypeName();
+        int     index  = variable.getIndex();
+        
+    	if (variable.isHolder()) {
+            cv.visitVarInsn(ALOAD, index);
+            cv.visitInsn(SWAP);  
+            cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V");
+        }
+        else {
+            store(variable,false);
+        }
+    }
+
+    public void putField(FieldNode fld) {
+    	putField(fld, getClassInternalName(fld.getOwner()));
+    }
+
+    public void putField(FieldNode fld, String ownerName) {
+    	cv.visitFieldInsn(PUTFIELD, ownerName, fld.getName(), getTypeDescription(fld.getType()));
+    }
+    
+    public void swapObjectWith(ClassNode type) {
+        if (type==ClassHelper.long_TYPE || type==ClassHelper.double_TYPE) {
+            cv.visitInsn(DUP_X2);
+            cv.visitInsn(POP);
+        } else {
+            cv.visitInsn(SWAP);
+        }
+    }
+    
+    public void swapWithObject(ClassNode type) {
+        if (type==ClassHelper.long_TYPE || type==ClassHelper.double_TYPE) {
+            cv.visitInsn(DUP2_X1);
+            cv.visitInsn(POP2);
+        } else {
+            cv.visitInsn(SWAP);
+        }
+    }
+
+    public static ClassNode boxOnPrimitive(ClassNode type) {
+        if (!type.isArray()) return ClassHelper.getWrapper(type);
+        return boxOnPrimitive(type.getComponentType()).makeArray();
+    }
+
+    /**
+     * convert boolean to Boolean
+     */
+    public void boxBoolean() {
+        Label l0 = new Label();
+        cv.visitJumpInsn(IFEQ, l0);
+        cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
+        Label l1 = new Label();
+        cv.visitJumpInsn(GOTO, l1);
+        cv.visitLabel(l0);
+        cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
+        cv.visitLabel(l1);
+    }
+
+    /**
+     * negate a boolean on stack. true->false, false->true
+     */
+    public void negateBoolean(){
+        // code to negate the primitive boolean
+        Label endLabel = new Label();
+        Label falseLabel = new Label();
+        cv.visitJumpInsn(IFNE,falseLabel);
+        cv.visitInsn(ICONST_1);
+        cv.visitJumpInsn(GOTO,endLabel);
+        cv.visitLabel(falseLabel);
+        cv.visitInsn(ICONST_0);
+        cv.visitLabel(endLabel);
+    }
+
+    /**
+     * load a message on the stack and remove it right away. Good for put a mark in the generated bytecode for debugging purpose.
+     * @param msg
+     */
+    public void mark(String msg) {
+        cv.visitLdcInsn(msg);
+        cv.visitInsn(POP);
+    }
+    
+    /**
+     * returns a name that Class.forName() can take. Notablely for arrays:
+     * [I, [Ljava.lang.String; etc
+     * Regular object type:  java.lang.String
+     * @param name
+     */
+    public static String formatNameForClassLoading(String name) {
+        if (name.equals("int")
+        		|| name.equals("long")
+				|| name.equals("short")
+				|| name.equals("float")
+				|| name.equals("double")
+				|| name.equals("byte")
+				|| name.equals("char")
+				|| name.equals("boolean")
+				|| name.equals("void")
+        	) {
+            return name;
+        }
+
+        if (name == null) {
+            return "java.lang.Object;";
+        }
+
+        if (name.startsWith("[")) {
+            return name.replace('/', '.');
+        }
+        
+        if (name.startsWith("L")) {
+        	name = name.substring(1);
+        	if (name.endsWith(";")) {
+        		name = name.substring(0, name.length() - 1);
+        	}
+        	return name.replace('/', '.');
+        }
+
+        String prefix = "";
+        if (name.endsWith("[]")) { // todo need process multi
+            prefix = "[";
+            name = name.substring(0, name.length() - 2);
+            if (name.equals("int")) {
+                return prefix + "I";
+            }
+            else if (name.equals("long")) {
+                return prefix + "J";
+            }
+            else if (name.equals("short")) {
+                return prefix + "S";
+            }
+            else if (name.equals("float")) {
+                return prefix + "F";
+            }
+            else if (name.equals("double")) {
+                return prefix + "D";
+            }
+            else if (name.equals("byte")) {
+                return prefix + "B";
+            }
+            else if (name.equals("char")) {
+                return prefix + "C";
+            }
+            else if (name.equals("boolean")) {
+                return prefix + "Z";
+            }
+            else {
+            	return prefix + "L" + name.replace('/', '.') + ";";
+            }
+        }
+        return name.replace('/', '.');
+
+    }
+
+    public void dup() {
+        cv.visitInsn(DUP);
+    }
+
+    public void doReturn(ClassNode returnType) {
+        if (returnType==ClassHelper.double_TYPE) {
+            cv.visitInsn(DRETURN);
+        } else if (returnType==ClassHelper.float_TYPE) {
+            cv.visitInsn(FRETURN);
+        } else if (returnType==ClassHelper.long_TYPE) {
+            cv.visitInsn(LRETURN);
+        } else if (
+                   returnType==ClassHelper.boolean_TYPE
+                || returnType==ClassHelper.char_TYPE
+                || returnType==ClassHelper.byte_TYPE
+                || returnType==ClassHelper.int_TYPE
+                || returnType==ClassHelper.short_TYPE) 
+        { 
+            //byte,short,boolean,int are all IRETURN
+            cv.visitInsn(IRETURN);
+        } else if (returnType==ClassHelper.VOID_TYPE){
+            cv.visitInsn(RETURN);
+        } else {
+            cv.visitInsn(ARETURN);
+        }
+        
+    }
+    
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/ClassCompletionVerifier.java b/groovy-core/src/main/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
new file mode 100644
index 0000000..2b12d2d
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
@@ -0,0 +1,313 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM - Initial API and implementation
+ * Groovy community - subsequent modifications
+ ******************************************************************************/
+package org.codehaus.groovy.classgen;
+
+import java.lang.reflect.Modifier;
+import java.util.Iterator;
+import java.util.List;
+
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.MapEntryExpression;
+import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.control.SourceUnit;
+import org.objectweb.asm.Opcodes;
+import org.codehaus.groovy.syntax.Types;
+
+/**
+ * ClassCompletionVerifier
+ */
+public class ClassCompletionVerifier extends ClassCodeVisitorSupport {
+
+    private ClassNode currentClass;
+    private SourceUnit source;
+
+    public ClassCompletionVerifier(SourceUnit source) {
+        this.source = source;
+    }
+
+    public ClassNode getClassNode() {
+        return currentClass;
+    }
+
+    public void visitClass(ClassNode node) {
+        ClassNode oldClass = currentClass;
+        currentClass = node;
+        checkImplementsAndExtends(node);
+        if (source != null && !source.getErrorCollector().hasErrors()) {
+            checkClassForIncorrectModifiers(node);
+            checkClassForOverwritingFinal(node);
+            checkMethodsForIncorrectModifiers(node);
+            checkMethodsForOverwritingFinal(node);
+            checkNoAbstractMethodsNonabstractClass(node);
+        }
+        super.visitClass(node);
+        currentClass = oldClass;
+    }
+
+    private void checkNoAbstractMethodsNonabstractClass(ClassNode node) {
+        if (Modifier.isAbstract(node.getModifiers())) return;
+        List abstractMethods = node.getAbstractMethods();
+        if (abstractMethods == null) return;
+        for (Iterator iter = abstractMethods.iterator(); iter.hasNext();) {
+            MethodNode method = (MethodNode) iter.next();
+            String methodName = method.getTypeDescriptor();
+            addError("Can't have an abstract method in a non-abstract class." +
+                    " The " + getDescription(node) + " must be declared abstract or" +
+                    " the " + getDescription(method) + " must be implemented.", node);
+        }
+    }
+
+    private void checkClassForIncorrectModifiers(ClassNode node) {
+        checkClassForAbstractAndFinal(node);
+        checkClassForOtherModifiers(node);
+    }
+
+    private void checkClassForAbstractAndFinal(ClassNode node) {
+        if (!Modifier.isAbstract(node.getModifiers())) return;
+        if (!Modifier.isFinal(node.getModifiers())) return;
+        if (node.isInterface()) {
+            addError("The " + getDescription(node) +" must not be final. It is by definition abstract.", node);
+        } else {
+            addError("The " + getDescription(node) + " must not be both final and abstract.", node);
+        }
+    }
+
+    private void checkClassForOtherModifiers(ClassNode node) {
+        // TODO: work out why "synchronised" can't be used here
+        checkClassForModifier(node, Modifier.isTransient(node.getModifiers()), "transient");
+        checkClassForModifier(node, Modifier.isVolatile(node.getModifiers()), "volatile");
+    }
+
+    private void checkClassForModifier(ClassNode node, boolean condition, String modifierName) {
+        if (!condition) return;
+        addError("The " + getDescription(node) + " has an incorrect modifier " + modifierName + ".", node);
+    }
+
+    private String getDescription(ClassNode node) {
+        return (node.isInterface() ? "interface" : "class") + " '" + node.getName() + "'";
+    }
+
+    private String getDescription(MethodNode node) {
+        return "method '" + node.getName() + "'";
+    }
+
+    private String getDescription(FieldNode node) {
+        return "field '" + node.getName() + "'";
+    }
+
+    private void checkAbstractDeclaration(MethodNode methodNode) {
+        if (!Modifier.isAbstract(methodNode.getModifiers())) return;
+        if (Modifier.isAbstract(currentClass.getModifiers())) return;
+        addError("Can't have an abstract method in a non-abstract class." +
+                " The " + getDescription(currentClass) + " must be declared abstract or the method '" +
+                methodNode.getTypeDescriptor() + "' must not be abstract.", methodNode);
+    }
+
+    private void checkClassForOverwritingFinal(ClassNode cn) {
+        ClassNode superCN = cn.getSuperClass();
+        if (superCN == null) return;
+        if (!Modifier.isFinal(superCN.getModifiers())) return;
+        StringBuffer msg = new StringBuffer();
+        msg.append("You are not allowed to overwrite the final ");
+        msg.append(getDescription(superCN));
+        msg.append(".");
+        addError(msg.toString(), cn);
+    }
+
+    private void checkImplementsAndExtends(ClassNode node) {
+        ClassNode cn = node.getSuperClass();
+        if (cn.isInterface() && !node.isInterface()) {
+            addError("You are not allowed to extend the " + getDescription(cn) + ", use implements instead.", node);
+        }
+        ClassNode[] interfaces = node.getInterfaces();
+        for (int i = 0; i < interfaces.length; i++) {
+            cn = interfaces[i];
+            if (!cn.isInterface()) {
+                addError("You are not allowed to implement the " + getDescription(cn) + ", use extends instead.", node);
+            }
+        }
+    }
+
+    private void checkMethodsForIncorrectModifiers(ClassNode cn) {
+        if (!cn.isInterface()) return;
+        List methods = cn.getMethods();
+        for (Iterator cnIter = methods.iterator(); cnIter.hasNext();) {
+            MethodNode method = (MethodNode) cnIter.next();
+            if (Modifier.isFinal(method.getModifiers())) {
+                addError("The " + getDescription(method) + " from " + getDescription(cn) +
+                        " must not be final. It is by definition abstract.", method);
+            }
+            if (Modifier.isStatic(method.getModifiers()) && !isConstructor(method)) {
+                addError("The " + getDescription(method) + " from " + getDescription(cn) +
+                        " must not be static. Only fields may be static in an interface.", method);
+            }
+        }
+    }
+
+    private boolean isConstructor(MethodNode method) {
+        return method.getName().equals("<clinit>");
+    }
+
+    private void checkMethodsForOverwritingFinal(ClassNode cn) {
+        List methods = cn.getMethods();
+        for (Iterator cnIter = methods.iterator(); cnIter.hasNext();) {
+            MethodNode method = (MethodNode) cnIter.next();
+            Parameter[] params = method.getParameters();
+            for (ClassNode superCN = cn.getSuperClass(); superCN != null; superCN = superCN.getSuperClass()) {
+                List superMethods = superCN.getMethods(method.getName());
+                for (Iterator iter = superMethods.iterator(); iter.hasNext();) {
+                    MethodNode superMethod = (MethodNode) iter.next();
+                    Parameter[] superParams = superMethod.getParameters();
+                    if (!hasEqualParameterTypes(params, superParams)) continue;
+                    if (!Modifier.isFinal(superMethod.getModifiers())) return;
+                    addInvalidUseOfFinalError(method, params, superCN);
+                    return;
+                }
+            }
+        }
+    }
+
+    private void addInvalidUseOfFinalError(MethodNode method, Parameter[] parameters, ClassNode superCN) {
+        StringBuffer msg = new StringBuffer();
+        msg.append("You are not allowed to overwrite the final method ").append(method.getName());
+        msg.append("(");
+        boolean needsComma = false;
+        for (int i = 0; i < parameters.length; i++) {
+            if (needsComma) {
+                msg.append(",");
+            } else {
+                needsComma = true;
+            }
+            msg.append(parameters[i].getType());
+        }
+        msg.append(") from ").append(getDescription(superCN));
+        msg.append(".");
+        addError(msg.toString(), method);
+    }
+
+    private boolean hasEqualParameterTypes(Parameter[] first, Parameter[] second) {
+        if (first.length != second.length) return false;
+        for (int i = 0; i < first.length; i++) {
+            String ft = first[i].getType().getName();
+            String st = second[i].getType().getName();
+            if (ft.equals(st)) continue;
+            return false;
+        }
+        return true;
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+
+    public void visitConstructorCallExpression(ConstructorCallExpression call) {
+        ClassNode type = call.getType();
+        if (Modifier.isAbstract(type.getModifiers())) {
+            addError("You cannot create an instance from the abstract " + getDescription(type) + ".", call);
+        }
+        super.visitConstructorCallExpression(call);
+    }
+
+    public void visitMethod(MethodNode node) {
+        checkAbstractDeclaration(node);
+        checkRepetitiveMethod(node);
+        checkOverloadingPrivateAndPublic(node);
+        super.visitMethod(node);
+    }
+
+    private void checkOverloadingPrivateAndPublic(MethodNode node) {
+        if (isConstructor(node)) return;
+        List methods = currentClass.getMethods(node.getName());
+        boolean hasPrivate=false;
+        boolean hasPublic=false;
+        for (Iterator iter = methods.iterator(); iter.hasNext();) {
+            MethodNode element = (MethodNode) iter.next();
+            if (element == node) continue;
+            int modifiers = element.getModifiers();
+            if (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)){
+                hasPublic=true;
+            } else {
+                hasPrivate=true;
+            }
+        }
+        if (hasPrivate && hasPublic) {
+            addError("Mixing private and public/protected methods of the same name causes multimethods to be disabled and is forbidden to avoid surprising behaviour. Renaming the private methods will solve the problem.",node);
+        }
+    }
+    
+    private void checkRepetitiveMethod(MethodNode node) {
+        if (isConstructor(node)) return;
+        List methods = currentClass.getMethods(node.getName());
+        for (Iterator iter = methods.iterator(); iter.hasNext();) {
+            MethodNode element = (MethodNode) iter.next();
+            if (element == node) continue;
+            if (!element.getDeclaringClass().equals(node.getDeclaringClass())) continue;
+            Parameter[] p1 = node.getParameters();
+            Parameter[] p2 = element.getParameters();
+            if (p1.length != p2.length) continue;
+            addErrorIfParamsAndReturnTypeEqual(p2, p1, node, element);
+        }
+    }
+
+    private void addErrorIfParamsAndReturnTypeEqual(Parameter[] p2, Parameter[] p1,
+                                                    MethodNode node, MethodNode element) {
+        boolean isEqual = true;
+        for (int i = 0; i < p2.length; i++) {
+            isEqual &= p1[i].getType().equals(p2[i].getType());
+        }
+        isEqual &= node.getReturnType().equals(element.getReturnType());
+        if (isEqual) {
+            addError("Repetitive method name/signature for " + getDescription(node) +
+                    " in " + getDescription(currentClass) + ".", node);
+        }
+    }
+
+    public void visitField(FieldNode node) {
+        if (currentClass.getField(node.getName()) != node) {
+            addError("The " + getDescription(node) + " is declared multiple times.", node);
+        }
+        checkInterfaceFieldModifiers(node);
+        super.visitField(node);
+    }
+
+    private void checkInterfaceFieldModifiers(FieldNode node) {
+        if (!currentClass.isInterface()) return;
+        if ((node.getModifiers() & (Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL)) == 0) {
+            addError("The " + getDescription(node) + " is not 'public final static' but is defined in the " +
+                    getDescription(currentClass) + ".", node);
+        }
+    }
+
+    public void visitBinaryExpression(BinaryExpression expression) {
+        if (expression.getOperation().getType() == Types.LEFT_SQUARE_BRACKET &&
+                expression.getRightExpression() instanceof MapEntryExpression) {
+            addError("You tried to use a map entry for an index operation, this is not allowed. " +
+                    "Maybe something should be set in parentheses or a comma is missing?",
+                    expression.getRightExpression());
+        }
+        super.visitBinaryExpression(expression);
+    }
+
+    public void visitCatchStatement(CatchStatement cs) {
+        if (!(cs.getExceptionType().isDerivedFrom(ClassHelper.make(Throwable.class)))) {
+            addError("Catch statement parameter type is not a subclass of Throwable.", cs);
+        }
+        super.visitCatchStatement(cs);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/ClassGenerator.java b/groovy-core/src/main/org/codehaus/groovy/classgen/ClassGenerator.java
new file mode 100644
index 0000000..3371e7f
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/ClassGenerator.java
@@ -0,0 +1,83 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.control.SourceUnit;
+import org.objectweb.asm.Opcodes;
+
+import java.util.LinkedList;
+
+/**
+ * Abstract base class for generator of Java class versions of Groovy AST classes
+ *
+ * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
+ * @author Russel Winder
+ * @version $Revision$
+ */
+public abstract class ClassGenerator extends ClassCodeVisitorSupport implements Opcodes {
+    protected ClassLoader classLoader;
+    // inner classes created while generating bytecode
+    protected LinkedList innerClasses = new LinkedList();
+
+    public ClassGenerator(ClassLoader classLoader) {
+        this.classLoader = classLoader;
+    }
+    
+    public LinkedList getInnerClasses() {
+        return innerClasses;
+    }
+
+    public ClassLoader getClassLoader() {
+        return classLoader;
+    }
+
+  /**
+   *  A constant that is the ASM representation of the JDK version number for use in the
+   *  <code>ClassWriter.visitor</code> method calls.
+   *
+   *  <p>Prior to version 1.5 of ASM, the code generated was always JDK1.3 compliant.  As of ASM version
+   *  1.5 there is an extra (first) parameter to specify the bytecode version to generate.  In
+   *  version 1.5 these are in Constants.  The CVS (as at 2004.12.12) and presumably in version 2.0,
+   *  the interface Constants is replaced by Opcodes.</p>
+   */
+  public final static int asmJDKVersion = V1_3 ;
+  //  We can use V1_3 and not org.objectweb.asm.Opcodes.V1_3 because this abstract class
+  //  implements org.objectweb.asm.Opcodes so all its constants are available directly.
+  
+  
+  protected SourceUnit getSourceUnit() {
+      return null;
+  }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/ClassGeneratorException.java b/groovy-core/src/main/org/codehaus/groovy/classgen/ClassGeneratorException.java
new file mode 100644
index 0000000..8ebabaf
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/ClassGeneratorException.java
@@ -0,0 +1,64 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.classgen;
+
+/**
+ * An exception thrown by the class generator
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ClassGeneratorException extends RuntimeException {
+
+    public ClassGeneratorException(String message) {
+        super(message);
+    }
+
+    public ClassGeneratorException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/CompileStack.java b/groovy-core/src/main/org/codehaus/groovy/classgen/CompileStack.java
new file mode 100644
index 0000000..5b97854
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/CompileStack.java
@@ -0,0 +1,652 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.VariableScope;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * This class is a helper for AsmClassGenerator. It manages
+ * different aspects of the code of a code block like 
+ * handling labels, defining variables, and scopes. 
+ * After a MethodNode is visited clear should be called, for 
+ * initialization the method init should be used.
+ * <p> 
+ * Some Notes:
+ * <ul>
+ * <li> every push method will require a later pop call
+ * <li> method parameters may define a category 2 variable, so
+ *      don't ignore the type stored in the variable object
+ * <li> the index of the variable may not be as assumed when
+ *      the variable is a parameter of a method because the 
+ *      parameter may be used in a closure, so don't ignore
+ *      the stored variable index
+ * <li> the names of temporary variables can be ignored. The names
+ *      are only used for debugging and do not conflict with each 
+ *      other or normal variables. For accessing the index of the
+ *      variable must be used.
+ * </ul>
+ * 
+ * 
+ * @see org.codehaus.groovy.classgen.AsmClassGenerator
+ * @author Jochen Theodorou
+ */
+public class CompileStack implements Opcodes {
+    /**
+     * @TODO remove optimization of this.foo -> this.@foo
+     * 
+     */
+    
+    // state flag
+    private boolean clear=true;
+    // current scope
+    private VariableScope scope;
+    // current label for continue
+    private Label continueLabel;
+    // current label for break
+    private Label breakLabel;
+    // available variables on stack
+    private HashMap stackVariables = new HashMap();
+    // index of the last variable on stack
+    private int currentVariableIndex = 1;
+    // index for the next variable on stack
+    private int nextVariableIndex = 1;
+    // currently temporary variables in use
+    private LinkedList temporaryVariables = new LinkedList();
+    // overall used variables for a method/constructor
+    private LinkedList usedVariables = new LinkedList();
+    // map containing named labels of parenting blocks
+    private HashMap superBlockNamedLabels = new HashMap();
+    // map containing named labels of current block
+    private HashMap currentBlockNamedLabels = new HashMap();
+    // list containing runnables representing a finally block
+    // such a block is created by synchronized or finally and
+    // must be called for break/continue/return
+    private LinkedList finallyBlocks = new LinkedList();
+    // a list of blocks already visiting. 
+    private List visitedBlocks = new LinkedList();
+    
+    private Label thisStartLabel, thisEndLabel;
+
+    // current class index
+    private int currentClassIndex , currentMetaClassIndex;
+    
+    private MethodVisitor mv;
+    private BytecodeHelper helper;
+    
+    // helper to handle different stack based variables    
+    private LinkedList stateStack = new LinkedList();
+    
+    // defines the first variable index useable after
+    // all parameters of a method 
+    private int localVariableOffset;
+    // this is used to store the goals for a "break foo" call
+    // in a loop where foo is a label.
+	private HashMap namedLoopBreakLabel = new HashMap();
+	//this is used to store the goals for a "continue foo" call
+    // in a loop where foo is a label.
+	private HashMap namedLoopContinueLabel = new HashMap();
+    private String className;
+	
+    private class StateStackElement {
+        VariableScope _scope;
+        Label _continueLabel;
+        Label _breakLabel;
+        Label _finallyLabel;
+        int _lastVariableIndex;
+        int _nextVariableIndex;
+        HashMap _stackVariables;
+        LinkedList _temporaryVariables = new LinkedList();
+        LinkedList _usedVariables = new LinkedList();
+        HashMap _superBlockNamedLabels;
+        HashMap _currentBlockNamedLabels;
+        LinkedList _finallyBlocks;
+        
+        StateStackElement() {
+            _scope = CompileStack.this.scope;
+            _continueLabel = CompileStack.this.continueLabel;
+            _breakLabel = CompileStack.this.breakLabel;
+            _lastVariableIndex = CompileStack.this.currentVariableIndex;
+            _stackVariables = CompileStack.this.stackVariables;
+            _temporaryVariables = CompileStack.this.temporaryVariables;
+            _nextVariableIndex = nextVariableIndex;
+            _superBlockNamedLabels = superBlockNamedLabels;
+            _currentBlockNamedLabels = currentBlockNamedLabels;
+            _finallyBlocks = finallyBlocks;
+        }
+    }
+    
+    private void pushState() {
+        stateStack.add(new StateStackElement());
+        stackVariables = new HashMap(stackVariables);
+        finallyBlocks = new LinkedList(finallyBlocks);
+    }
+    
+    private void popState() {
+        if (stateStack.size()==0) {
+             throw new GroovyBugError("Tried to do a pop on the compile stack without push.");
+        }
+        StateStackElement element = (StateStackElement) stateStack.removeLast();
+        scope = element._scope;
+        continueLabel = element._continueLabel;
+        breakLabel = element._breakLabel;
+        currentVariableIndex = element._lastVariableIndex;
+        stackVariables = element._stackVariables;
+        nextVariableIndex = element._nextVariableIndex;
+        finallyBlocks = element._finallyBlocks;
+    }
+    
+    public Label getContinueLabel() {
+        return continueLabel;
+    }
+
+    public Label getBreakLabel() {
+        return breakLabel;
+    }
+
+    public void removeVar(int tempIndex) {
+        for (Iterator iter = temporaryVariables.iterator(); iter.hasNext();) {
+            Variable element = (Variable) iter.next();
+            if (element.getIndex()==tempIndex) {
+                iter.remove();
+                return;
+            }
+        }
+        throw new GroovyBugError("CompileStack#removeVar: tried to remove a temporary variable with a non existent index");
+    }
+
+    private void setEndLabels(){
+        Label endLabel = new Label();
+        mv.visitLabel(endLabel);
+        for (Iterator iter = stackVariables.values().iterator(); iter.hasNext();) {
+            Variable var = (Variable) iter.next();
+            var.setEndLabel(endLabel);
+        }
+        thisEndLabel = endLabel;
+    }
+    
+    public void pop() {
+        setEndLabels();
+        popState();
+    }
+
+    public VariableScope getScope() {
+        return scope;
+    }
+
+    /**
+     * creates a temporary variable. 
+     * 
+     * @param var defines type and name
+     * @param store defines if the toplevel argument of the stack should be stored
+     * @return the index used for this temporary variable
+     */
+    public int defineTemporaryVariable(org.codehaus.groovy.ast.Variable var, boolean store) {
+        return defineTemporaryVariable(var.getName(), var.getType(),store);
+    }
+
+    public Variable getVariable(String variableName ) {
+        return getVariable(variableName,true);
+    }
+    
+    public Variable getVariable(String variableName, boolean mustExist) {
+        if (variableName.equals("this")) return Variable.THIS_VARIABLE;
+        if (variableName.equals("super")) return Variable.SUPER_VARIABLE;
+        Variable v = (Variable) stackVariables.get(variableName);
+        if (v==null && mustExist)  throw new GroovyBugError("tried to get a variable with the name "+variableName+" as stack variable, but a variable with this name was not created");
+        return v;
+    }
+
+    /**
+     * creates a temporary variable. 
+     * 
+     * @param name defines type and name
+     * @param store defines if the toplevel argument of the stack should be stored
+     * @return the index used for this temporary variable
+     */
+    public int defineTemporaryVariable(String name,boolean store) {
+        return defineTemporaryVariable(name, ClassHelper.DYNAMIC_TYPE,store);
+    }
+
+    /**
+     * creates a temporary variable. 
+     * 
+     * @param name defines the name
+     * @param node defines the node
+     * @param store defines if the toplevel argument of the stack should be stored 
+     * @return the index used for this temporary variable
+     */
+    public int defineTemporaryVariable(String name, ClassNode node, boolean store) {
+        Variable answer = defineVar(name,node,false);
+        temporaryVariables.add(answer);
+        usedVariables.removeLast();
+        
+        if (store) mv.visitVarInsn(ASTORE, currentVariableIndex);
+        
+        return answer.getIndex();
+    }
+    
+    private void resetVariableIndex(boolean isStatic) {
+        if (!isStatic) {
+            currentVariableIndex=1;
+            nextVariableIndex=1;
+        } else {
+            currentVariableIndex=0;
+            nextVariableIndex=0;
+        }
+    }
+  
+    /**
+     * Clears the state of the class. This method should be called 
+     * after a MethodNode is visited. Note that a call to init will
+     * fail if clear is not called before
+     */
+    public void clear() {
+        if (stateStack.size()>1) {
+            int size = stateStack.size()-1;
+            throw new GroovyBugError("the compile stack contains "+size+" more push instruction"+(size==1?"":"s")+" than pops.");
+        }
+        clear = true;
+        // br experiment with local var table so debuggers can retrieve variable names
+        if (true) {//AsmClassGenerator.CREATE_DEBUG_INFO) {
+            if (thisEndLabel==null) setEndLabels();
+            
+            if (!scope.isInStaticContext()) {
+                // write "this"
+                mv.visitLocalVariable("this", className, null, thisStartLabel, thisEndLabel, 0);
+            }
+           
+            for (Iterator iterator = usedVariables.iterator(); iterator.hasNext();) {
+                Variable v = (Variable) iterator.next();
+                String type = BytecodeHelper.getTypeDescription(v.getType());
+                Label start = v.getStartLabel();
+                Label end = v.getEndLabel();
+                mv.visitLocalVariable(v.getName(), type, null, start, end, v.getIndex());
+            }
+        }
+        pop();
+        stackVariables.clear();
+        usedVariables.clear();
+        scope = null;
+        mv=null;
+        resetVariableIndex(false);
+        superBlockNamedLabels.clear();
+        currentBlockNamedLabels.clear();
+        namedLoopBreakLabel.clear();
+        namedLoopContinueLabel.clear();
+        continueLabel=null;
+        breakLabel=null;
+        helper = null;
+        thisStartLabel=null;
+        thisEndLabel=null;
+    }
+    
+    /**
+     * initializes this class for a MethodNode. This method will
+     * automatically define varibales for the method parameters
+     * and will create references if needed. the created variables
+     * can be get by getVariable
+     * 
+     */
+    protected void init(VariableScope el, Parameter[] parameters, MethodVisitor mv, ClassNode cn) {
+        if (!clear) throw new GroovyBugError("CompileStack#init called without calling clear before");
+        clear=false;
+        pushVariableScope(el);
+        this.mv = mv;
+        this.helper = new BytecodeHelper(mv);
+        defineMethodVariables(parameters,el.isInStaticContext());
+        this.className = BytecodeHelper.getTypeDescription(cn);
+        currentClassIndex = -1; currentMetaClassIndex = -1;
+    }
+
+    /**
+     * Causes the statestack to add an element and sets
+     * the given scope as new current variable scope. Creates 
+     * a element for the state stack so pop has to be called later
+     */
+    protected void pushVariableScope(VariableScope el) {
+        pushState();
+        scope = el;
+        superBlockNamedLabels = new HashMap(superBlockNamedLabels);
+        superBlockNamedLabels.putAll(currentBlockNamedLabels);
+        currentBlockNamedLabels = new HashMap();
+    }
+    
+    /**
+     * Should be called when decending into a loop that defines
+     * also a scope. Calls pushVariableScope and prepares labels 
+     * for a loop structure. Creates a element for the state stack
+     * so pop has to be called later 
+     */
+    protected void pushLoop(VariableScope el, String labelName) {
+        pushVariableScope(el);
+        initLoopLabels(labelName);
+    }
+
+    private void initLoopLabels(String labelName) {
+        continueLabel = new Label();
+        breakLabel = new Label();
+        if (labelName!=null) {
+        	namedLoopBreakLabel.put(labelName,breakLabel);
+        	namedLoopContinueLabel.put(labelName,continueLabel);
+        }
+    }
+    
+    /**
+     * Should be called when decending into a loop that does 
+     * not define a scope. Creates a element for the state stack
+     * so pop has to be called later
+     */
+    protected void pushLoop(String labelName) {
+        pushState();
+        initLoopLabels(labelName);
+    }
+    
+    /**
+     * Used for <code>break foo</code> inside a loop to end the
+     * execution of the marked loop. This method will return the
+     * break label of the loop if there is one found for the name.
+     * If not, the current break label is returned.
+     */
+    protected Label getNamedBreakLabel(String name) {
+    	Label label = getBreakLabel();
+    	Label endLabel = null;
+        if (name!=null) endLabel = (Label) namedLoopBreakLabel.get(name);
+    	if (endLabel!=null) label = endLabel;
+        return label;
+    }
+    
+    /**
+     * Used for <code>continue foo</code> inside a loop to continue
+     * the execution of the marked loop. This method will return 
+     * the break label of the loop if there is one found for the 
+     * name. If not, getLabel is used.
+     */
+    protected Label getNamedContinueLabel(String name) {
+    	Label label = getLabel(name);
+    	Label endLabel = null;
+        if (name!=null) endLabel = (Label) namedLoopContinueLabel.get(name);
+    	if (endLabel!=null) label = endLabel;
+        return label;
+    }    
+    
+    /**
+     * Creates a new break label and a element for the state stack
+     * so pop has to be called later
+     */
+    protected Label pushSwitch(){
+        pushState();
+        breakLabel = new Label();
+        return breakLabel;
+    }
+    
+    /**
+     * because a boolean Expression may not be evaluated completly
+     * it is important to keep the registers clean
+     */
+    protected void pushBooleanExpression(){
+        pushState();
+    }
+    
+    private Variable defineVar(String name, ClassNode type, boolean methodParameterUsedInClosure) {
+        makeNextVariableID(type);
+        int index = currentVariableIndex;
+        if (methodParameterUsedInClosure) {
+            index = localVariableOffset++;
+        }
+        Variable answer = new Variable(index, type, name);
+        usedVariables.add(answer);
+        answer.setHolder(methodParameterUsedInClosure);
+        return answer;
+    }
+    
+    private void makeLocalVariablesOffset(Parameter[] paras,boolean isInStaticContext) {
+        resetVariableIndex(isInStaticContext);
+        
+        for (int i = 0; i < paras.length; i++) {
+            makeNextVariableID(paras[i].getType());
+        }
+        localVariableOffset = nextVariableIndex;
+        
+        resetVariableIndex(isInStaticContext);
+    }
+    
+    private void defineMethodVariables(Parameter[] paras,boolean isInStaticContext) {
+        Label startLabel  = new Label();
+        thisStartLabel = startLabel;
+        mv.visitLabel(startLabel);
+        
+        makeLocalVariablesOffset(paras,isInStaticContext);      
+        
+        boolean hasHolder = false;
+        for (int i = 0; i < paras.length; i++) {
+            String name = paras[i].getName();
+            Variable answer;
+            if (paras[i].isClosureSharedVariable()) {
+                answer = defineVar(name, ClassHelper.getWrapper(paras[i].getType()), true);
+                ClassNode type = paras[i].getType();
+                helper.load(type,currentVariableIndex);
+                helper.box(type);
+                createReference(answer);
+                hasHolder = true;
+            } else {
+                answer = defineVar(name,paras[i].getType(),false);
+            }
+            answer.setStartLabel(startLabel);
+            stackVariables.put(name, answer);
+        }
+        
+        if (hasHolder) {
+            nextVariableIndex = localVariableOffset;
+        }
+    }
+
+    private void createReference(Variable reference) {
+        mv.visitTypeInsn(NEW, "groovy/lang/Reference");
+        mv.visitInsn(DUP_X1);
+        mv.visitInsn(SWAP);
+        mv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "(Ljava/lang/Object;)V");
+        mv.visitVarInsn(ASTORE, reference.getIndex());
+    }
+    
+    /**
+     * Defines a new Variable using an AST variable.
+     * @param initFromStack if true the last element of the 
+     *                      stack will be used to initilize
+     *                      the new variable. If false null
+     *                      will be used.
+     */
+    public Variable defineVariable(org.codehaus.groovy.ast.Variable v, boolean initFromStack) {
+        String name = v.getName();
+        Variable answer = defineVar(name,v.getType(),false);
+        if (v.isClosureSharedVariable()) answer.setHolder(true);
+        stackVariables.put(name, answer);
+        
+        Label startLabel  = new Label();
+        answer.setStartLabel(startLabel);
+        if (answer.isHolder())  {
+            if (!initFromStack) mv.visitInsn(ACONST_NULL);
+            createReference(answer);
+        } else {
+            if (!initFromStack) mv.visitInsn(ACONST_NULL);
+            mv.visitVarInsn(ASTORE, currentVariableIndex);            
+        } 
+        mv.visitLabel(startLabel);
+        return answer;
+    }
+
+    /**
+     * Returns true if a varibale is already defined
+     */
+    public boolean containsVariable(String name) {
+        return stackVariables.containsKey(name);
+    }
+    
+    /**
+     * Calculates the index of the next free register stores ir
+     * and sets the current variable index to the old value
+     */
+    private void makeNextVariableID(ClassNode type) {
+        currentVariableIndex = nextVariableIndex;
+        if (type==ClassHelper.long_TYPE || type==ClassHelper.double_TYPE) {
+            nextVariableIndex++;
+        }
+        nextVariableIndex++;
+    }
+    
+    /**
+     * Returns the label for the given name 
+     */
+    public Label getLabel(String name) {
+        if (name==null) return null;
+        Label l = (Label) superBlockNamedLabels.get(name);
+        if (l==null) l = createLocalLabel(name);
+        return l;
+    }
+    
+    /**
+     * creates a new named label
+     */
+    public Label createLocalLabel(String name) {
+        Label l = (Label) currentBlockNamedLabels.get(name);
+        if (l==null) {
+            l = new Label();
+            currentBlockNamedLabels.put(name,l);
+        }
+        return l;
+    }
+    
+    public int getCurrentClassIndex(){
+        return currentClassIndex;
+    }
+    
+    public void setCurrentClassIndex(int index){
+        currentClassIndex=index;
+    }
+    
+    public int getCurrentMetaClassIndex(){
+        return currentMetaClassIndex;
+    }
+    
+    public void setCurrentMetaClassIndex(int index){
+        currentMetaClassIndex=index;
+    }
+
+    public void applyFinallyBlocks(Label label, boolean isBreakLabel) {
+        // first find the state defining the label. That is the state
+        // directly after the state not knowing this label. If no state
+        // in the list knows that label, then the defining state is the
+        // current state.
+        StateStackElement result = null;
+        for (ListIterator iter = stateStack.listIterator(stateStack.size()); iter.hasPrevious();) {
+            StateStackElement element = (StateStackElement) iter.previous();
+            if (!element._currentBlockNamedLabels.values().contains(label)) {
+                if (isBreakLabel && element._breakLabel != label) {
+                    result = element;
+                    break;
+                }
+                if (!isBreakLabel && element._continueLabel != label) {
+                    result = element;
+                    break;
+                }
+            }
+        }
+        
+        List blocksToRemove;
+        if (result==null) {
+            // all Blocks do know the label, so use all finally blocks
+            blocksToRemove = Collections.EMPTY_LIST;
+        } else {
+            blocksToRemove = result._finallyBlocks;
+        }
+        
+        ArrayList blocks = new ArrayList(finallyBlocks);
+        blocks.removeAll(blocksToRemove);
+        applyFinallyBlocks(blocks);
+    }
+
+    private void applyFinallyBlocks(List blocks) {
+        for (Iterator iter = blocks.iterator(); iter.hasNext();) {
+            Runnable block = (Runnable) iter.next();
+            if (visitedBlocks.contains(block)) continue;
+            visitedBlocks.add(block);
+            block.run();
+        }     
+    }
+    
+    public void applyFinallyBlocks() {
+        applyFinallyBlocks(finallyBlocks); 
+    }
+
+    public boolean hasFinallyBlocks() {
+        return !finallyBlocks.isEmpty();
+    }
+
+    public void pushFinallyBlock(Runnable block) {
+        finallyBlocks.addFirst(block);
+        pushState();
+    }
+
+    public void popFinallyBlock() {
+        popState();
+        finallyBlocks.removeFirst();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/DummyClassGenerator.java b/groovy-core/src/main/org/codehaus/groovy/classgen/DummyClassGenerator.java
new file mode 100644
index 0000000..ed951d6
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/DummyClassGenerator.java
@@ -0,0 +1,190 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package org.codehaus.groovy.classgen;
+
+import groovy.lang.GroovyRuntimeException;
+import org.codehaus.groovy.ast.*;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+
+import java.util.*;
+
+/**
+ * To generate a class that has all the fields and methods, except that fields are not initilized
+ * and methods are empty. It's intended for being used as a place holder during code generation
+ * of reference to the "this" class itself.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author <a href="mailto:b55r@sina.com">Bing Ran</a>
+ *
+ * @version $Revision$
+ */
+public class DummyClassGenerator extends ClassGenerator {
+
+    private ClassVisitor cw;
+    private MethodVisitor cv;
+    private GeneratorContext context;
+
+    private String sourceFile;
+
+    // current class details
+    private ClassNode classNode;
+    private String internalClassName;
+    private String internalBaseClassName;
+
+
+    public DummyClassGenerator(
+        GeneratorContext context,
+        ClassVisitor classVisitor,
+        ClassLoader classLoader,
+        String sourceFile) {
+        super(classLoader);
+        this.context = context;
+        this.cw = classVisitor;
+        this.sourceFile = sourceFile;
+    }
+
+    // GroovyClassVisitor interface
+    //-------------------------------------------------------------------------
+    public void visitClass(ClassNode classNode) {
+        try {
+            this.classNode = classNode;
+            this.internalClassName = BytecodeHelper.getClassInternalName(classNode);
+
+            //System.out.println("Generating class: " + classNode.getName());
+
+            this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass());
+
+            cw.visit(
+                asmJDKVersion,
+                classNode.getModifiers(),
+                internalClassName,
+                (String)null,
+                internalBaseClassName,
+                BytecodeHelper.getClassInternalNames(classNode.getInterfaces())
+                );
+
+            classNode.visitContents(this);
+
+            for (Iterator iter = innerClasses.iterator(); iter.hasNext();) {
+                ClassNode innerClass = (ClassNode) iter.next();
+                ClassNode innerClassType = innerClass;
+                String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassType);
+                String outerClassName = internalClassName; // default for inner classes
+                MethodNode enclosingMethod = innerClass.getEnclosingMethod();
+                if (enclosingMethod != null) {
+                    // local inner classes do not specify the outer class name
+                    outerClassName = null;
+                }
+                cw.visitInnerClass(
+                    innerClassInternalName,
+                    outerClassName,
+                    innerClassType.getName(),
+                    innerClass.getModifiers());
+            }
+            cw.visitEnd();
+        }
+        catch (GroovyRuntimeException e) {
+            e.setModule(classNode.getModule());
+            throw e;
+        }
+    }
+
+    public void visitConstructor(ConstructorNode node) {
+
+        visitParameters(node, node.getParameters());
+
+        String methodType = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, node.getParameters());
+        cv = cw.visitMethod(node.getModifiers(), "<init>", methodType, null, null);
+        cv.visitTypeInsn(NEW, "java/lang/RuntimeException");
+        cv.visitInsn(DUP);
+        cv.visitLdcInsn("not intended for execution");
+        cv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V");
+        cv.visitInsn(ATHROW);
+        cv.visitMaxs(0, 0);
+    }
+
+    public void visitMethod(MethodNode node) {
+
+        visitParameters(node, node.getParameters());
+
+        String methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), node.getParameters());
+        cv = cw.visitMethod(node.getModifiers(), node.getName(), methodType, null, null);
+
+        cv.visitTypeInsn(NEW, "java/lang/RuntimeException");
+        cv.visitInsn(DUP);
+        cv.visitLdcInsn("not intended for execution");
+        cv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V");
+        cv.visitInsn(ATHROW);
+
+        cv.visitMaxs(0, 0);
+    }
+
+    public void visitField(FieldNode fieldNode) {
+
+        cw.visitField(
+            fieldNode.getModifiers(),
+            fieldNode.getName(),
+            BytecodeHelper.getTypeDescription(fieldNode.getType()),
+            null, //fieldValue,  //br  all the sudden that one cannot init the field here. init is done in static initilizer and instace intializer.
+            null);
+    }
+
+    /**
+     * Creates a getter, setter and field
+     */
+    public void visitProperty(PropertyNode statement) {
+    }
+    
+    protected CompileUnit getCompileUnit() {
+        CompileUnit answer = classNode.getCompileUnit();
+        if (answer == null) {
+            answer = context.getCompileUnit();
+        }
+        return answer;
+    }
+
+    protected void visitParameters(ASTNode node, Parameter[] parameters) {
+        for (int i = 0, size = parameters.length; i < size; i++ ) {
+            visitParameter(node, parameters[i]);
+        }
+    }
+
+    protected void visitParameter(ASTNode node, Parameter parameter) {
+    }
+
+
+    public void visitAnnotations(AnnotatedNode node) {
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/GeneratorContext.java b/groovy-core/src/main/org/codehaus/groovy/classgen/GeneratorContext.java
new file mode 100644
index 0000000..285c6d3
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/GeneratorContext.java
@@ -0,0 +1,107 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.MethodNode;
+
+
+/**
+ * A context shared across generations of a class and its inner classes
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class GeneratorContext {
+
+    private int innerClassIdx = 1;
+    private CompileUnit compileUnit;
+    
+    public GeneratorContext(CompileUnit compileUnit) {
+        this.compileUnit = compileUnit;
+    }
+
+    public int getNextInnerClassIdx() {
+        return innerClassIdx++;
+    }
+    
+    public CompileUnit getCompileUnit() {
+        return compileUnit;
+    }
+
+    public String getNextClosureInnerName(ClassNode owner, ClassNode enclosingClass, MethodNode enclosingMethod) {
+        String ownerShortName = owner.getNameWithoutPackage();
+        String classShortName = enclosingClass.getNameWithoutPackage();
+        if (classShortName.equals(ownerShortName)) {
+            classShortName = "";
+        }
+        else {
+            classShortName += "_";
+        }
+        // remove $
+        int dp = classShortName.lastIndexOf("$");
+        if (dp >= 0) {
+            classShortName = classShortName.substring(++dp);
+        }
+        // remove leading _
+        if (classShortName.startsWith("_")) {
+            classShortName = classShortName.substring(1);
+        }
+        String methodName = "";
+        if (enclosingMethod != null) {
+            methodName = enclosingMethod.getName() + "_";
+
+            if (enclosingClass.isDerivedFrom(ClassHelper.CLOSURE_TYPE)) {
+                methodName = "";
+            }
+            methodName = methodName.replace('<', '_');
+            methodName = methodName.replace('>', '_');
+        }
+        return "_" + classShortName + methodName + "closure" + getNextInnerClassIdx();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/MethodCaller.java b/groovy-core/src/main/org/codehaus/groovy/classgen/MethodCaller.java
new file mode 100644
index 0000000..f4d50b0
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/MethodCaller.java
@@ -0,0 +1,110 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.classgen;
+
+import java.lang.reflect.Method;
+
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * A helper class to invoke methods more easily in ASM
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MethodCaller implements Opcodes {
+
+    private int opcode;
+    private String internalName;
+    private String name;
+    private Class theClass;
+    private String methodDescriptor;
+
+    public static MethodCaller newStatic(Class theClass, String name) {
+        return new MethodCaller(INVOKESTATIC, theClass, name);
+    }
+
+    public static MethodCaller newInterface(Class theClass, String name) {
+        return new MethodCaller(INVOKEINTERFACE, theClass, name);
+    }
+
+    public static MethodCaller newVirtual(Class theClass, String name) {
+        return new MethodCaller(INVOKEVIRTUAL, theClass, name);
+    }
+
+    public MethodCaller(int opcode, Class theClass, String name) {
+        this.opcode = opcode;
+        this.internalName = Type.getInternalName(theClass);
+        this.theClass = theClass;
+        this.name = name;
+
+    }
+
+    public void call(MethodVisitor methodVisitor) {
+        methodVisitor.visitMethodInsn(opcode, internalName, name, getMethodDescriptor());
+    }
+
+    public String getMethodDescriptor() {
+        if (methodDescriptor == null) {
+            Method method = getMethod();
+            methodDescriptor = Type.getMethodDescriptor(method);
+        }
+        return methodDescriptor;
+    }
+
+    protected Method getMethod() {
+        Method[] methods = theClass.getMethods();
+        for (int i = 0; i < methods.length; i++) {
+            Method method = methods[i];
+            if (method.getName().equals(name)) {
+                return method;
+            }
+        }
+        throw new ClassGeneratorException("Could not find method: " + name + " on class: " + theClass);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/MethodCallerMultiAdapter.java b/groovy-core/src/main/org/codehaus/groovy/classgen/MethodCallerMultiAdapter.java
new file mode 100644
index 0000000..b7e4668
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/MethodCallerMultiAdapter.java
@@ -0,0 +1,72 @@
+/*

+ * InvokeMethodAdapter.java created on 14.09.2006

+ *

+ * To change this generated comment go to 

+ * Window>Preferences>Java>Code Generation>Code and Comments

+ */

+package org.codehaus.groovy.classgen;

+

+import org.objectweb.asm.MethodVisitor;

+

+public class MethodCallerMultiAdapter {

+    private MethodCaller[] methods;

+    boolean skipSpreadSafeAndSafe;

+    

+    public final static int maxArgs = 0;

+    

+    public static MethodCallerMultiAdapter newStatic(Class theClass, String baseName, boolean createNArgs, boolean skipSpreadSafeAndSafe) {

+        MethodCallerMultiAdapter mcma = new MethodCallerMultiAdapter();

+        mcma.skipSpreadSafeAndSafe = skipSpreadSafeAndSafe;

+        if (createNArgs) {

+            int numberOfBaseMethods = mcma.numberOfBaseMethods();

+            mcma.methods = new MethodCaller[(maxArgs+2)*numberOfBaseMethods];

+            for (int i=0; i<=maxArgs; i++) {

+                mcma.methods[i*numberOfBaseMethods] = MethodCaller.newStatic(theClass,baseName+i);

+                if (skipSpreadSafeAndSafe) continue;

+                mcma.methods[i*numberOfBaseMethods+1] = MethodCaller.newStatic(theClass,baseName+i+"Safe");

+                mcma.methods[i*numberOfBaseMethods+2] = MethodCaller.newStatic(theClass,baseName+i+"SpreadSafe");

+            }

+            mcma.methods[(maxArgs+1)*numberOfBaseMethods] = MethodCaller.newStatic(theClass,baseName+"N");

+            if (!skipSpreadSafeAndSafe) {

+                mcma.methods[(maxArgs+1)*numberOfBaseMethods+1] = MethodCaller.newStatic(theClass,baseName+"N"+"Safe");

+                mcma.methods[(maxArgs+1)*numberOfBaseMethods+2] = MethodCaller.newStatic(theClass,baseName+"N"+"SpreadSafe");

+            }

+            

+        } else if (!skipSpreadSafeAndSafe) {

+            mcma.methods = new MethodCaller[]{

+                    MethodCaller.newStatic(theClass,baseName),

+                    MethodCaller.newStatic(theClass,baseName+"Safe"),

+                    MethodCaller.newStatic(theClass,baseName+"SpreadSafe")

+            };

+        } else {

+            mcma.methods = new MethodCaller[]{

+                    MethodCaller.newStatic(theClass,baseName)

+            };

+        }

+        return mcma;

+    }

+    

+    /**

+     * 

+     * @param methodVisitor

+     * @param numberOfArguments a value >0 describing how many arguments are additionally used for the method call

+     * @param safe

+     * @param spreadSafe

+     */

+    public void call(MethodVisitor methodVisitor, int numberOfArguments, boolean safe, boolean spreadSafe) {

+        int offset = 0;

+        if (safe && !skipSpreadSafeAndSafe) offset = 1;

+        if (spreadSafe && !skipSpreadSafeAndSafe) offset = 2;

+        if (numberOfArguments>maxArgs || numberOfArguments<0){

+            offset += (maxArgs+1)*numberOfBaseMethods();

+        } else {

+            offset += numberOfArguments*numberOfBaseMethods();

+        }

+        methods[offset].call(methodVisitor);

+    }

+    

+    private int numberOfBaseMethods(){

+        if (skipSpreadSafeAndSafe) return 1;

+        return 3;

+    }

+}
\ No newline at end of file
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/ReflectorGenerator.java b/groovy-core/src/main/org/codehaus/groovy/classgen/ReflectorGenerator.java
new file mode 100644
index 0000000..84947a9
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/ReflectorGenerator.java
@@ -0,0 +1,284 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.classgen;
+
+import groovy.lang.MetaMethod;
+
+import java.util.List;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Label;
+
+/**
+ * Code generates a Reflector 
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ReflectorGenerator implements Opcodes {
+
+    private List methods;
+    private ClassVisitor cw;
+    private MethodVisitor cv;
+    private BytecodeHelper helper = new BytecodeHelper(null);
+    private String classInternalName;
+
+    public ReflectorGenerator(List methods) {
+        this.methods = methods;
+    }
+
+    public void generate(ClassVisitor cw, String className) {
+        this.cw = cw;
+
+        classInternalName = BytecodeHelper.getClassInternalName(className);
+        cw.visit(ClassGenerator.asmJDKVersion, ACC_PUBLIC + ACC_SUPER, classInternalName, (String)null, "org/codehaus/groovy/runtime/Reflector", null);
+
+        cv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+        cv.visitVarInsn(ALOAD, 0);
+        cv.visitMethodInsn(INVOKESPECIAL, "org/codehaus/groovy/runtime/Reflector", "<init>", "()V");
+        cv.visitInsn(RETURN);
+        cv.visitMaxs(1, 1);
+
+        generateInvokeMethod();
+
+        cw.visitEnd();
+    }
+
+    protected void generateInvokeMethod() {
+        int methodCount = methods.size();
+
+        cv =
+            cw.visitMethod(
+                ACC_PUBLIC,
+                "invoke",
+                "(Lgroovy/lang/MetaMethod;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;",
+                null,
+                null);
+        helper = new BytecodeHelper(cv);
+
+        cv.visitVarInsn(ALOAD, 1);
+        cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/MetaMethod", "getMethodIndex", "()I");
+        Label defaultLabel = new Label();
+        Label[] labels = new Label[methodCount];
+        int[] indices = new int[methodCount];
+        for (int i = 0; i < methodCount; i++) {
+            labels[i] = new Label();
+
+            MetaMethod method = (MetaMethod) methods.get(i);
+            method.setMethodIndex(i + 1);
+            indices[i] = method.getMethodIndex();
+
+            //System.out.println("Index: " + method.getMethodIndex() + " for: " + method);
+        }
+
+        cv.visitLookupSwitchInsn(defaultLabel, indices, labels);
+        //cv.visitTableSwitchInsn(minMethodIndex, maxMethodIndex, defaultLabel, labels);
+
+        for (int i = 0; i < methodCount; i++) {
+            cv.visitLabel(labels[i]);
+
+            MetaMethod method = (MetaMethod) methods.get(i);
+            invokeMethod(method);
+            if (method.getReturnType() == void.class) {
+                cv.visitInsn(ACONST_NULL);
+            }
+            cv.visitInsn(ARETURN);
+        }
+
+        cv.visitLabel(defaultLabel);
+        cv.visitVarInsn(ALOAD, 0);
+        cv.visitVarInsn(ALOAD, 1);
+        cv.visitVarInsn(ALOAD, 2);
+        cv.visitVarInsn(ALOAD, 3);
+        cv.visitMethodInsn(
+            INVOKEVIRTUAL,
+            classInternalName,
+            "noSuchMethod",
+            "(Lgroovy/lang/MetaMethod;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
+        cv.visitInsn(ARETURN);
+        cv.visitMaxs(4, 4);
+    }
+
+    protected void invokeMethod(MetaMethod method) {
+        /** simple
+        cv.visitVarInsn(ALOAD, 2);
+        cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
+        */
+        Class callClass = method.getInterfaceClass();
+        boolean useInterface = false;
+        if (callClass == null) {
+            callClass = method.getCallClass();
+        }
+        else {
+            useInterface = true;
+        }
+        String type = BytecodeHelper.getClassInternalName(callClass.getName());
+        String descriptor = BytecodeHelper.getMethodDescriptor(method.getReturnType(), method.getParameterTypes());
+
+        //        System.out.println("Method: " + method);
+        //        System.out.println("Descriptor: " + descriptor);
+
+        if (method.isStatic()) {
+            loadParameters(method, 3);
+            cv.visitMethodInsn(INVOKESTATIC, type, method.getName(), descriptor);
+        }
+        else {
+            cv.visitVarInsn(ALOAD, 2);
+            helper.doCast(callClass);
+            loadParameters(method, 3);
+            cv.visitMethodInsn((useInterface) ? INVOKEINTERFACE : INVOKEVIRTUAL, type, method.getName(), descriptor);
+        }
+
+        helper.box(method.getReturnType());
+    }
+
+    /*
+    protected void generateInvokeSuperMethod() {
+        List superMethods = new ArrayList(methods);
+        for (Iterator iter = methods.iterator(); iter.hasNext();) {
+            MetaMethod method = (MetaMethod) iter.next();
+            if (!validSuperMethod(method)) {
+                superMethods.remove(method);
+            }
+        }
+        int methodCount = superMethods.size();
+        if (methodCount == 0) {
+            return;
+        }
+        cv =
+            cw.visitMethod(
+                ACC_PUBLIC,
+                "invokeSuper",
+                "(Lgroovy/lang/MetaMethod;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;",
+                null,
+                null);
+        helper = new BytecodeHelper(cv);
+
+        cv.visitVarInsn(ALOAD, 1);
+        cv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/MetaMethod", "getMethodIndex", "()I");
+        Label defaultLabel = new Label();
+        Label[] labels = new Label[methodCount];
+        int[] indices = new int[methodCount];
+        for (int i = 0; i < methodCount; i++) {
+            labels[i] = new Label();
+
+            MetaMethod method = (MetaMethod) superMethods.get(i);
+            method.setMethodIndex(i + 1);
+            indices[i] = method.getMethodIndex();
+
+            //System.out.println("Index: " + method.getMethodIndex() + " for: " + method);
+        }
+
+        cv.visitLookupSwitchInsn(defaultLabel, indices, labels);
+        //cv.visitTableSwitchInsn(minMethodIndex, maxMethodIndex, defaultLabel, labels);
+
+        for (int i = 0; i < methodCount; i++) {
+            MetaMethod method = (MetaMethod) superMethods.get(i);
+            cv.visitLabel(labels[i]);
+
+            invokeSuperMethod(method);
+            if (method.getReturnType() == void.class) {
+                cv.visitInsn(ACONST_NULL);
+            }
+            cv.visitInsn(ARETURN);
+        }
+
+        cv.visitLabel(defaultLabel);
+        cv.visitVarInsn(ALOAD, 0);
+        cv.visitVarInsn(ALOAD, 1);
+        cv.visitVarInsn(ALOAD, 2);
+        cv.visitVarInsn(ALOAD, 3);
+        cv.visitMethodInsn(
+            INVOKEVIRTUAL,
+            classInternalName,
+            "noSuchMethod",
+            "(Lgroovy/lang/MetaMethod;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
+        cv.visitInsn(ARETURN);
+        cv.visitMaxs(4, 4);
+    }
+
+    protected boolean validSuperMethod(MetaMethod method) {
+        return !method.isStatic() && (method.getModifiers() & (Modifier.FINAL | Modifier.ABSTRACT)) == 0 && theClass == method.getDeclaringClass();
+    }
+
+    protected void invokeSuperMethod(MetaMethod method) {
+        Class ownerClass = method.getDeclaringClass();
+        String type = helper.getClassInternalName(ownerClass.getName());
+        String descriptor = helper.getMethodDescriptor(method.getReturnType(), method.getParameterTypes());
+
+//        System.out.println("Method: " + method.getName());
+//        System.out.println("Descriptor: " + descriptor);
+
+        cv.visitVarInsn(ALOAD, 2);
+        //helper.doCast(ownerClass);
+        loadParameters(method, 3);
+        cv.visitMethodInsn(INVOKESPECIAL, type, method.getName(), descriptor);
+
+        helper.box(method.getReturnType());
+    }
+*/
+    
+    protected void loadParameters(MetaMethod method, int argumentIndex) {
+        Class[] parameters = method.getParameterTypes();
+        int size = parameters.length;
+        for (int i = 0; i < size; i++) {
+            cv.visitVarInsn(ALOAD, argumentIndex);
+            helper.pushConstant(i);
+            cv.visitInsn(AALOAD);
+
+            // we should cast to something
+            Class type = parameters[i];
+            if (type.isPrimitive()) {
+                helper.unbox(type);
+            }
+            else {
+                helper.doCast(type);
+            }
+        }
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/RuntimeIncompleteClassException.java b/groovy-core/src/main/org/codehaus/groovy/classgen/RuntimeIncompleteClassException.java
new file mode 100644
index 0000000..8e733c9
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/RuntimeIncompleteClassException.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2004 IBM Corporation and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ * IBM - Initial API and implementation
+ ******************************************************************************/
+
+
+package org.codehaus.groovy.classgen;
+
+import java.util.List;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.syntax.RuntimeParserException;
+
+
+/**
+ * RuntimeIncompleteClassException
+ * 
+ */
+public class RuntimeIncompleteClassException extends RuntimeParserException {
+
+    /**
+     * @param a_classnames
+     * @param a_node
+     */
+    public RuntimeIncompleteClassException(List a_classnames, ASTNode a_node) {
+        super("Incomplete class: does not implement abstract methods: " + a_classnames, a_node);
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/Variable.java b/groovy-core/src/main/org/codehaus/groovy/classgen/Variable.java
new file mode 100644
index 0000000..77edfc3
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/Variable.java
@@ -0,0 +1,160 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.objectweb.asm.Label;
+
+
+/**
+ * Represents compile time variable metadata while compiling a method.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class Variable {
+    
+    public static Variable THIS_VARIABLE = new Variable();
+    public static Variable SUPER_VARIABLE = new Variable();
+
+    private int index;
+    private ClassNode type;
+    private String name;
+    private boolean holder;
+    private boolean property;
+
+    // br for setting on the LocalVariableTable in the class file
+    // these fields should probably go to jvm Operand class
+    private Label startLabel = null;
+    private Label endLabel = null;
+    private boolean dynamicTyped;
+
+    private Variable(){
+        dynamicTyped = true;
+        index=0;
+        holder=false;
+        property=false;
+    }
+    
+    public Variable(int index, ClassNode type, String name) {
+        this.index = index;
+        this.type = type;
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public ClassNode getType() {
+        return type;
+    }
+    
+    public String getTypeName() {
+        return type.getName();
+    }
+
+    /**
+     * @return the stack index for this variable
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * @return is this local variable shared in other scopes (and so must use a ValueHolder)
+     */
+    public boolean isHolder() {
+        return holder;
+    }
+
+    public void setHolder(boolean holder) {
+        this.holder = holder;
+    }
+
+    public boolean isProperty() {
+        return property;
+    }
+
+    public void setProperty(boolean property) {
+        this.property = property;
+    }
+    
+    public Label getStartLabel() {
+        return startLabel;
+    }
+
+    public void setStartLabel(Label startLabel) {
+        this.startLabel = startLabel;
+    }
+
+    public Label getEndLabel() {
+        return endLabel;
+    }
+
+    public void setEndLabel(Label endLabel) {
+        this.endLabel = endLabel;
+    }
+
+    public String toString() {
+        // TODO Auto-generated method stub
+        return super.toString() + "[" + type + " " + name + " (" + index + ")";
+    }
+
+    public void setType(ClassNode type) {
+        this.type = type;
+        dynamicTyped |= type==ClassHelper.DYNAMIC_TYPE;
+    }
+
+    public void setDynamicTyped(boolean b) {
+        dynamicTyped = b;
+    }
+    
+    public boolean isDynamicTyped() {
+        return dynamicTyped;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/VariableScopeVisitor.java b/groovy-core/src/main/org/codehaus/groovy/classgen/VariableScopeVisitor.java
new file mode 100644
index 0000000..80d5976
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/VariableScopeVisitor.java
@@ -0,0 +1,467 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.classgen;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.DynamicVariable;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.control.SourceUnit;
+
+/**
+ * goes through an AST and initializes the scopes 
+ * @author Jochen Theodorou
+ */
+public class VariableScopeVisitor extends ClassCodeVisitorSupport {
+    private VariableScope currentScope = null;
+    private VariableScope headScope = new VariableScope();
+    private ClassNode currentClass=null;
+    private SourceUnit source;
+    private boolean inClosure=false;
+    
+    private LinkedList stateStack=new LinkedList();
+    
+    private class StateStackElement {
+        VariableScope scope;
+        ClassNode clazz;
+        boolean dynamic;
+        boolean closure;
+        
+        StateStackElement() {
+            scope = VariableScopeVisitor.this.currentScope;
+            clazz = VariableScopeVisitor.this.currentClass;
+            closure = VariableScopeVisitor.this.inClosure;
+        }
+    }
+    
+    public VariableScopeVisitor(SourceUnit source) {
+        this.source = source;
+        currentScope  = headScope;
+    }
+    
+    
+    // ------------------------------
+    // helper methods   
+    //------------------------------
+    
+    private void pushState(boolean isStatic) {
+        stateStack.add(new StateStackElement());
+        currentScope = new VariableScope(currentScope);
+        currentScope.setInStaticContext(isStatic);
+    }
+    
+    private void pushState() {
+        pushState(currentScope.isInStaticContext());
+    }
+    
+    private void popState() {
+        // a scope in a closure is never really static
+        // the checking needs this to be as the surrounding
+        // method to correctly check the access to variables.
+        // But a closure and all nested scopes are a result
+        // of calling a non static method, so the context
+        // is not static.
+        if (inClosure) currentScope.setInStaticContext(false);
+        
+        StateStackElement element = (StateStackElement) stateStack.removeLast();
+        currentScope = element.scope;
+        currentClass = element.clazz;
+        inClosure = element.closure;
+    }
+    
+    private void declare(Parameter[] parameters, ASTNode node) {
+        for (int i = 0; i < parameters.length; i++) {
+            if (parameters[i].hasInitialExpression()) {
+                parameters[i].getInitialExpression().visit(this);
+            }
+            declare(parameters[i],node);
+        }
+    }        
+    
+    private void declare(VariableExpression expr) {
+        declare(expr,expr);
+    }
+    
+    private void declare(Variable var, ASTNode expr) {
+        String scopeType = "scope";
+        String variableType = "variable";
+        
+        if (expr.getClass()==FieldNode.class){
+            scopeType = "class"; 
+            variableType = "field";
+        } else if (expr.getClass()==PropertyNode.class){
+            scopeType = "class"; 
+            variableType = "property";
+        }
+        
+        StringBuffer msg = new StringBuffer();
+        msg.append("The current ").append(scopeType);
+        msg.append(" does already contain a ").append(variableType);
+        msg.append(" of the name ").append(var.getName());
+        
+        if (currentScope.getDeclaredVariable(var.getName())!=null) {
+            addError(msg.toString(),expr);
+            return;
+        }
+        
+        for (VariableScope scope = currentScope.getParent(); scope!=null; scope = scope.getParent()) {
+            // if we are in a class and no variable is declared until
+            // now, then we can break the loop, because we are allowed
+            // to declare a variable of the same name as a class member
+            if (scope.getClassScope()!=null) break;
+            
+            Map declares = scope.getDeclaredVariables();
+            if (declares.get(var.getName())!=null) {
+                // variable already declared
+                addError(msg.toString(), expr);
+                break;
+            }
+        }
+        // declare the variable even if there was an error to allow more checks
+        currentScope.getDeclaredVariables().put(var.getName(),var);
+    }
+    
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+    
+    private Variable findClassMember(ClassNode cn, String name) {
+        if (cn == null) return null;
+        if (cn.isScript()) {
+            return new DynamicVariable(name,false);
+        }
+        List l = cn.getFields();
+        for (Iterator iter = l.iterator(); iter.hasNext();) {
+            FieldNode f = (FieldNode) iter.next();
+            if (f.getName().equals(name)) return f;
+        }
+
+        l = cn.getMethods();
+        for (Iterator iter = l.iterator(); iter.hasNext();) {
+            MethodNode f =(MethodNode) iter.next();
+            String methodName = f.getName();
+            String pName = getPropertyName(f);
+            if (pName == null) continue; 
+            if (!pName.equals(name)) continue;
+            PropertyNode var = new PropertyNode(pName,f.getModifiers(),getPropertyType(f),cn,null,null,null);
+            return var;
+        }
+
+        l = cn.getProperties();
+        for (Iterator iter = l.iterator(); iter.hasNext();) {
+            PropertyNode f = (PropertyNode) iter.next();
+            if (f.getName().equals(name)) return f;
+        }
+        
+        Variable ret = findClassMember(cn.getSuperClass(),name);
+        if (ret!=null) return ret;
+        return findClassMember(cn.getOuterClass(),name); 
+    }
+    
+    private ClassNode getPropertyType(MethodNode m) {
+        String name = m.getName();
+        if (m.getReturnType()!=ClassHelper.VOID_TYPE) {
+            return m.getReturnType();
+        }
+        return m.getParameters()[0].getType();
+    }
+
+    private String getPropertyName(MethodNode m) {
+        String name = m.getName();
+        if (!(name.startsWith("set") || name.startsWith("get"))) return null;
+        String pname = name.substring(3);
+        if (pname.length() == 0) return null;
+        String s = pname.substring(0, 1).toLowerCase();
+        String rest = pname.substring(1);
+        pname = s + rest;
+        
+        if (name.startsWith("get") && m.getReturnType()==ClassHelper.VOID_TYPE) {
+            return null;
+        }
+        if (name.startsWith("set") && m.getParameters().length!=1) {
+            return null;
+        }
+        return pname;
+    }     
+    
+    // -------------------------------
+    // different Variable based checks  
+    // -------------------------------
+    
+    private Variable checkVariableNameForDeclaration(String name, Expression expression) {
+        if ("super".equals(name) || "this".equals(name)) return null;
+
+        VariableScope scope = currentScope;
+        Variable var = new DynamicVariable(name,currentScope.isInStaticContext());
+        Variable dummyStart = var;
+        // try to find a declaration of a variable
+        VariableScope dynamicScope = null;
+        while (!scope.isRoot()) {
+            if (dynamicScope==null && scope.isResolvingDynamic()) {
+                dynamicScope = scope;
+            }
+            
+            Map declares = scope.getDeclaredVariables();
+            if (declares.get(var.getName())!=null) {
+                var = (Variable) declares.get(var.getName());
+                break;
+            }
+            Map localReferenced = scope.getReferencedLocalVariables(); 
+            if (localReferenced.get(var.getName())!=null) {
+                var = (Variable) localReferenced.get(var.getName());
+                break;
+            }
+
+            Map classReferenced = scope.getReferencedClassVariables(); 
+            if (classReferenced.get(var.getName())!=null) {
+                var = (Variable) classReferenced.get(var.getName());
+                break;
+            }
+            
+            ClassNode classScope = scope.getClassScope();
+            if (classScope!=null) {
+                Variable member = findClassMember(classScope,var.getName());
+                if (member!=null && (currentScope.isInStaticContext() ^ member instanceof DynamicVariable)) var = member;
+                break;
+            }            
+            scope = scope.getParent();
+        }
+
+        VariableScope end = scope;
+
+        if (scope.isRoot() && dynamicScope==null) {
+            // no matching scope found
+            declare(var,expression);
+            addError("The variable " + var.getName() +
+                     " is undefined in the current scope", expression);
+        } else if (scope.isRoot() && dynamicScope!=null) {
+            // no matching scope found, but there was a scope that
+            // resolves dynamic
+            scope = dynamicScope;
+        } 
+        
+        if (!scope.isRoot()) {
+            scope = currentScope;
+            while (scope != end) {
+                Map references = null;
+                if (end.isClassScope() || end.isRoot() || 
+                        (end.isReferencedClassVariable(name) && end.getDeclaredVariable(name)==null)) 
+                {
+                    references = scope.getReferencedClassVariables();
+                } else {
+                    references = scope.getReferencedLocalVariables();
+                    var.setClosureSharedVariable(var.isClosureSharedVariable() || inClosure);
+                }
+                references.put(var.getName(),var);
+                scope = scope.getParent();
+            }
+            if (end.isResolvingDynamic()) {
+                if (end.getDeclaredVariable(var.getName())==null) {
+                    end.getDeclaredVariables().put(var.getName(),var);
+                }
+            }
+        }
+        
+        return var;
+    }
+    
+    private void checkVariableContextAccess(Variable v, Expression expr) {
+        if (v.isInStaticContext() || !currentScope.isInStaticContext()) return;        
+        
+        String msg =  v.getName()+
+                      " is declared in a dynamic context, but you tried to"+
+                      " access it from a static context.";
+        addError(msg,expr);
+        
+        // declare a static variable to be able to continue the check
+        DynamicVariable v2 = new DynamicVariable(v.getName(),currentScope.isInStaticContext());
+        currentScope.getDeclaredVariables().put(v.getName(),v2);
+    }
+    
+    // ------------------------------
+    // code visit  
+    // ------------------------------
+    
+    public void visitBlockStatement(BlockStatement block) {
+        pushState();
+        block.setVariableScope(currentScope);
+        super.visitBlockStatement(block);
+        popState();
+    }
+    
+    public void visitForLoop(ForStatement forLoop) {
+        pushState();
+        forLoop.setVariableScope(currentScope);
+        Parameter p = (Parameter) forLoop.getVariable();
+        p.setInStaticContext(currentScope.isInStaticContext());
+        declare(p, forLoop);        
+        super.visitForLoop(forLoop);
+        popState();
+    }
+
+    public void visitDeclarationExpression(DeclarationExpression expression) {
+        // visit right side first to avoid the usage of a 
+        // variable before its declaration
+        expression.getRightExpression().visit(this);
+        // no need to visit left side, just get the variable name
+        VariableExpression vex = expression.getVariableExpression();
+        vex.setInStaticContext(currentScope.isInStaticContext());
+        declare(vex);
+        vex.setAccessedVariable(vex);
+    }
+    
+    public void visitVariableExpression(VariableExpression expression) {
+        String name = expression.getName();
+        Variable v = checkVariableNameForDeclaration(name,expression);
+        if (v==null) return;
+        expression.setAccessedVariable(v);
+        checkVariableContextAccess(v,expression);
+    }
+    
+    public void visitClosureExpression(ClosureExpression expression) {
+        pushState();
+
+        inClosure=true;
+        // as result of the Paris meeting Closure resolves
+        // always dynamically
+        currentScope.setDynamicResolving(true);
+        
+        expression.setVariableScope(currentScope);
+
+        if (expression.isParameterSpecified()) {
+            Parameter[] parameters = expression.getParameters();
+            for (int i = 0; i < parameters.length; i++) {
+                parameters[i].setInStaticContext(currentScope.isInStaticContext());
+                declare(parameters[i],expression);
+            }
+        } else if (expression.getParameters()!=null){
+            DynamicVariable var = new DynamicVariable("it",currentScope.isInStaticContext());
+            currentScope.getDeclaredVariables().put("it",var);
+        }
+
+        super.visitClosureExpression(expression);
+        popState();
+    }
+    
+    public void visitCatchStatement(CatchStatement statement) {
+        pushState();
+        Parameter p = (Parameter) statement.getVariable();
+        p.setInStaticContext(currentScope.isInStaticContext());
+        declare(p, statement);
+        super.visitCatchStatement(statement);
+        popState();
+    }
+    
+    public void visitFieldExpression(FieldExpression expression) {
+        String name = expression.getFieldName();
+        //TODO: change that to get the correct scope
+        Variable v = checkVariableNameForDeclaration(name,expression);
+        checkVariableContextAccess(v,expression);  
+    }
+    
+    // ------------------------------
+    // class visit  
+    // ------------------------------
+    
+    public void visitClass(ClassNode node) {
+        pushState();
+        boolean dynamicMode = node.isScript();
+        currentScope.setDynamicResolving(dynamicMode);
+        currentScope.setClassScope(node);
+        
+        super.visitClass(node);
+        popState();
+    }
+
+    protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
+        pushState(node.isStatic());
+        
+        node.setVariableScope(currentScope);
+        declare(node.getParameters(),node);
+        
+        super.visitConstructorOrMethod(node, isConstructor);
+        popState();
+    }
+    
+    public void visitMethodCallExpression(MethodCallExpression call) {
+    	if (call.isImplicitThis() && call.getMethod() instanceof ConstantExpression) {
+            Object value = ((ConstantExpression) call.getMethod()).getText();
+            if (! (value instanceof String)) {
+                throw new GroovyBugError("tried to make a method call with an constant as"+
+                                         " name, but the constant was no String.");
+            }
+            String methodName = (String) value;
+	        Variable v = checkVariableNameForDeclaration(methodName,call);
+	        if (v!=null && !(v instanceof DynamicVariable)) {
+	            checkVariableContextAccess(v,call);
+	        }
+    	}
+        super.visitMethodCallExpression(call);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/Verifier.java b/groovy-core/src/main/org/codehaus/groovy/classgen/Verifier.java
new file mode 100644
index 0000000..0edbd0a
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/Verifier.java
@@ -0,0 +1,627 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.classgen;
+
+import groovy.lang.GroovyObject;
+import groovy.lang.MetaClass;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GroovyClassVisitor;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.EmptyStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
+import org.codehaus.groovy.syntax.Types;
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.RuntimeParserException;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Verifies the AST node and adds any defaulted AST code before
+ * bytecode generation occurs.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class Verifier implements GroovyClassVisitor, Opcodes {
+
+    public static final String __TIMESTAMP = "__timeStamp";
+	private ClassNode classNode;
+    private MethodNode methodNode;
+
+    public ClassNode getClassNode() {
+        return classNode;
+    }
+
+    public MethodNode getMethodNode() {
+        return methodNode;
+    }
+
+    /**
+     * add code to implement GroovyObject
+     * @param node
+     */
+    public void visitClass(ClassNode node) {
+        this.classNode = node;
+                
+        if ((classNode.getModifiers() & Opcodes.ACC_INTERFACE) >0) {
+            //interfaces have no construcotrs, but this code expects one, 
+            //so creta a dummy and don't add it to the class node
+            ConstructorNode dummy = new ConstructorNode(0,null);
+            addInitialization(node, dummy);
+            node.visitContents(this);
+            return;
+        }
+        
+        addDefaultParameterMethods(node);
+        addDefaultParameterConstructors(node);
+
+        if (!node.isDerivedFromGroovyObject()) {
+            node.addInterface(ClassHelper.make(GroovyObject.class));
+
+            // lets add a new field for the metaclass
+            StaticMethodCallExpression initMetaClassCall =
+                new StaticMethodCallExpression(
+                    ClassHelper.make(ScriptBytecodeAdapter.class),
+                    "initMetaClass",
+                    VariableExpression.THIS_EXPRESSION);
+
+            PropertyNode metaClassProperty =
+                node.addProperty("metaClass", ACC_PUBLIC, ClassHelper.make(MetaClass.class), initMetaClassCall, null, null);
+            metaClassProperty.setSynthetic(true);
+            FieldNode metaClassField = metaClassProperty.getField();
+            metaClassField.setModifiers(metaClassField.getModifiers() | ACC_TRANSIENT);
+
+            FieldExpression metaClassVar = new FieldExpression(metaClassField);
+            IfStatement initMetaClassField =
+                new IfStatement(
+                    new BooleanExpression(
+                        new BinaryExpression(metaClassVar, Token.newSymbol( Types.COMPARE_EQUAL, -1, -1), ConstantExpression.NULL)),
+                    new ExpressionStatement(new BinaryExpression(metaClassVar, Token.newSymbol( Types.EQUAL, -1, -1), initMetaClassCall)),
+                    EmptyStatement.INSTANCE);
+
+            node.addSyntheticMethod(
+                "getMetaClass",
+                ACC_PUBLIC,
+                ClassHelper.make(MetaClass.class),
+                Parameter.EMPTY_ARRAY,
+                ClassNode.EMPTY_ARRAY,
+                new BlockStatement(new Statement[] { initMetaClassField, new ReturnStatement(metaClassVar)}, new VariableScope())
+            );
+
+            // @todo we should check if the base class implements the invokeMethod method
+
+            // lets add the invokeMethod implementation
+            ClassNode superClass = node.getSuperClass();
+            boolean addDelegateObject =
+                (node instanceof InnerClassNode && superClass.equals(ClassHelper.CLOSURE_TYPE))
+                    || superClass.equals(ClassHelper.GSTRING_TYPE);
+
+            // don't do anything as the base class implements the invokeMethod
+            if (!addDelegateObject) {
+                
+                VariableExpression vMethods = new VariableExpression("method");
+                VariableExpression vArguments = new VariableExpression("arguments");
+                VariableScope blockScope = new VariableScope();
+                blockScope.getReferencedLocalVariables().put("method",vMethods);
+                blockScope.getReferencedLocalVariables().put("arguments",vArguments);
+                
+                node.addSyntheticMethod(
+                    "invokeMethod",
+                    ACC_PUBLIC,
+                    ClassHelper.OBJECT_TYPE,
+                    new Parameter[] {
+                        new Parameter(ClassHelper.STRING_TYPE, "method"),
+                        new Parameter(ClassHelper.OBJECT_TYPE, "arguments")
+                    },
+                    ClassNode.EMPTY_ARRAY,    
+                    new BlockStatement(
+                        new Statement[] {
+                            initMetaClassField,
+                            new ReturnStatement(
+                                new MethodCallExpression(
+                                    metaClassVar,
+                                    "invokeMethod",
+                                    new ArgumentListExpression(
+                                        new Expression[] {
+                                            VariableExpression.THIS_EXPRESSION,
+                                            vMethods,
+                                            vArguments}
+                                        )
+                                    )
+                                )
+                        },
+                        blockScope
+                    )
+                );
+                
+
+                if (!node.isScript()) {
+                    node.addSyntheticMethod(
+                        "getProperty",
+                        ACC_PUBLIC,
+                        ClassHelper.OBJECT_TYPE,
+                        new Parameter[] { new Parameter(ClassHelper.STRING_TYPE, "property")},
+                        ClassNode.EMPTY_ARRAY,
+                        new BlockStatement(
+                            new Statement[] {
+                                initMetaClassField,
+                                new ReturnStatement(
+                                    new MethodCallExpression(
+                                        metaClassVar,
+                                        "getProperty",
+                                        new ArgumentListExpression(
+                                            new Expression[] {
+                                                VariableExpression.THIS_EXPRESSION,
+                                                new VariableExpression("property")})))
+                            },
+                            new VariableScope()
+                        ));
+                    VariableExpression vProp = new VariableExpression("property");
+                    VariableExpression vValue = new VariableExpression("value");
+                    blockScope = new VariableScope();
+                    blockScope.getReferencedLocalVariables().put("property",vProp);
+                    blockScope.getReferencedLocalVariables().put("value",vValue);
+                    
+                    node.addSyntheticMethod(
+                        "setProperty",
+                        ACC_PUBLIC,
+                        ClassHelper.VOID_TYPE,
+                        new Parameter[] {
+                            new Parameter(ClassHelper.STRING_TYPE, "property"),
+                            new Parameter(ClassHelper.OBJECT_TYPE, "value")
+                        },
+                        ClassNode.EMPTY_ARRAY,
+                        new BlockStatement(
+                            new Statement[] {
+                                initMetaClassField,
+                                new ExpressionStatement(
+                                    new MethodCallExpression(
+                                        metaClassVar,
+                                        "setProperty",
+                                        new ArgumentListExpression(
+                                            new Expression[] {
+                                                VariableExpression.THIS_EXPRESSION,
+                                                vProp,
+                                                vValue})))
+                            },
+                            blockScope
+                    ));
+                }
+            }
+        }
+
+        if (node.getDeclaredConstructors().isEmpty()) {
+            ConstructorNode constructor = new ConstructorNode(ACC_PUBLIC, null);
+            constructor.setSynthetic(true);
+            node.addConstructor(constructor);
+        }
+        
+        if (!(node instanceof InnerClassNode)) {// add a static timestamp field to the class
+            FieldNode timeTagField = new FieldNode(
+                    Verifier.__TIMESTAMP,
+                    Modifier.PUBLIC | Modifier.STATIC,
+                    ClassHelper.Long_TYPE,
+                    //"",
+                    node,
+                    new ConstantExpression(new Long(System.currentTimeMillis())));
+            // alternatively , FieldNode timeTagField = SourceUnit.createFieldNode("public static final long __timeStamp = " + System.currentTimeMillis() + "L");
+            timeTagField.setSynthetic(true);
+            node.addField(timeTagField);
+        }
+        
+        addInitialization(node);
+        node.getObjectInitializerStatements().clear();
+        node.visitContents(this);
+    }
+    public void visitConstructor(ConstructorNode node) {
+        CodeVisitorSupport checkSuper = new CodeVisitorSupport() {
+            boolean firstMethodCall = true;
+            String type=null;
+            public void visitMethodCallExpression(MethodCallExpression call) {
+                if (!firstMethodCall) return;
+                firstMethodCall = false;
+                String name = call.getMethodAsString();
+                if (!name.equals("super") && !name.equals("this")) return;
+                type=name;
+                call.getArguments().visit(this);
+                type=null;
+            }
+            public void visitVariableExpression(VariableExpression expression) {
+                if (type==null) return;
+                String name = expression.getName();
+                if (!name.equals("this") && !name.equals("super")) return;
+                throw new RuntimeParserException("cannot reference "+name+" inside of "+type+"(....) before supertype constructor has been called",expression);
+            }            
+        };
+        Statement s = node.getCode();
+        //todo why can a statement can be null?
+        if (s == null) return;
+        s.visit(checkSuper);
+    }
+
+    public void visitMethod(MethodNode node) {
+        this.methodNode = node;
+        Statement statement = node.getCode();
+        if (!node.isVoidMethod()) {
+            if (statement instanceof ExpressionStatement) {
+                ExpressionStatement expStmt = (ExpressionStatement) statement;
+                node.setCode(new ReturnStatement(expStmt.getExpression()));
+            }
+            else if (statement instanceof BlockStatement) {
+                BlockStatement block = (BlockStatement) statement;
+
+                // lets copy the list so we create a new block
+                List list = new ArrayList(block.getStatements());
+                if (!list.isEmpty()) {
+                    int idx = list.size() - 1;
+                    Statement last = (Statement) list.get(idx);
+                    if (last instanceof ExpressionStatement) {
+                        ExpressionStatement expStmt = (ExpressionStatement) last;
+                        list.set(idx, new ReturnStatement(expStmt));
+                    }
+                    else if (!(last instanceof ReturnStatement)) {
+                        list.add(new ReturnStatement(ConstantExpression.NULL));
+                    }
+                }
+                else {
+                    list.add(new ReturnStatement(ConstantExpression.NULL));
+                }
+
+                node.setCode(new BlockStatement(filterStatements(list),block.getVariableScope()));
+            }
+        }
+        else if (!node.isAbstract()) {
+        	BlockStatement newBlock = new BlockStatement();
+            if (statement instanceof BlockStatement) {
+                newBlock.addStatements(filterStatements(((BlockStatement)statement).getStatements()));
+            }
+            else {
+                newBlock.addStatement(filterStatement(statement));
+            }
+            newBlock.addStatement(ReturnStatement.RETURN_NULL_OR_VOID);
+            node.setCode(newBlock);
+        }
+        if (node.getName().equals("main") && node.isStatic()) {
+            Parameter[] params = node.getParameters();
+            if (params.length == 1) {
+                Parameter param = params[0];
+                if (param.getType() == null || param.getType()==ClassHelper.OBJECT_TYPE) {
+                    param.setType(ClassHelper.STRING_TYPE.makeArray());
+                }
+            }
+        }
+        statement = node.getCode();
+        if (statement!=null) statement.visit(new VerifierCodeVisitor(this));
+    }
+
+    public void visitField(FieldNode node) {
+    }
+
+    public void visitProperty(PropertyNode node) {
+        String name = node.getName();
+        FieldNode field = node.getField();
+
+        String getterName = "get" + capitalize(name);
+        String setterName = "set" + capitalize(name);
+
+        Statement getterBlock = node.getGetterBlock();
+        if (getterBlock == null) {
+            if (!node.isPrivate() && classNode.getGetterMethod(getterName) == null) {
+                getterBlock = createGetterBlock(node, field);
+            }
+        }
+        Statement setterBlock = node.getSetterBlock();
+        if (setterBlock == null) {
+            if (!node.isPrivate() && (node.getModifiers()&ACC_FINAL)==0 && classNode.getSetterMethod(setterName) == null) {
+                setterBlock = createSetterBlock(node, field);
+            }
+        }
+
+        if (getterBlock != null) {
+            MethodNode getter =
+                new MethodNode(getterName, node.getModifiers(), node.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, getterBlock);
+            getter.setSynthetic(true);
+            classNode.addMethod(getter);
+            visitMethod(getter);
+
+            if (ClassHelper.boolean_TYPE==node.getType() || ClassHelper.Boolean_TYPE==node.getType()) {
+                String secondGetterName = "is" + capitalize(name);
+                MethodNode secondGetter =
+                    new MethodNode(secondGetterName, node.getModifiers(), node.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, getterBlock);
+                secondGetter.setSynthetic(true);
+                classNode.addMethod(secondGetter);
+                visitMethod(secondGetter);
+            }
+        }
+        if (setterBlock != null) {
+            Parameter[] setterParameterTypes = { new Parameter(node.getType(), "value")};
+            MethodNode setter =
+                new MethodNode(setterName, node.getModifiers(), ClassHelper.VOID_TYPE, setterParameterTypes, ClassNode.EMPTY_ARRAY, setterBlock);
+            setter.setSynthetic(true);
+            classNode.addMethod(setter);
+            visitMethod(setter);
+        }
+    }
+
+    // Implementation methods
+    //-------------------------------------------------------------------------
+    
+    private interface DefaultArgsAction {
+        public void call(ArgumentListExpression arguments, Parameter[] newParams, MethodNode method);
+    }
+    
+    /**
+     * Creates a new helper method for each combination of default parameter expressions 
+     */
+    protected void addDefaultParameterMethods(final ClassNode node) {
+        List methods = new ArrayList(node.getMethods());
+        addDefaultParameters(methods, new DefaultArgsAction(){
+            public void call(ArgumentListExpression arguments, Parameter[] newParams, MethodNode method) {
+                MethodCallExpression expression = new MethodCallExpression(VariableExpression.THIS_EXPRESSION, method.getName(), arguments);
+                expression.setImplicitThis(true);
+                Statement code = null;
+                if (method.isVoidMethod()) {
+                    code = new ExpressionStatement(expression);
+                } else {
+                    code = new ReturnStatement(expression);
+                }
+                node.addMethod(method.getName(), method.getModifiers(), method.getReturnType(), newParams, method.getExceptions(), code);
+            }
+        });
+    }
+    
+    protected void addDefaultParameterConstructors(final ClassNode node) {
+        List methods = new ArrayList(node.getDeclaredConstructors());
+        addDefaultParameters(methods, new DefaultArgsAction(){
+            public void call(ArgumentListExpression arguments, Parameter[] newParams, MethodNode method) {
+                ConstructorNode ctor = (ConstructorNode) method;
+                ConstructorCallExpression expression = new ConstructorCallExpression(ClassNode.THIS, arguments);
+                Statement code = new ExpressionStatement(expression);
+                node.addConstructor(ctor.getModifiers(), newParams, ctor.getExceptions(), code);
+            }
+        });
+    }
+
+    /**
+     * Creates a new helper method for each combination of default parameter expressions 
+     */
+    protected void addDefaultParameters(List methods, DefaultArgsAction action) {
+        for (Iterator iter = methods.iterator(); iter.hasNext();) {
+            MethodNode method = (MethodNode) iter.next();
+            if (method.hasDefaultValue()) {
+                Parameter[] parameters = method.getParameters();
+                int counter = 0;
+                ArrayList paramValues = new ArrayList();
+                int size = parameters.length;
+                for (int i = size - 1; i >= 0; i--) {
+                    Parameter parameter = parameters[i];
+                    if (parameter != null && parameter.hasInitialExpression()) {
+                        paramValues.add(new Integer(i));
+                        paramValues.add(parameter.getInitialExpression());
+                        counter++;
+                    }
+                }
+
+                for (int j = 1; j <= counter; j++) {
+                    Parameter[] newParams =  new Parameter[parameters.length - j];
+                    ArgumentListExpression arguments = new ArgumentListExpression();
+                    int index = 0;
+                    int k = 1;
+                    for (int i = 0; i < parameters.length; i++) {
+                        if (k > counter - j && parameters[i] != null && parameters[i].hasInitialExpression()) {
+                            arguments.addExpression(parameters[i].getInitialExpression());
+                            k++;
+                        }
+                        else if (parameters[i] != null && parameters[i].hasInitialExpression()) {
+                            newParams[index++] = parameters[i];
+                            arguments.addExpression(new VariableExpression(parameters[i].getName()));
+                            k++;
+                        }
+                        else {
+                            newParams[index++] = parameters[i];
+                            arguments.addExpression(new VariableExpression(parameters[i].getName()));
+                        }
+                    }
+                    action.call(arguments,newParams,method);
+                }
+            }
+        }
+    }
+
+    protected void addClosureCode(InnerClassNode node) {
+        // add a new invoke
+    }
+
+    protected void addInitialization(ClassNode node) {
+        for (Iterator iter = node.getDeclaredConstructors().iterator(); iter.hasNext();) {
+            addInitialization(node, (ConstructorNode) iter.next());
+        }
+    }
+
+    protected void addInitialization(ClassNode node, ConstructorNode constructorNode) {
+        Statement firstStatement = constructorNode.getFirstStatement();
+        ConstructorCallExpression first = getFirstIfSpecialConstructorCall(firstStatement);
+        
+        // in case of this(...) let the other constructor do the intit
+        if (first!=null && first.isThisCall()) return;
+        
+        List statements = new ArrayList();
+        List staticStatements = new ArrayList();
+        for (Iterator iter = node.getFields().iterator(); iter.hasNext();) {
+            addFieldInitialization(statements, staticStatements, (FieldNode) iter.next());
+        }
+        statements.addAll(node.getObjectInitializerStatements());
+        if (!statements.isEmpty()) {
+            Statement code = constructorNode.getCode();
+            BlockStatement block = new BlockStatement();
+            List otherStatements = block.getStatements();
+            if (code instanceof BlockStatement) {
+                block = (BlockStatement) code;
+                otherStatements=block.getStatements();
+            }
+            else if (code != null) {
+                otherStatements.add(code);
+            }
+            if (!otherStatements.isEmpty()) {
+                if (first!=null) {
+                    // it is super(..) since this(..) is already covered
+                    otherStatements.remove(0);
+                    statements.add(0, firstStatement);
+                } 
+                statements.addAll(otherStatements);
+            }
+            constructorNode.setCode(new BlockStatement(statements, block.getVariableScope()));
+        }
+
+        if (!staticStatements.isEmpty()) {
+            node.addStaticInitializerStatements(staticStatements,true);
+        }
+    }
+
+    private ConstructorCallExpression getFirstIfSpecialConstructorCall(Statement code) {
+        if (code == null || !(code instanceof ExpressionStatement)) return null;
+
+        Expression expression = ((ExpressionStatement)code).getExpression();
+        if (!(expression instanceof ConstructorCallExpression)) return null;
+        ConstructorCallExpression cce = (ConstructorCallExpression) expression;
+        if (cce.isSpecialCall()) return cce;
+        return null;
+    }
+
+    protected void addFieldInitialization(
+        List list,
+        List staticList,
+        FieldNode fieldNode) {
+        Expression expression = fieldNode.getInitialExpression();
+        if (expression != null) {
+            ExpressionStatement statement =
+                new ExpressionStatement(
+                    new BinaryExpression(
+                        new FieldExpression(fieldNode),
+                        Token.newSymbol(Types.EQUAL, fieldNode.getLineNumber(), fieldNode.getColumnNumber()),
+                        expression));
+            if (fieldNode.isStatic()) {
+                staticList.add(statement);
+            }
+            else {
+                list.add(statement);
+            }
+        }
+    }
+
+    /**
+     * Capitalizes the start of the given bean property name
+     */
+    public static String capitalize(String name) {
+        return name.substring(0, 1).toUpperCase() + name.substring(1, name.length());
+    }
+
+    protected Statement createGetterBlock(PropertyNode propertyNode, FieldNode field) {
+        Expression expression = new FieldExpression(field);
+        return new ReturnStatement(expression);
+    }
+
+    protected Statement createSetterBlock(PropertyNode propertyNode, FieldNode field) {
+        Expression expression = new FieldExpression(field);
+        return new ExpressionStatement(
+            new BinaryExpression(expression, Token.newSymbol(Types.EQUAL, 0, 0), new VariableExpression("value")));
+    }
+
+    /**
+     * Filters the given statements
+     */
+    protected List filterStatements(List list) {
+        List answer = new ArrayList(list.size());
+        for (Iterator iter = list.iterator(); iter.hasNext();) {
+            answer.add(filterStatement((Statement) iter.next()));
+        }
+        return answer;
+    }
+
+    protected Statement filterStatement(Statement statement) {
+        if (statement instanceof ExpressionStatement) {
+            ExpressionStatement expStmt = (ExpressionStatement) statement;
+            Expression expression = expStmt.getExpression();
+            if (expression instanceof ClosureExpression) {
+                ClosureExpression closureExp = (ClosureExpression) expression;
+                if (!closureExp.isParameterSpecified()) {
+                    return closureExp.getCode();
+                }
+            }
+        }
+        return statement;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/VerifierCodeVisitor.java b/groovy-core/src/main/org/codehaus/groovy/classgen/VerifierCodeVisitor.java
new file mode 100644
index 0000000..6b5cb51
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/VerifierCodeVisitor.java
@@ -0,0 +1,150 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.classgen;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.MapEntryExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.syntax.RuntimeParserException;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Verifies the method code
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class VerifierCodeVisitor extends CodeVisitorSupport implements Opcodes {
+
+    private Verifier verifier;
+
+    VerifierCodeVisitor(Verifier verifier) {
+        this.verifier = verifier;
+    }
+
+    public void visitMethodCallExpression(MethodCallExpression call) {
+        super.visitMethodCallExpression(call);
+    }
+
+    public void visitForLoop(ForStatement expression) {
+        assertValidIdentifier(expression.getVariable().getName(), "for loop variable name", expression);
+        super.visitForLoop(expression);
+    }
+
+    public void visitPropertyExpression(PropertyExpression expression) {
+        // assertValidIdentifier(expression.getProperty(), "property name", expression);  // This has been commented out to fix the issue Groovy-843
+        super.visitPropertyExpression(expression);
+    }
+
+    public void visitFieldExpression(FieldExpression expression) {
+        assertValidIdentifier(expression.getFieldName(), "field name", expression);
+        super.visitFieldExpression(expression);
+    }
+
+    public void visitVariableExpression(VariableExpression expression) {
+        assertValidIdentifier(expression.getName(), "variable name", expression);
+        super.visitVariableExpression(expression);
+    }
+
+    public void visitBinaryExpression(BinaryExpression expression) {
+        /*
+        if (verifier.getClassNode().isScript() && expression.getOperation().getType() == Token.EQUAL) {
+            // lets turn variable assignments into property assignments
+            Expression left = expression.getLeftExpression();
+            if (left instanceof VariableExpression) {
+                VariableExpression varExp = (VariableExpression) left;
+
+                //System.out.println("Converting variable expression: " + varExp.getVariable());
+
+                PropertyExpression propExp =
+                    new PropertyExpression(VariableExpression.THIS_EXPRESSION, varExp.getVariable());
+                expression.setLeftExpression(propExp);
+            }
+        }
+        */
+        super.visitBinaryExpression(expression);
+    }
+
+    public static void assertValidIdentifier(String name, String message, ASTNode node) {
+        int size = name.length();
+        if (size <= 0) {
+            throw new RuntimeParserException("Invalid " + message + ". Identifier must not be empty", node);
+        }
+        char firstCh = name.charAt(0);
+        if (!Character.isJavaIdentifierStart(firstCh) || firstCh == '$') {
+            throw new RuntimeParserException("Invalid " + message + ". Must start with a letter but was: " + name, node);
+        }
+
+        for (int i = 1; i < size; i++) {
+            char ch = name.charAt(i);
+            if (!Character.isJavaIdentifierPart(ch)) {
+                throw new RuntimeParserException("Invalid " + message + ". Invalid character at position: " + (i + 1) + " of value:  " + ch + " in name: " + name, node);
+            }
+        }
+    }
+    
+    public void visitListExpression(ListExpression expression) {
+        List expressions = expression.getExpressions();
+        for (Iterator iter = expressions.iterator(); iter.hasNext();) {
+            Object element = iter.next();
+            if (element instanceof MapEntryExpression) {
+                throw new RuntimeParserException ("no map entry allowed at this place",(Expression) element);
+            }
+        }
+        super.visitListExpression(expression);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/classgen/package.html b/groovy-core/src/main/org/codehaus/groovy/classgen/package.html
new file mode 100644
index 0000000..2069221
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/classgen/package.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>package org.codehaus.groovy.classgen.*</title>
+  </head>
+  <body>
+    <p>Generates Java classes for Groovy classes using ASM.</p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/CompilationFailedException.java b/groovy-core/src/main/org/codehaus/groovy/control/CompilationFailedException.java
new file mode 100644
index 0000000..afea7bf
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/CompilationFailedException.java
@@ -0,0 +1,110 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+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>
+ * @version $Id$
+ */
+
+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;
+    }
+
+}
+
+
+
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/CompilationUnit.java b/groovy-core/src/main/org/codehaus/groovy/control/CompilationUnit.java
new file mode 100644
index 0000000..0e69aa7
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/CompilationUnit.java
@@ -0,0 +1,1011 @@
+/*
+ $Id$
+
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+package org.codehaus.groovy.control;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.CodeSource;
+import java.util.*;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.classgen.ClassCompletionVerifier;
+import org.codehaus.groovy.classgen.ClassGenerator;
+import org.codehaus.groovy.classgen.GeneratorContext;
+import org.codehaus.groovy.classgen.VariableScopeVisitor;
+import org.codehaus.groovy.classgen.Verifier;
+import org.codehaus.groovy.control.io.InputStreamReaderSource;
+import org.codehaus.groovy.control.io.ReaderSource;
+import org.codehaus.groovy.control.messages.ExceptionMessage;
+import org.codehaus.groovy.control.messages.Message;
+import org.codehaus.groovy.control.messages.SimpleMessage;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.codehaus.groovy.syntax.ClassSource;
+import org.codehaus.groovy.syntax.SourceSummary;
+import org.codehaus.groovy.tools.GroovyClass;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyRuntimeException;
+
+/**
+ * Collects all compilation data as it is generated by the compiler system.
+ * Allows additional source units to be added and compilation run again (to
+ * affect only the deltas).
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * @version $Id$
+ */
+
+public class CompilationUnit extends ProcessingUnit {
+
+
+    //---------------------------------------------------------------------------
+    // CONSTRUCTION AND SUCH
+
+
+    protected HashMap sources;    // The SourceUnits from which this unit is built
+    protected Map summariesBySourceName;      // Summary of each SourceUnit
+    protected Map summariesByPublicClassName;       // Summary of each SourceUnit
+    protected Map classSourcesByPublicClassName;    // Summary of each Class
+    protected ArrayList names;      // Names for each SourceUnit in sources.
+    protected LinkedList queuedSources;
+    
+    
+    protected CompileUnit ast;        // The overall AST for this CompilationUnit.
+    protected ArrayList generatedClasses;    // The classes generated during classgen.
+
+
+    protected Verifier verifier;   // For use by verify().
+
+    
+    protected boolean debug;      // Controls behaviour of classgen() and other routines.
+    protected boolean configured; // Set true after the first configure() operation
+
+
+    protected ClassgenCallback classgenCallback;  // A callback for use during classgen()
+    protected ProgressCallback progressCallback;  // A callback for use during compile()
+    protected ResolveVisitor resolveVisitor;
+
+    LinkedList[] phaseOperations;
+    
+
+    /**
+     * Initializes the CompilationUnit with defaults.
+     */
+    public CompilationUnit() {
+        this(null, null, null);
+    }
+
+
+
+    /**
+     * Initializes the CompilationUnit with defaults except for class loader.
+     */
+    public CompilationUnit(GroovyClassLoader loader) {
+        this(null, null, loader);
+    }
+
+
+
+    /**
+     * Initializes the CompilationUnit with no security considerations.
+     */
+    public CompilationUnit(CompilerConfiguration configuration) {
+        this(configuration, null, null);
+    }
+
+    /**
+     * Initializes the CompilationUnit with a CodeSource for controlling
+     * security stuff and a class loader for loading classes.
+     */
+    public CompilationUnit(CompilerConfiguration configuration, CodeSource security, GroovyClassLoader loader) {
+        super(configuration, loader, null);
+        this.names = new ArrayList();
+        this.queuedSources = new LinkedList();
+        this.sources = new HashMap();
+        this.summariesBySourceName = new HashMap();
+        this.summariesByPublicClassName = new HashMap();
+        this.classSourcesByPublicClassName = new HashMap();
+        
+        this.ast = new CompileUnit(this.classLoader, security, this.configuration);
+        this.generatedClasses = new ArrayList();
+
+
+        this.verifier = new Verifier();
+        this.resolveVisitor = new ResolveVisitor(this);
+        
+        phaseOperations = new LinkedList[Phases.ALL+1];
+        for (int i=0; i<phaseOperations.length; i++) {
+            phaseOperations[i] = new LinkedList();
+        }
+        addPhaseOperation(new SourceUnitOperation() {
+            public void call(SourceUnit source) throws CompilationFailedException {
+                source.parse();
+            }
+        }, Phases.PARSING);
+        addPhaseOperation(summarize, Phases.PARSING);
+        addPhaseOperation(convert,   Phases.CONVERSION);
+        addPhaseOperation(resolve,   Phases.SEMANTIC_ANALYSIS);
+        addPhaseOperation(compileCompleteCheck, Phases.CANONICALIZATION);
+        addPhaseOperation(classgen,  Phases.CLASS_GENERATION);
+        addPhaseOperation(output);
+        
+        this.classgenCallback = null;
+    }
+    
+    
+    
+    
+    
+    public void addPhaseOperation(SourceUnitOperation op, int phase) {
+        if (phase<0 || phase>Phases.ALL) throw new IllegalArgumentException("phase "+phase+" is unknown");
+        phaseOperations[phase].add(op);
+    }
+    
+    public void addPhaseOperation(PrimaryClassNodeOperation op, int phase) {
+        if (phase<0 || phase>Phases.ALL) throw new IllegalArgumentException("phase "+phase+" is unknown");
+        phaseOperations[phase].add(op);        
+    }
+    
+    public void addPhaseOperation(GroovyClassOperation op) {
+        phaseOperations[Phases.OUTPUT].addFirst(op);
+    }
+    
+
+    /**
+     * Configures its debugging mode and classloader classpath from a given compiler configuration.
+     * This cannot be done more than once due to limitations in {@link java.net.URLClassLoader URLClassLoader}.
+     */
+    public void configure(CompilerConfiguration configuration) {
+        super.configure(configuration);
+        this.debug = configuration.getDebug();
+
+        if (!this.configured && this.classLoader instanceof GroovyClassLoader) {
+            appendCompilerConfigurationClasspathToClassLoader(configuration, (GroovyClassLoader) this.classLoader);
+        }
+
+        this.configured = true;
+    }
+
+    private void appendCompilerConfigurationClasspathToClassLoader(CompilerConfiguration configuration, GroovyClassLoader classLoader) {
+        /*for (Iterator iterator = configuration.getClasspath().iterator(); iterator.hasNext(); ) {
+            classLoader.addClasspath((String) iterator.next());
+        }*/
+    }
+
+    /**
+     * Returns the CompileUnit that roots our AST.
+     */
+    public CompileUnit getAST() {
+        return this.ast;
+    }
+
+    /**
+     * Get the source summaries
+     */
+    public Map getSummariesBySourceName() {
+        return summariesBySourceName;
+    }
+    public Map getSummariesByPublicClassName() {
+        return summariesByPublicClassName;
+    }
+    public Map getClassSourcesByPublicClassName() {
+        return classSourcesByPublicClassName;
+    }
+
+    public boolean isPublicClass(String className) {
+        return summariesByPublicClassName.containsKey(className);
+    }
+    
+    
+    /**
+     * Get the GroovyClasses generated by compile().
+     */
+    public List getClasses() {
+        return generatedClasses;
+    }
+
+
+    /**
+     * Convenience routine to get the first ClassNode, for
+     * when you are sure there is only one.
+     */
+    public ClassNode getFirstClassNode() {
+        return (ClassNode) ((ModuleNode) this.ast.getModules().get(0)).getClasses().get(0);
+    }
+
+
+    /**
+     * Convenience routine to get the named ClassNode.
+     */
+    public ClassNode getClassNode(final String name) {
+        final ClassNode[] result = new ClassNode[]{null};
+        PrimaryClassNodeOperation handler = new PrimaryClassNodeOperation() {
+            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
+                if (classNode.getName().equals(name)) {
+                    result[0] = classNode;
+                }
+            }
+        };
+
+        try {
+            applyToPrimaryClassNodes(handler);
+        } catch (CompilationFailedException e) {
+            if (debug) e.printStackTrace();
+        }
+        return result[0];
+    }
+
+
+
+
+
+    //---------------------------------------------------------------------------
+    // SOURCE CREATION
+
+
+    /**
+     * Adds a set of file paths to the unit.
+     */
+    public void addSources(String[] paths) {
+        for (int i = 0; i < paths.length; i++) {
+            File file = new File(paths[i]);
+            addSource(file);
+        }
+    }
+
+
+    /**
+     * Adds a set of source files to the unit.
+     */
+    public void addSources(File[] files) {
+        for (int i = 0; i < files.length; i++) {
+            addSource(files[i]);
+        }
+    }
+
+
+    /**
+     * Adds a source file to the unit.
+     */
+    public SourceUnit addSource(File file) {
+        return addSource(new SourceUnit(file, configuration, classLoader, getErrorCollector()));
+    }
+    
+    /**
+     * Adds a source file to the unit.
+     */
+    public SourceUnit addSource(URL url) {
+        return addSource(new SourceUnit(url, configuration, classLoader,getErrorCollector()));
+    }
+
+
+    /**
+     * Adds a InputStream source to the unit.
+     */
+    public SourceUnit addSource(String name, InputStream stream) {
+        ReaderSource source = new InputStreamReaderSource(stream, configuration);
+        return addSource(new SourceUnit(name, source, configuration, classLoader, getErrorCollector()));
+    }
+
+
+    /**
+     * Adds a SourceUnit to the unit.
+     */
+    public SourceUnit addSource(SourceUnit source) {
+        String name = source.getName();
+        source.setClassLoader(this.classLoader);
+        for (Iterator iter = queuedSources.iterator(); iter.hasNext();) {
+			SourceUnit su = (SourceUnit) iter.next();
+			if (name.equals(su.getName())) return su;
+		}
+        queuedSources.add(source);
+        return source;
+    }
+
+
+    /**
+     * Returns an iterator on the unit's SourceUnits.
+     */
+    public Iterator iterator() {
+        return new Iterator() {
+            Iterator nameIterator = names.iterator();
+
+
+            public boolean hasNext() {
+                return nameIterator.hasNext();
+            }
+
+
+            public Object next() {
+                String name = (String) nameIterator.next();
+                return sources.get(name);
+            }
+
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+
+    /**
+     * Adds a ClassNode directly to the unit (ie. without source).
+     * WARNING: the source is needed for error reporting, using
+     *          this method without setting a SourceUnit will cause
+     *          NullPinterExceptions
+     */
+    public void addClassNode(ClassNode node) {
+        ModuleNode module = new ModuleNode(this.ast);
+        this.ast.addModule(module);
+        module.addClass(node);
+    }
+
+
+    //---------------------------------------------------------------------------
+    // EXTERNAL CALLBACKS
+
+
+    /**
+     * A callback interface you can use to "accompany" the classgen()
+     * code as it traverses the ClassNode tree.  You will be called-back
+     * for each primary and inner class.  Use setClassgenCallback() before
+     * running compile() to set your callback.
+     */
+    public static abstract class ClassgenCallback {
+        public abstract void call(ClassVisitor writer, ClassNode node) throws CompilationFailedException;
+    }
+
+
+    /**
+     * Sets a ClassgenCallback.  You can have only one, and setting
+     * it to null removes any existing setting.
+     */
+    public void setClassgenCallback(ClassgenCallback visitor) {
+        this.classgenCallback = visitor;
+    }
+
+
+    /**
+     * A callback interface you can use to get a callback after every
+     * unit of the compile process.  You will be called-back with a
+     * ProcessingUnit and a phase indicator.  Use setProgressCallback()
+     * before running compile() to set your callback.
+     */
+    public static abstract class ProgressCallback {
+
+        public abstract void call(ProcessingUnit context, int phase) throws CompilationFailedException;
+    }
+
+    /**
+     * Sets a ProgressCallback.  You can have only one, and setting
+     * it to null removes any existing setting.
+     */
+    public void setProgressCallback(ProgressCallback callback) {
+        this.progressCallback = callback;
+    }
+
+
+    //---------------------------------------------------------------------------
+    // ACTIONS
+
+
+    /**
+     * Synonym for compile(Phases.ALL).
+     */
+    public void compile() throws CompilationFailedException {
+        compile(Phases.ALL);
+    }
+
+    /**
+     * Compiles the compilation unit from sources.
+     */
+    public void compile(int throughPhase) throws CompilationFailedException {
+        //
+        // To support delta compilations, we always restart
+        // the compiler.  The individual passes are responsible
+        // for not reprocessing old code.
+        gotoPhase(Phases.INITIALIZATION);
+        throughPhase = Math.min(throughPhase,Phases.ALL);
+
+        while (throughPhase >= phase && phase <= Phases.ALL) {
+            
+            for (Iterator it = phaseOperations[phase].iterator(); it.hasNext();) {
+                Object operation = it.next();
+                if (operation instanceof PrimaryClassNodeOperation) {
+                    applyToPrimaryClassNodes((PrimaryClassNodeOperation) operation);
+                } else if (operation instanceof SourceUnitOperation) {
+                    applyToSourceUnits((SourceUnitOperation)operation);
+                } else {
+                    applyToGeneratedGroovyClasses((GroovyClassOperation)operation);
+                }
+            }
+            
+            if (dequeued()) continue;
+           
+            if (progressCallback != null) progressCallback.call(this, phase);
+            completePhase();
+            applyToSourceUnits(mark);
+            
+            gotoPhase(phase+1);
+            
+            if (phase==Phases.CLASS_GENERATION) {
+                sortClasses();
+            }
+        }
+            
+        errorCollector.failIfErrors();
+    }
+    
+    private void sortClasses() throws CompilationFailedException {
+        Iterator modules = this.ast.getModules().iterator();
+        while (modules.hasNext()) {
+            ModuleNode module = (ModuleNode) modules.next();
+            
+            // before we actually do the sorting we should check
+            // for cyclic references
+            List classes = module.getClasses();
+            for (Iterator iter = classes.iterator(); iter.hasNext();) {
+                ClassNode start = (ClassNode) iter.next();
+                ClassNode cn = start;
+                HashSet parents = new HashSet();
+                do {
+                    if (parents.contains(cn.getName())) {
+                        getErrorCollector().addErrorAndContinue(
+                                new SimpleMessage("cyclic inheritance involving "+cn.getName()+" in class "+start.getName(),this)
+                        );
+                        cn=null;
+                    } else {
+                        parents.add(cn.getName());
+                        cn = cn.getSuperClass();
+                    }
+                } while (cn!=null);
+            }
+            errorCollector.failIfErrors();
+            module.sortClasses();
+            
+        }
+    }
+    
+    
+    /**
+     * Dequeues any source units add through addSource and resets the compiler phase
+     * to initialization. 
+     * 
+     * Note: this does not mean a file is recompiled. If a SoucreUnit has already passed
+     * a phase it is skipped until a higher phase is reached. 
+     * @return TODO
+     * 
+     * @throws CompilationFailedException
+     */    
+    protected boolean dequeued() throws CompilationFailedException {
+        boolean dequeue = !queuedSources.isEmpty();
+        while (!queuedSources.isEmpty()) {
+            SourceUnit su = (SourceUnit) queuedSources.removeFirst();
+            String name = su.getName();
+            names.add(name);
+            sources.put(name,su);
+        }
+        if (dequeue) {
+            gotoPhase(Phases.INITIALIZATION);
+        }
+        return dequeue;
+    }
+
+
+    /**
+     * Adds summary of each class to maps
+     */
+    private SourceUnitOperation summarize = new SourceUnitOperation() {
+        public void call(SourceUnit source) throws CompilationFailedException {
+            SourceSummary sourceSummary = source.getSourceSummary();
+            if (sourceSummary != null) {
+                summariesBySourceName.put(source.getName(),sourceSummary);
+                List publicClassSources = sourceSummary.getPublicClassSources();
+                if (publicClassSources == null || publicClassSources.size() == 0) {
+                    //todo - is this the best way to handle scripts?
+                    summariesByPublicClassName.put("*NoName*",sourceSummary);
+                    // nothing to put into classSourcesByClassName as no ClassSource
+                } else {
+                    Iterator itr = publicClassSources.iterator();
+                    while (itr.hasNext()) {
+                        ClassSource classSource = (ClassSource)itr.next();
+                        summariesByPublicClassName.put(classSource.getName(),sourceSummary);
+                        classSourcesByPublicClassName.put(classSource.getName(),classSource);
+                    }
+                }
+            }
+        }
+    };
+    
+    /**
+     * Resolves all types
+     */
+    private SourceUnitOperation resolve = new SourceUnitOperation() {
+        public void call(SourceUnit source) throws CompilationFailedException {
+            List classes = source.ast.getClasses();
+            for (Iterator it = classes.iterator(); it.hasNext();) {
+                ClassNode node = (ClassNode) it.next();
+                
+                VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source);
+                scopeVisitor.visitClass(node);
+                
+                resolveVisitor.startResolving(node,source);
+            }
+            
+        }
+    };
+    
+    /**
+     * Runs convert() on a single SourceUnit.
+     */
+    private SourceUnitOperation convert = new SourceUnitOperation() {
+        public void call(SourceUnit source) throws CompilationFailedException {
+            source.convert();
+            CompilationUnit.this.ast.addModule(source.getAST());
+
+
+            if (CompilationUnit.this.progressCallback != null) {
+                CompilationUnit.this.progressCallback.call(source, CompilationUnit.this.phase);
+            }
+        }
+    };
+    
+    private GroovyClassOperation output = new GroovyClassOperation() {
+        public void call(GroovyClass gclass) throws CompilationFailedException {
+            boolean failures = false;
+            String name = gclass.getName().replace('.', File.separatorChar) + ".class";
+            File path = new File(configuration.getTargetDirectory(), name);
+            
+            //
+            // Ensure the path is ready for the file
+            //
+            File directory = path.getParentFile();
+            if (directory != null && !directory.exists()) {
+                directory.mkdirs();
+            }
+            
+            //
+            // Create the file and write out the data
+            //
+            byte[] bytes = gclass.getBytes();
+            
+            FileOutputStream stream = null;
+            try {
+                stream = new FileOutputStream(path);
+                stream.write(bytes, 0, bytes.length);
+            } catch (IOException e) {
+                getErrorCollector().addError(Message.create(e.getMessage(),CompilationUnit.this));
+                failures = true;
+            } finally {
+                if (stream != null) {
+                    try {
+                        stream.close();
+                    } catch (Exception e) {
+                    }
+                }
+            }            
+        }
+    };
+    
+    /* checks if all needed classes are compiled before generating the bytecode */
+    private SourceUnitOperation compileCompleteCheck = new SourceUnitOperation() {
+        public void call(SourceUnit source) throws CompilationFailedException {
+            List classes = source.ast.getClasses();
+            for (Iterator it = classes.iterator(); it.hasNext();) {
+                ClassNode node = (ClassNode) it.next();
+                CompileUnit cu = node.getCompileUnit();
+                for (Iterator iter = cu.iterateClassNodeToCompile(); iter.hasNext();) {
+                    String name = (String) iter.next();
+                    SourceUnit su = ast.getScriptSourceLocation(name);
+                    List classesInSourceUnit = su.ast.getClasses();
+                    StringBuffer message = new StringBuffer();
+                    message
+                    .append ("Compilation incomplete: expected to find the class ")
+                    .append (name)
+                    .append (" in ")
+                    .append (su.getName());
+                    if (classesInSourceUnit.size()==0) {
+                        message.append(", but the file seems not to contain any classes");
+                    } else {
+                        message.append(", but the file contains the classes: ");
+                        boolean first = true;
+                        for (Iterator suClassesIter = classesInSourceUnit
+                                .iterator(); suClassesIter.hasNext();) {
+                            ClassNode cn = (ClassNode) suClassesIter.next();
+                            if (!first) {
+                                message.append(", ");
+                            } else {
+                                first=false;
+                            }
+                            message.append(cn.getName());                                
+                        }
+                    }
+                    
+                    getErrorCollector().addErrorAndContinue(
+                            new SimpleMessage(message.toString(),CompilationUnit.this)
+                    );
+                    iter.remove();
+                } 
+            }
+        }
+    };
+    
+
+    /**
+     * Runs classgen() on a single ClassNode.
+     */
+    private PrimaryClassNodeOperation classgen = new PrimaryClassNodeOperation() {
+        public boolean needSortedInput() {
+            return true;
+        }
+        public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
+
+        	//
+            // Run the Verifier on the outer class
+            //
+            try {
+                verifier.visitClass(classNode);
+            } catch (GroovyRuntimeException rpe) {
+                ASTNode node = rpe.getNode();
+                getErrorCollector().addError(
+                        new SyntaxException(rpe.getMessage(),null,node.getLineNumber(),node.getColumnNumber()),
+                        source
+                );
+            }
+            
+            LabelVerifier lv = new LabelVerifier(source);
+            lv.visitClass(classNode);
+
+            ClassCompletionVerifier completionVerifier = new ClassCompletionVerifier(source);
+            completionVerifier.visitClass(classNode);
+            
+            // because the class may be generated even if a error was found
+            // and that class may have an invalid format we fail here if needed
+            getErrorCollector().failIfErrors();
+            
+            //
+            // Prep the generator machinery
+            //
+            ClassVisitor visitor = createClassVisitor();
+
+
+            String sourceName = (source == null ? classNode.getModule().getDescription() : source.getName());
+            // only show the file name and its extension like javac does in its stacktraces rather than the full path
+            // also takes care of both \ and / depending on the host compiling environment
+            if (sourceName != null)
+                sourceName = sourceName.substring(Math.max(sourceName.lastIndexOf('\\'), sourceName.lastIndexOf('/')) + 1);
+            ClassGenerator generator = new AsmClassGenerator(context, visitor, classLoader, sourceName);
+
+
+            //
+            // Run the generation and create the class (if required)
+            //
+            generator.visitClass(classNode);
+ 
+
+            byte[] bytes = ((ClassWriter) visitor).toByteArray();
+            generatedClasses.add(new GroovyClass(classNode.getName(), bytes));
+
+
+            //
+            // Handle any callback that's been set
+            //
+            if (CompilationUnit.this.classgenCallback != null) {
+                classgenCallback.call(visitor, classNode);
+            }
+
+
+            //
+            // Recurse for inner classes
+            //
+            LinkedList innerClasses = generator.getInnerClasses();
+            while (!innerClasses.isEmpty()) {
+                classgen.call(source, context, (ClassNode) innerClasses.removeFirst());
+            }
+        }
+    };
+
+
+    protected ClassVisitor createClassVisitor() {
+        return new ClassWriter(true);
+    }
+
+    //---------------------------------------------------------------------------
+    // PHASE HANDLING
+
+
+    /**
+     * Updates the phase marker on all sources.
+     */
+    protected void mark() throws CompilationFailedException {
+        applyToSourceUnits(mark);
+    }
+
+
+    /**
+     * Marks a single SourceUnit with the current phase,
+     * if it isn't already there yet.
+     */
+    private SourceUnitOperation mark = new SourceUnitOperation() {
+        public void call(SourceUnit source) throws CompilationFailedException {
+            if (source.phase < phase) {
+                source.gotoPhase(phase);
+            }
+
+
+            if (source.phase == phase && phaseComplete && !source.phaseComplete) {
+                source.completePhase();
+            }
+        }
+    };
+
+
+
+
+
+    //---------------------------------------------------------------------------
+    // LOOP SIMPLIFICATION FOR SourceUnit OPERATIONS
+
+
+    /**
+     * An callback interface for use in the applyToSourceUnits loop driver.
+     */
+    public static abstract class SourceUnitOperation {
+        public abstract void call(SourceUnit source) throws CompilationFailedException;
+    }
+  
+
+    /**
+     * A loop driver for applying operations to all SourceUnits.
+     * Automatically skips units that have already been processed
+     * through the current phase.
+     */
+    public void applyToSourceUnits(SourceUnitOperation body) throws CompilationFailedException {
+        Iterator keys = names.iterator();
+        while (keys.hasNext()) {
+            String name = (String) keys.next();
+            SourceUnit source = (SourceUnit) sources.get(name);
+            if ( (source.phase < phase) || (source.phase == phase && !source.phaseComplete)) {
+                try {
+                    body.call(source);
+                } catch (CompilationFailedException e) {
+                    throw e;
+                } catch (Exception e) {
+                    GroovyBugError gbe = new GroovyBugError(e);
+                    changeBugText(gbe,source);
+                    throw gbe;
+                } catch (GroovyBugError e) {
+                    changeBugText(e,source);
+                    throw e;
+                }
+            }
+        }
+
+
+        getErrorCollector().failIfErrors();
+    }
+
+
+    //---------------------------------------------------------------------------
+    // LOOP SIMPLIFICATION FOR PRIMARY ClassNode OPERATIONS
+
+
+
+    /**
+     * An callback interface for use in the applyToSourceUnits loop driver.
+     */
+    public static abstract class PrimaryClassNodeOperation {
+        public abstract void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException;
+        public boolean needSortedInput(){
+            return false;
+        }
+    }
+
+    public static abstract class GroovyClassOperation {
+        public abstract void call(GroovyClass gclass) throws CompilationFailedException;
+    }
+
+    private List getPrimaryClassNodes(boolean sort) {
+        ArrayList unsorted = new ArrayList();
+        Iterator modules = this.ast.getModules().iterator();
+        while (modules.hasNext()) {
+            ModuleNode module = (ModuleNode) modules.next();
+
+            Iterator classNodes = module.getClasses().iterator();
+            while (classNodes.hasNext()) {
+                ClassNode classNode = (ClassNode) classNodes.next();
+                unsorted.add(classNode);
+            }
+        }
+        
+        if(sort==false) return unsorted;
+        
+        int[] indexClass = new int[unsorted.size()];
+        int[] indexInterface = new int[unsorted.size()];
+        {            
+            int i = 0;
+            for (Iterator iter = unsorted.iterator(); iter.hasNext(); i++) {
+                ClassNode node = (ClassNode) iter.next();
+                int count = 0;
+                ClassNode element = node;
+                while (element!=null){
+                    count++;
+                    element = element.getSuperClass();
+                }
+                if (node.isInterface()) {
+                    indexInterface[i] = count;
+                    indexClass[i] = -1;
+                } else {
+                    indexClass[i] = count;
+                    indexInterface[i] = -1;
+                }
+            }
+        }
+        
+        List sorted = getSorted(indexInterface,unsorted);
+        sorted.addAll(getSorted(indexClass,unsorted));
+        
+        return sorted;
+    }
+    
+    private List getSorted(int[] index, List unsorted) {
+        ArrayList sorted = new ArrayList(unsorted.size());
+        int start = 0;
+        for (int i=0; i<unsorted.size(); i++) {           
+            int min = -1;
+            for (int j=0; j<unsorted.size(); j++) {
+                if (index[j]==-1) continue;
+                if (min==-1) {
+                    min = j;
+                } else if (index[j]<index[min]) {
+                    min = j;
+                }
+            }
+            if (min==-1) break;
+            sorted.add(unsorted.get(min));
+            index[min] = -1;
+        }
+        return sorted;
+    }
+
+    /**
+     * A loop driver for applying operations to all primary ClassNodes in
+     * our AST.  Automatically skips units that have already been processed
+     * through the current phase.
+     */
+    public void applyToPrimaryClassNodes(PrimaryClassNodeOperation body) throws CompilationFailedException {
+        Iterator classNodes = getPrimaryClassNodes(body.needSortedInput()).iterator();
+        while (classNodes.hasNext()) {
+            SourceUnit context=null;
+            try {
+               ClassNode classNode = (ClassNode) classNodes.next();
+               context = classNode.getModule().getContext();
+               if (context == null || context.phase <= phase) {
+                   body.call(context, new GeneratorContext(this.ast), classNode);
+               }
+            } catch (CompilationFailedException e) {
+                // fall thorugh, getErrorREporter().failIfErrors() will triger
+            } catch (NullPointerException npe){
+                throw npe;
+            } catch (GroovyBugError e) {
+                changeBugText(e,context);
+                throw e;
+            } catch (Exception e) {
+                // check the exception for a nested compilation exception
+                ErrorCollector nestedCollector = null;
+                for (Throwable next = e.getCause(); next!=e && next!=null; next=next.getCause()) {
+                    if (!(next instanceof MultipleCompilationErrorsException)) continue;
+                    MultipleCompilationErrorsException mcee = (MultipleCompilationErrorsException) next;
+                    nestedCollector = mcee.collector;
+                    break;
+                }
+
+                if (nestedCollector!=null) {
+                    getErrorCollector().addCollectorContents(nestedCollector);
+                } else {
+                    getErrorCollector().addError(new ExceptionMessage(e,configuration.getDebug(),this));
+                }
+            }
+        }
+
+        getErrorCollector().failIfErrors();
+    }
+    
+    public void applyToGeneratedGroovyClasses(GroovyClassOperation body) throws CompilationFailedException {
+        if (this.phase != Phases.OUTPUT && !(this.phase == Phases.CLASS_GENERATION && this.phaseComplete)) {
+            throw new GroovyBugError("CompilationUnit not ready for output(). Current phase="+getPhaseDescription());
+        }
+
+        boolean failures = false;
+
+        Iterator iterator = this.generatedClasses.iterator();
+        while (iterator.hasNext()) {
+            //
+            // Get the class and calculate its filesystem name
+            //
+            GroovyClass gclass = (GroovyClass) iterator.next();
+            try {
+                body.call(gclass);
+            } catch (CompilationFailedException e) {
+                // fall thorugh, getErrorREporter().failIfErrors() will triger
+            } catch (NullPointerException npe){
+                throw npe;
+            } catch (GroovyBugError e) {
+                changeBugText(e,null);
+                throw e;
+            } catch (Exception e) {
+                GroovyBugError gbe = new GroovyBugError(e);
+                throw gbe;
+            }
+        }
+        
+        getErrorCollector().failIfErrors();
+    }
+
+    private void changeBugText(GroovyBugError e, SourceUnit context) {
+        e.setBugText("exception in phase '"+getPhaseDescription()+"' in source unit '"+((context!=null)?context.getName():"?")+"' "+e.getBugText());
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/CompilerConfiguration.java b/groovy-core/src/main/org/codehaus/groovy/control/CompilerConfiguration.java
new file mode 100644
index 0000000..92f1f7d
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/CompilerConfiguration.java
@@ -0,0 +1,573 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.control;
+
+import org.codehaus.groovy.control.io.NullWriter;
+import org.codehaus.groovy.control.messages.WarningMessage;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+
+/**
+ * Compilation control flags and coordination stuff.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * @version $Id$
+ */
+
+public class CompilerConfiguration {
+    public static final CompilerConfiguration DEFAULT = new CompilerConfiguration();
+
+    /** Whether to use the JSR parser or not if no property is explicitly stated */
+    protected static final boolean DEFAULT_JSR_FLAG = true;
+
+    private static boolean jsrGroovy;
+
+    /**
+     * See WarningMessage for levels
+     */
+    private int warningLevel;
+    /**
+     * Encoding for source files
+     */
+    private String sourceEncoding;
+    /**
+     * A PrintWriter for communicating with the user
+     */
+    private PrintWriter output;
+    /**
+     * Directory into which to write classes
+     */
+    private File targetDirectory;
+    /**
+     * Classpath for use during compilation
+     */
+    private LinkedList classpath;
+    /**
+     * If true, the compiler should produce action information
+     */
+    private boolean verbose;
+    /**
+     * If true, debugging code should be activated
+     */
+    private boolean debug;
+    /**
+     * The number of non-fatal errors to allow before bailing
+     */
+    private int tolerance;
+    /**
+     * Base class name for scripts (must derive from Script)
+     */
+    private String scriptBaseClass;
+    /**
+     * should we use the New JSR Groovy parser or stay with the static one
+     */
+    private boolean useNewGroovy = getDefaultJsrFlag();
+
+    private ParserPluginFactory pluginFactory;
+
+    /**
+     * extension used to find a groovy file
+     */
+    private String defaultScriptExtension = ".groovy";
+    
+    /**
+     * if set to true recompilation is enabled
+     */
+    private boolean recompileGroovySource;
+    
+    /**
+     * sets the minimum of time after a script can be recompiled.
+     */
+    private int minimumRecompilationInterval;
+
+    /**
+     * Sets the Flags to defaults.
+     */
+    public CompilerConfiguration() {
+        //
+        // Set in safe defaults
+
+        setWarningLevel(WarningMessage.LIKELY_ERRORS);
+        setSourceEncoding("US-ASCII");
+        setOutput(null);
+        setTargetDirectory((File) null);
+        setClasspath("");
+        setVerbose(false);
+        setDebug(false);
+        setTolerance(10);
+        setScriptBaseClass(null);
+        setRecompileGroovySource(false);
+        setMinimumRecompilationInterval(100);
+
+
+        //
+        // Try for better defaults, ignore errors.
+
+        try {
+            setSourceEncoding(System.getProperty("file.encoding", "US-ASCII"));
+        }
+        catch (Exception e) {
+        }
+        try {
+            setOutput(new PrintWriter(System.err));
+        }
+        catch (Exception e) {
+        }
+        /*try {
+            setClasspath(System.getProperty("java.class.path"));
+        }
+        catch (Exception e) {
+        }*/
+
+        try {
+            String target = System.getProperty("groovy.target.directory");
+            if (target != null) {
+                setTargetDirectory(target);
+            }
+        }
+        catch (Exception e) {
+        }
+    }
+
+
+    /**
+     * Sets the Flags to the specified configuration, with defaults
+     * for those not supplied.
+     */
+
+    public CompilerConfiguration(Properties configuration) throws ConfigurationException {
+        this();
+
+        String text = null;
+        int numeric = 0;
+
+
+        //
+        // Warning level
+
+        numeric = getWarningLevel();
+        try {
+            text = configuration.getProperty("groovy.warnings", "likely errors");
+            numeric = Integer.parseInt(text);
+        }
+        catch (NumberFormatException e) {
+            if (text.equals("none")) {
+                numeric = WarningMessage.NONE;
+            }
+            else if (text.startsWith("likely")) {
+                numeric = WarningMessage.LIKELY_ERRORS;
+            }
+            else if (text.startsWith("possible")) {
+                numeric = WarningMessage.POSSIBLE_ERRORS;
+            }
+            else if (text.startsWith("paranoia")) {
+                numeric = WarningMessage.PARANOIA;
+            }
+            else {
+                throw new ConfigurationException("unrecogized groovy.warnings: " + text);
+            }
+        }
+
+        setWarningLevel(numeric);
+
+
+        //
+        // Source file encoding
+
+        text = configuration.getProperty("groovy.source.encoding");
+        if (text != null) {
+            setSourceEncoding(text);
+        }
+
+
+        //
+        // Target directory for classes
+
+        text = configuration.getProperty("groovy.target.directory");
+        if (text != null) {
+            setTargetDirectory(text);
+        }
+
+
+        //
+        // Classpath
+
+        text = configuration.getProperty("groovy.classpath");
+        if (text != null) {
+            setClasspath(text);
+        }
+
+
+        //
+        // Verbosity
+
+        text = configuration.getProperty("groovy.output.verbose");
+        if (text != null && text.equals("true")) {
+            setVerbose(true);
+        }
+
+
+        //
+        // Debugging
+
+        text = configuration.getProperty("groovy.output.debug");
+        if (text != null && text.equals("true")) {
+            setDebug(true);
+        }
+
+
+        //
+        // Tolerance
+
+        numeric = 10;
+
+        try {
+            text = configuration.getProperty("groovy.errors.tolerance", "10");
+            numeric = Integer.parseInt(text);
+        }
+        catch (NumberFormatException e) {
+            throw new ConfigurationException(e);
+        }
+
+        setTolerance(numeric);
+
+
+        //
+        // Script Base Class
+
+        text = configuration.getProperty("groovy.script.base");
+        setScriptBaseClass(text);
+
+        text = configuration.getProperty("groovy.jsr");
+        if (text != null) {
+            setUseNewGroovy(text.equalsIgnoreCase("true"));
+        }
+        
+        
+        //
+        // recompilation options
+        //
+        text = configuration.getProperty("groovy.recompile");
+        if (text != null) {
+            setRecompileGroovySource(text.equalsIgnoreCase("true"));
+        }
+        
+        numeric = 100;
+        try {
+            text = configuration.getProperty("groovy.recompile.minimumIntervall", ""+numeric);
+            numeric = Integer.parseInt(text);
+        }
+        catch (NumberFormatException e) {
+            throw new ConfigurationException(e);
+        }
+        setMinimumRecompilationInterval(numeric);
+        
+        
+    }
+
+
+    /**
+     * Gets the currently configured warning level.  See WarningMessage
+     * for level details.
+     */
+    public int getWarningLevel() {
+        return this.warningLevel;
+    }
+
+
+    /**
+     * Sets the warning level.  See WarningMessage for level details.
+     */
+    public void setWarningLevel(int level) {
+        if (level < WarningMessage.NONE || level > WarningMessage.PARANOIA) {
+            this.warningLevel = WarningMessage.LIKELY_ERRORS;
+        }
+        else {
+            this.warningLevel = level;
+        }
+    }
+
+
+    /**
+     * Gets the currently configured source file encoding.
+     */
+    public String getSourceEncoding() {
+        return this.sourceEncoding;
+    }
+
+
+    /**
+     * Sets the encoding to be used when reading source files.
+     */
+    public void setSourceEncoding(String encoding) {
+        this.sourceEncoding = encoding;
+    }
+
+
+    /**
+     * Gets the currently configured output writer.
+     */
+    public PrintWriter getOutput() {
+        return this.output;
+    }
+
+
+    /**
+     * Sets the output writer.
+     */
+    public void setOutput(PrintWriter output) {
+        if (this.output == null) {
+            this.output = new PrintWriter(NullWriter.DEFAULT);
+        }
+        else {
+            this.output = output;
+        }
+    }
+
+
+    /**
+     * Gets the target directory for writing classes.
+     */
+    public File getTargetDirectory() {
+        return this.targetDirectory;
+    }
+
+
+    /**
+     * Sets the target directory.
+     */
+    public void setTargetDirectory(String directory) {
+        if (directory != null && directory.length() > 0) {
+            this.targetDirectory = new File(directory);
+        }
+        else {
+            this.targetDirectory = null;
+        }
+    }
+
+
+    /**
+     * Sets the target directory.
+     */
+    public void setTargetDirectory(File directory) {
+        this.targetDirectory = directory;
+    }
+
+
+    /**
+     * Gets the classpath.
+     */
+    public List getClasspath() {
+        return this.classpath;
+    }
+
+
+    /**
+     * Sets the classpath.
+     */
+    public void setClasspath(String classpath) {
+        this.classpath = new LinkedList();
+
+        StringTokenizer tokenizer = new StringTokenizer(classpath, File.pathSeparator);
+        while (tokenizer.hasMoreTokens()) {
+            this.classpath.add(tokenizer.nextToken());
+        }
+    }
+
+
+    /**
+     * Returns true if verbose operation has been requested.
+     */
+    public boolean getVerbose() {
+        return this.verbose;
+    }
+
+
+    /**
+     * Turns verbose operation on or off.
+     */
+    public void setVerbose(boolean verbose) {
+        this.verbose = verbose;
+    }
+
+
+    /**
+     * Returns true if debugging operation has been requested.
+     */
+    public boolean getDebug() {
+        return this.debug;
+    }
+
+
+    /**
+     * Turns debugging operation on or off.
+     */
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+
+    /**
+     * Returns the requested error tolerance.
+     */
+    public int getTolerance() {
+        return this.tolerance;
+    }
+
+
+    /**
+     * Sets the error tolerance, which is the number of
+     * non-fatal errors (per unit) that should be tolerated before
+     * compilation is aborted.
+     */
+    public void setTolerance(int tolerance) {
+        this.tolerance = tolerance;
+    }
+
+
+    /**
+     * Gets the name of the base class for scripts.  It must be a subclass
+     * of Script.
+     */
+    public String getScriptBaseClass() {
+        return this.scriptBaseClass;
+    }
+
+
+    /**
+     * Sets the name of the base class for scripts.  It must be a subclass
+     * of Script.
+     */
+    public void setScriptBaseClass(String scriptBaseClass) {
+        this.scriptBaseClass = scriptBaseClass;
+    }
+
+    /**
+     * Returns true if the new groovy (JSR) parser is enabled
+     */
+    public boolean isUseNewGroovy() {
+        return useNewGroovy;
+    }
+
+    public void setUseNewGroovy(boolean useNewGroovy) {
+        this.useNewGroovy = useNewGroovy;
+    }
+
+    public ParserPluginFactory getPluginFactory() {
+        if (pluginFactory == null) {
+            pluginFactory = ParserPluginFactory.newInstance(isUseNewGroovy());
+        }
+        return pluginFactory;
+    }
+
+    public void setPluginFactory(ParserPluginFactory pluginFactory) {
+        this.pluginFactory = pluginFactory;
+    }
+
+    /**
+     * Returns true if we are the JSR compatible Groovy language
+     */
+    public static boolean isJsrGroovy() {
+        return jsrGroovy;
+    }
+
+    /**
+     * Should only be called by the JSR parser
+     */
+    public static void setJsrGroovy(boolean value) {
+        jsrGroovy = value;
+    }
+
+    protected static boolean getDefaultJsrFlag() {
+        // TODO a temporary hack while we have 2 parsers
+        String property = null;
+        try {
+             property = System.getProperty("groovy.jsr");
+        }
+        catch (Throwable e) {
+            // ignore security warnings
+        }
+        if (property != null) {
+            return "true".equalsIgnoreCase(property);
+        }
+        return DEFAULT_JSR_FLAG;
+    }
+
+
+    public String getDefaultScriptExtension() {
+        return defaultScriptExtension;
+    }
+
+
+    public void setDefaultScriptExtension(String defaultScriptExtension) {
+        this.defaultScriptExtension = defaultScriptExtension;
+    }
+    
+    public void setRecompileGroovySource(boolean recompile) {
+        recompileGroovySource = recompile;
+    }
+    
+    public boolean getRecompileGroovySource(){
+        return recompileGroovySource;
+    }
+    
+    public void setMinimumRecompilationInterval(int time) {
+        minimumRecompilationInterval = Math.max(0,time);
+    }
+    
+    public int getMinimumRecompilationInterval() {
+        return minimumRecompilationInterval;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/ConfigurationException.java b/groovy-core/src/main/org/codehaus/groovy/control/ConfigurationException.java
new file mode 100644
index 0000000..1cecdb5
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/ConfigurationException.java
@@ -0,0 +1,123 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.control;
+
+import org.codehaus.groovy.GroovyExceptionInterface;
+
+
+
+
+/**
+ *  Thrown when configuration data is invalid.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class ConfigurationException extends RuntimeException implements GroovyExceptionInterface
+{
+    
+  //---------------------------------------------------------------------------
+  // CONSTRUCTION AND SUCH
+
+    protected Exception cause;   // The phase in which the failures occurred
+
+    
+   /**
+    *  Initializes the exception from a cause exception.
+    */
+    
+    public ConfigurationException( Exception cause ) 
+    {
+        super( cause.getMessage() );
+        this.cause = cause;
+    }
+    
+    
+   /**
+    *  Initializes the exception with just a message.
+    */
+    
+    public ConfigurationException( String message )
+    {
+        super( message );
+    }
+
+    
+    
+   /**
+    *  Returns the causing exception, if available.
+    */
+    
+    public Throwable getCause()
+    {
+        return cause;
+    }
+    
+    
+   /**
+    *  Its always fatal.
+    */
+    
+    public boolean isFatal()
+    {
+        return true;
+    }
+    
+    
+    
+   /**
+    *  Set fatal is just ignored.
+    */
+    
+    public void setFatal( boolean fatal )
+    {
+    }
+    
+}
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/ErrorCollector.java b/groovy-core/src/main/org/codehaus/groovy/control/ErrorCollector.java
new file mode 100644
index 0000000..be83bdc
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/ErrorCollector.java
@@ -0,0 +1,362 @@
+/*
+$Id$
+
+Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+package org.codehaus.groovy.control;
+
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.codehaus.groovy.control.messages.ExceptionMessage;
+import org.codehaus.groovy.control.messages.LocatedMessage;
+import org.codehaus.groovy.control.messages.Message;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.control.messages.WarningMessage;
+import org.codehaus.groovy.syntax.CSTNode;
+import org.codehaus.groovy.syntax.SyntaxException;
+
+/**
+ * A base class for collecting messages and errors during processing.
+ * Each CompilationUnit should have one and SourceUnits should share
+ * their ErrorCollector with the CompilationUnit.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * @version $Id$
+ */
+public class ErrorCollector {
+    
+    /**
+     * WarningMessages collected during processing
+     */
+    protected LinkedList warnings;
+    /**
+     * ErrorMessages collected during processing
+     */
+    protected LinkedList errors;
+    /**
+     * Configuration and other settings that control processing
+     */
+    protected CompilerConfiguration configuration;
+
+    /**
+     * Initialize the ErrorReporter.
+     */
+    public ErrorCollector(CompilerConfiguration configuration) {
+        this.warnings = null;
+        this.errors = null;
+        
+        this.configuration = configuration;
+    }
+    
+    public void addCollectorContents(ErrorCollector er) {
+        if (er.errors!=null) {
+            if (errors==null) {
+                errors = er.errors;
+            } else {
+                errors.addAll(errors);
+            }
+        }
+        if (er.warnings!=null) {
+            if (warnings==null) {
+                warnings = er.warnings;
+            } else {
+                warnings.addAll(warnings);
+            }            
+        }
+    }
+    
+    
+    
+    /**
+     * Adds an error to the message set, but don't fail.
+     */
+    public void addErrorAndContinue(Message message) {
+        if (this.errors == null) {
+            this.errors = new LinkedList();
+        }
+
+        this.errors.add(message);
+    }
+    
+    /**
+     * Adds a non-fatal error to the message set.
+     */
+    public void addError(Message message) throws CompilationFailedException {
+        addErrorAndContinue(message);
+
+        if (errors!=null && this.errors.size() >= configuration.getTolerance()) {
+            failIfErrors();
+        }
+    }
+    
+    /**
+     * Adds an optionally-fatal error to the message set.  Throws
+     * the unit as a PhaseFailedException, if the error is fatal.
+     */
+    public void addError(Message message, boolean fatal) throws CompilationFailedException {
+        if (fatal) {
+            addFatalError(message);
+        }
+        else {
+            addError(message);
+        }
+    }
+
+    
+    /**
+     * Convenience wrapper for addError().
+     */
+    public void addError(SyntaxException error, SourceUnit source) throws CompilationFailedException {
+        addError(Message.create(error, source), error.isFatal());
+    }
+
+
+    /**
+     * Convenience wrapper for addError().
+     */
+    public void addError(String text, CSTNode context, SourceUnit source) throws CompilationFailedException {
+        addError(new LocatedMessage(text, context, source));
+    }
+    
+    
+    /**
+     * Adds a fatal exception to the message set and throws
+     * the unit as a PhaseFailedException.
+     */
+    public void addFatalError(Message message) throws CompilationFailedException {
+        addError(message);
+        failIfErrors();
+    }
+
+
+    public void addException(Exception cause, SourceUnit source) throws CompilationFailedException {
+        addError(new ExceptionMessage(cause,configuration.getDebug(),source));
+        failIfErrors();
+    }
+
+    /**
+     * Returns true if there are any errors pending.
+     */
+    public boolean hasErrors() {
+        return this.errors != null;
+    }
+    
+    /**
+     * Returns true if there are any warnings pending.
+     */
+    public boolean hasWarnings() {
+        return this.warnings != null;
+    }
+    
+    /**
+     * Returns the list of warnings, or null if there are none.
+     */
+    public List getWarnings() {
+        return this.warnings;
+    }
+
+    /**
+     * Returns the list of errors, or null if there are none.
+     */
+    public List getErrors() {
+        return this.errors;
+    }
+
+    /**
+     * Returns the number of warnings.
+     */
+    public int getWarningCount() {
+        return ((this.warnings == null) ? 0 : this.warnings.size());
+    }
+
+    /**
+     * Returns the number of errors.
+     */
+    public int getErrorCount() {
+        return ((this.errors == null) ? 0 : this.errors.size());
+    }
+
+    /**
+     * Returns the specified warning message, or null.
+     */
+    public WarningMessage getWarning(int index) {
+        if (index < getWarningCount()) {
+            return (WarningMessage) this.warnings.get(index);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the specified error message, or null.
+     */
+    public Message getError(int index) {
+        if (index < getErrorCount()) {
+            return (Message) this.errors.get(index);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the last error reported
+     */
+    public Message getLastError() {
+        return (Message) this.errors.getLast();
+    }
+    
+    /**
+     * Convenience routine to return the specified error's
+     * underlying SyntaxException, or null if it isn't one.
+     */
+    public SyntaxException getSyntaxError(int index) {
+        SyntaxException exception = null;
+
+        Message message = getError(index);
+        if (message != null && message instanceof SyntaxErrorMessage) {
+            exception = ((SyntaxErrorMessage) message).getCause();
+        }
+        return exception;
+    }
+
+    /**
+     * Convenience routine to return the specified error's
+     * underlying Exception, or null if it isn't one.
+     */
+    public Exception getException(int index) {
+        Exception exception = null;
+
+        Message message = getError(index);
+        if (message != null) {
+            if (message instanceof ExceptionMessage) {
+                exception = ((ExceptionMessage) message).getCause();
+            }
+            else if (message instanceof SyntaxErrorMessage) {
+                exception = ((SyntaxErrorMessage) message).getCause();
+            }
+        }
+        return exception;
+    }
+
+    /**
+     * Adds a WarningMessage to the message set.
+     */
+    public void addWarning(WarningMessage message) {
+        if (message.isRelevant(configuration.getWarningLevel())) {
+            if (this.warnings == null) {
+                this.warnings = new LinkedList();
+            }
+
+            this.warnings.add(message);
+        }
+    }
+
+
+    /**
+     * Convenience wrapper for addWarning() that won't create an object
+     * unless it is relevant.
+     */
+    public void addWarning(int importance, String text, CSTNode context, SourceUnit source) {
+        if (WarningMessage.isRelevant(importance, configuration.getWarningLevel())) {
+            addWarning(new WarningMessage(importance, text, context, source));
+        }
+    }
+    
+    
+    /**
+     * Convenience wrapper for addWarning() that won't create an object
+     * unless it is relevant.
+     */
+    public void addWarning(int importance, String text, Object data, CSTNode context, SourceUnit source) {
+        if (WarningMessage.isRelevant(importance, configuration.getWarningLevel())) {
+            addWarning(new WarningMessage(importance, text, data, context, source));
+        }
+    }
+   
+
+    /**
+     * Causes the current phase to fail by throwing a
+     * CompilationFailedException.
+     */
+    protected void failIfErrors() throws CompilationFailedException {
+        if (hasErrors()) {
+            throw new MultipleCompilationErrorsException(this);
+        }
+    }
+    
+    //---------------------------------------------------------------------------
+    // OUTPUT
+
+
+    private void write(PrintWriter writer, Janitor janitor, List messages, String txt) {
+        if (messages==null || messages.size()==0) return;
+        Iterator iterator = messages.iterator();
+        while (iterator.hasNext()) {
+            Message message = (Message) iterator.next();
+            message.write(writer, janitor);
+            
+            if (configuration.getDebug() && (message instanceof SyntaxErrorMessage)){
+                SyntaxErrorMessage sem = (SyntaxErrorMessage) message;
+                sem.getCause().printStackTrace(writer);
+            } 
+        }
+
+        writer.println();
+        writer.print(messages.size());
+        writer.print(" "+txt);
+        if (messages.size()>1) writer.print("s");
+        writer.println();
+    }
+    
+    /**
+     * Writes error messages to the specified PrintWriter.
+     */
+    public void write(PrintWriter writer, Janitor janitor) {
+        write(writer,janitor,warnings,"warning");
+        write(writer,janitor,errors,"error");
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/HasCleanup.java b/groovy-core/src/main/org/codehaus/groovy/control/HasCleanup.java
new file mode 100644
index 0000000..a1f285c
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/HasCleanup.java
@@ -0,0 +1,68 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.control;
+
+
+
+
+/**
+ *  An interface for things that need to be cleaned up after
+ *  operations complete.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public interface HasCleanup 
+{
+    public void cleanup();
+}
+
+
+
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/Janitor.java b/groovy-core/src/main/org/codehaus/groovy/control/Janitor.java
new file mode 100644
index 0000000..efd9dbf
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/Janitor.java
@@ -0,0 +1,89 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.control;
+
+import java.util.HashSet;
+import java.util.Iterator;
+
+
+
+
+/**
+ *  An agent that can be used to defer cleanup operations to 
+ *  a later time.  Users much implement the HasCleanup interface.  
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class Janitor implements HasCleanup
+{
+    private HashSet pending = new HashSet();   // All objects pending cleanup
+    
+    public void register( HasCleanup object )
+    {
+        pending.add( object );
+    }
+    
+    public void cleanup()
+    {
+        Iterator iterator = pending.iterator();
+        while( iterator.hasNext() )
+        {
+            HasCleanup object = (HasCleanup)iterator.next();
+            
+            try { object.cleanup(); } catch( Exception e ) {}
+        }
+        
+        pending.clear();
+    }
+}
+
+
+
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/LabelVerifier.java b/groovy-core/src/main/org/codehaus/groovy/control/LabelVerifier.java
new file mode 100644
index 0000000..83a8cd2
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/LabelVerifier.java
@@ -0,0 +1,198 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.control;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.stmt.BreakStatement;
+import org.codehaus.groovy.ast.stmt.ContinueStatement;
+import org.codehaus.groovy.ast.stmt.DoWhileStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.stmt.SwitchStatement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
+
+/**
+ * This class checks the handling of labels in the AST
+ * 
+ * @author Jochen Theodorou
+ */
+public class LabelVerifier extends ClassCodeVisitorSupport {
+
+    private SourceUnit source;
+    private LinkedList visitedLabels;
+    private LinkedList continueLabels;
+    private LinkedList breakLabels;
+    boolean inLoop=false;
+    boolean inSwitch=false;
+    
+    public LabelVerifier(SourceUnit src) {
+        source = src;
+    }
+    
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+    
+    private void init(){
+        visitedLabels = new LinkedList();
+        continueLabels = new LinkedList();
+        breakLabels = new LinkedList();
+        inLoop=false;
+        inSwitch=false;
+    }
+    
+    protected void visitClassCodeContainer(Statement code) {
+        init();
+        super.visitClassCodeContainer(code);
+        assertNoLabelsMissed();
+    }
+    
+   public void visitStatement(Statement statement) {
+       String label = statement.getStatementLabel();
+       
+       if (label!=null) {
+           for (Iterator iter = breakLabels.iterator(); iter.hasNext();) {
+               BreakStatement element = (BreakStatement) iter.next();
+               if (element.getLabel().equals(label)) iter.remove();
+           }
+           
+           for (Iterator iter = continueLabels.iterator(); iter.hasNext();) {
+               ContinueStatement element = (ContinueStatement) iter.next();
+               if (element.getLabel().equals(label)) iter.remove();
+           }
+           
+           visitedLabels.add(label);
+       }
+       
+       super.visitStatement(statement);
+}
+    
+    public void visitForLoop(ForStatement forLoop) {
+        boolean oldInLoop = inLoop;
+        inLoop = true;
+        super.visitForLoop(forLoop);
+        inLoop = oldInLoop;
+    }
+    
+    public void visitDoWhileLoop(DoWhileStatement loop) {
+        boolean oldInLoop = inLoop;
+        inLoop = true;
+        super.visitDoWhileLoop(loop);
+        inLoop = oldInLoop;
+    }     
+    
+    public void visitWhileLoop(WhileStatement loop) {
+        boolean oldInLoop = inLoop;
+        inLoop = true;
+        super.visitWhileLoop(loop);
+        inLoop = oldInLoop;
+    }
+    
+    public void visitBreakStatement(BreakStatement statement) {
+        String label = statement.getLabel();
+        boolean hasNamedLabel = label!=null;
+        if (!hasNamedLabel && !inLoop && !inSwitch) {
+            addError("the break statement is only allowed inside loops or switches",statement);
+        } else if (hasNamedLabel && !inLoop) {
+            addError("the break statement with named label is only allowed inside loops",statement);
+        }
+        if (label!=null) {
+            boolean found=false;
+            for (Iterator iter = visitedLabels.iterator(); iter.hasNext();) {
+                String element = (String) iter.next();
+                if (element.equals(label)) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) breakLabels.add(statement);
+        }
+        
+        super.visitBreakStatement(statement);
+    }
+    
+    public void visitContinueStatement(ContinueStatement statement) {
+        String label = statement.getLabel();
+        boolean hasNamedLabel = label!=null;
+        if (!hasNamedLabel && !inLoop) {
+            addError("the continue statement is only allowed inside loops",statement);
+        } 
+        if (label!=null) {
+            boolean found=false;
+            for (Iterator iter = visitedLabels.iterator(); iter.hasNext();) {
+                String element = (String) iter.next();
+                if (element.equals(label)) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) continueLabels.add(statement);
+        }
+        
+        super.visitContinueStatement(statement);
+    }
+    
+    protected void assertNoLabelsMissed() {
+        //TODO: report multiple missing labels of the same name only once
+        for (Iterator iter = continueLabels.iterator(); iter.hasNext();) {
+            ContinueStatement element = (ContinueStatement) iter.next();
+            addError("continue to missing label",element);
+        }
+        for (Iterator iter = breakLabels.iterator(); iter.hasNext();) {
+            BreakStatement element = (BreakStatement) iter.next();
+            addError("break to missing label",element);
+        }
+    }
+    
+    public void visitSwitch(SwitchStatement statement) {
+        inSwitch=true;
+        super.visitSwitch(statement);
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/MultipleCompilationErrorsException.java b/groovy-core/src/main/org/codehaus/groovy/control/MultipleCompilationErrorsException.java
new file mode 100644
index 0000000..37cbbae
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/MultipleCompilationErrorsException.java
@@ -0,0 +1,90 @@
+/*
+$Id$
+
+Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+package org.codehaus.groovy.control;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * @author Jochen Theodorou
+ */
+public class MultipleCompilationErrorsException extends
+        CompilationFailedException {
+    
+    protected ErrorCollector collector;
+    
+    public MultipleCompilationErrorsException(ErrorCollector ec) {
+        super(0, null);
+        if (ec == null) {
+            CompilerConfiguration config = super.getUnit() != null ?
+                super.getUnit().getConfiguration() :
+                new CompilerConfiguration();
+            collector = new ErrorCollector(config);
+        } else {
+            collector = ec;
+        }
+    }
+
+    public ErrorCollector getErrorCollector() {
+        return collector;
+    }
+    
+    public String getMessage() {
+        
+        StringWriter data = new StringWriter();
+        PrintWriter writer = new PrintWriter(data);
+        Janitor janitor = new Janitor();
+
+        try {
+            collector.write(writer, janitor);
+        }
+        finally {
+            janitor.cleanup();
+        }
+
+        return super.getMessage() + ", " + data.toString();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/ParserPlugin.java b/groovy-core/src/main/org/codehaus/groovy/control/ParserPlugin.java
new file mode 100644
index 0000000..d3d0034
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/ParserPlugin.java
@@ -0,0 +1,39 @@
+/**
+ *
+ * Copyright 2004 James Strachan
+ *
+ * Licensed 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.syntax.Reduction;
+import org.codehaus.groovy.syntax.ParserException;
+import org.codehaus.groovy.syntax.SourceSummary;
+import org.codehaus.groovy.ast.ModuleNode;
+
+import java.io.Reader;
+
+/**
+ * A simple extension point to allow us to switch between the classic Groovy parser and the new Antlr based parser
+ * 
+ * @version $Revision$
+ */
+public interface ParserPlugin {
+
+    public Reduction parseCST(SourceUnit sourceUnit, Reader reader) throws CompilationFailedException;
+
+    public SourceSummary getSummary();
+
+    public ModuleNode buildAST(SourceUnit sourceUnit, ClassLoader classLoader, Reduction cst) throws ParserException;
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/ParserPluginFactory.java b/groovy-core/src/main/org/codehaus/groovy/control/ParserPluginFactory.java
new file mode 100644
index 0000000..54071b5
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/ParserPluginFactory.java
@@ -0,0 +1,66 @@
+/**
+ *
+ * Copyright 2004 James Strachan
+ *
+ * Licensed 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.antlr.AntlrParserPluginFactory;
+
+/**
+ * A factory of parser plugin instances
+ *
+ * @version $Revision$
+ */
+public abstract class ParserPluginFactory {
+    public static ParserPluginFactory newInstance(boolean useNewParser) {
+        if (useNewParser) {
+            Class type = null;
+            String name = "org.codehaus.groovy.antlr.AntlrParserPluginFactory";
+            try {
+                type = Class.forName(name);
+            }
+            catch (ClassNotFoundException e) {
+                try {
+                    type = ParserPluginFactory.class.getClassLoader().loadClass(name);
+                }
+                catch (ClassNotFoundException e1) {
+                    ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+                    if (contextClassLoader != null) {
+                        try {
+                            type = contextClassLoader.loadClass(name);
+                        }
+                        catch (ClassNotFoundException e2) {
+                            // ignore
+                        }
+                    }
+                }
+            }
+
+            if (type != null) {
+                try {
+                    return (ParserPluginFactory) type.newInstance();
+                }
+                catch (Exception e) {
+                    throw new RuntimeException("Could not create AntlrParserPluginFactory: " + e, e);
+                }
+            }
+            // can't find Antlr parser, so lets use the Classic one
+        }
+        return new AntlrParserPluginFactory();
+    }
+
+    public abstract ParserPlugin createParserPlugin();
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/Phases.java b/groovy-core/src/main/org/codehaus/groovy/control/Phases.java
new file mode 100644
index 0000000..45de743
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/Phases.java
@@ -0,0 +1,101 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.control;
+
+
+
+
+/**
+ *  Compilation phase identifiers.  
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class Phases
+{
+    public static final int INITIALIZATION        = 1;   // Opening of files and such
+    public static final int PARSING               = 2;   // Lexing, parsing, and AST building
+    public static final int CONVERSION            = 3;   // CST to AST conversion
+    public static final int SEMANTIC_ANALYSIS     = 4;   // AST semantic analysis and elucidation
+    public static final int CANONICALIZATION      = 5;   // AST completion
+    public static final int INSTRUCTION_SELECTION = 6;   // Class generation, phase 1
+    public static final int CLASS_GENERATION      = 7;   // Class generation, phase 2
+    public static final int OUTPUT                = 8;   // Output of class to disk
+    public static final int FINALIZATION          = 9;   // Cleanup
+    public static final int ALL                   = 9;   // Synonym for full compilation
+    
+    public static String[] descriptions = {
+          "startup"
+        , "initialization"
+        , "parsing"
+        , "conversion"
+        , "semantic analysis"
+        , "canonicalization"
+        , "instruction selection"
+        , "class generation"
+        , "output"
+        , "cleanup"
+    };
+    
+    
+    
+   /**
+    *  Returns a description of the specified phase.
+    */
+    
+    public static String getDescription( int phase )
+    {
+        return descriptions[phase];
+    }
+    
+}
+
+
+
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/ProcessingUnit.java b/groovy-core/src/main/org/codehaus/groovy/control/ProcessingUnit.java
new file mode 100644
index 0000000..422b023
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/ProcessingUnit.java
@@ -0,0 +1,197 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.control;
+
+import groovy.lang.GroovyClassLoader;
+
+/**
+ * A base class for data structures that can collect messages and errors
+ * during processing.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ * @version $Id$
+ */
+
+public abstract class ProcessingUnit {
+
+    /**
+     * The current phase
+     */
+    protected int phase;
+    /**
+     * Set true if phase is finished
+     */
+    protected boolean phaseComplete;
+
+    /**
+     * Configuration and other settings that control processing
+     */
+    protected CompilerConfiguration configuration;
+  
+    /**
+     * The ClassLoader to use during processing
+     */
+    protected GroovyClassLoader classLoader;
+    
+    /**
+     * a helper to share errors and report them
+     */
+    protected ErrorCollector errorCollector;
+
+
+    /**
+     * Initialize the ProcessingUnit to the empty state.
+     */
+
+    public ProcessingUnit(CompilerConfiguration configuration, GroovyClassLoader classLoader, ErrorCollector er) {
+
+        this.phase = Phases.INITIALIZATION;
+        this.setClassLoader(classLoader);
+        configure((configuration == null ? new CompilerConfiguration() : configuration));
+        if (er==null) er = new ErrorCollector(getConfiguration());
+        this.errorCollector = er;
+    }
+
+
+    /**
+     * Reconfigures the ProcessingUnit.
+     */
+    public void configure(CompilerConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+
+    public CompilerConfiguration getConfiguration() {
+        return configuration;
+    }
+
+    public void setConfiguration(CompilerConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+    /**
+     * Returns the class loader in use by this ProcessingUnit.
+     */
+
+    public GroovyClassLoader getClassLoader() {
+        return classLoader;
+    }
+
+
+    /**
+     * Sets the class loader for use by this ProcessingUnit.
+     */
+
+    public void setClassLoader(GroovyClassLoader loader) {
+        ClassLoader parent = Thread.currentThread().getContextClassLoader();
+        if (parent == null) parent = ProcessingUnit.class.getClassLoader();
+        this.classLoader = (loader == null ? new GroovyClassLoader(parent, configuration) : loader);
+    }
+
+
+    /**
+     * Returns the current phase.
+     */
+
+    public int getPhase() {
+        return this.phase;
+    }
+
+
+    /**
+     * Returns the description for the current phase.
+     */
+
+    public String getPhaseDescription() {
+        return Phases.getDescription(this.phase);
+    }
+
+    public ErrorCollector getErrorCollector() {
+        return errorCollector;
+    }
+    
+    //---------------------------------------------------------------------------
+    // PROCESSING
+
+
+    /**
+     * Marks the current phase complete and processes any
+     * errors.
+     */
+
+    public void completePhase() throws CompilationFailedException {       
+        errorCollector.failIfErrors();
+        phaseComplete = true;
+    }
+
+
+    /**
+     * A synonym for <code>gotoPhase( phase + 1 )</code>.
+     */
+    public void nextPhase() throws CompilationFailedException {
+        gotoPhase(this.phase + 1);
+    }
+
+
+    /**
+     * Wraps up any pending operations for the current phase
+     * and switches to the next phase.
+     */
+    public void gotoPhase(int phase) throws CompilationFailedException {
+        if (!this.phaseComplete) {
+            completePhase();
+        }
+
+        this.phase = phase;
+        this.phaseComplete = false;
+    }
+
+}
+
+
+
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/ResolveVisitor.java b/groovy-core/src/main/org/codehaus/groovy/control/ResolveVisitor.java
new file mode 100644
index 0000000..685c0a5
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/ResolveVisitor.java
@@ -0,0 +1,852 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package org.codehaus.groovy.control;
+
+import groovy.lang.GroovyClassLoader;
+
+import java.io.IOException;
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.net.URL;
+import java.net.MalformedURLException;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.DynamicVariable;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.ImportNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ExpressionTransformer;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.AssertStatement;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.CaseStatement;
+import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.stmt.DoWhileStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.stmt.SwitchStatement;
+import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
+import org.codehaus.groovy.ast.stmt.ThrowStatement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
+import org.codehaus.groovy.classgen.Verifier;
+import org.codehaus.groovy.control.messages.ExceptionMessage;
+import org.codehaus.groovy.syntax.Types;
+
+/**
+ * Visitor to resolve Types and convert VariableExpression to
+ * ClassExpressions if needed. The ResolveVisitor will try to
+ * find the Class for a ClassExpression and prints an error if
+ * it fails to do so. Constructions like C[], foo as C, (C) foo 
+ * will force creation of a ClasssExpression for C   
+ *
+ * Note: the method to start the resolving is  startResolving(ClassNode, SourceUnit).
+ *
+ *
+ * @author Jochen Theodorou
+ */
+public class ResolveVisitor extends ClassCodeVisitorSupport implements ExpressionTransformer {
+    private ClassNode currentClass;
+    // note: BigInteger and BigDecimal are also imported by default
+    private static final String[] DEFAULT_IMPORTS = {"java.lang.", "java.io.", "java.net.", "java.util.", "groovy.lang.", "groovy.util."};
+    private CompilationUnit compilationUnit;
+    private Map cachedClasses = new HashMap();
+    private static final Object NO_CLASS = new Object();
+    private static final Object SCRIPT = new Object();
+    private SourceUnit source;
+    private VariableScope currentScope;
+
+    private boolean isTopLevelProperty = true;
+    private boolean inClosure = false;
+
+    public ResolveVisitor(CompilationUnit cu) {
+        compilationUnit = cu;
+    }
+
+    public void startResolving(ClassNode node,SourceUnit source) {
+        this.source = source;
+        visitClass(node);
+    }
+
+    public void visitConstructor(ConstructorNode node) {
+        visitAnnotations(node);
+        VariableScope oldScope = currentScope;
+        currentScope = node.getVariableScope();
+        Parameter[] paras = node.getParameters();
+        for (int i=0; i<paras.length; i++) {
+            ClassNode t = paras[i].getType();
+            resolveOrFail(t,node);
+        }
+        ClassNode[] exceptions = node.getExceptions();
+        for (int i=0; i<exceptions.length; i++) {
+            ClassNode t = exceptions[i];
+            resolveOrFail(t,node);
+        }
+        Statement code = node.getCode();
+        if (code!=null) code.visit(this);
+        currentScope = oldScope;
+    }
+
+    public void visitSwitch(SwitchStatement statement) {
+        Expression exp = statement.getExpression();
+        statement.setExpression(transform(exp));
+        List list = statement.getCaseStatements();
+        for (Iterator iter = list.iterator(); iter.hasNext(); ) {
+            CaseStatement caseStatement = (CaseStatement) iter.next();
+            caseStatement.visit(this);
+        }
+        statement.getDefaultStatement().visit(this);
+    }
+
+    public void visitMethod(MethodNode node) {
+        visitAnnotations(node);
+        VariableScope oldScope = currentScope;
+        currentScope = node.getVariableScope();
+        Parameter[] paras = node.getParameters();
+        for (int i=0; i<paras.length; i++) {
+            ClassNode t = paras[i].getType();
+            resolveOrFail(t,node);
+            if (paras[i].hasInitialExpression()) {
+                Expression init = paras[i].getInitialExpression(); 
+                paras[i].setInitialExpression(transform(init));
+            }
+        }
+        ClassNode[] exceptions = node.getExceptions();
+        for (int i=0; i<exceptions.length; i++) {
+            ClassNode t = exceptions[i];
+            resolveOrFail(t,node);
+        }       
+        resolveOrFail(node.getReturnType(),node);
+        Statement code = node.getCode();
+        if (code!=null) code.visit(this);
+        currentScope = oldScope;
+    }
+
+    public void visitField(FieldNode node) {
+        visitAnnotations(node);
+        ClassNode t = node.getType();
+        resolveOrFail(t,node);
+        Expression init = node.getInitialExpression();
+        node.setInitialValueExpression(transform(init));
+    }
+
+    public void visitProperty(PropertyNode node) {
+        visitAnnotations(node);
+        ClassNode t = node.getType();
+        resolveOrFail(t,node);
+        Statement code = node.getGetterBlock();
+        if (code!=null) code.visit(this);
+        code = node.getSetterBlock();
+        if (code!=null) code.visit(this);
+    }
+
+    public void visitIfElse(IfStatement ifElse) {
+        visitStatement(ifElse);
+        ifElse.setBooleanExpression((BooleanExpression) (transform(ifElse.getBooleanExpression())));
+        ifElse.getIfBlock().visit(this);
+        ifElse.getElseBlock().visit(this);
+    }
+
+    private void resolveOrFail(ClassNode type, String msg, ASTNode node) {
+        if (resolve(type)) return;
+        addError("unable to resolve class "+type.getName()+" "+msg,node);
+    }
+
+    private void resolveOrFail(ClassNode type, ASTNode node, boolean prefereImports) {
+        if (prefereImports && resolveAliasFromModule(type)) return;
+        resolveOrFail(type,node);
+    }
+    
+    private void resolveOrFail(ClassNode type, ASTNode node) {
+        resolveOrFail(type,"",node);
+    }
+
+    private boolean resolve(ClassNode type) {
+        String name = type.getName();
+        return resolve(type,true,true,true);
+    }
+
+    private boolean resolve(ClassNode type, boolean testModuleImports, boolean testDefaultImports, boolean testStaticInnerClasses) {
+        if (type.isResolved()) return true;
+        if (type.isArray()) {
+            ClassNode element = type.getComponentType();
+            boolean resolved = resolve(element,testModuleImports,testDefaultImports,testStaticInnerClasses);
+            if (resolved) {
+                ClassNode cn = element.makeArray();
+                type.setRedirect(cn);
+            }
+            return resolved;
+        }
+
+        // test if vanilla name is current class name
+        if (currentClass==type) return true;
+        if (currentClass.getNameWithoutPackage().equals(type.getName())) {
+            type.setRedirect(currentClass);
+            return true;
+        }
+
+        return  resolveFromModule(type,testModuleImports) ||
+                resolveFromCompileUnit(type) ||
+                resovleFromDefaultImports(type,testDefaultImports) ||
+                resolveFromStaticInnerClasses(type,testStaticInnerClasses) ||
+                resolveFromClassCache(type) ||
+                resolveToClass(type) ||
+                resolveToScript(type);
+
+    }
+
+    private boolean resolveFromClassCache(ClassNode type) {
+        String name = type.getName();
+        Object val = cachedClasses.get(name);
+        if (val==null || val==NO_CLASS){
+            return false;
+        } else {
+            setClass(type,(Class) val);
+            return true;
+        }
+    }
+
+    // NOTE: copied from GroovyClassLoader
+    private long getTimeStamp(Class cls) {
+        Field field;
+        Long o;
+        try {
+            field = cls.getField(Verifier.__TIMESTAMP);
+            o = (Long) field.get(null);
+        } catch (Exception e) {
+            return Long.MAX_VALUE;
+        }
+        return o.longValue();
+    }
+
+    // NOTE: copied from GroovyClassLoader
+    private boolean isSourceNewer(URL source, Class 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 {
+                lastMod = source.openConnection().getLastModified();
+            }
+            return lastMod > getTimeStamp(cls);            
+        } catch (IOException e) {
+            // if the stream can't be opened, let's keep the old reference
+            return false;
+        }
+    }
+
+
+    private boolean resolveToScript(ClassNode type) {
+        String name = type.getName();
+        if (cachedClasses.get(name)==NO_CLASS) return false;
+        if (cachedClasses.get(name)==SCRIPT) cachedClasses.put(name,NO_CLASS);
+        if (name.startsWith("java.")) return type.isResolved();
+        //TODO: don't ignore inner static classes completly
+        if (name.indexOf('$')!=-1) return type.isResolved();
+        ModuleNode module = currentClass.getModule();
+        if (module.hasPackageName() && name.indexOf('.')==-1) return type.isResolved();
+        // 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) {
+            if (type.isResolved()) {
+                Class cls = type.getTypeClass();
+                // if the file is not newer we don't want to recompile
+                if (!isSourceNewer(url,cls)) return true;
+                cachedClasses.remove(type.getName());
+                type.setRedirect(null);
+            }
+            SourceUnit su = compilationUnit.addSource(url);
+            currentClass.getCompileUnit().addClassNodeToCompile(type,su);
+            return true;
+        }
+        // type may be resolved through the classloader before
+        return type.isResolved();
+    }
+
+
+    private boolean resolveFromStaticInnerClasses(ClassNode type, boolean testStaticInnerClasses) {
+        // try to resolve a public static inner class' name
+        testStaticInnerClasses &= type.hasPackageName();
+        if (testStaticInnerClasses) {
+            String name = type.getName();
+            String replacedPointType = name;
+            int lastPoint = replacedPointType.lastIndexOf('.');
+            replacedPointType = new StringBuffer()
+                .append(replacedPointType.substring(0, lastPoint))
+                .append("$")
+                .append(replacedPointType.substring(lastPoint + 1))
+                .toString();
+            type.setName(replacedPointType);
+            if (resolve(type,false,false,true)) return true;
+            type.setName(name);
+        }
+        return false;
+    }
+
+    private boolean resovleFromDefaultImports(ClassNode type, boolean testDefaultImports) {
+        // test default imports
+        testDefaultImports &= !type.hasPackageName();
+        if (testDefaultImports) {
+            for (int i = 0, size = DEFAULT_IMPORTS.length; i < size; i++) {
+                String packagePrefix = DEFAULT_IMPORTS[i];
+                String name = type.getName();
+                String fqn = packagePrefix+name;
+                type.setName(fqn);
+                if (resolve(type,false,false,false)) return true;
+                type.setName(name);
+            }
+            String name = type.getName();
+            if (name.equals("BigInteger")) {
+                type.setRedirect(ClassHelper.BigInteger_TYPE);
+                return true;
+            } else if (name.equals("BigDecimal")) {
+                type.setRedirect(ClassHelper.BigDecimal_TYPE);
+                return true;    
+            }
+        }
+        return false;
+    }
+
+    private boolean resolveFromCompileUnit(ClassNode type) {
+        // look into the compile unit if there is a class with that name
+        CompileUnit compileUnit = currentClass.getCompileUnit();
+        if (compileUnit == null) return false;
+        ClassNode cuClass = compileUnit.getClass(type.getName());
+        if (cuClass!=null) {
+        	if (type!=cuClass) type.setRedirect(cuClass);
+        	return true;
+        }
+        return false;
+    }
+
+
+    private void setClass(ClassNode n, Class cls) {
+        ClassNode cn = ClassHelper.make(cls);
+        n.setRedirect(cn);
+    }
+
+    private void ambigousClass(ClassNode type, ClassNode iType, String name, boolean resolved){
+        if (resolved && !type.getName().equals(iType.getName())) {
+            addError("reference to "+name+" is ambigous, both class "+type.getName()+" and "+iType.getName()+" match",type);
+        } else {
+            type.setRedirect(iType);
+        }
+    }
+    
+    private boolean resolveAliasFromModule(ClassNode type) {
+        ModuleNode module = currentClass.getModule();
+        if (module==null) return false;
+        String name = type.getName();
+        
+        // check module node imports aliases
+        // the while loop enables a check for inner classes which are not fully imported,
+        // but visible as the surrounding class is imported and the inner class is public/protected static
+        String pname = name;
+        int index = name.length();
+        /*
+         * we have a name foo.bar and an import foo.foo. This means foo.bar is possibly
+         * foo.foo.bar rather than foo.bar. This means to cut at the dot in foo.bar and
+         * foo for import
+         */
+        while (true) {
+            pname = name.substring(0,index);
+            ClassNode aliasedNode = module.getImport(pname);
+            if (aliasedNode!=null) {
+                if (pname.length()==name.length()){
+                    // full match, no need to create a new class
+                    type.setRedirect(aliasedNode);
+                    return true;
+                } else {
+                    //partial match
+                    String newName = aliasedNode.getName()+name.substring(pname.length());
+                    type.setName(newName);
+                    if (resolve(type,true,true,true)) return true;
+                    // was not resolved soit was a fake match
+                    type.setName(name);
+                }
+            }
+            index = pname.lastIndexOf('.');
+            if (index==-1) break;
+        }
+         return false;
+        
+    }
+
+    private boolean resolveFromModule(ClassNode type, boolean testModuleImports) {
+        ModuleNode module = currentClass.getModule();
+        if (module==null) return false;
+
+        String name = type.getName();
+
+        if (!type.hasPackageName() && module.hasPackageName()){
+            type.setName(module.getPackageName()+name);
+        }
+        // look into the module node if there is a class with that name
+        List moduleClasses = module.getClasses();
+        for (Iterator iter = moduleClasses.iterator(); iter.hasNext();) {
+            ClassNode mClass = (ClassNode) iter.next();
+            if (mClass.getName().equals(type.getName())){
+                if (mClass!=type) type.setRedirect(mClass);
+                return true;
+            }
+        }
+        type.setName(name);
+
+        if (testModuleImports) {
+            if (resolveAliasFromModule(type)) return true;
+            
+            boolean resolved = false;
+            if (module.hasPackageName()) { 
+                // check package this class is defined in
+                type.setName(module.getPackageName()+name);
+                resolved = resolve(type,false,false,false);
+            }
+            // check module node imports packages
+            List packages = module.getImportPackages();
+            ClassNode iType = ClassHelper.makeWithoutCaching(name);
+            for (Iterator iter = packages.iterator(); iter.hasNext();) {
+                String packagePrefix = (String) iter.next();
+                String fqn = packagePrefix+name;
+                iType.setName(fqn);
+                if (resolve(iType,false,false,true)) {
+                	ambigousClass(type,iType,name,resolved);
+                    return true;
+                }
+                iType.setName(name);
+            }
+            if (!resolved) type.setName(name);
+            return resolved;
+        }
+        return false;
+    }
+
+    private boolean resolveToClass(ClassNode type) {
+        String name = type.getName();
+        if (cachedClasses.get(name)==NO_CLASS) return false;
+        if (currentClass.getModule().hasPackageName() && name.indexOf('.')==-1) return false;
+        GroovyClassLoader loader  = compilationUnit.getClassLoader();
+        Class cls = null;
+        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) {
+            cachedClasses.put(name,SCRIPT);
+            return false;
+        } catch (CompilationFailedException cfe) {
+            compilationUnit.getErrorCollector().addErrorAndContinue(new ExceptionMessage(cfe,true,source));
+            return false;
+        } 
+        //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 completly compiled before
+        // we can again search for the current name.
+        /*catch (NoClassDefFoundError ncdfe) {
+            cachedClasses.put(name,SCRIPT);
+            return false;
+        }*/
+        if (cls==null) return false;
+        cachedClasses.put(name,cls);
+        setClass(type,cls);
+        //NOTE: we return false here even if we found a class,
+        //but 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.
+        return cls.getClassLoader()==loader;
+    }
+
+
+
+    public Expression transform(Expression exp) {
+        if (exp==null) return null;
+        if (exp instanceof VariableExpression) {
+            return transformVariableExpression((VariableExpression) exp);
+        } else if (exp.getClass()==PropertyExpression.class) {
+            return transformPropertyExpression((PropertyExpression) exp);
+        } else if (exp instanceof DeclarationExpression) {
+            return transformDeclarationExpression((DeclarationExpression)exp);
+        } else if (exp instanceof BinaryExpression) {
+            return transformBinaryExpression((BinaryExpression)exp);
+        } else if (exp instanceof MethodCallExpression) {
+            return transformMethodCallExpression((MethodCallExpression)exp);
+        } else if (exp instanceof ClosureExpression) {
+        	return transformClosureExpression((ClosureExpression) exp);
+        } else if (exp instanceof ConstructorCallExpression) {
+        	return transformConstructorCallExpression((ConstructorCallExpression) exp);
+        } else {
+            resolveOrFail(exp.getType(),exp);
+            return exp.transformExpression(this);
+        }
+    }
+
+
+    private String lookupClassName(PropertyExpression pe) {
+        String name = "";
+        for (Expression it = pe; it!=null; it = ((PropertyExpression)it).getObjectExpression()) {
+            if (it instanceof VariableExpression) {
+                VariableExpression ve = (VariableExpression) it;
+                // stop at super and this
+                if (ve==VariableExpression.SUPER_EXPRESSION || ve==VariableExpression.THIS_EXPRESSION) {
+                    return null;
+                }
+                name= ve.getName()+"."+name;
+                break;
+            } 
+            // anything other than PropertyExpressions, ClassExpression or
+            // VariableExpressions will stop resolving
+            else if (!(it.getClass()==PropertyExpression.class)) {
+                return null;
+            } else {
+                PropertyExpression current = (PropertyExpression) it;
+                String propertyPart = current.getPropertyAsString();
+                // the class property stops resolving, dynamic property names too
+                if (propertyPart==null || propertyPart.equals("class")) {
+                    return null;
+                }
+                name = propertyPart+"."+name;
+            }
+        }
+        if (name.length()>0) return name.substring(0,name.length()-1);
+        return null;
+    }
+
+    // iterate from the inner most to the outer and check for classes
+    // this check will ignore a .class property, for Exmaple Integer.class will be
+    // a PropertyExpression with the ClassExpression of Integer as objectExpression
+    // and class as property
+    private Expression correctClassClassChain(PropertyExpression pe){
+        LinkedList stack = new LinkedList();
+        ClassExpression found = null;
+        for (Expression it = pe; it!=null; it = ((PropertyExpression)it).getObjectExpression()) {
+            if (it instanceof ClassExpression) {
+                found = (ClassExpression) it;
+                break;
+            } else if (! (it.getClass()==PropertyExpression.class)) {
+                return pe;
+            }
+            stack.addFirst(it);
+        }
+        if (found==null) return pe;
+
+        if (stack.isEmpty()) return pe;
+        Object stackElement = stack.removeFirst();
+        if (!(stackElement.getClass()==PropertyExpression.class)) return pe;
+        PropertyExpression classPropertyExpression = (PropertyExpression) stackElement;
+        String propertyNamePart = classPropertyExpression.getPropertyAsString();
+        if (propertyNamePart==null || ! propertyNamePart.equals("class")) return pe;
+
+        if (stack.isEmpty()) return found;
+        stackElement = stack.removeFirst();
+        if (!(stackElement.getClass()==PropertyExpression.class)) return pe;
+        PropertyExpression classPropertyExpressionContainer = (PropertyExpression) stackElement;
+
+        classPropertyExpressionContainer.setObjectExpression(found);
+        return pe;
+    }
+    
+    protected Expression transformPropertyExpression(PropertyExpression pe) {
+        boolean itlp = isTopLevelProperty;
+        
+        Expression objectExpression = pe.getObjectExpression();
+        isTopLevelProperty = !(objectExpression.getClass()==PropertyExpression.class);
+        objectExpression = transform(objectExpression);
+        Expression property = transform(pe.getProperty());
+        isTopLevelProperty = itlp;
+        
+        boolean spreadSafe = pe.isSpreadSafe();
+        pe = new PropertyExpression(objectExpression,property,pe.isSafe());
+        pe.setSpreadSafe(spreadSafe);
+        
+        String className = lookupClassName(pe);
+        if (className!=null) {
+            ClassNode type = ClassHelper.make(className);
+            if (resolve(type)) return new ClassExpression(type);
+        }  
+        if (objectExpression instanceof ClassExpression && pe.getPropertyAsString()!=null){
+            // possibly a inner class
+            ClassExpression ce = (ClassExpression) objectExpression;
+            ClassNode type = ClassHelper.make(ce.getType().getName()+"$"+pe.getPropertyAsString());
+            if (resolve(type,false,false,false)) return new ClassExpression(type);
+        }
+        if (isTopLevelProperty) return correctClassClassChain(pe);
+        
+        return pe;
+    }
+       
+    protected Expression transformVariableExpression(VariableExpression ve) {
+        if (ve.getName().equals("this"))  return VariableExpression.THIS_EXPRESSION;
+        if (ve.getName().equals("super")) return VariableExpression.SUPER_EXPRESSION;
+        Variable v = ve.getAccessedVariable();
+        if (v instanceof DynamicVariable) {
+            ClassNode t = ClassHelper.make(ve.getName());
+            if (resolve(t)) {
+                // the name is a type so remove it from the scoping
+                // as it is only a classvariable, it is only in 
+                // referencedClassVariables, but must be removed
+                // for each parentscope too
+                for (VariableScope scope = currentScope; scope!=null && !scope.isRoot(); scope = scope.getParent()) {
+                    if (scope.isRoot()) break;
+                    if (scope.getReferencedClassVariables().remove(ve.getName())==null) break;
+                }
+                ClassExpression ce = new ClassExpression(t);
+                ce.setSourcePosition(ve);
+                return ce;
+            } else if (!inClosure && ve.isInStaticContext()) {
+                addError("the name "+v.getName()+" doesn't refer to a declared variable or class. The static"+
+                         " scope requires to declare variables before using them. If the variable should have"+
+                         " been a class check the spelling.",ve);
+            }
+        }
+        resolveOrFail(ve.getType(),ve);
+        return ve;
+    }
+    
+    protected Expression transformBinaryExpression(BinaryExpression be) {
+        Expression left = transform(be.getLeftExpression());
+        if (be.getOperation().getType()==Types.ASSIGNMENT_OPERATOR && left instanceof ClassExpression){
+            ClassExpression  ce = (ClassExpression) left;
+            addError("you tried to assign a value to "+ce.getType().getName(),be.getLeftExpression());
+            return be;
+        }
+        if (left instanceof ClassExpression && be.getRightExpression() instanceof ListExpression) {
+            // we have C[] if the list is empty -> should be an array then!
+            ListExpression list = (ListExpression) be.getRightExpression();
+            ClassExpression ce = (ClassExpression) left;
+            if (list.getExpressions().isEmpty()) {
+                return new ClassExpression(left.getType().makeArray());
+            }
+        }
+        Expression right = transform(be.getRightExpression());
+        Expression ret = new BinaryExpression(left,be.getOperation(),right);
+        ret.setSourcePosition(be);
+        return ret;
+    }
+    
+    protected Expression transformClosureExpression(ClosureExpression ce) {
+        boolean oldInClosure = inClosure;
+        inClosure = true;
+        Parameter[] paras = ce.getParameters();
+        if (paras!=null) {
+	        for (int i=0; i<paras.length; i++) {
+	            ClassNode t = paras[i].getType();
+	            resolveOrFail(t,ce);
+	        }
+        }
+        Statement code = ce.getCode();
+        if (code!=null) code.visit(this);
+    	ClosureExpression newCe= new ClosureExpression(paras,code);
+        newCe.setVariableScope(ce.getVariableScope());
+        newCe.setSourcePosition(ce);
+        inClosure = oldInClosure;
+        return newCe;
+    }
+    
+    protected Expression transformConstructorCallExpression(ConstructorCallExpression cce){
+    	ClassNode type = cce.getType();
+    	resolveOrFail(type,cce);
+    	Expression expr = cce.transformExpression(this);
+        return expr;
+    }
+    
+    protected Expression transformMethodCallExpression(MethodCallExpression mce) {
+        Expression obj = mce.getObjectExpression();
+        Expression newObject = transform(obj);
+        Expression args = transform(mce.getArguments());
+        Expression method = transform(mce.getMethod());
+        MethodCallExpression ret = new MethodCallExpression(newObject,method,args);
+        ret.setSafe(mce.isSafe());
+        ret.setImplicitThis(mce.isImplicitThis());
+        ret.setSpreadSafe(mce.isSpreadSafe());
+        ret.setSourcePosition(mce);
+        return ret;
+    }
+    
+    protected Expression transformDeclarationExpression(DeclarationExpression de) {
+        Expression oldLeft = de.getLeftExpression();
+        Expression left = transform(oldLeft);
+        if (left!=oldLeft){
+            ClassExpression  ce = (ClassExpression) left;
+            addError("you tried to assign a value to "+ce.getType().getName(),oldLeft);
+            return de;
+        }
+        Expression right = transform(de.getRightExpression());
+        if (right==de.getRightExpression()) return de;
+        return new DeclarationExpression((VariableExpression) left,de.getOperation(),right);
+    }
+    
+    public void visitAnnotations(AnnotatedNode node) {
+        Map annotionMap = node.getAnnotations();
+        if (annotionMap.isEmpty()) return;
+        Iterator it = annotionMap.values().iterator(); 
+        while (it.hasNext()) {
+            AnnotationNode an = (AnnotationNode) it.next();
+            //skip builtin properties
+            if (an.isBuiltIn()) continue;
+            ClassNode type = an.getClassNode();
+            resolveOrFail(type,"unable to find class for annotation",an);
+        }
+    }
+
+    public void visitClass(ClassNode node) {
+        ClassNode oldNode = currentClass;
+        currentClass = node;
+        
+        ModuleNode module = node.getModule();
+        if (!module.hasImportsResolved()) {
+           List l = module.getImports();
+           for (Iterator iter = l.iterator(); iter.hasNext();) {
+               ImportNode element = (ImportNode) iter.next();
+               ClassNode type = element.getType();
+               if (resolve(type,false,false,false)) continue;
+               addError("unable to resolve class "+type.getName(),type);
+           }
+           module.setImportsResolved(true);
+        }
+        
+        ClassNode sn = node.getUnresolvedSuperClass();
+        if (sn!=null) resolveOrFail(sn,node,true);
+        ClassNode[] interfaces = node.getInterfaces();
+        for (int i=0; i<interfaces.length; i++) {
+            resolveOrFail(interfaces[i],node,true);
+        }        
+        super.visitClass(node);
+        currentClass = oldNode;        
+    }
+    
+    public void visitReturnStatement(ReturnStatement statement) {
+       statement.setExpression(transform(statement.getExpression()));
+    }
+
+    public void visitAssertStatement(AssertStatement as) {
+        as.setBooleanExpression((BooleanExpression) (transform(as.getBooleanExpression())));
+        as.setMessageExpression(transform(as.getMessageExpression()));
+    }
+    
+    public void visitCaseStatement(CaseStatement statement) {
+    	statement.setExpression(transform(statement.getExpression()));
+    	statement.getCode().visit(this);
+    }
+
+    public void visitCatchStatement(CatchStatement cs) {
+        resolveOrFail(cs.getExceptionType(),cs);
+        if (cs.getExceptionType()==ClassHelper.DYNAMIC_TYPE) {
+            cs.getVariable().setType(ClassHelper.make(Exception.class));
+        } 
+        super.visitCatchStatement(cs);
+    }
+
+    public void visitDoWhileLoop(DoWhileStatement loop) {
+        loop.setBooleanExpression((BooleanExpression) (transform(loop.getBooleanExpression())));
+        super.visitDoWhileLoop(loop);
+    }
+    
+    public void visitForLoop(ForStatement forLoop) {
+        forLoop.setCollectionExpression(transform(forLoop.getCollectionExpression()));
+        resolveOrFail(forLoop.getVariableType(),forLoop);
+        super.visitForLoop(forLoop);
+    }
+    
+    public void visitSynchronizedStatement(SynchronizedStatement sync) {
+        sync.setExpression(transform(sync.getExpression()));
+        super.visitSynchronizedStatement(sync);
+    }
+    
+    public void visitThrowStatement(ThrowStatement ts) {
+        ts.setExpression(transform(ts.getExpression()));
+    }
+    
+    public void visitWhileLoop(WhileStatement loop) {
+    	loop.setBooleanExpression((BooleanExpression) transform(loop.getBooleanExpression()));
+    	super.visitWhileLoop(loop);
+    }
+    
+    public void visitExpressionStatement(ExpressionStatement es) {
+        es.setExpression(transform(es.getExpression()));
+    }
+    
+    public void visitBlockStatement(BlockStatement block) {
+        VariableScope oldScope = currentScope;
+        currentScope = block.getVariableScope();
+        super.visitBlockStatement(block);
+        currentScope = oldScope;
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/SourceUnit.java b/groovy-core/src/main/org/codehaus/groovy/control/SourceUnit.java
new file mode 100644
index 0000000..cc0be2b
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/SourceUnit.java
@@ -0,0 +1,388 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.control;
+
+import groovy.lang.GroovyClassLoader;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Reader;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.control.io.FileReaderSource;
+import org.codehaus.groovy.control.io.ReaderSource;
+import org.codehaus.groovy.control.io.StringReaderSource;
+import org.codehaus.groovy.control.io.URLReaderSource;
+import org.codehaus.groovy.control.messages.Message;
+import org.codehaus.groovy.control.messages.SimpleMessage;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.syntax.*;
+import org.codehaus.groovy.tools.Utilities;
+
+import antlr.CharScanner;
+import antlr.MismatchedTokenException;
+import antlr.NoViableAltException;
+import antlr.NoViableAltForCharException;
+
+import com.thoughtworks.xstream.XStream;
+
+
+/**
+ * Provides an anchor for a single source unit (usually a script file)
+ * as it passes through the compiler system.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ * @author <a href="mailto:b55r@sina.com">Bing Ran</a>
+ * @version $Id$
+ */
+
+public class SourceUnit extends ProcessingUnit {
+
+    /**
+     * The pluggable parser used to generate the AST - we allow pluggability currently as we need to have Classic and JSR support
+     */
+    private ParserPlugin parserPlugin;
+
+    /**
+     * Where we can get Readers for our source unit
+     */
+    protected ReaderSource source;
+    /**
+     * A descriptive name of the source unit. This name shouldn't
+     * be used for controling the SourceUnit, it is only for error
+     * messages
+     */
+    protected String name;
+    /**
+     * A Concrete Syntax Tree of the source
+     */
+    protected Reduction cst;
+
+    /**
+     * A facade over the CST
+     */
+    protected SourceSummary sourceSummary;
+    /**
+     * The root of the Abstract Syntax Tree for the source
+     */
+    protected ModuleNode ast;
+
+
+    /**
+     * Initializes the SourceUnit from existing machinery.
+     */
+    public SourceUnit(String name, ReaderSource source, CompilerConfiguration flags, GroovyClassLoader loader, ErrorCollector er) {
+        super(flags, loader, er);
+
+        this.name = name;
+        this.source = source;
+    }
+
+
+    /**
+     * Initializes the SourceUnit from the specified file.
+     */
+    public SourceUnit(File source, CompilerConfiguration configuration, GroovyClassLoader loader, ErrorCollector er) {
+        this(source.getPath(), new FileReaderSource(source, configuration), configuration, loader, er);
+    }
+
+
+    /**
+     * Initializes the SourceUnit from the specified URL.
+     */
+    public SourceUnit(URL source, CompilerConfiguration configuration, GroovyClassLoader loader, ErrorCollector er) {
+        this(source.getPath(), new URLReaderSource(source, configuration), configuration, loader, er);
+    }
+
+
+    /**
+     * Initializes the SourceUnit for a string of source.
+     */
+    public SourceUnit(String name, String source, CompilerConfiguration configuration, GroovyClassLoader loader, ErrorCollector er) {
+        this(name, new StringReaderSource(source, configuration), configuration, loader, er);
+    }
+
+
+    /**
+     * Returns the name for the SourceUnit. This name shouldn't
+     * be used for controling the SourceUnit, it is only for error
+     * messages
+     */
+    public String getName() {
+        return name;
+    }
+
+
+    /**
+     * Returns the Concrete Syntax Tree produced during parse()ing.
+     */
+    public Reduction getCST() {
+        return this.cst;
+    }
+
+    /**
+     * Returns the Source Summary
+     */
+    public SourceSummary getSourceSummary() {
+        return this.sourceSummary;
+    }
+    /**
+     * Returns the Abstract Syntax Tree produced during parse()ing
+     * and expanded during later phases.
+     */
+    public ModuleNode getAST() {
+        return this.ast;
+    }
+
+
+    /**
+     * Convenience routine, primarily for use by the InteractiveShell,
+     * that returns true if parse() failed with an unexpected EOF.
+     */
+    public boolean failedWithUnexpectedEOF() {
+    	// Implementation note - there are several ways for the Groovy compiler
+    	// to report an unexpected EOF. Perhaps this implementation misses some.
+    	// If you find another way, please add it.
+        if (getErrorCollector().hasErrors()) {
+            Message last = (Message) getErrorCollector().getLastError();
+            Throwable cause = null;
+            if (last instanceof SyntaxErrorMessage) {
+                cause = ((SyntaxErrorMessage) last).getCause().getCause();
+            }
+            if (cause != null) {
+            	if (cause instanceof NoViableAltException) {
+                    return isEofToken(((NoViableAltException) cause).token);
+            	} else if (cause instanceof NoViableAltForCharException) {
+            		char badChar = ((NoViableAltForCharException) cause).foundChar;
+            		return badChar == CharScanner.EOF_CHAR;
+                } else if (cause instanceof MismatchedTokenException) {
+                    return isEofToken(((MismatchedTokenException) cause).token);
+                }
+            }
+        }
+        return false;    
+    }
+
+    protected boolean isEofToken(antlr.Token token) {
+        return token.getType() == antlr.Token.EOF_TYPE;
+    }
+
+
+
+    //---------------------------------------------------------------------------
+    // FACTORIES
+
+
+    /**
+     * A convenience routine to create a standalone SourceUnit on a String
+     * with defaults for almost everything that is configurable.
+     */
+    public static SourceUnit create(String name, String source) {
+        CompilerConfiguration configuration = new CompilerConfiguration();
+        configuration.setTolerance(1);
+
+        return new SourceUnit(name, source, configuration, null, new ErrorCollector(configuration));
+    }
+
+
+    /**
+     * A convenience routine to create a standalone SourceUnit on a String
+     * with defaults for almost everything that is configurable.
+     */
+    public static SourceUnit create(String name, String source, int tolerance) {
+        CompilerConfiguration configuration = new CompilerConfiguration();
+        configuration.setTolerance(tolerance);
+
+        return new SourceUnit(name, source, configuration, null, new ErrorCollector(configuration));
+    }
+
+
+
+
+
+    //---------------------------------------------------------------------------
+    // PROCESSING
+
+
+    /**
+     * Parses the source to a CST.  You can retrieve it with getCST().
+     */
+    public void parse() throws CompilationFailedException {
+        if (this.phase > Phases.PARSING) {
+            throw new GroovyBugError("parsing is already complete");
+        }
+
+        if (this.phase == Phases.INITIALIZATION) {
+            nextPhase();
+        }
+
+
+        //
+        // Create a reader on the source and run the parser.
+
+        Reader reader = null;
+        try {
+            reader = source.getReader();
+
+            // lets recreate the parser each time as it tends to keep around state
+            parserPlugin = getConfiguration().getPluginFactory().createParserPlugin();
+
+            cst = parserPlugin.parseCST(this, reader);
+            sourceSummary = parserPlugin.getSummary();
+
+            reader.close();
+            
+        }
+        catch (IOException e) {
+            getErrorCollector().addFatalError(new SimpleMessage(e.getMessage(),this));
+        }
+        finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                }
+                catch (IOException e) {
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Generates an AST from the CST.  You can retrieve it with getAST().
+     */
+    public void convert() throws CompilationFailedException {
+        if (this.phase == Phases.PARSING && this.phaseComplete) {
+            gotoPhase(Phases.CONVERSION);
+        }
+
+        if (this.phase != Phases.CONVERSION) {
+            throw new GroovyBugError("SourceUnit not ready for convert()");
+        }
+
+        
+        //
+        // Build the AST
+        
+        try {
+            this.ast = parserPlugin.buildAST(this, this.classLoader, this.cst);
+
+            this.ast.setDescription(this.name);
+        }
+        catch (SyntaxException e) {
+            getErrorCollector().addError(new SyntaxErrorMessage(e,this));
+        }
+
+        String property = (String) AccessController.doPrivileged(new PrivilegedAction() {
+        	public Object run() {
+        		return System.getProperty("groovy.ast");
+        	}
+        });
+        
+        if ("xml".equals(property)) {
+            saveAsXML(name,ast);
+        }
+    }
+
+    private void saveAsXML(String name, ModuleNode ast) {
+        XStream xstream = new XStream();
+        try {
+            xstream.toXML(ast,new FileWriter(name + ".xml"));
+            System.out.println("Written AST to " + name + ".xml");
+        } catch (Exception e) {
+            System.out.println("Couldn't write to " + name + ".xml");
+            e.printStackTrace();
+        }
+    }
+    //---------------------------------------------------------------------------    // SOURCE SAMPLING
+
+    /**
+     * Returns a sampling of the source at the specified line and column,
+     * of null if it is unavailable.
+     */
+    public String getSample(int line, int column, Janitor janitor) {
+        String sample = null;
+        String text = source.getLine(line, janitor);
+
+        if (text != null) {
+            if (column > 0) {
+                String marker = Utilities.repeatString(" ", column - 1) + "^";
+
+                if (column > 40) {
+                    int start = column - 30 - 1;
+                    int end = (column + 10 > text.length() ? text.length() : column + 10 - 1);
+                    sample = "   " + text.substring(start, end) + Utilities.eol() + "   " + marker.substring(start, marker.length());
+                }
+                else {
+                    sample = "   " + text + Utilities.eol() + "   " + marker;
+                }
+            }
+            else {
+                sample = text;
+            }
+        }
+
+        return sample;
+    }
+    
+    public void addException(Exception e) throws CompilationFailedException {
+        getErrorCollector().addException(e,this);
+    }
+    
+    public void addError(SyntaxException se) throws CompilationFailedException {
+        getErrorCollector().addError(se,this);
+    }
+}
+
+
+
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/io/AbstractReaderSource.java b/groovy-core/src/main/org/codehaus/groovy/control/io/AbstractReaderSource.java
new file mode 100644
index 0000000..da13aed
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/io/AbstractReaderSource.java
@@ -0,0 +1,182 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.control.io;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.Janitor;
+
+
+/**
+ *  For ReaderSources that can choose a parent class, a base that
+ *  provides common functionality.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public abstract class AbstractReaderSource implements ReaderSource
+{
+    protected CompilerConfiguration configuration;   // Configuration data
+
+    
+   /**
+    *  Standard construction stuff.
+    */
+    
+    public AbstractReaderSource( CompilerConfiguration configuration )
+    {
+        if (configuration == null) {
+            throw new IllegalArgumentException("Compiler configuration must not be null!");
+            // ... or more relaxed?
+            // configuration = CompilerConfiguration.DEFAULT;
+        }
+        this.configuration = configuration;
+    }
+    
+    
+   /**
+    *  Returns true if the source can be restarted (ie. if getReader()
+    *  will return non-null on subsequent calls.
+    */
+    
+    public boolean canReopenSource()
+    {
+        return true;
+    }
+    
+    
+    
+  //---------------------------------------------------------------------------
+  // LINE SUPPLY
+
+    
+    private BufferedReader lineSource = null;    // If set, a reader on the current source file
+    private String         line       = null;    // The last line read from the current source file
+    private int            number     = 0;       // The last line number read 
+
+   
+   /**
+    *  Returns a line from the source, or null, if unavailable.  If
+    *  you supply a Janitor, resources will be cached.
+    */
+    
+    public String getLine( int lineNumber, Janitor janitor )
+    {
+        //
+        // If the source is already open and is passed the line we
+        // want, close it.
+        
+        if( lineSource != null && number > lineNumber )
+        {
+            cleanup();
+        }
+    
+        
+        //
+        // If the line source is closed, try to open it.
+        
+        if( lineSource == null )
+        {
+            try { lineSource = new BufferedReader( getReader() ); } catch( Exception e ) {}
+            number = 0;
+        }
+        
+        
+        //
+        // Read until the appropriate line number.
+
+        if( lineSource != null )
+        {
+            while( number < lineNumber )
+            {
+                try
+                {
+                    line = lineSource.readLine();
+                    number++;
+                }
+                catch( IOException e )
+                {
+                    cleanup();
+                }
+            }
+            
+            if( janitor == null )
+            {
+                cleanup();
+            }
+            else
+            {
+                janitor.register( this );
+            }
+        }
+        
+        return line; 
+    }
+    
+    
+    
+   /**
+    *  Cleans up any cached resources used by getLine().
+    */
+    
+    public void cleanup()
+    {
+        if( lineSource != null ) 
+        {
+            try { lineSource.close(); } catch( Exception e ) {}
+        }
+        
+        lineSource = null;
+        line       = null;
+        number     = 0;
+    }
+    
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/io/FileReaderSource.java b/groovy-core/src/main/org/codehaus/groovy/control/io/FileReaderSource.java
new file mode 100644
index 0000000..296f29c
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/io/FileReaderSource.java
@@ -0,0 +1,109 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.control.io;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+
+import org.codehaus.groovy.control.CompilerConfiguration;
+
+
+/**
+ *  A ReaderSource for source files.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class FileReaderSource extends AbstractReaderSource
+{
+  //---------------------------------------------------------------------------
+  // CONSTRUCTION AND SUCH
+      
+    private File file;  // The File from which we produce Readers.
+    
+    
+   /**
+    *  Creates the ReaderSource from a File descriptor.
+    */
+    
+    public FileReaderSource( File file, CompilerConfiguration configuration )
+    {
+        super( configuration );
+        this.file = file;
+    }
+    
+    
+    
+   /**
+    *  Creates the ReaderSource from a file path.
+    */
+    
+    public FileReaderSource( String path, CompilerConfiguration configuration )
+    {
+        this( new File(path), configuration );
+    }
+   
+    
+    
+   /**
+    *  Returns a new Reader on the underlying source object.  
+    */
+    
+    public Reader getReader() throws IOException
+    {
+        return new InputStreamReader( new FileInputStream(file), configuration.getSourceEncoding() );
+    }
+    
+    
+    
+ 
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/io/InputStreamReaderSource.java b/groovy-core/src/main/org/codehaus/groovy/control/io/InputStreamReaderSource.java
new file mode 100644
index 0000000..3124cfb
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/io/InputStreamReaderSource.java
@@ -0,0 +1,119 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.control.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+
+import org.codehaus.groovy.control.CompilerConfiguration;
+
+
+/**
+ *  A ReaderSource for source strings.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class InputStreamReaderSource extends AbstractReaderSource
+{
+    
+  //---------------------------------------------------------------------------
+  // CONSTRUCTION AND SUCH
+      
+    private InputStream stream;  // The InputStream from which we produce a Reader.
+    
+    
+   /**
+    *  Creates the ReaderSource from a File descriptor.
+    */
+    
+    public InputStreamReaderSource( InputStream stream, CompilerConfiguration configuration )
+    {
+        super( configuration );
+        this.stream = stream;
+    }
+    
+    
+    
+   /**
+    *  Returns a new Reader on the underlying source object.  
+    */
+    
+    public Reader getReader() throws IOException
+    {
+        if( stream != null )
+        {
+            Reader reader = new InputStreamReader( stream, configuration.getSourceEncoding() );
+            stream = null;
+            
+            return reader;
+        }
+        
+        return null;
+    }
+
+    
+
+   /**
+    *  Returns true if the source can be restarted (ie. if getReader()
+    *  will return non-null on subsequent calls.
+    */
+    
+    public boolean canReopenSource()
+    {
+        return false;
+    }
+    
+    
+    
+
+    
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/io/NullWriter.java b/groovy-core/src/main/org/codehaus/groovy/control/io/NullWriter.java
new file mode 100644
index 0000000..afd6b29
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/io/NullWriter.java
@@ -0,0 +1,69 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.control.io;
+
+import java.io.Writer;
+
+
+/**
+ *  An Writer than eats its input.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class NullWriter extends Writer
+{
+    public static final NullWriter DEFAULT = new NullWriter();
+    
+    public void close() {}
+    
+    public void flush() {}
+    
+    public void write( char[] cbuf, int off, int len ) {}
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/io/ReaderSource.java b/groovy-core/src/main/org/codehaus/groovy/control/io/ReaderSource.java
new file mode 100644
index 0000000..00e01c4
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/io/ReaderSource.java
@@ -0,0 +1,101 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.control.io;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.codehaus.groovy.control.HasCleanup;
+import org.codehaus.groovy.control.Janitor;
+
+
+/**
+ *  An interface for things that can supply (and resupply) a Reader
+ *  on a source stream.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public interface ReaderSource extends HasCleanup
+{
+   
+   /**
+    *  Returns a new Reader on the underlying source object.  Returns
+    *  null if the source can't be reopened.
+    */
+    
+    Reader getReader() throws IOException;
+    
+    
+    
+   /**
+    *  Returns true if the source can be restarted (ie. if getReader()
+    *  will return non-null on subsequent calls.
+    */
+    
+    boolean canReopenSource();
+    
+    
+    
+   /**
+    *  Returns a line from the source, or null, if unavailable.  If
+    *  you supply a Janitor, resources will be cached.
+    */
+    
+    String getLine( int lineNumber, Janitor janitor );
+    
+    
+    
+   /**
+    *  Cleans up any cached resources used by getLine().
+    */
+    
+    void cleanup();
+    
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/io/StringReaderSource.java b/groovy-core/src/main/org/codehaus/groovy/control/io/StringReaderSource.java
new file mode 100644
index 0000000..ca2d9ae
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/io/StringReaderSource.java
@@ -0,0 +1,97 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.control.io;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+
+import org.codehaus.groovy.control.CompilerConfiguration;
+
+
+/**
+ *  A ReaderSource for source strings.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class StringReaderSource extends AbstractReaderSource
+{
+    
+  //---------------------------------------------------------------------------
+  // CONSTRUCTION AND SUCH
+      
+    private String string;  // The String from which we produce Readers.
+    
+    
+   /**
+    *  Creates the ReaderSource from a File descriptor.
+    */
+    
+    public StringReaderSource( String string, CompilerConfiguration configuration )
+    {
+        super( configuration );
+        this.string= string;
+    }
+    
+    
+    
+   /**
+    *  Returns a new Reader on the underlying source object.  
+    */
+    
+    public Reader getReader() throws IOException
+    {
+        return new StringReader( string );
+    }
+    
+    
+    
+ 
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/io/URLReaderSource.java b/groovy-core/src/main/org/codehaus/groovy/control/io/URLReaderSource.java
new file mode 100644
index 0000000..9ef43b8
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/io/URLReaderSource.java
@@ -0,0 +1,97 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.control.io;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URL;
+
+import org.codehaus.groovy.control.CompilerConfiguration;
+
+
+/**
+ *  A ReaderSource for source files.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class URLReaderSource extends AbstractReaderSource
+{
+  //---------------------------------------------------------------------------
+  // CONSTRUCTION AND SUCH
+      
+    private URL url;  // The URL from which we produce Readers.
+    
+    
+   /**
+    *  Creates the ReaderSource from a File descriptor.
+    */
+    
+    public URLReaderSource( URL url, CompilerConfiguration configuration )
+    {
+        super( configuration );
+        this.url = url;
+    }
+    
+    
+    
+   /**
+    *  Returns a new Reader on the underlying source object.  
+    */
+    
+    public Reader getReader() throws IOException
+    {
+        return new InputStreamReader( url.openStream(), configuration.getSourceEncoding() );
+    }
+    
+    
+    
+ 
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/messages/ExceptionMessage.java b/groovy-core/src/main/org/codehaus/groovy/control/messages/ExceptionMessage.java
new file mode 100644
index 0000000..6526784
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/messages/ExceptionMessage.java
@@ -0,0 +1,72 @@
+package org.codehaus.groovy.control.messages;
+
+import java.io.PrintWriter;
+
+import org.codehaus.groovy.control.Janitor;
+import org.codehaus.groovy.control.ProcessingUnit;
+
+
+
+/**
+ *  A class for error messages produced by the parser system.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class ExceptionMessage extends Message
+{
+    protected boolean verbose = true;
+
+    private Exception cause = null;   // The exception source of the message, if any
+    ProcessingUnit owner = null;
+
+    public ExceptionMessage( Exception cause, boolean v, ProcessingUnit owner )
+    {
+        this.verbose = v;
+        this.cause = cause;
+        this.owner = owner;
+    }
+    
+    
+   
+   /**
+    *  Returns the underlying Exception.
+    */
+
+    public Exception getCause()
+    {
+        return this.cause;
+    }
+    
+
+
+   /**
+    *  Writes out a nicely formatted summary of the exception. 
+    */
+    
+    public void write( PrintWriter output, Janitor janitor )
+    {
+        String description = "General error during " + owner.getPhaseDescription() + ": "; 
+        
+        String message = cause.getMessage();
+        if( message != null )
+        {
+            output.println( description + message );
+        }
+        else
+        {
+            output.println( description + cause );
+        }
+        output.println();
+
+        //if (verbose) {
+            cause.printStackTrace(output);
+        //}
+    }
+    
+}
+
+
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/messages/LocatedMessage.java b/groovy-core/src/main/org/codehaus/groovy/control/messages/LocatedMessage.java
new file mode 100644
index 0000000..c71da99
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/messages/LocatedMessage.java
@@ -0,0 +1,59 @@
+package org.codehaus.groovy.control.messages;
+
+import java.io.PrintWriter;
+
+import org.codehaus.groovy.control.Janitor;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.syntax.CSTNode;
+
+
+
+/**
+ *  A base class for compilation messages.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class LocatedMessage extends SimpleMessage
+{
+    protected CSTNode context;  // The CSTNode that indicates the location to which the message applies
+    
+    public LocatedMessage( String message, CSTNode context, SourceUnit source ) 
+    {
+        super( message, source );
+        this.context = context;
+    }
+    
+    
+    public LocatedMessage( String message, Object data, CSTNode context, SourceUnit source ) 
+    {
+        super( message, data, source );
+        this.context = context;
+    }
+    
+    
+    public void write( PrintWriter writer, Janitor janitor )
+    {
+        SourceUnit source = (SourceUnit) owner;
+        
+        String name   = source.getName();
+        int    line   = context.getStartLine();
+        int    column = context.getStartColumn();
+        String sample = source.getSample( line, column, janitor );
+        
+        if( sample != null )
+        {
+            writer.println( source.getSample(line, column, janitor) );
+        }
+        
+        writer.println( name + ": " + line + ": " + this.message );
+        writer.println("");
+    }
+    
+}
+
+
+
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/messages/Message.java b/groovy-core/src/main/org/codehaus/groovy/control/messages/Message.java
new file mode 100644
index 0000000..4caac9e
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/messages/Message.java
@@ -0,0 +1,85 @@
+package org.codehaus.groovy.control.messages;
+
+import java.io.PrintWriter;
+
+import org.codehaus.groovy.control.Janitor;
+import org.codehaus.groovy.control.ProcessingUnit;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.syntax.SyntaxException;
+
+
+
+/**
+ *  A base class for compilation messages.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public abstract class Message
+{
+    
+    
+   /**
+    *  Writes the message to the specified PrintWriter.  The supplied
+    *  ProcessingUnit is the unit that holds this Message.
+    */
+    
+    public abstract void write( PrintWriter writer, Janitor janitor );
+    
+    
+   /**
+    *  A synonyn for write( writer, owner, null ).
+    */
+    
+    public final void write( PrintWriter writer)
+    {
+        write( writer,  null );
+    }
+    
+    
+    
+  //---------------------------------------------------------------------------
+  // FACTORY METHODS
+    
+    
+   /**
+    *  Creates a new Message from the specified text.
+    */
+    
+    public static Message create( String text, ProcessingUnit owner )
+    {
+        return new SimpleMessage( text, owner );
+    }
+    
+    
+          
+   /**
+    *  Creates a new Message from the specified text.
+    */
+     
+    public static Message create( String text, Object data, ProcessingUnit owner  )
+    {
+        return new SimpleMessage( text, data, owner);
+    }
+     
+     
+           
+   /**
+    *  Creates a new Message from the specified SyntaxException.
+    */
+      
+    public static Message create( SyntaxException error, SourceUnit owner )
+    {
+        return new SyntaxErrorMessage( error, owner );
+    }
+      
+    
+      
+    
+}
+
+
+
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/messages/SimpleMessage.java b/groovy-core/src/main/org/codehaus/groovy/control/messages/SimpleMessage.java
new file mode 100644
index 0000000..02364ff
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/messages/SimpleMessage.java
@@ -0,0 +1,61 @@
+package org.codehaus.groovy.control.messages;
+
+import java.io.PrintWriter;
+
+import org.codehaus.groovy.control.Janitor;
+import org.codehaus.groovy.control.ProcessingUnit;
+import org.codehaus.groovy.control.SourceUnit;
+
+
+
+/**
+ *  A base class for compilation messages.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class SimpleMessage extends Message
+{
+    protected String message;  // Message text
+    protected Object data;     // Data, when the message text is an I18N identifier
+    protected ProcessingUnit owner;
+    
+    public SimpleMessage( String message, ProcessingUnit source ) 
+    {
+        this( message, null, source );
+    }
+    
+    public SimpleMessage( String message, Object data, ProcessingUnit source )
+    {
+        this.message = message;
+        this.data    = null;
+        this.owner = source;
+    }
+    
+    
+    public void write( PrintWriter writer, Janitor janitor )
+    {
+        if( owner instanceof SourceUnit )
+        {
+            String name = ((SourceUnit)owner).getName();
+            writer.println( "" + name + ": " + message );
+        }
+        else
+        {
+            writer.println( message );
+        }
+    }
+    
+    
+    public String getMessage()
+    {
+        return message;
+    }
+    
+}
+
+
+
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/messages/SyntaxErrorMessage.java b/groovy-core/src/main/org/codehaus/groovy/control/messages/SyntaxErrorMessage.java
new file mode 100644
index 0000000..6057155
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/messages/SyntaxErrorMessage.java
@@ -0,0 +1,59 @@
+package org.codehaus.groovy.control.messages;
+
+import java.io.PrintWriter;
+
+import org.codehaus.groovy.control.Janitor;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.syntax.SyntaxException;
+
+
+/**
+ * A class for error messages produced by the parser system.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ * @version $Id$
+ */
+
+public class SyntaxErrorMessage extends Message {
+    protected SyntaxException cause = null;
+    protected SourceUnit source;
+    
+    public SyntaxErrorMessage(SyntaxException cause, SourceUnit source) {
+        this.cause = cause;
+        this.source = source;
+        cause.setSourceLocator(source.getName());
+    }
+
+
+    /**
+     * Returns the underlying SyntaxException.
+     */
+
+    public SyntaxException getCause() {
+        return this.cause;
+    }
+
+
+    /**
+     * Writes out a nicely formatted summary of the syntax error.
+     */
+
+    public void write(PrintWriter output, Janitor janitor) {
+        String name = source.getName();
+        int line = getCause().getStartLine();
+        int column = getCause().getStartColumn();
+        String sample = source.getSample(line, column, janitor);
+
+        output.print(name + ": " + line + ": " + getCause().getMessage());
+        if (sample != null) {
+            output.println();
+            output.print(sample);
+            output.println();
+        }
+    }
+
+
+}
+
+
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/control/messages/WarningMessage.java b/groovy-core/src/main/org/codehaus/groovy/control/messages/WarningMessage.java
new file mode 100644
index 0000000..6319395
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/control/messages/WarningMessage.java
@@ -0,0 +1,102 @@
+package org.codehaus.groovy.control.messages;
+
+import java.io.PrintWriter;
+
+import org.codehaus.groovy.control.Janitor;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.syntax.CSTNode;
+
+
+
+/**
+ *  A class for warning messages.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class WarningMessage extends LocatedMessage
+{
+  //---------------------------------------------------------------------------
+  // WARNING LEVELS
+
+    public static final int NONE            = 0;  // For querying, ignore all errors
+    public static final int LIKELY_ERRORS   = 1;  // Warning indicates likely error
+    public static final int POSSIBLE_ERRORS = 2;  // Warning indicates possible error
+    public static final int PARANOIA        = 3;  // Warning indicates paranoia on the part of the compiler
+    
+    
+   /**
+    *  Returns true if a warning would be relevant to the specified level.
+    */
+    
+    public static boolean isRelevant( int actual, int limit )
+    {
+        return actual <= limit;
+    }
+    
+    
+    
+   /**
+    *  Returns true if this message is as or more important than the 
+    *  specified importance level.
+    */
+    
+    public boolean isRelevant( int importance )
+    {
+        return isRelevant( this.importance, importance );
+    }
+    
+    
+    
+  //---------------------------------------------------------------------------
+  // CONSTRUCTION AND DATA ACCESS
+
+    private int importance;  // The warning level, for filtering
+    
+    
+   /**
+    *  Creates a new warning message.
+    * 
+    *  @param importance the warning level 
+    *  @param message    the message text
+    *  @param context    context information for locating the offending source text
+    */
+     
+    public WarningMessage( int importance, String message, CSTNode context, SourceUnit owner )
+    {
+        super( message, context, owner );
+        this.importance = importance;
+    }
+
+    
+    
+   /**
+    *  Creates a new warning message.
+    *
+    *  @param importance the warning level 
+    *  @param message    the message text
+    *  @param data       additional data needed when generating the message
+    *  @param context    context information for locating the offending source text
+    */
+     
+    public WarningMessage( int importance, String message, Object data, CSTNode context, SourceUnit owner )
+    {
+        super( message, data, context, owner );
+        this.importance = importance;
+    }
+    
+    
+    public void write( PrintWriter writer, Janitor janitor )
+    {
+        writer.print( "warning: " );
+        super.write( writer, janitor );
+    }
+
+     
+     
+}
+
+
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/package.html b/groovy-core/src/main/org/codehaus/groovy/package.html
new file mode 100644
index 0000000..0bbd7fc
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/package.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>package org.codehaus.groovy.*</title>
+  </head>
+  <body>
+    <p>Groovy Language for the JVM</p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/ClassExtender.java b/groovy-core/src/main/org/codehaus/groovy/runtime/ClassExtender.java
new file mode 100644
index 0000000..0d60407
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/ClassExtender.java
@@ -0,0 +1,117 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.Closure;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * A helper class used by the runtime to allow Groovy classes to be extended at runtime
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ClassExtender {
+    private Map variables;
+    private Map methods;
+
+    public synchronized Object get(String name) {
+        if (variables != null) {
+            return variables.get(name);
+        }
+        return null;
+    }
+
+    public synchronized void set(String name, Object value) {
+        if (variables == null) {
+            variables = createMap();
+        }
+        variables.put(name, value);
+    }
+
+    public synchronized void remove(String name) {
+        if (variables != null) {
+            variables.remove(name);
+        }
+    }
+
+    public void call(String name, Object params) {
+        Closure closure = null;
+        synchronized (this) {
+            if (methods != null) {
+                closure = (Closure) methods.get(name);
+            }
+        }
+        if (closure != null) {
+            closure.call(params);
+        }
+        /*
+        else {
+            throw DoesNotUnderstandException();
+        }
+        */
+    }
+
+    public synchronized void addMethod(String name, Closure closure) {
+        if (methods == null) {
+            methods = createMap();
+        }
+        methods.put(name, methods);
+    }
+
+    public synchronized void removeMethod(String name) {
+        if (methods != null) {
+            methods.remove(name);
+        }
+    }
+
+    protected Map createMap() {
+        return new HashMap();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/ClosureListener.java b/groovy-core/src/main/org/codehaus/groovy/runtime/ClosureListener.java
new file mode 100644
index 0000000..351c390
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/ClosureListener.java
@@ -0,0 +1,91 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.Closure;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+/**
+ * Represents a method on an object using a closure which can be invoked at any
+ * time
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ClosureListener implements InvocationHandler {
+
+    private String listenerMethodName;
+    private Closure closure;
+
+    public ClosureListener(String listenerMethodName, Closure closure) {
+        this.listenerMethodName = listenerMethodName;
+        this.closure = closure;
+    }
+
+    public Object invoke(Object object, Method method, Object[] arguments) throws Throwable {
+        if (listenerMethodName.equals(method.getName())) {
+            /** @todo hack! */
+            closure.call(arguments[0]);
+            return null;
+        }
+
+        // lets try call this object
+        String name = method.getName();
+        if (name.equals("equals")) {
+            return object == arguments[0] ? Boolean.TRUE : Boolean.FALSE;
+        }
+        else if (name.equals("hashCode")) {
+            return new Integer(hashCode());
+        }
+        else if (name.equals("toString")) {
+            return super.toString() + "[listener:" + listenerMethodName + "]";
+        }
+
+        /*
+		 * int paramCount = method.getParameterTypes().length;
+		 * 
+		 * System.out.println("Now calling method: " + method);
+		 * 
+		 * Method[] methods = Object.class.getMethods(); for (int i = 0; i
+		 * < methods.length; i++ ) { Method aMethod = methods[i]; if
+		 * (name.equals(aMethod.getName()) &&
+		 * aMethod.getParameterTypes().length == paramCount) { return
+		 * aMethod.invoke(object, arguments); } }
+		 */
+        return null;
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/ConversionHandler.java b/groovy-core/src/main/org/codehaus/groovy/runtime/ConversionHandler.java
new file mode 100644
index 0000000..4112d5a
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/ConversionHandler.java
@@ -0,0 +1,115 @@
+package org.codehaus.groovy.runtime;

+

+import java.lang.reflect.InvocationHandler;

+import java.lang.reflect.InvocationTargetException;

+import java.lang.reflect.Method;

+

+/**

+ * This class is a general adapter to map a call to an Java interface 

+ * to a given delegate.

+ * <p>

+ * @author Ben Yu

+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>

+ */

+public abstract class ConversionHandler implements InvocationHandler {

+    private Object delegate;

+    

+    /**

+     * Creates a ConversionHandler with an deleagte.

+     * @param delegate the delegate

+     * @throws IllegalArgumentException if the given delegate is null

+     */

+    public ConversionHandler(Object delegate) {

+        if (delegate==null) throw new IllegalArgumentException("delegate must not be null");

+        this.delegate = delegate;

+    }

+    

+    /**

+     * gets the delegate.

+     * @return the delegate

+     */

+    public Object getDelegate(){

+        return delegate;

+    }

+    

+    /**

+     * This method is a default implementation for the invoke method

+     * given in Invocationhandler. Any call to an method with an

+     * declaring class that is not Object is redirected to invokeCustom. 

+     * Methods like tostring, equals and hashcode are called on the class

+     * itself instead of the delegate. It is better to overwrite the 

+     * invokeCustom method where the Object related methods are filtered out.

+     * 

+     * @see #invokeCustom(Object, Method, Object[])

+     * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])

+     * 

+     * @param proxy the proxy

+     * @param method the method

+     * @param args the arguments

+     * @return the result of the invocation by method or delegate

+     * @throws Throwable any exception caused by the delegate or the method

+     */

+    public Object invoke(Object proxy, Method method, Object[] args)

+    throws Throwable {

+        if(!isObjectMethod(method)){

+            return invokeCustom(proxy,method,args);

+        }

+        try {

+            return method.invoke(this, args);

+        } catch (InvocationTargetException ite) {

+            throw ite.getTargetException();

+        }  

+    }

+    

+    /**

+     * This method is called for all Methods not defined on Object. 

+     * The delegate should be called here.

+     * 

+     * @param proxy the proxy

+     * @param method the method

+     * @param args the arguments

+     * @return the result of the invocation of the delegate

+     * @throws Throwable any exception causes by the delegate

+     * @see #invoke(Object, Method, Object[])

+     * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])

+     * 

+     */

+    public abstract Object invokeCustom(Object proxy, Method method, Object[] args) throws Throwable;

+    

+    /**

+     * Indicates whether some other object is "equal to" this one.

+     * The delegate is used if the class of the parameter and the

+     * current class are equal. In other cases the method will return 

+     * false. The exact class is here used, if inheritance is needed,

+     * this method must be overwritten. 

+     *        

+     * @see java.lang.Object#equals(java.lang.Object)

+     */

+    public boolean equals(Object obj) {

+        if (obj!=null && obj.getClass()==this.getClass()){

+            return (((ConversionHandler)obj).getDelegate()).equals(obj);

+        } else {

+            return false;

+        }

+    }

+

+    /**

+     * Returns a hash code value for the delegate. 

+     * @see java.lang.Object#hashCode()

+     */

+    public int hashCode() {

+        return delegate.hashCode();

+    }

+    

+    /**

+     * Returns a String version of the delegate.

+     * @see java.lang.Object#toString()

+     */

+    public String toString() {

+        return delegate.toString();

+    }

+    

+    private static boolean isObjectMethod(Method mtd){

+        return mtd.getDeclaringClass().equals(Object.class);

+    }

+}

diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/ConvertedClosure.java b/groovy-core/src/main/org/codehaus/groovy/runtime/ConvertedClosure.java
new file mode 100644
index 0000000..5a4ce58
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/ConvertedClosure.java
@@ -0,0 +1,28 @@
+package org.codehaus.groovy.runtime;

+

+import java.lang.reflect.Method;

+import groovy.lang.Closure;

+

+/**

+ * This class is a general adapter to adapt a closure to any Java interface.

+ * <p>

+ * @author Ben Yu

+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>

+ * Jul 27, 2006 3:50:51 PM

+ */

+public class ConvertedClosure extends ConversionHandler {

+    

+    /**

+     * to create a ConvertedClosure object.

+     * @param closure the closure object.

+     */

+    protected ConvertedClosure(Closure closure) {

+        super(closure);

+    }

+    

+    public Object invokeCustom(Object proxy, Method method, Object[] args)

+    throws Throwable {

+        return ((Closure) getDelegate()).call(args);

+    }

+}

+

diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/ConvertedMap.java b/groovy-core/src/main/org/codehaus/groovy/runtime/ConvertedMap.java
new file mode 100644
index 0000000..90590d6
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/ConvertedMap.java
@@ -0,0 +1,41 @@
+/*

+ * ConvertedClosure.java created on 12.10.2006

+ *

+ * To change this generated comment go to 

+ * Window>Preferences>Java>Code Generation>Code and Comments

+ */

+package org.codehaus.groovy.runtime;

+

+import java.lang.reflect.Method;

+import java.util.Map;

+

+import groovy.lang.Closure;

+

+/**

+ * This class is a general adapter to adapt a map of closures to

+ * any Java interface.

+ * <p>

+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>

+ */

+public class ConvertedMap extends ConversionHandler {

+        

+    /**

+     * to create a ConvertedMap object.

+     * @param map the map of closres

+     */

+    protected ConvertedMap(Map closures) {

+        super(closures);

+    }

+    

+    public Object invokeCustom(Object proxy, Method method, Object[] args)

+    throws Throwable {

+        Map m = (Map) getDelegate();

+        Closure cl = (Closure) m.get(method.getName());

+        return cl.call(args);

+    }

+    

+    public String toString() {

+        return DefaultGroovyMethods.toString((Map) getDelegate());

+    }

+}

+

diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/CurriedClosure.java b/groovy-core/src/main/org/codehaus/groovy/runtime/CurriedClosure.java
new file mode 100644
index 0000000..4517982
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/CurriedClosure.java
@@ -0,0 +1,29 @@
+
+package org.codehaus.groovy.runtime;
+
+
+import groovy.lang.Closure;
+ 
+/**
+ * Represents wrapper around a Closure to support currying
+ * 
+ * @author Jochen Theodorou
+ */
+public class CurriedClosure extends Closure {
+
+    private Object[] curriedParams;
+    
+    public CurriedClosure(Closure uncurriedClosure, Object[] arguments) {
+        super(uncurriedClosure);
+        curriedParams = arguments;
+        maximumNumberOfParameters = uncurriedClosure.getMaximumNumberOfParameters()-arguments.length;
+    }
+
+    public Object[] getUncurriedArguments(Object[] arguments) {
+        final Object newCurriedParams[] = new Object[curriedParams.length + arguments.length];
+        System.arraycopy(curriedParams, 0, newCurriedParams, 0, curriedParams.length);
+        System.arraycopy(arguments, 0, newCurriedParams, curriedParams.length, arguments.length);
+        return newCurriedParams;        
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/groovy-core/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
new file mode 100644
index 0000000..2559ea6
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -0,0 +1,6917 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.*;
+import groovy.util.CharsetToolkit;
+import groovy.util.ClosureComparator;
+import groovy.util.OrderBy;
+
+import java.io.*;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.MalformedURLException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.*;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.codehaus.groovy.runtime.typehandling.NumberMath;
+import org.codehaus.groovy.tools.RootLoader;
+import org.w3c.dom.NodeList;
+
+/**
+ * This class defines all the new groovy methods which appear on normal JDK
+ * classes inside the Groovy environment. Static methods are used with the
+ * first parameter the destination class.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Jeremy Rayner
+ * @author Sam Pullara
+ * @author Rod Cope
+ * @author Guillaume Laforge
+ * @author John Wilson
+ * @author Hein Meling
+ * @author Dierk Koenig
+ * @author Pilho Kim
+ * @author Marc Guillemot
+ * @author Russel Winder
+ * @author bing ran
+ * @author Jochen Theodorou
+ * @version $Revision$
+ */
+public class DefaultGroovyMethods {
+
+    private static final Logger LOG = Logger.getLogger(DefaultGroovyMethods.class.getName());
+    private static final Integer ONE = new Integer(1);
+
+    /**
+     * Identity check. Since == is overridden in Groovy with the meaning of equality
+     * we need some fallback to check for object identity.
+     *
+     * @param self
+     * @param other
+     * @return true if self and other are identical, false otherwise
+     */
+    public static boolean is(Object self, Object other) {
+        return self == other;
+    }
+
+    /**
+     * Allows the closure to be called for the object reference self
+     *
+     * @param self    the object to have a closure act upon
+     * @param closure the closure to call on the object
+     * @return result of calling the closure
+     */
+    public static Object identity(Object self, Closure closure) {
+        final Closure clonedClosure = (Closure) closure.clone();
+        clonedClosure.setDelegate(self);
+        return clonedClosure.call(self);
+    }
+
+    /**
+     * Allows the subscript operator to be used to lookup dynamic property values.
+     * <code>bean[somePropertyNameExpression]</code>. The normal property notation
+     * of groovy is neater and more concise but only works with compile-time known
+     * property names.
+     *
+     * @param self the object to act upon
+     */
+    public static Object getAt(Object self, String property) {
+        return InvokerHelper.getProperty(self, property);
+    }
+
+    /**
+     * Allows the subscript operator to be used to set dynamically named property values.
+     * <code>bean[somePropertyNameExpression] = foo</code>. The normal property notation
+     * of groovy is neater and more concise but only works with property names which
+     * are known at compile time.
+     *
+     * @param self     the object to act upon
+     * @param property the name of the property to set
+     * @param newValue the value to set
+     */
+    public static void putAt(Object self, String property, Object newValue) {
+        InvokerHelper.setProperty(self, property, newValue);
+    }
+
+    /**
+     * Generates a detailed dump string of an object showing its class,
+     * hashCode and fields
+     */
+    public static String dump(Object self) {
+        if (self == null) {
+            return "null";
+        }
+        StringBuffer buffer = new StringBuffer("<");
+        Class klass = self.getClass();
+        buffer.append(klass.getName());
+        buffer.append("@");
+        buffer.append(Integer.toHexString(self.hashCode()));
+        boolean groovyObject = self instanceof GroovyObject;
+
+        /*jes this may be rewritten to use the new getProperties() stuff
+         * but the original pulls out private variables, whereas getProperties()
+         * does not. What's the real use of dump() here?
+         */
+        while (klass != null) {
+            Field[] fields = klass.getDeclaredFields();
+            for (int i = 0; i < fields.length; i++) {
+                final Field field = fields[i];
+                if ((field.getModifiers() & Modifier.STATIC) == 0) {
+                    if (groovyObject && field.getName().equals("metaClass")) {
+                        continue;
+                    }
+                    AccessController.doPrivileged(new PrivilegedAction() {
+                        public Object run() {
+                            field.setAccessible(true);
+                            return null;
+                        }
+                    });
+                    buffer.append(" ");
+                    buffer.append(field.getName());
+                    buffer.append("=");
+                    try {
+                        buffer.append(InvokerHelper.toString(field.get(self)));
+                    } catch (Exception e) {
+                        buffer.append(e);
+                    }
+                }
+            }
+
+            klass = klass.getSuperclass();
+        }
+
+        /* here is a different implementation that uses getProperties(). I have left
+         * it commented out because it returns a slightly different list of properties;
+         * ie it does not return privates. I don't know what dump() really should be doing,
+         * although IMO showing private fields is a no-no
+         */
+        /*
+        List props = getProperties(self);
+            for(Iterator itr = props.keySet().iterator(); itr.hasNext(); ) {
+            String propName = itr.next().toString();
+
+            // the original skipped this, so I will too
+            if(pv.getName().equals("metaClass")) continue;
+            if(pv.getName().equals("class")) continue;
+
+            buffer.append(" ");
+            buffer.append(propName);
+            buffer.append("=");
+            try {
+                buffer.append(InvokerHelper.toString(props.get(propName)));
+            }
+            catch (Exception e) {
+                buffer.append(e);
+            }
+        }
+        */
+
+        buffer.append(">");
+        return buffer.toString();
+    }
+
+    /**
+     * Retrieves the list of {@link MetaProperty} objects for 'self' and wraps it
+     * in a list of {@link PropertyValue} objects that additionally provide
+     * the value for each property of 'self'.
+     *
+     * @param self the receiver object
+     * @return list of {@link PropertyValue} objects
+     * @see groovy.util.Expando#getMetaPropertyValues()
+     */
+    public static List getMetaPropertyValues(Object self) {
+        MetaClass metaClass = InvokerHelper.getMetaClass(self);
+        List mps = metaClass.getProperties();
+        List props = new ArrayList(mps.size());
+        for (Iterator itr = mps.iterator(); itr.hasNext();) {
+            MetaProperty mp = (MetaProperty) itr.next();
+            PropertyValue pv = new PropertyValue(self, mp);
+            props.add(pv);
+        }
+        return props;
+    }
+
+    /**
+     * Convenience method that calls {@link #getMetaPropertyValues(Object)}(self)
+     * and provides the data in form of simple key/value pairs, i.e. without
+     * type() information.
+     *
+     * @param self the receiver object
+     * @return meta properties as Map of key/value pairs
+     */
+    public static Map getProperties(Object self) {
+        List metaProps = getMetaPropertyValues(self);
+        Map props = new HashMap(metaProps.size());
+
+        for (Iterator itr = metaProps.iterator(); itr.hasNext();) {
+            PropertyValue pv = (PropertyValue) itr.next();
+            try {
+                props.put(pv.getName(), pv.getValue());
+            } catch (Exception e) {
+                LOG.throwing(self.getClass().getName(), "getProperty(" + pv.getName() + ")", e);
+            }
+        }
+        return props;
+    }
+
+    /**
+     * Scoped use method
+     */
+    public static void use(Object self, Class categoryClass, Closure closure) {
+        GroovyCategorySupport.use(categoryClass, closure);
+    }
+
+    /**
+     * Scoped use method with list of categories
+     */
+    public static void use(Object self, List categoryClassList, Closure closure) {
+        GroovyCategorySupport.use(categoryClassList, closure);
+    }
+
+
+    /**
+     * use() a list of categories, specifying the list as varargs:<br>
+     * use(CategoryClass1, CategoryClass2) { ... }<br>
+     * This method prevents the error of forgetting to wrap the the category
+     * classes in a list.
+     *
+     * @param self
+     * @param array
+     */
+    public static void use(Object self, Object[] array) {
+        if (array.length < 2)
+            throw new IllegalArgumentException(
+                    "Expecting at least 2 arguments, a category class and a Closure");
+        Closure closure;
+        try {
+            closure = (Closure) array[array.length - 1];
+        } catch (ClassCastException e) {
+            throw new IllegalArgumentException("Expecting a Closure to be the last argument");
+        }
+        List list = new ArrayList(array.length - 1);
+        for (int i = 0; i < array.length - 1; ++i)
+            list.add(array[i]);
+        GroovyCategorySupport.use(list, closure);
+    }
+
+    /**
+     * Print to a console in interactive format
+     */
+    public static void print(Object self, Object value) {
+        System.out.print(InvokerHelper.toString(value));
+    }
+
+    /**
+     * Print a linebreak to the standard out.
+     */
+    public static void println(Object self) {
+        System.out.println();
+    }
+
+    /**
+     * Print to a console in interactive format along with a newline
+     */
+    public static void println(Object self, Object value) {
+        System.out.println(InvokerHelper.toString(value));
+    }
+
+    /**
+     * Printf to a console.  Only works with JDK1.5 or later.
+     */
+    public static void printf(Object self, String format, Object[] values) {
+        if (System.getProperty("java.version").charAt(2) == '5') {
+            //
+            //  Cannot just do:
+            //
+            //        System.out.printf(format, values) ;
+            //
+            //  because this fails to compile on JDK1.4.x and earlier.  So until the entire world is using
+            //  JDK1.5 or later then we have to do things by reflection so as to hide the use of printf
+            //  from the compiler.  In JDK1.5 you might try:
+            //
+            //        System.out.getClass().getMethod("printf", String.class, Object[].class).invoke(System.out, format, values) ;
+            //
+            //  but of course this doesn't work on JDK1.4 as it relies on varargs.  argh.  So we are
+            //  forced into:
+            //
+            try {
+                System.out.getClass().getMethod("printf", new Class[]{String.class, Object[].class}).invoke(System.out, new Object[]{format, values});
+            } catch (NoSuchMethodException nsme) {
+                throw new RuntimeException("getMethod threw a NoSuchMethodException.  This is impossible.");
+            } catch (IllegalAccessException iae) {
+                throw new RuntimeException("invoke threw a IllegalAccessException.  This is impossible.");
+            } catch (java.lang.reflect.InvocationTargetException ite) {
+                throw new RuntimeException("invoke threw a InvocationTargetException.  This is impossible.");
+            }
+        } else {
+            throw new RuntimeException("printf requires JDK1.5 or later.");
+        }
+    }
+
+    /**
+     * Returns a formatted string using the specified format string and
+     * arguments.
+     * <p/>
+     * <p/>
+     * For examples, <pre>
+     *     printf ( "Hello, %s!\n" , [ "world" ] as String[] )
+     *     printf ( "Hello, %s!\n" , [ "Groovy" ])
+     *     printf ( "%d + %d = %d\n" , [ 1 , 2 , 1+2 ] as Integer[] )
+     *     printf ( "%d + %d = %d\n" , [ 3 , 3 , 3+3 ])
+     * <p/>
+     *     ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as Integer[] ) }
+     *     ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as int[] ) }
+     *     ( 0x41..0x45 ).each { printf ( "-- %c\n" , [ it ] as char[] ) }
+     *     ( 07..011 ).each { printf ( "-- %d\n" , [ it ] as byte[] ) }
+     *     ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as short[] ) }
+     *     ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as long[] ) }
+     *     ( 7..11 ).each { printf ( "-- %5.2f\n" , [ it ] as float[] ) }
+     *     ( 7..11 ).each { printf ( "-- %5.2g\n" , [ it ] as double[] ) }
+     * </pre>
+     * <p/>
+     *
+     * @param format A format string
+     * @param arg    Argument which is referenced by the format specifiers in the format
+     *               string.  The type of <code>arg</code> should be one of Object[], List,
+     *               int[], short[], byte[], char[], boolean[], long[], float[], or double[].
+     * @since JDK 1.5
+     */
+    public static void printf(Object self, String format, Object arg) {
+        if (arg instanceof Object[]) {
+            printf(self, format, (Object[]) arg);
+            return;
+        } else if (arg instanceof List) {
+            printf(self, format, ((List) arg).toArray());
+            return;
+        } else if (!arg.getClass().isArray()) {
+            Object[] o = (Object[]) java.lang.reflect.Array.newInstance(arg.getClass(), 1);
+            o[0] = arg;
+            printf(self, format, o);
+            return;
+        }
+
+        Object[] ans = null;
+        String elemType = arg.getClass().getName();
+        if (elemType.equals("[I")) {
+            int[] ia = (int[]) arg;
+            ans = new Integer[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                ans[i] = new Integer(ia[i]);
+            }
+        } else if (elemType.equals("[C")) {
+            char[] ia = (char[]) arg;
+            ans = new Character[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                ans[i] = new Character(ia[i]);
+            }
+        } else if (elemType.equals("[Z")) {
+            boolean[] ia = (boolean[]) arg;
+            ans = new Boolean[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                ans[i] = new Boolean(ia[i]);
+            }
+        } else if (elemType.equals("[B")) {
+            byte[] ia = (byte[]) arg;
+            ans = new Byte[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                ans[i] = new Byte(ia[i]);
+            }
+        } else if (elemType.equals("[S")) {
+            short[] ia = (short[]) arg;
+            ans = new Short[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                ans[i] = new Short(ia[i]);
+            }
+        } else if (elemType.equals("[F")) {
+            float[] ia = (float[]) arg;
+            ans = new Float[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                ans[i] = new Float(ia[i]);
+            }
+        } else if (elemType.equals("[J")) {
+            long[] ia = (long[]) arg;
+            ans = new Long[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                ans[i] = new Long(ia[i]);
+            }
+        } else if (elemType.equals("[D")) {
+            double[] ia = (double[]) arg;
+            ans = new Double[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                ans[i] = new Double(ia[i]);
+            }
+        } else {
+            throw new RuntimeException("printf(String," + arg + ")");
+        }
+        printf(self, format, (Object[]) ans);
+    }
+
+
+    /**
+     * @return a String that matches what would be typed into a terminal to
+     *         create this object. e.g. [1, 'hello'].inspect() -> [1, "hello"]
+     */
+    public static String inspect(Object self) {
+        return InvokerHelper.inspect(self);
+    }
+
+    /**
+     * Print to a console in interactive format
+     */
+    public static void print(Object self, PrintWriter out) {
+        if (out == null) {
+            out = new PrintWriter(System.out);
+        }
+        out.print(InvokerHelper.toString(self));
+    }
+
+    /**
+     * Print to a console in interactive format
+     *
+     * @param out the PrintWriter used for printing
+     */
+    public static void println(Object self, PrintWriter out) {
+        if (out == null) {
+            out = new PrintWriter(System.out);
+        }
+        InvokerHelper.invokeMethod(self, "print", out);
+        out.println();
+    }
+
+    /**
+     * Provide a dynamic method invocation method which can be overloaded in
+     * classes to implement dynamic proxies easily.
+     */
+    public static Object invokeMethod(Object object, String method, Object arguments) {
+        return InvokerHelper.invokeMethod(object, method, arguments);
+    }
+
+    // isCase methods
+    //-------------------------------------------------------------------------
+    public static boolean isCase(Object caseValue, Object switchValue) {
+        return caseValue.equals(switchValue);
+    }
+
+    public static boolean isCase(String caseValue, Object switchValue) {
+        if (switchValue == null) {
+            return caseValue == null;
+        }
+        return caseValue.equals(switchValue.toString());
+    }
+
+    public static boolean isCase(Class caseValue, Object switchValue) {
+        if (switchValue instanceof Class) {
+            Class val = (Class) switchValue;
+            return caseValue.isAssignableFrom(val);
+        }
+        return caseValue.isInstance(switchValue);
+    }
+
+    public static boolean isCase(Collection caseValue, Object switchValue) {
+        return caseValue.contains(switchValue);
+    }
+
+    public static boolean isCase(Pattern caseValue, Object switchValue) {
+        if (switchValue == null) {
+            return caseValue == null;
+        }
+        final Matcher matcher = caseValue.matcher(switchValue.toString());
+        if (matcher.matches()) {
+            RegexSupport.setLastMatcher(matcher);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    // Collection based methods
+    //-------------------------------------------------------------------------
+
+    public static Collection unique(Collection self) {
+        if (self instanceof Set)
+            return self;
+        List answer = new ArrayList();
+        NumberComparator comparator = new NumberComparator();
+        for (Iterator it = self.iterator(); it.hasNext();) {
+            Object o = it.next();
+            boolean duplicated = false;
+            for (Iterator it2 = answer.iterator(); it2.hasNext();) {
+                Object o2 = it2.next();
+                if (comparator.compare(o, o2) == 0) {
+                    duplicated = true;
+                    break;
+                }
+            }
+            if (!duplicated)
+                answer.add(o);
+        }
+        self.clear();
+        self.addAll(answer);
+        return self;
+    }
+
+    /**
+     * A convenience method for making a collection unique using a closure as a comparator
+     * (by Michael Baehr)
+     *
+     * @param self    a Collection
+     * @param closure a Closure used as a comparator
+     * @return self   without any duplicates
+     */
+    public static Collection unique(Collection self, Closure closure) {
+        if (self instanceof Set)
+            return self;
+        // use a comparator of one item or two
+        int params = closure.getMaximumNumberOfParameters();
+        if (params == 1) {
+            unique(self, new OrderBy(closure));
+        } else {
+            unique(self, new ClosureComparator(closure));
+        }
+        return self;
+    }
+
+    /**
+     * Remove all duplicates from a given Collection.
+     * Works on the receiver object and returns it.
+     * The order of members in the Collection are compared by the given Comparator.
+     * For each duplicate, the first member which is returned
+     * by the given Collection's iterator is retained, but all other ones are removed.
+     * The given Collection's original order is preserved.
+     * <p/>
+     * <code><pre>
+     *     class Person {
+     *         @Property fname, lname
+     *         public String toString() {
+     *             return fname + " " + lname
+     *         }
+     *     }
+     * <p/>
+     *     class PersonComparator implements Comparator {
+     *         public int compare(Object o1, Object o2) {
+     *             Person p1 = (Person) o1
+     *             Person p2 = (Person) o2
+     *             if (p1.lname != p2.lname)
+     *                 return p1.lname.compareTo(p2.lname)
+     *             else
+     *                 return p1.fname.compareTo(p2.fname)
+     *         }
+     * <p/>
+     *         public boolean equals(Object obj) {
+     *             return this.equals(obj)
+     *         }
+     *     }
+     * <p/>
+     *     Person a = new Person(fname:"John", lname:"Taylor")
+     *     Person b = new Person(fname:"Clark", lname:"Taylor")
+     *     Person c = new Person(fname:"Tom", lname:"Cruz")
+     *     Person d = new Person(fname:"Clark", lname:"Taylor")
+     * <p/>
+     *     def list = [a, b, c, d]
+     *     List list2 = list.unique(new PersonComparator())
+     *     assert( list2 == list && list == [a, b, c] )
+     * <p/>
+     * </pre></code>
+     *
+     * @param self       a Collection
+     * @param comparator a Comparator.
+     * @return self       without duplicates
+     */
+    public static Collection unique(Collection self, Comparator comparator) {
+        if (self instanceof Set)
+            return self;
+        List answer = new ArrayList();
+        for (Iterator it = self.iterator(); it.hasNext();) {
+            Object o = it.next();
+            boolean duplicated = false;
+            for (Iterator it2 = answer.iterator(); it2.hasNext();) {
+                Object o2 = it2.next();
+                if (comparator.compare(o, o2) == 0) {
+                    duplicated = true;
+                    break;
+                }
+            }
+            if (!duplicated)
+                answer.add(o);
+        }
+        self.clear();
+        self.addAll(answer);
+        return self;
+    }
+
+    /**
+     * Allows objects to be iterated through using a closure
+     *
+     * @param self    the object over which we iterate
+     * @param closure the closure applied on each element found
+     */
+    public static void each(Object self, Closure closure) {
+        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
+            closure.call(iter.next());
+        }
+    }
+
+    /**
+     * Allows object to be iterated through a closure with a counter
+     *
+     * @param self    an Object
+     * @param closure a Closure
+     */
+    public static void eachWithIndex(Object self, Closure closure) {
+        int counter = 0;
+        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
+            closure.call(new Object[]{iter.next(), new Integer(counter++)});
+        }
+    }
+
+    /**
+     * Allows objects to be iterated through using a closure
+     *
+     * @param self    the collection over which we iterate
+     * @param closure the closure applied on each element of the collection
+     */
+    public static void each(Collection self, Closure closure) {
+        for (Iterator iter = self.iterator(); iter.hasNext();) {
+            closure.call(iter.next());
+        }
+    }
+
+    /**
+     * Allows a Map to be iterated through using a closure. If the
+     * closure takes one parameter then it will be passed the Map.Entry
+     * otherwise if the closure takes two parameters then it will be
+     * passed the key and the value.
+     *
+     * @param self    the map over which we iterate
+     * @param closure the closure applied on each entry of the map
+     */
+    public static void each(Map self, Closure closure) {
+        for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            callClosureForMapEntry(closure, entry);
+        }
+    }
+
+
+    /**
+     * Iterates over every element of a collection, and check whether a predicate is valid for all elements.
+     *
+     * @param self    the object over which we iterate
+     * @param closure the closure predicate used for matching
+     * @return true if every item in the collection matches the closure
+     *         predicate
+     */
+    public static boolean every(Object self, Closure closure) {
+        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
+            if (!DefaultTypeTransformation.castToBoolean(closure.call(iter.next()))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Iterates over every element of a collection, and check whether a predicate is valid for at least one element
+     *
+     * @param self    the object over which we iterate
+     * @param closure the closure predicate used for matching
+     * @return true if any item in the collection matches the closure predicate
+     */
+    public static boolean any(Object self, Closure closure) {
+        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
+            if (DefaultTypeTransformation.castToBoolean(closure.call(iter.next()))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Iterates over every element of the collection and return each object that matches
+     * the given filter - calling the isCase() method used by switch statements.
+     * This method can be used with different kinds of filters like regular expresions, classes, ranges etc.
+     *
+     * @param self   the object over which we iterate
+     * @param filter the filter to perform on the collection (using the isCase(object) method)
+     * @return a list of objects which match the filter
+     */
+    public static List grep(Object self, Object filter) {
+        List answer = new ArrayList();
+        MetaClass metaClass = InvokerHelper.getMetaClass(filter);
+        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
+            Object object = iter.next();
+            if (DefaultTypeTransformation.castToBoolean(metaClass.invokeMethod(filter, "isCase", object))) {
+                answer.add(object);
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Counts the number of occurencies of the given value inside this collection
+     *
+     * @param self  the collection within which we count the number of occurencies
+     * @param value the value
+     * @return the number of occurrencies
+     */
+    public static int count(Collection self, Object value) {
+        int answer = 0;
+        for (Iterator iter = self.iterator(); iter.hasNext();) {
+            if (DefaultTypeTransformation.compareEqual(iter.next(), value)) {
+                ++answer;
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Convert a collection to a List.
+     *
+     * @param self a collection
+     * @return a List
+     */
+    public static List toList(Collection self) {
+        List answer = new ArrayList(self.size());
+        answer.addAll(self);
+        return answer;
+    }
+
+    /**
+     * Iterates through this object transforming each object into a new value using the closure
+     * as a transformer, returning a list of transformed values.
+     *
+     * @param self    the values of the object to map
+     * @param closure the closure used to map each element of the collection
+     * @return a List of the mapped values
+     */
+    public static List collect(Object self, Closure closure) {
+        return (List) collect(self, new ArrayList(), closure);
+    }
+
+    /**
+     * Iterates through this object transforming each object into a new value using the closure
+     * as a transformer and adding it to the collection, returning the resulting collection.
+     *
+     * @param self       the values of the object to map
+     * @param collection the Collection to which the mapped values are added
+     * @param closure    the closure used to map each element of the collection
+     * @return the resultant collection
+     */
+    public static Collection collect(Object self, Collection collection, Closure closure) {
+        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
+            collection.add(closure.call(iter.next()));
+        }
+        return collection;
+    }
+
+    /**
+     * Iterates through this collection transforming each entry into a new value using the closure
+     * as a transformer, returning a list of transformed values.
+     *
+     * @param self    a collection
+     * @param closure the closure used for mapping
+     * @return a List of the mapped values
+     */
+    public static List collect(Collection self, Closure closure) {
+        return (List) collect(self, new ArrayList(self.size()), closure);
+    }
+
+    /**
+     * Iterates through this collection transforming each entry into a new value using the closure
+     * as a transformer, returning a list of transformed values.
+     *
+     * @param self       a collection
+     * @param collection the Collection to which the mapped values are added
+     * @param closure    the closure used to map each element of the collection
+     * @return the resultant collection
+     */
+    public static Collection collect(Collection self, Collection collection, Closure closure) {
+        for (Iterator iter = self.iterator(); iter.hasNext();) {
+            collection.add(closure.call(iter.next()));
+            if (closure.getDirective() == Closure.DONE) {
+                break;
+            }
+        }
+        return collection;
+    }
+
+    /**
+     * Iterates through this Map transforming each entry into a new value using the closure
+     * as a transformer, returning a list of transformed values.
+     *
+     * @param self       a Map
+     * @param collection the Collection to which the mapped values are added
+     * @param closure    the closure used for mapping, which can be with one(Map.Entry) or two(key, value) parameters
+     * @return a List of the mapped values
+     */
+    public static Collection collect(Map self, Collection collection, Closure closure) {
+        boolean isTwoParams = (closure.getParameterTypes().length == 2);
+        for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
+            if (isTwoParams) {
+                Map.Entry entry = (Map.Entry) iter.next();
+                collection.add(closure.call(new Object[]{entry.getKey(), entry.getValue()}));
+            } else {
+                collection.add(closure.call(iter.next()));
+            }
+        }
+        return collection;
+    }
+
+    /**
+     * Iterates through this Map transforming each entry into a new value using the closure
+     * as a transformer, returning a list of transformed values.
+     *
+     * @param self    a Map
+     * @param closure the closure used to map each element of the collection
+     * @return the resultant collection
+     */
+    public static List collect(Map self, Closure closure) {
+        return (List) collect(self, new ArrayList(self.size()), closure);
+    }
+
+    /**
+     * Finds the first value matching the closure condition
+     *
+     * @param self    an Object with an iterator returning its values
+     * @param closure a closure condition
+     * @return the first Object found
+     */
+    public static Object find(Object self, Closure closure) {
+        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
+            Object value = iter.next();
+            if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
+                return value;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Finds the first value matching the closure condition
+     *
+     * @param self    a Collection
+     * @param closure a closure condition
+     * @return the first Object found
+     */
+    public static Object find(Collection self, Closure closure) {
+        for (Iterator iter = self.iterator(); iter.hasNext();) {
+            Object value = iter.next();
+            if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
+                return value;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Finds the first value matching the closure condition
+     *
+     * @param self    a Map
+     * @param closure a closure condition
+     * @return the first Object found
+     */
+    public static Object find(Map self, Closure closure) {
+        for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
+            Object value = iter.next();
+            if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
+                return value;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Finds all values matching the closure condition
+     *
+     * @param self    an Object with an Iterator returning its values
+     * @param closure a closure condition
+     * @return a List of the values found
+     */
+    public static List findAll(Object self, Closure closure) {
+        List answer = new ArrayList();
+        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
+            Object value = iter.next();
+            if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
+                answer.add(value);
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Finds all values matching the closure condition
+     *
+     * @param self    a Collection
+     * @param closure a closure condition
+     * @return a List of the values found
+     */
+    public static List findAll(Collection self, Closure closure) {
+        List answer = new ArrayList(self.size());
+        for (Iterator iter = self.iterator(); iter.hasNext();) {
+            Object value = iter.next();
+            if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
+                answer.add(value);
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Finds all entries matching the closure condition. If the
+     * closure takes one parameter then it will be passed the Map.Entry
+     * otherwise if the closure takes two parameters then it will be
+     * passed the key and the value.
+     *
+     * @param self    a Map
+     * @param closure a closure condition applying on the entries
+     * @return a new subMap
+     */
+    public static Map findAll(Map self, Closure closure) {
+        Map answer = new HashMap(self.size());
+        for (Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            if (DefaultTypeTransformation.castToBoolean(callClosureForMapEntry(closure, entry))) {
+                answer.put(entry.getKey(), entry.getValue());
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Groups all collection members into groups determined by the
+     * supplied mapping closure.
+     *
+     * @param self    a collection to group (no map)
+     * @param closure a closure mapping entries on keys
+     * @return a new Map grouped by keys
+     */
+    public static Map groupBy(Collection self, Closure closure) {
+        Map answer = new HashMap();
+        for (Iterator iter = self.iterator(); iter.hasNext();) {
+            groupCurrentElement(closure, answer, iter);
+        }
+        return answer;
+    }
+
+    /**
+     * Groups all map members into groups determined by the
+     * supplied mapping closure.
+     * 
+     * @param self     a map to group
+     * @param closure  a closure mapping entries on keys
+     * @return         a new Map grouped by keys
+     */
+    /* Removed for 1.0, to be discussed for 1.1
+    public static Map groupBy(Map self, Closure closure) {
+        final Map answer = new HashMap();
+        for (final Iterator iter = self.entrySet().iterator(); iter.hasNext();) {
+            groupCurrentElement(closure, answer, iter);
+        }
+        return answer;
+    }
+    */
+    
+    /**
+     * Groups the current element of the iterator as determined
+     * by the mapping closure.
+     * 
+     * @param closure  a closure mapping the current entry on a key
+     * @param answer   the map containing the results
+     * @param iter     the iterator from which the current element stems
+     */   
+    private static void groupCurrentElement(Closure closure, Map answer, Iterator iter) {
+	Object element = iter.next();
+	Object value = closure.call(element);
+	if (answer.containsKey(value)) {
+	    ((List) answer.get(value)).add(element);
+	} else {
+	    ArrayList groupedElements = new ArrayList();
+	    groupedElements.add(element);
+	    answer.put(value, groupedElements);
+	}
+    }
+    
+    // internal helper method
+    protected static Object callClosureForMapEntry(Closure closure, Map.Entry entry) {
+        if (closure.getMaximumNumberOfParameters() == 2) {
+            return closure.call(new Object[]{entry.getKey(), entry.getValue()});
+        }
+        return closure.call(entry);
+    }
+
+
+    /**
+     * Iterates through the given collection, passing in the initial value to
+     * the closure along with the current iterated item then passing into the
+     * next iteration the value of the previous closure.
+     *
+     * @param self    a Collection
+     * @param value   a value
+     * @param closure a closure
+     * @return the last value of the last iteration
+     */
+    public static Object inject(Collection self, Object value, Closure closure) {
+        Object[] params = new Object[2];
+        for (Iterator iter = self.iterator(); iter.hasNext();) {
+            Object item = iter.next();
+            params[0] = value;
+            params[1] = item;
+            value = closure.call(params);
+        }
+        return value;
+    }
+
+    /**
+     * Iterates through the given array of objects, passing in the initial value to
+     * the closure along with the current iterated item then passing into the
+     * next iteration the value of the previous closure.
+     *
+     * @param self    an Object[]
+     * @param value   a value
+     * @param closure a closure
+     * @return the last value of the last iteration
+     */
+    public static Object inject(Object[] self, Object value, Closure closure) {
+        Object[] params = new Object[2];
+        for (int i = 0; i < self.length; i++) {
+            params[0] = value;
+            params[1] = self[i];
+            value = closure.call(params);
+        }
+        return value;
+    }
+
+    /**
+     * Sums a collection of numeric values. <code>coll.sum()</code> is equivalent to:
+     * <code>coll.inject(0) {value, item -> value + item}</code>.
+     *
+     * @param self Collection of values to add together.
+     * @return The sum of all of the list itmems.
+     */
+    public static Object sum(Collection self) {
+        Object result = null;
+
+        if (self.size() == 0) return result;
+
+        boolean isNumber = true;
+
+        Class classref = null;
+        try {
+            classref = Class.forName("java.lang.Number");
+        } catch (Exception ex) {
+        }
+
+        for (Iterator iter = self.iterator(); iter.hasNext();) {
+            if (!classref.isInstance(iter.next())) {
+                isNumber = false;
+                break;
+            }
+        }
+
+        if (isNumber) {
+            result = new Integer(0);
+        } else {
+            result = new String();
+        }
+
+        Object[] param = new Object[1];
+        for (Iterator iter = self.iterator(); iter.hasNext();) {
+            param[0] = iter.next();
+            MetaClass metaClass = InvokerHelper.getMetaClass(result);
+            result = metaClass.invokeMethod(result, "plus", param);
+        }
+        return result;
+    }
+
+    /**
+     * Sums the result of apply a closure to each item of a collection.
+     * <code>coll.sum(closure)</code> is equivalent to:
+     * <code>coll.collect(closure).sum()</code>.
+     *
+     * @param self    a Collection
+     * @param closure a single parameter closure that returns a numeric value.
+     * @return The sum of the values returned by applying the closure to each
+     *         item of the list.
+     */
+    public static Object sum(Collection self, Closure closure) {
+        Object result = new Integer(0);
+        Object[] closureParam = new Object[1];
+        Object[] plusParam = new Object[1];
+        for (Iterator iter = self.iterator(); iter.hasNext();) {
+            closureParam[0] = iter.next();
+            plusParam[0] = closure.call(closureParam);
+            MetaClass metaClass = InvokerHelper.getMetaClass(result);
+            result = metaClass.invokeMethod(result, "plus", plusParam);
+        }
+        return result;
+    }
+
+    /**
+     * Concatenates all of the items of the collection together with the given String as a separator
+     *
+     * @param self      a Collection of objects
+     * @param separator a String separator
+     * @return the joined String
+     */
+    public static String join(Collection self, String separator) {
+        StringBuffer buffer = new StringBuffer();
+        boolean first = true;
+
+        if (separator == null) separator = "";
+
+        for (Iterator iter = self.iterator(); iter.hasNext();) {
+            Object value = iter.next();
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(separator);
+            }
+            buffer.append(InvokerHelper.toString(value));
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Concatenates all of the elements of the array together with the given String as a separator
+     *
+     * @param self      an array of Object
+     * @param separator a String separator
+     * @return the joined String
+     */
+    public static String join(Object[] self, String separator) {
+        StringBuffer buffer = new StringBuffer();
+        boolean first = true;
+
+        if (separator == null) separator = "";
+
+        for (int i = 0; i < self.length; i++) {
+            String value = InvokerHelper.toString(self[i]);
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(separator);
+            }
+            buffer.append(value);
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Selects the maximum value found in the collection
+     *
+     * @param self a Collection
+     * @return the maximum value
+     */
+    public static Object max(Collection self) {
+        Object answer = null;
+        for (Iterator iter = self.iterator(); iter.hasNext();) {
+            Object value = iter.next();
+            if (value != null) {
+                if (answer == null || ScriptBytecodeAdapter.compareGreaterThan(value, answer)) {
+                    answer = value;
+                }
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Selects the maximum value found in the collection using the given comparator
+     *
+     * @param self       a Collection
+     * @param comparator a Comparator
+     * @return the maximum value
+     */
+    public static Object max(Collection self, Comparator comparator) {
+        Object answer = null;
+        for (Iterator iter = self.iterator(); iter.hasNext();) {
+            Object value = iter.next();
+            if (answer == null || comparator.compare(value, answer) > 0) {
+                answer = value;
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Selects the minimum value found in the collection
+     *
+     * @param self a Collection
+     * @return the minimum value
+     */
+    public static Object min(Collection self) {
+        Object answer = null;
+        for (Iterator iter = self.iterator(); iter.hasNext();) {
+            Object value = iter.next();
+            if (value != null) {
+                if (answer == null || ScriptBytecodeAdapter.compareLessThan(value, answer)) {
+                    answer = value;
+                }
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Selects the minimum value found in the collection using the given comparator
+     *
+     * @param self       a Collection
+     * @param comparator a Comparator
+     * @return the minimum value
+     */
+    public static Object min(Collection self, Comparator comparator) {
+        Object answer = null;
+        for (Iterator iter = self.iterator(); iter.hasNext();) {
+            Object value = iter.next();
+            if (answer == null || comparator.compare(value, answer) < 0) {
+                answer = value;
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Selects the minimum value found in the collection using the given closure as a comparator
+     *
+     * @param self    a Collection
+     * @param closure a closure used as a comparator
+     * @return the minimum value
+     */
+    public static Object min(Collection self, Closure closure) {
+        int params = closure.getMaximumNumberOfParameters();
+        if (params == 1) {
+            Object answer = null;
+            Object answer_value = null;
+            for (Iterator iter = self.iterator(); iter.hasNext();) {
+                Object item = iter.next();
+                Object value = closure.call(item);
+                if (answer == null || ScriptBytecodeAdapter.compareLessThan(value, answer_value)) {
+                    answer = item;
+                    answer_value = value;
+                }
+            }
+            return answer;
+        } else {
+            return min(self, new ClosureComparator(closure));
+        }
+    }
+
+    /**
+     * Selects the maximum value found in the collection using the given closure as a comparator
+     *
+     * @param self    a Collection
+     * @param closure a closure used as a comparator
+     * @return the maximum value
+     */
+    public static Object max(Collection self, Closure closure) {
+        int params = closure.getMaximumNumberOfParameters();
+        if (params == 1) {
+            Object answer = null;
+            Object answer_value = null;
+            for (Iterator iter = self.iterator(); iter.hasNext();) {
+                Object item = iter.next();
+                Object value = closure.call(item);
+                if (answer == null || ScriptBytecodeAdapter.compareLessThan(answer_value, value)) {
+                    answer = item;
+                    answer_value = value;
+                }
+            }
+            return answer;
+        } else {
+            return max(self, new ClosureComparator(closure));
+        }
+    }
+
+    /**
+     * Makes a String look like a Collection by adding support for the size() method
+     *
+     * @param text a String
+     * @return the length of the String
+     */
+    public static int size(String text) {
+        return text.length();
+    }
+
+    /**
+     * Provide standard Groovy size() method for StringBuffers
+     *
+     * @param buffer a StringBuffer
+     * @return the length of the StringBuffer
+     */
+    public static int size(StringBuffer buffer) {
+        return buffer.length();
+    }
+
+    /**
+     * Provide the standard Groovy size method
+     */
+    public static long size(File file) {
+        return file.length();
+    }
+
+
+    /**
+     * Provide the standard Groovy size method
+     */
+    public static long size(Matcher matcher) {
+        return getCount(matcher);
+    }
+
+    /**
+     * Makes an Array look like a Collection by adding support for the size() method
+     *
+     * @param self an Array of Object
+     * @return the size of the Array
+     */
+    public static int size(Object[] self) {
+        return self.length;
+    }
+
+    /**
+     * Support the subscript operator for String.
+     *
+     * @param text  a String
+     * @param index the index of the Character to get
+     * @return the Character at the given index
+     */
+    public static CharSequence getAt(CharSequence text, int index) {
+        index = normaliseIndex(index, text.length());
+        return text.subSequence(index, index + 1);
+    }
+
+    /**
+     * Support the subscript operator for String
+     *
+     * @param text a String
+     * @return the Character object at the given index
+     */
+    public static String getAt(String text, int index) {
+        index = normaliseIndex(index, text.length());
+        return text.substring(index, index + 1);
+    }
+
+    /**
+     * Support the range subscript operator for CharSequence
+     *
+     * @param text  a CharSequence
+     * @param range a Range
+     * @return the subsequence CharSequence
+     */
+    public static CharSequence getAt(CharSequence text, Range range) {
+        int from = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getFrom()), text.length());
+        int to = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getTo()), text.length());
+
+        // If this is a backwards range, reverse the arguments to substring.
+        if (from > to) {
+            int tmp = from;
+            from = to;
+            to = tmp;
+        }
+
+        return text.subSequence(from, to + 1);
+    }
+
+    /**
+     * Support the range subscript operator for CharSequence or StringBuffer with IntRange
+     *
+     * @param text  a CharSequence
+     * @param range an IntRange
+     * @return the subsequence CharSequence
+     */
+    public static CharSequence getAt(CharSequence text, IntRange range) {
+        return getAt(text, (Range) range);
+    }
+
+    /**
+     * Support the range subscript operator for String with IntRange
+     *
+     * @param text  a String
+     * @param range an IntRange
+     * @return the resulting String
+     */
+    public static String getAt(String text, IntRange range) {
+        return getAt(text, (Range) range);
+    }
+
+    /**
+     * Support the range subscript operator for String
+     *
+     * @param text  a String
+     * @param range a Range
+     * @return a substring corresponding to the Range
+     */
+    public static String getAt(String text, Range range) {
+        int from = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getFrom()), text.length());
+        int to = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getTo()), text.length());
+
+        // If this is a backwards range, reverse the arguments to substring.
+        boolean reverse = range.isReverse();
+        if (from > to) {
+            int tmp = to;
+            to = from;
+            from = tmp;
+            reverse = !reverse;
+        }
+
+        String answer = text.substring(from, to + 1);
+        if (reverse) {
+            answer = reverse(answer);
+        }
+        return answer;
+    }
+
+    /**
+     * Creates a new string which is the reverse (backwards) of this string
+     *
+     * @param self a String
+     * @return a new string with all the characters reversed.
+     */
+    public static String reverse(String self) {
+        int size = self.length();
+        StringBuffer buffer = new StringBuffer(size);
+        for (int i = size - 1; i >= 0; i--) {
+            buffer.append(self.charAt(i));
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Transforms a String representing a URL into a URL object.
+     *
+     * @param self the String representing a URL
+     * @return a URL
+     * @throws MalformedURLException is thrown if the URL is not well formed.
+     */
+    public static URL toURL(String self) throws MalformedURLException {
+        return new URL(self);
+    }
+
+    /**
+     * Transforms a String representing a URI into a URI object.
+     *
+     * @param self the String representing a URI
+     * @return a URI
+     * @throws URISyntaxException is thrown if the URI is not well formed.
+     */
+    public static URI toURI(String self) throws URISyntaxException {
+        return new URI(self);
+    }
+
+    /**
+     * Turns a String into a regular expression pattern
+     *
+     * @param self a String to convert into a regular expression
+     * @return the regular expression pattern
+     */
+    public static Pattern negate(String self) {
+        return Pattern.compile(self);
+    }
+
+    /**
+     * Replaces all occurrencies of a captured group by the result of a closure on that text.
+     * <p/>
+     * <p> For examples,
+     * <pre>
+     *     assert "FOOBAR-FOOBAR-" == "foobar-FooBar-".replaceAll("(([fF][oO]{2})[bB]ar)", { Object[] it -> it[0].toUpperCase() })
+     * <p/>
+     *     Here,
+     *          it[0] is the global string of the matched group
+     *          it[1] is the first string in the matched group
+     *          it[2] is the second string in the matched group
+     * <p/>
+     * <p/>
+     *     assert "FOO-FOO-" == "foobar-FooBar-".replaceAll("(([fF][oO]{2})[bB]ar)", { x, y, z -> z.toUpperCase() })
+     * <p/>
+     *     Here,
+     *          x is the global string of the matched group
+     *          y is the first string in the matched group
+     *          z is the second string in the matched group
+     * </pre>
+     *
+     * @param self    a String
+     * @param regex   the capturing regex
+     * @param closure the closure to apply on each captured group
+     * @return a String with replaced content
+     */
+    public static String replaceAll(String self, String regex, Closure closure) {
+        Matcher matcher = Pattern.compile(regex).matcher(self);
+        if (matcher.find()) {
+            matcher.reset();
+            StringBuffer sb = new StringBuffer();
+            while (matcher.find()) {
+                int count = matcher.groupCount();
+                ArrayList groups = new ArrayList();
+                for (int i = 0; i <= count; i++) {
+                    groups.add(matcher.group(i));
+                }
+                matcher.appendReplacement(sb, String.valueOf(closure.call((Object[]) groups.toArray())));
+            }
+            matcher.appendTail(sb);
+            return sb.toString();
+        } else {
+            return self;
+        }
+    }
+
+    private static String getPadding(String padding, int length) {
+        if (padding.length() < length) {
+            return multiply(padding, new Integer(length / padding.length() + 1)).substring(0, length);
+        } else {
+            return padding.substring(0, length);
+        }
+    }
+
+    /**
+     * Pad a String with the characters appended to the left
+     *
+     * @param numberOfChars the total number of characters
+     * @param padding       the charaters used for padding
+     * @return the String padded to the left
+     */
+    public static String padLeft(String self, Number numberOfChars, String padding) {
+        int numChars = numberOfChars.intValue();
+        if (numChars <= self.length()) {
+            return self;
+        } else {
+            return getPadding(padding, numChars - self.length()) + self;
+        }
+    }
+
+    /**
+     * Pad a String with the spaces appended to the left
+     *
+     * @param numberOfChars the total number of characters
+     * @return the String padded to the left
+     */
+
+    public static String padLeft(String self, Number numberOfChars) {
+        return padLeft(self, numberOfChars, " ");
+    }
+
+    /**
+     * Pad a String with the characters appended to the right
+     *
+     * @param numberOfChars the total number of characters
+     * @param padding       the charaters used for padding
+     * @return the String padded to the right
+     */
+
+    public static String padRight(String self, Number numberOfChars, String padding) {
+        int numChars = numberOfChars.intValue();
+        if (numChars <= self.length()) {
+            return self;
+        } else {
+            return self + getPadding(padding, numChars - self.length());
+        }
+    }
+
+    /**
+     * Pad a String with the spaces appended to the right
+     *
+     * @param numberOfChars the total number of characters
+     * @return the String padded to the right
+     */
+
+    public static String padRight(String self, Number numberOfChars) {
+        return padRight(self, numberOfChars, " ");
+    }
+
+    /**
+     * Center a String and padd it with the characters appended around it
+     *
+     * @param numberOfChars the total number of characters
+     * @param padding       the charaters used for padding
+     * @return the String centered with padded character around
+     */
+    public static String center(String self, Number numberOfChars, String padding) {
+        int numChars = numberOfChars.intValue();
+        if (numChars <= self.length()) {
+            return self;
+        } else {
+            int charsToAdd = numChars - self.length();
+            String semiPad = charsToAdd % 2 == 1 ?
+                    getPadding(padding, charsToAdd / 2 + 1) :
+                    getPadding(padding, charsToAdd / 2);
+            if (charsToAdd % 2 == 0)
+                return semiPad + self + semiPad;
+            else
+                return semiPad.substring(0, charsToAdd / 2) + self + semiPad;
+        }
+    }
+
+    /**
+     * Center a String and padd it with spaces appended around it
+     *
+     * @param numberOfChars the total number of characters
+     * @return the String centered with padded character around
+     */
+    public static String center(String self, Number numberOfChars) {
+        return center(self, numberOfChars, " ");
+    }
+
+    /**
+     * Support the subscript operator, e.g. matcher[index], for a regex Matcher.
+     * <p/>
+     * For an example using no group match, <code><pre>
+     *    def p = /ab[d|f]/
+     *    def m = "abcabdabeabf" =~ p
+     *    for (i in 0..<m.count) {
+     *        println( "m.groupCount() = " + m.groupCount())
+     *        println( "  " + i + ": " + m[i] )   // m[i] is a String
+     *    }
+     * </pre></code>
+     * <p/>
+     * For an example using group matches, <code><pre>
+     *    def p = /(?:ab([c|d|e|f]))/
+     *    def m = "abcabdabeabf" =~ p
+     *    for (i in 0..<m.count) {
+     *        println( "m.groupCount() = " + m.groupCount())
+     *        println( "  " + i + ": " + m[i] )   // m[i] is a List
+     *    }
+     * </pre></code>
+     * <p/>
+     * For another example using group matches, <code><pre>
+     *    def m = "abcabdabeabfabxyzabx" =~ /(?:ab([d|x-z]+))/
+     *    m.count.times {
+     *        println( "m.groupCount() = " + m.groupCount())
+     *        println( "  " + it + ": " + m[it] )   // m[it] is a List
+     *    }
+     * </pre></code>
+     *
+     * @param matcher a Matcher
+     * @param idx     an index
+     * @return object a matched String if no groups matched, list of matched groups otherwise.
+     */
+    public static Object getAt(Matcher matcher, int idx) {
+        try {
+            int count = getCount(matcher);
+            if (idx < -count || idx >= count) {
+                throw new IndexOutOfBoundsException("index is out of range " + (-count) + ".." + (count - 1) + " (index = " + idx + ")");
+            }
+            idx = normaliseIndex(idx, count);
+            matcher.reset();
+            for (int i = 0; i <= idx; i++) {
+                matcher.find();
+            }
+
+            if (hasGroup(matcher)) {
+                // are we using groups?
+                // yes, so return the specified group as list
+                ArrayList list = new ArrayList(matcher.groupCount());
+                for (int i = 0; i <= matcher.groupCount(); i++) {
+                    list.add(matcher.group(i));
+                }
+                return list;
+            } else {
+                // not using groups, so return the nth
+                // occurrence of the pattern
+                return matcher.group();
+            }
+        }
+        catch (IllegalStateException ex) {
+            return null;
+        }
+    }
+
+    /**
+     * Set the position of the given Matcher to the given index.
+     *
+     * @param matcher a Matcher
+     * @param idx     the index number
+     */
+    public static void setIndex(Matcher matcher, int idx) {
+        int count = getCount(matcher);
+        if (idx < -count || idx >= count) {
+            throw new IndexOutOfBoundsException("index is out of range " + (-count) + ".." + (count - 1) + " (index = " + idx + ")");
+        }
+        if (idx == 0) {
+            matcher.reset();
+        } else if (idx > 0) {
+            matcher.reset();
+            for (int i = 0; i < idx; i++) {
+                matcher.find();
+            }
+        } else if (idx < 0) {
+            matcher.reset();
+            idx += getCount(matcher);
+            for (int i = 0; i < idx; i++) {
+                matcher.find();
+            }
+        }
+    }
+
+    /**
+     * Find the number of Strings matched to the given Matcher.
+     *
+     * @param matcher a Matcher
+     * @return int  the number of Strings matched to the given matcher.
+     */
+    public static int getCount(Matcher matcher) {
+        int counter = 0;
+        matcher.reset();
+        while (matcher.find()) {
+            counter++;
+        }
+        matcher.reset();
+        return counter;
+    }
+
+    /**
+     * Check whether a Matcher contains a group or not.
+     *
+     * @param matcher a Matcher
+     * @return boolean  <code>true</code> if matcher contains at least one group.
+     */
+    public static boolean hasGroup(Matcher matcher) {
+        return matcher.groupCount() > 0;
+    }
+
+    /**
+     * Support the range subscript operator for a List
+     *
+     * @param self  a List
+     * @param range a Range
+     * @return a sublist based on range borders or a new list if range is reversed
+     * @see java.util.List#subList(int,int)
+     */
+    public static List getAt(List self, IntRange range) {
+        RangeInfo info = subListBorders(self.size(), range);
+        List answer = self.subList(info.from, info.to);  // sublist is always exclusive, but Ranges are not
+        if (info.reverse) {
+            answer = reverse(answer);
+        }
+        return answer;
+    }
+
+    // helper method for getAt and putAt
+    protected static RangeInfo subListBorders(int size, IntRange range) {
+        int from = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getFrom()), size);
+        int to = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getTo()), size);
+        boolean reverse = range.isReverse();
+        if (from > to) {                        // support list[1..-1]
+            int tmp = to;
+            to = from;
+            from = tmp;
+            reverse = !reverse;
+        }
+        return new RangeInfo(from, to + 1, reverse);
+    }
+
+    // helper method for getAt and putAt
+    protected static RangeInfo subListBorders(int size, EmptyRange range) {
+        int from = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getFrom()), size);
+        return new RangeInfo(from, from, false);
+    }
+
+    /**
+     * Allows a List to be used as the indices to be used on a List
+     *
+     * @param self    a List
+     * @param indices a Collection of indices
+     * @return a new list of the values at the given indices
+     */
+    public static List getAt(List self, Collection indices) {
+        List answer = new ArrayList(indices.size());
+        for (Iterator iter = indices.iterator(); iter.hasNext();) {
+            Object value = iter.next();
+            if (value instanceof Range) {
+                answer.addAll(getAt(self, (Range) value));
+            } else if (value instanceof List) {
+                answer.addAll(getAt(self, (List) value));
+            } else {
+                int idx = DefaultTypeTransformation.intUnbox(value);
+                answer.add(getAt(self, idx));
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Allows a List to be used as the indices to be used on a List
+     *
+     * @param self    an Array of Objects
+     * @param indices a Collection of indices
+     * @return a new list of the values at the given indices
+     */
+    public static List getAt(Object[] self, Collection indices) {
+        List answer = new ArrayList(indices.size());
+        for (Iterator iter = indices.iterator(); iter.hasNext();) {
+            Object value = iter.next();
+            if (value instanceof Range) {
+                answer.addAll(getAt(self, (Range) value));
+            } else if (value instanceof Collection) {
+                answer.addAll(getAt(self, (Collection) value));
+            } else {
+                int idx = DefaultTypeTransformation.intUnbox(value);
+                answer.add(getAt(self, idx));
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Allows a List to be used as the indices to be used on a CharSequence
+     *
+     * @param self    a CharSequence
+     * @param indices a Collection of indices
+     * @return a String of the values at the given indices
+     */
+    public static CharSequence getAt(CharSequence self, Collection indices) {
+        StringBuffer answer = new StringBuffer();
+        for (Iterator iter = indices.iterator(); iter.hasNext();) {
+            Object value = iter.next();
+            if (value instanceof Range) {
+                answer.append(getAt(self, (Range) value));
+            } else if (value instanceof Collection) {
+                answer.append(getAt(self, (Collection) value));
+            } else {
+                int idx = DefaultTypeTransformation.intUnbox(value);
+                answer.append(getAt(self, idx));
+            }
+        }
+        return answer.toString();
+    }
+
+    /**
+     * Allows a List to be used as the indices to be used on a String
+     *
+     * @param self    a String
+     * @param indices a Collection of indices
+     * @return a String of the values at the given indices
+     */
+    public static String getAt(String self, Collection indices) {
+        return (String) getAt((CharSequence) self, indices);
+    }
+
+    /**
+     * Allows a List to be used as the indices to be used on a Matcher
+     *
+     * @param self    a Matcher
+     * @param indices a Collection of indices
+     * @return a String of the values at the given indices
+     */
+    public static String getAt(Matcher self, Collection indices) {
+        StringBuffer answer = new StringBuffer();
+        for (Iterator iter = indices.iterator(); iter.hasNext();) {
+            Object value = iter.next();
+            if (value instanceof Range) {
+                answer.append(getAt(self, (Range) value));
+            } else if (value instanceof Collection) {
+                answer.append(getAt(self, (Collection) value));
+            } else {
+                int idx = DefaultTypeTransformation.intUnbox(value);
+                answer.append(getAt(self, idx));
+            }
+        }
+        return answer.toString();
+    }
+
+    /**
+     * Creates a sub-Map containing the given keys. This method is similar to
+     * List.subList() but uses keys rather than index ranges.
+     *
+     * @param map  a Map
+     * @param keys a Collection of keys
+     * @return a new Map containing the given keys
+     */
+    public static Map subMap(Map map, Collection keys) {
+        Map answer = new HashMap(keys.size());
+        for (Iterator iter = keys.iterator(); iter.hasNext();) {
+            Object key = iter.next();
+            answer.put(key, map.get(key));
+        }
+        return answer;
+    }
+
+    /**
+     * Looks up an item in a Map for the given key and returns the value - unless
+     * there is no entry for the given key in which case add the default value
+     * to the map and return that.
+     *
+     * @param map          a Map
+     * @param key          the key to lookup the value of
+     * @param defaultValue the value to return and add to the map for this key if
+     *                     there is no entry for the given key
+     * @return the value of the given key or the default value, added to the map if the
+     *         key did not exist
+     */
+    public static Object get(Map map, Object key, Object defaultValue) {
+        Object answer = map.get(key);
+        if (answer == null) {
+            answer = defaultValue;
+            map.put(key, answer);
+        }
+        return answer;
+    }
+
+    /**
+     * Support the range subscript operator for an Array
+     *
+     * @param array an Array of Objects
+     * @param range a Range
+     * @return a range of a list from the range's from index up to but not
+     *         including the ranges's to value
+     */
+    public static List getAt(Object[] array, Range range) {
+        List list = Arrays.asList(array);
+        return getAt(list, range);
+    }
+
+    public static List getAt(Object[] array, IntRange range) {
+        List list = Arrays.asList(array);
+        return getAt(list, range);
+    }
+
+    public static List getAt(Object[] array, ObjectRange range) {
+        List list = Arrays.asList(array);
+        return getAt(list, range);
+    }
+
+    /**
+     * Support the subscript operator for an Array
+     *
+     * @param array an Array of Objects
+     * @param idx   an index
+     * @return the value at the given index
+     */
+    public static Object getAt(Object[] array, int idx) {
+        return array[normaliseIndex(idx, array.length)];
+    }
+
+    /**
+     * Support the subscript operator for an Array
+     *
+     * @param array an Array of Objects
+     * @param idx   an index
+     * @param value an Object to put at the given index
+     */
+    public static void putAt(Object[] array, int idx, Object value) {
+        if (value instanceof Number) {
+            Class arrayComponentClass = array.getClass().getComponentType();
+
+            if (!arrayComponentClass.equals(value.getClass())) {
+                Object newVal = DefaultTypeTransformation.castToType(value, arrayComponentClass);
+                array[normaliseIndex(idx, array.length)] = newVal;
+                return;
+            }
+        }
+        array[normaliseIndex(idx, array.length)] = value;
+    }
+
+    /**
+     * Allows conversion of arrays into a mutable List
+     *
+     * @param array an Array of Objects
+     * @return the array as a List
+     */
+    public static List toList(Object[] array) {
+        int size = array.length;
+        List list = new ArrayList(size);
+        for (int i = 0; i < size; i++) {
+            list.add(array[i]);
+        }
+        return list;
+    }
+
+    /**
+     * Support the subscript operator for a List
+     *
+     * @param self a List
+     * @param idx  an index
+     * @return the value at the given index
+     */
+    public static Object getAt(List self, int idx) {
+        int size = self.size();
+        int i = normaliseIndex(idx, size);
+        if (i < size) {
+            return self.get(i);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * A helper method to allow lists to work with subscript operators
+     *
+     * @param self  a List
+     * @param idx   an index
+     * @param value the value to put at the given index
+     */
+    public static void putAt(List self, int idx, Object value) {
+        int size = self.size();
+        idx = normaliseIndex(idx, size);
+        if (idx < size) {
+            self.set(idx, value);
+        } else {
+            while (size < idx) {
+                self.add(size++, null);
+            }
+            self.add(idx, value);
+        }
+    }
+
+
+    /**
+     * Support the range subscript operator for StringBuffer
+     *
+     * @param self  a StringBuffer
+     * @param range a Range
+     * @param value the object that's toString() will be inserted
+     */
+    public static void putAt(StringBuffer self, IntRange range, Object value) {
+        RangeInfo info = subListBorders(self.length(), range);
+        self.replace(info.from, info.to, value.toString());
+    }
+
+    /**
+     * Support the range subscript operator for StringBuffer
+     *
+     * @param self  a StringBuffer
+     * @param range a Range
+     * @param value the object that's toString() will be inserted
+     */
+    public static void putAt(StringBuffer self, EmptyRange range, Object value) {
+        RangeInfo info = subListBorders(self.length(), range);
+        self.replace(info.from, info.to, value.toString());
+    }
+
+    /**
+     * A helper method to allow lists to work with subscript operators
+     *
+     * @param self  a List
+     * @param range the subset of the list to set
+     * @param value the values to put at the given sublist or a Collection of values
+     */
+    public static void putAt(List self, EmptyRange range, Object value) {
+        RangeInfo info = subListBorders(self.size(), range);
+        List sublist = self.subList(info.from, info.to);
+        sublist.clear();
+        if (value instanceof Collection) {
+            Collection col = (Collection) value;
+            if (col.size() == 0) return;
+            sublist.addAll(col);
+        } else {
+            sublist.add(value);
+        }
+    }
+
+    /**
+     * A helper method to allow lists to work with subscript operators
+     *
+     * @param self  a List
+     * @param range the subset of the list to set
+     * @param value the value to put at the given sublist or a Collection of values
+     */
+    public static void putAt(List self, IntRange range, Object value) {
+        RangeInfo info = subListBorders(self.size(), range);
+        List sublist = self.subList(info.from, info.to);
+        sublist.clear();
+        if (value instanceof Collection) {
+            Collection col = (Collection) value;
+            if (col.size() == 0) return;
+            sublist.addAll(col);
+        } else {
+            sublist.add(value);
+        }
+    }
+
+    /**
+     * A helper method to allow lists to work with subscript operators
+     *
+     * @param self   a List
+     * @param splice the subset of the list to set
+     * @param values the value to put at the given sublist
+     * @deprecated replace with putAt(List self, Range range, List value)
+     */
+    public static void putAt(List self, List splice, List values) {
+        List sublist = getSubList(self, splice);
+        sublist.clear();
+        sublist.addAll(values);
+    }
+
+    /**
+     * A helper method to allow lists to work with subscript operators
+     *
+     * @param self   a List
+     * @param splice the subset of the list to set
+     * @param value  the value to put at the given sublist
+     * @deprecated replace with putAt(List self, Range range, Object value)
+     */
+    public static void putAt(List self, List splice, Object value) {
+        List sublist = getSubList(self, splice);
+        sublist.clear();
+        sublist.add(value);
+    }
+
+    // helper method for putAt(Splice)
+    // todo: remove after putAt(Splice) gets deleted
+    protected static List getSubList(List self, List splice) {
+        int left /* = 0 */;
+        int right = 0;
+        boolean emptyRange = false;
+        if (splice.size() == 2) {
+            left = DefaultTypeTransformation.intUnbox(splice.get(0));
+            right = DefaultTypeTransformation.intUnbox(splice.get(1));
+        } else if (splice instanceof IntRange) {
+            IntRange range = (IntRange) splice;
+            left = range.getFromInt();
+            right = range.getToInt();
+        } else if (splice instanceof EmptyRange) {
+            RangeInfo info = subListBorders(self.size(), (EmptyRange) splice);
+            left = info.from;
+            emptyRange = true;
+        } else {
+            throw new IllegalArgumentException("You must specify a list of 2 indexes to create a sub-list");
+        }
+        int size = self.size();
+        left = normaliseIndex(left, size);
+        right = normaliseIndex(right, size);
+        List sublist /* = null */;
+        if (!emptyRange) {
+            sublist = self.subList(left, right + 1);
+        } else {
+            sublist = self.subList(left, left);
+        }
+        return sublist;
+    }
+
+    /**
+     * Support the subscript operator for a List
+     *
+     * @param self a Map
+     * @param key  an Object as a key for the map
+     * @return the value corresponding to the given key
+     */
+    public static Object getAt(Map self, Object key) {
+        return self.get(key);
+    }
+
+    /**
+     * A helper method to allow lists to work with subscript operators
+     *
+     * @param self a Map
+     * @param key  an Object as a key for the map
+     * @return the value corresponding to the given key
+     */
+    public static Object putAt(Map self, Object key, Object value) {
+        return self.put(key, value);
+    }
+
+    /**
+     * This converts a possibly negative index to a real index into the array.
+     *
+     * @param i
+     * @param size
+     */
+    protected static int normaliseIndex(int i, int size) {
+        int temp = i;
+        if (i < 0) {
+            i += size;
+        }
+        if (i < 0) {
+            throw new ArrayIndexOutOfBoundsException("Negative array index [" + temp + "] too large for array size " + size);
+        }
+        return i;
+    }
+
+    /**
+     * Support the subscript operator for List
+     *
+     * @param coll     a Collection
+     * @param property a String
+     * @return a List
+     */
+    public static List getAt(Collection coll, String property) {
+        List answer = new ArrayList(coll.size());
+        for (Iterator iter = coll.iterator(); iter.hasNext();) {
+            Object item = iter.next();
+            Object value = InvokerHelper.getProperty(item, property);
+            if (value instanceof Collection) {
+                answer.addAll((Collection) value);
+            } else {
+                answer.add(value);
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * A convenience method for creating an immutable map
+     *
+     * @param self a Map
+     * @return an immutable Map
+     */
+    public static Map asImmutable(Map self) {
+        return Collections.unmodifiableMap(self);
+    }
+
+    /**
+     * A convenience method for creating an immutable sorted map
+     *
+     * @param self a SortedMap
+     * @return an immutable SortedMap
+     */
+    public static SortedMap asImmutable(SortedMap self) {
+        return Collections.unmodifiableSortedMap(self);
+    }
+
+    /**
+     * A convenience method for creating an immutable list
+     *
+     * @param self a List
+     * @return an immutable List
+     */
+    public static List asImmutable(List self) {
+        return Collections.unmodifiableList(self);
+    }
+
+    /**
+     * A convenience method for creating an immutable list
+     *
+     * @param self a Set
+     * @return an immutable Set
+     */
+    public static Set asImmutable(Set self) {
+        return Collections.unmodifiableSet(self);
+    }
+
+    /**
+     * A convenience method for creating an immutable sorted set
+     *
+     * @param self a SortedSet
+     * @return an immutable SortedSet
+     */
+    public static SortedSet asImmutable(SortedSet self) {
+        return Collections.unmodifiableSortedSet(self);
+    }
+
+    /**
+     * A convenience method for creating an immutable Collection
+     *
+     * @param self a Collection
+     * @return an immutable Collection
+     */
+    public static Collection asImmutable(Collection self) {
+        return Collections.unmodifiableCollection(self);
+    }
+
+    /**
+     * A convenience method for creating a synchronized Map
+     *
+     * @param self a Map
+     * @return a synchronized Map
+     */
+    public static Map asSynchronized(Map self) {
+        return Collections.synchronizedMap(self);
+    }
+
+    /**
+     * A convenience method for creating a synchronized SortedMap
+     *
+     * @param self a SortedMap
+     * @return a synchronized SortedMap
+     */
+    public static SortedMap asSynchronized(SortedMap self) {
+        return Collections.synchronizedSortedMap(self);
+    }
+
+    /**
+     * A convenience method for creating a synchronized Collection
+     *
+     * @param self a Collection
+     * @return a synchronized Collection
+     */
+    public static Collection asSynchronized(Collection self) {
+        return Collections.synchronizedCollection(self);
+    }
+
+    /**
+     * A convenience method for creating a synchronized List
+     *
+     * @param self a List
+     * @return a synchronized List
+     */
+    public static List asSynchronized(List self) {
+        return Collections.synchronizedList(self);
+    }
+
+    /**
+     * A convenience method for creating a synchronized Set
+     *
+     * @param self a Set
+     * @return a synchronized Set
+     */
+    public static Set asSynchronized(Set self) {
+        return Collections.synchronizedSet(self);
+    }
+
+    /**
+     * A convenience method for creating a synchronized SortedSet
+     *
+     * @param self a SortedSet
+     * @return a synchronized SortedSet
+     */
+    public static SortedSet asSynchronized(SortedSet self) {
+        return Collections.synchronizedSortedSet(self);
+    }
+
+     public static SpreadMap spread(Map self) {
+        return toSpreadMap(self);
+    }
+
+    /**
+     * Returns the converted <code>SpreadLMap</code> of the given <code>self</code>.
+     * <p/>
+     * For examples, if there is defined a function like as
+     * <blockquote><pre>
+     *     def fn(a, b, c, d) { return a + b + c + d }
+     * </pre></blockquote>, then all of the following three have the same meaning.
+     * <blockquote><pre>
+     *     println fn(a:1, [b:2, c:3].toSpreadMap(), d:4)
+     *     println fn(a:1, *:[b:2, c:3], d:4)
+     *     println fn(a:1, b:2, c:3, d:4)
+     * </pre></blockquote>
+     * <p/>
+     *
+     * @param self a list to be converted into a spreadmap
+     * @return a newly created Spreadmap if this list is not null and its size is positive.
+     */
+    public static SpreadMap toSpreadMap(Map self) {
+        if (self == null)
+            throw new GroovyRuntimeException("Fail to convert Map to SpreadMap, because it is null.");
+        else
+            return new SpreadMap(self);
+    }
+
+    public static SpreadMap toSpreadMap(Object[] self) {
+        if (self == null)
+            throw new GroovyRuntimeException("Fail to convert Object[] to SpreadMap, because it is null.");
+        else if (self.length % 2 != 0)
+            throw new GroovyRuntimeException("Fail to convert Object[] to SpreadMap, because it's size is not even.");
+        else
+            return new SpreadMap(self);
+    }
+
+    /**
+     * Sorts the given collection into a sorted list.
+     *
+     * @param self the collection to be sorted
+     * @return the sorted collection as a List
+     */
+    public static List sort(Collection self) {
+        List answer = asList(self);
+        Collections.sort(answer, new NumberComparator());
+        return answer;
+    }
+
+    /**
+     * Avoids doing unnecessary work when sorting an already sorted set
+     *
+     * @param self
+     * @return the sorted set
+     */
+    public static SortedSet sort(SortedSet self) {
+        return self;
+    }
+
+    /**
+     * Removes the last item from the List. Using add() and pop()
+     * is similar to push and pop on a Stack.
+     *
+     * @param self a List
+     * @return the item removed from the List
+     * @throws NoSuchElementException if the list is empty and you try to pop() it.
+     */
+    public static Object pop(List self) {
+        if (self.isEmpty()) {
+            throw new NoSuchElementException("Cannot pop() an empty List");
+        }
+        return self.remove(self.size() - 1);
+    }
+
+    /**
+     * A convenience method for sorting a Collection with a specific comparator
+     *
+     * @param self       a collection to be sorted
+     * @param comparator a Comparator used for the comparison
+     * @return a newly created sorted List
+     */
+    public static List sort(Collection self, Comparator comparator) {
+        List list = asList(self);
+        Collections.sort(list, comparator);
+        return list;
+    }
+
+    /**
+     * A convenience method for sorting a Collection using a closure as a comparator
+     *
+     * @param self    a Collection to be sorted
+     * @param closure a Closure used as a comparator
+     * @return a newly created sorted List
+     */
+    public static List sort(Collection self, Closure closure) {
+        List list = asList(self);
+        // use a comparator of one item or two
+        int params = closure.getMaximumNumberOfParameters();
+        if (params == 1) {
+            Collections.sort(list, new OrderBy(closure));
+        } else {
+            Collections.sort(list, new ClosureComparator(closure));
+        }
+        return list;
+    }
+
+    /**
+     * Converts the given collection into a List
+     *
+     * @param self a collection to be converted into a List
+     * @return a newly created List if this collection is not already a List
+     */
+    public static List asList(Collection self) {
+        if (self instanceof List) {
+            return (List) self;
+        } else {
+            return new ArrayList(self);
+        }
+    }
+
+    public static Object asType(Collection col, Class clazz) {
+        if (clazz == List.class) {
+            return asList(col);
+        } else if (clazz == Set.class) {
+            if (col instanceof Set) return col;
+            return new HashSet(col);
+        }
+        return asType((Object) col, clazz);
+    }
+
+    public static Object asType(Closure cl, Class clazz) {
+        if (clazz.isInterface() && !(clazz.isInstance(cl))) {
+            return Proxy.newProxyInstance(
+                    clazz.getClassLoader(),
+                    new Class[]{clazz},
+                    new ConvertedClosure(cl));
+        }
+        return asType((Object) cl, clazz);
+    }
+
+    public static Object asType(Map map, Class clazz) {
+        if (clazz.isInterface() && !(clazz.isInstance(map))) {
+            return Proxy.newProxyInstance(
+                    clazz.getClassLoader(),
+                    new Class[]{clazz},
+                    new ConvertedMap(map));
+        }
+        return asType((Object) map, clazz);
+    }
+
+    /**
+     * Reverses the list
+     *
+     * @param self a List
+     * @return a reversed List
+     */
+    public static List reverse(List self) {
+        int size = self.size();
+        List answer = new ArrayList(size);
+        ListIterator iter = self.listIterator(size);
+        while (iter.hasPrevious()) {
+            answer.add(iter.previous());
+        }
+        return answer;
+    }
+
+    /**
+     * Create a List as a union of both Collections
+     *
+     * @param left  the left Collection
+     * @param right the right Collection
+     * @return a List
+     */
+    public static List plus(Collection left, Collection right) {
+        List answer = new ArrayList(left.size() + right.size());
+        answer.addAll(left);
+        answer.addAll(right);
+        return answer;
+    }
+
+    /**
+     * Create a List as a union of a Collection and an Object
+     *
+     * @param left  a Collection
+     * @param right an object to append
+     * @return a List
+     */
+    public static List plus(Collection left, Object right) {
+        List answer = new ArrayList(left.size() + 1);
+        answer.addAll(left);
+        answer.add(right);
+        return answer;
+    }
+
+    /**
+     * Create a List composed of the same elements repeated a certain number of times.
+     *
+     * @param self   a Collection
+     * @param factor the number of times to append
+     * @return a List
+     */
+    public static List multiply(Collection self, Number factor) {
+        int size = factor.intValue();
+        List answer = new ArrayList(self.size() * size);
+        for (int i = 0; i < size; i++) {
+            answer.addAll(self);
+        }
+        return answer;
+    }
+
+    /**
+     * Create a List composed of the intersection of both collections
+     *
+     * @param left  a Collection
+     * @param right a Collection
+     * @return a List as an intersection of both collections
+     */
+    public static List intersect(Collection left, Collection right) {
+        if (left.size() == 0)
+            return new ArrayList();
+
+        boolean nlgnSort = sameType(new Collection[]{left, right});
+
+        ArrayList result = new ArrayList();
+        //creates the collection to look for values.
+        Collection pickFrom = new TreeSet(new NumberComparator());
+        pickFrom.addAll(left);
+
+        for (Iterator iter = right.iterator(); iter.hasNext();) {
+            final Object o = iter.next();
+            if (pickFrom.contains(o))
+                result.add(o);
+        }
+        return result;
+    }
+
+    /**
+     * Returns <code>true</code> if the intersection of two collenctions is empty.
+     *
+     * @param left  a Collection
+     * @param right a Collection
+     * @return boolean   <code>true</code> if the intersection of two collenctions is empty, <code>false</code> otherwise.
+     */
+    public static boolean disjoint(Collection left, Collection right) {
+
+        if (left.size() == 0 || right.size() == 0)
+            return true;
+
+        boolean nlgnSort = sameType(new Collection[]{left, right});
+
+        Collection pickFrom = (Collection) new TreeSet(new NumberComparator());
+        ((TreeSet) pickFrom).addAll(right);
+
+        for (Iterator iter = left.iterator(); iter.hasNext();) {
+            final Object o = iter.next();
+            if (pickFrom.contains(o))
+                return false;
+        }
+        return true;
+    }
+
+    // Default comparator for numbers of different types.
+    private static class NumberComparator implements Comparator {
+        public int compare(Object o1, Object o2) {
+            if (o1 instanceof Number && o2 instanceof Number) {
+                BigDecimal x1 = new BigDecimal("" + o1);
+                BigDecimal x2 = new BigDecimal("" + o2);
+                return x1.compareTo(x2);
+            } else if (o1.getClass() == o2.getClass() && o1 instanceof Comparable) {
+                return ((Comparable) o1).compareTo((Comparable) o2);
+            } else {
+                int x1 = o1.hashCode();
+                int x2 = o2.hashCode();
+                return (x1 - x2);
+            }
+        }
+
+        public boolean equals(Object obj) {
+            return this.equals(obj);
+        }
+    }
+
+    /**
+     * Compare two Lists.
+     * If numbers exits in the Lists, then they are compared as numbers,
+     * for example 2 == 2L.
+     *
+     * @param left  a List
+     * @param right a List
+     * @return boolean   <code>true</code> if two Lists equals, <code>false</code> otherwise.
+     */
+    public static boolean equals(List left, List right) {
+        if (left == null) {
+            return right == null;
+        } else if (right == null) {
+            return false;
+        } else if (left.size() != right.size()) {
+            return false;
+        } else {
+            final NumberComparator numberComparator = new NumberComparator();
+            final Iterator it1 = left.iterator(), it2 = right.iterator();
+
+            while (it1.hasNext()) {
+                final Object o1 = it1.next();
+                final Object o2 = it2.next();
+
+                if (o1 == null) {
+                    if (o2 != null) return false;
+                } else {
+                    if (o1 instanceof Number) {
+                        if (!(o2 instanceof Number && numberComparator.compare(o1, o2) == 0)) {
+                            return false;
+                        }
+                    } else {
+                        // Use this way of calling equals in case the elament is a List
+                        // or any other type which has an equals in DGM
+                        if (!((Boolean) InvokerHelper.invokeMethod(o1, "equals", new Object[]{o2})).booleanValue())
+                            return false;
+                    }
+                }
+            }
+
+            return true;
+        }
+    }
+
+    /**
+     * Create a List composed of the elements of the first list minus the elements of the collection
+     *
+     * @param self     a List
+     * @param removeMe a Collection of elements to remove
+     * @return a List with the common elements removed
+     */
+    public static List minus(List self, Collection removeMe) {
+
+        if (self.size() == 0)
+            return new ArrayList();
+
+        boolean nlgnSort = sameType(new Collection[]{self, removeMe});
+
+        //we can't use the same tactic as for intersection
+        //since AbstractCollection only does a remove on the first
+        //element it encounter.
+
+        Comparator numberComparator = new NumberComparator();
+
+        if (nlgnSort && (self.get(0) instanceof Comparable)) {
+            //n*LOG(n) version
+            Set answer /* = null */;
+            if (Number.class.isInstance(self.get(0))) {
+                answer = new TreeSet(numberComparator);
+                answer.addAll(self);
+                for (Iterator it = self.iterator(); it.hasNext();) {
+                    Object o = it.next();
+                    if (Number.class.isInstance(o)) {
+                        for (Iterator it2 = removeMe.iterator(); it2.hasNext();) {
+                            Object o2 = it2.next();
+                            if (Number.class.isInstance(o2)) {
+                                if (numberComparator.compare(o, o2) == 0)
+                                    answer.remove(o);
+                            }
+                        }
+                    } else {
+                        if (removeMe.contains(o))
+                            answer.remove(o);
+                    }
+                }
+            } else {
+                answer = new TreeSet(numberComparator);
+                answer.addAll(self);
+                answer.removeAll(removeMe);
+            }
+
+            List ansList = new ArrayList();
+            for (Iterator it = self.iterator(); it.hasNext();) {
+                Object o = it.next();
+                if (answer.contains(o))
+                    ansList.add(o);
+            }
+            return ansList;
+        } else {
+            //n*n version
+            List tmpAnswer = new LinkedList(self);
+            for (Iterator iter = tmpAnswer.iterator(); iter.hasNext();) {
+                Object element = iter.next();
+                //boolean removeElement = false;
+                for (Iterator iterator = removeMe.iterator(); iterator.hasNext();) {
+                    Object elt = iterator.next();
+                    if (elt != null && numberComparator.compare(element, elt) == 0) {
+                        iter.remove();
+                    }
+                }
+            }
+
+            //remove duplicates
+            //can't use treeset since the base classes are different
+            return new ArrayList(tmpAnswer);
+        }
+    }
+
+    public static List minus(List self, Object operand) {
+        Comparator numberComparator = new NumberComparator();
+        List ansList = new ArrayList();
+        for (Iterator it = self.iterator(); it.hasNext();) {
+            Object o = it.next();
+            if (numberComparator.compare(o, operand) != 0) ansList.add(o);
+        }
+        return ansList;
+    }
+
+    /**
+     * Flatten a list
+     *
+     * @param self a List
+     * @return a flattened List
+     */
+    public static List flatten(List self) {
+        return new ArrayList(flatten(self, new LinkedList()));
+    }
+
+    /**
+     * Iterate over each element of the list in the reverse order.
+     *
+     * @param self    a List
+     * @param closure a closure
+     */
+    public static void reverseEach(List self, Closure closure) {
+        List reversed = reverse(self);
+        for (Iterator iter = reversed.iterator(); iter.hasNext();) {
+            closure.call(iter.next());
+        }
+    }
+
+    private static List flatten(Collection elements, List addTo) {
+        Iterator iter = elements.iterator();
+        while (iter.hasNext()) {
+            Object element = iter.next();
+            if (element instanceof Collection) {
+                flatten((Collection) element, addTo);
+            } else if (element instanceof Map) {
+                flatten(((Map) element).values(), addTo);
+            } else {
+                addTo.add(element);
+            }
+        }
+        return addTo;
+    }
+
+    /**
+     * Overloads the left shift operator to provide an easy way to append objects to a list
+     *
+     * @param self  a Collection
+     * @param value an Object to be added to the collection.
+     * @return a Collection with an Object added to it.
+     */
+    public static Collection leftShift(Collection self, Object value) {
+        self.add(value);
+        return self;
+    }
+
+    /**
+     * Overloads the left shift operator to provide an easy way to append multiple
+     * objects as string representations to a String
+     *
+     * @param self  a String
+     * @param value an Obect
+     * @return a StringBuffer
+     */
+    public static StringBuffer leftShift(String self, Object value) {
+        return new StringBuffer(self).append(value);
+    }
+
+    protected static StringWriter createStringWriter(String self) {
+        StringWriter answer = new StringWriter();
+        answer.write(self);
+        return answer;
+    }
+
+    protected static StringBufferWriter createStringBufferWriter(StringBuffer self) {
+        return new StringBufferWriter(self);
+    }
+
+    /**
+     * Overloads the left shift operator to provide an easy way to append multiple
+     * objects as string representations to a StringBuffer
+     *
+     * @param self  a StringBuffer
+     * @param value a value to append
+     * @return a StringBuffer
+     */
+    public static StringBuffer leftShift(StringBuffer self, Object value) {
+        self.append(value);
+        return self;
+    }
+
+    /**
+     * Overloads the left shift operator to provide an append mechanism to add things to a writer
+     *
+     * @param self  a Writer
+     * @param value a value to append
+     * @return a StringWriter
+     */
+    public static Writer leftShift(Writer self, Object value) throws IOException {
+        InvokerHelper.write(self, value);
+        return self;
+    }
+
+    /**
+     * Implementation of the left shift operator for integral types.  Non integral
+     * Number types throw UnsupportedOperationException.
+     */
+    public static Number leftShift(Number left, Number right) {
+        return NumberMath.leftShift(left, right);
+    }
+
+    /**
+     * Implementation of the right shift operator for integral types.  Non integral
+     * Number types throw UnsupportedOperationException.
+     */
+    public static Number rightShift(Number left, Number right) {
+        return NumberMath.rightShift(left, right);
+    }
+
+    /**
+     * Implementation of the right shift (unsigned) operator for integral types.  Non integral
+     * Number types throw UnsupportedOperationException.
+     */
+    public static Number rightShiftUnsigned(Number left, Number right) {
+        return NumberMath.rightShiftUnsigned(left, right);
+    }
+
+    /**
+     * A helper method so that dynamic dispatch of the writer.write(object) method
+     * will always use the more efficient Writable.writeTo(writer) mechanism if the
+     * object implements the Writable interface.
+     *
+     * @param self     a Writer
+     * @param writable an object implementing the Writable interface
+     */
+    public static void write(Writer self, Writable writable) throws IOException {
+        writable.writeTo(self);
+    }
+
+    /**
+     * Overloads the left shift operator to provide an append mechanism to add things to a stream
+     *
+     * @param self  an OutputStream
+     * @param value a value to append
+     * @return a Writer
+     */
+    public static Writer leftShift(OutputStream self, Object value) throws IOException {
+        OutputStreamWriter writer = new FlushingStreamWriter(self);
+        leftShift(writer, value);
+        return writer;
+    }
+
+    /**
+     * Pipe an inputstream into an outputstream for efficient stream copying.
+     *
+     * @param self stream on which to write
+     * @param in   stream to read from
+     * @return the outputstream itself
+     * @throws IOException
+     */
+    public static OutputStream leftShift(OutputStream self, InputStream in) throws IOException {
+        byte[] buf = new byte[1024];
+        while (true) {
+            int count = in.read(buf, 0, buf.length);
+            if (count == -1) break;
+            if (count == 0) {
+                Thread.yield();
+                continue;
+            }
+            self.write(buf, 0, count);
+        }
+        self.flush();
+        return self;
+    }
+
+    /**
+     * Overloads the left shift operator to provide an append mechanism to add bytes to a stream
+     *
+     * @param self  an OutputStream
+     * @param value a value to append
+     * @return an OutputStream
+     */
+    public static OutputStream leftShift(OutputStream self, byte[] value) throws IOException {
+        self.write(value);
+        self.flush();
+        return self;
+    }
+
+    private static boolean sameType(Collection[] cols) {
+        List all = new LinkedList();
+        for (int i = 0; i < cols.length; i++) {
+            all.addAll(cols[i]);
+        }
+        if (all.size() == 0)
+            return true;
+
+        Object first = all.get(0);
+
+        //trying to determine the base class of the collections
+        //special case for Numbers
+        Class baseClass;
+        if (first instanceof Number) {
+            baseClass = Number.class;
+        } else {
+            baseClass = first.getClass();
+        }
+
+        for (int i = 0; i < cols.length; i++) {
+            for (Iterator iter = cols[i].iterator(); iter.hasNext();) {
+                if (!baseClass.isInstance(iter.next())) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    // Primitive type array methods
+    //-------------------------------------------------------------------------
+
+    public static Object getAt(byte[] array, int idx) {
+        return primitiveArrayGet(array, idx);
+    }
+
+    public static Object getAt(char[] array, int idx) {
+        return primitiveArrayGet(array, idx);
+    }
+
+    public static Object getAt(short[] array, int idx) {
+        return primitiveArrayGet(array, idx);
+    }
+
+    public static Object getAt(int[] array, int idx) {
+        return primitiveArrayGet(array, idx);
+    }
+
+    public static Object getAt(long[] array, int idx) {
+        return primitiveArrayGet(array, idx);
+    }
+
+    public static Object getAt(float[] array, int idx) {
+        return primitiveArrayGet(array, idx);
+    }
+
+    public static Object getAt(double[] array, int idx) {
+        return primitiveArrayGet(array, idx);
+    }
+
+    public static Object getAt(boolean[] array, int idx) {
+        return primitiveArrayGet(array, idx);
+    }
+
+    public static Object getAt(byte[] array, Range range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(char[] array, Range range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(short[] array, Range range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(int[] array, Range range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(long[] array, Range range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(float[] array, Range range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(double[] array, Range range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(boolean[] array, Range range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(byte[] array, IntRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(char[] array, IntRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(short[] array, IntRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(int[] array, IntRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(long[] array, IntRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(float[] array, IntRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(double[] array, IntRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(boolean[] array, IntRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(byte[] array, ObjectRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(char[] array, ObjectRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(short[] array, ObjectRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(int[] array, ObjectRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(long[] array, ObjectRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(float[] array, ObjectRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(double[] array, ObjectRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(boolean[] array, ObjectRange range) {
+        return primitiveArrayGet(array, range);
+    }
+
+    public static Object getAt(byte[] array, Collection indices) {
+        return primitiveArrayGet(array, indices);
+    }
+
+    public static Object getAt(char[] array, Collection indices) {
+        return primitiveArrayGet(array, indices);
+    }
+
+    public static Object getAt(short[] array, Collection indices) {
+        return primitiveArrayGet(array, indices);
+    }
+
+    public static Object getAt(int[] array, Collection indices) {
+        return primitiveArrayGet(array, indices);
+    }
+
+    public static Object getAt(long[] array, Collection indices) {
+        return primitiveArrayGet(array, indices);
+    }
+
+    public static Object getAt(float[] array, Collection indices) {
+        return primitiveArrayGet(array, indices);
+    }
+
+    public static Object getAt(double[] array, Collection indices) {
+        return primitiveArrayGet(array, indices);
+    }
+
+    public static Object getAt(boolean[] array, Collection indices) {
+        return primitiveArrayGet(array, indices);
+    }
+
+    public static void putAt(boolean[] array, int idx, Boolean newValue) {
+        primitiveArrayPut(array, idx, newValue);
+    }
+
+    public static void putAt(byte[] array, int idx, Object newValue) {
+        if (!(newValue instanceof Byte)) {
+            Number n = (Number) newValue;
+            newValue = new Byte(n.byteValue());
+        }
+        primitiveArrayPut(array, idx, newValue);
+    }
+
+    public static void putAt(char[] array, int idx, Object newValue) {
+        if (newValue instanceof String) {
+            String s = (String) newValue;
+            if (s.length() != 1) throw new IllegalArgumentException("String of length 1 expected but got a bigger one");
+            char c = s.charAt(0);
+            newValue = new Character(c);
+        }
+        primitiveArrayPut(array, idx, newValue);
+    }
+
+    public static void putAt(short[] array, int idx, Object newValue) {
+        if (!(newValue instanceof Short)) {
+            Number n = (Number) newValue;
+            newValue = new Short(n.shortValue());
+        }
+        primitiveArrayPut(array, idx, newValue);
+    }
+
+    public static void putAt(int[] array, int idx, Object newValue) {
+        if (!(newValue instanceof Integer)) {
+            Number n = (Number) newValue;
+            newValue = new Integer(n.intValue());
+        }
+        primitiveArrayPut(array, idx, newValue);
+    }
+
+    public static void putAt(long[] array, int idx, Object newValue) {
+        if (!(newValue instanceof Long)) {
+            Number n = (Number) newValue;
+            newValue = new Long(n.longValue());
+        }
+        primitiveArrayPut(array, idx, newValue);
+    }
+
+    public static void putAt(float[] array, int idx, Object newValue) {
+        if (!(newValue instanceof Float)) {
+            Number n = (Number) newValue;
+            newValue = new Float(n.floatValue());
+        }
+        primitiveArrayPut(array, idx, newValue);
+    }
+
+    public static void putAt(double[] array, int idx, Object newValue) {
+        if (!(newValue instanceof Double)) {
+            Number n = (Number) newValue;
+            newValue = new Double(n.doubleValue());
+        }
+        primitiveArrayPut(array, idx, newValue);
+    }
+
+    public static int size(byte[] array) {
+        return Array.getLength(array);
+    }
+
+    public static int size(char[] array) {
+        return Array.getLength(array);
+    }
+
+    public static int size(short[] array) {
+        return Array.getLength(array);
+    }
+
+    public static int size(int[] array) {
+        return Array.getLength(array);
+    }
+
+    public static int size(long[] array) {
+        return Array.getLength(array);
+    }
+
+    public static int size(float[] array) {
+        return Array.getLength(array);
+    }
+
+    public static int size(double[] array) {
+        return Array.getLength(array);
+    }
+
+    public static List toList(byte[] array) {
+        return DefaultTypeTransformation.primitiveArrayToList(array);
+    }
+
+    public static List toList(char[] array) {
+        return DefaultTypeTransformation.primitiveArrayToList(array);
+    }
+
+    public static List toList(short[] array) {
+        return DefaultTypeTransformation.primitiveArrayToList(array);
+    }
+
+    public static List toList(int[] array) {
+        return DefaultTypeTransformation.primitiveArrayToList(array);
+    }
+
+    public static List toList(long[] array) {
+        return DefaultTypeTransformation.primitiveArrayToList(array);
+    }
+
+    public static List toList(float[] array) {
+        return DefaultTypeTransformation.primitiveArrayToList(array);
+    }
+
+    public static List toList(double[] array) {
+        return DefaultTypeTransformation.primitiveArrayToList(array);
+    }
+
+    private static final char[] tTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();
+
+    public static Writable encodeBase64(Byte[] data) {
+        return encodeBase64(DefaultTypeTransformation.convertToByteArray(data));
+    }
+
+    /**
+     * Produce a Writable object which writes the base64 encoding of the byte array
+     * Calling toString() on the result rerurns the encoding as a String
+     *
+     * @param data byte array to be encoded
+     * @return object which will write the base64 encoding of the byte array
+     */
+    public static Writable encodeBase64(final byte[] data) {
+        return new Writable() {
+            public Writer writeTo(final Writer writer) throws IOException {
+                int charCount = 0;
+                final int dLimit = (data.length / 3) * 3;
+
+                for (int dIndex = 0; dIndex != dLimit; dIndex += 3) {
+                    int d = ((data[dIndex] & 0XFF) << 16) | ((data[dIndex + 1] & 0XFF) << 8) | (data[dIndex + 2] & 0XFF);
+
+                    writer.write(tTable[d >> 18]);
+                    writer.write(tTable[(d >> 12) & 0X3F]);
+                    writer.write(tTable[(d >> 6) & 0X3F]);
+                    writer.write(tTable[d & 0X3F]);
+
+                    if (++charCount == 18) {
+                        writer.write('\n');
+                        charCount = 0;
+                    }
+                }
+
+                if (dLimit != data.length) {
+                    int d = (data[dLimit] & 0XFF) << 16;
+
+                    if (dLimit + 1 != data.length) {
+                        d |= (data[dLimit + 1] & 0XFF) << 8;
+                    }
+
+                    writer.write(tTable[d >> 18]);
+                    writer.write(tTable[(d >> 12) & 0X3F]);
+                    writer.write((dLimit + 1 < data.length) ? tTable[(d >> 6) & 0X3F] : '=');
+                    writer.write('=');
+                }
+
+                return writer;
+            }
+
+            public String toString() {
+                StringWriter buffer = new StringWriter();
+
+                try {
+                    writeTo(buffer);
+                } catch (IOException e) {
+                    throw new StringWriterIOException(e);
+                }
+
+                return buffer.toString();
+            }
+        };
+    }
+
+    private static final byte[] translateTable = (
+            //
+            "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //                    \t    \n                \r
+                    + "\u0042\u0042\u0041\u0041\u0042\u0042\u0041\u0042"
+                    //
+                    + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //
+                    + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //        sp    !     "     #     $     %     &     '
+                    + "\u0041\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //         (    )     *     +     ,     -     .     /
+                    + "\u0042\u0042\u0042\u003E\u0042\u0042\u0042\u003F"
+                    //         0    1     2     3     4     5     6     7
+                    + "\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B"
+                    //         8    9     :     ;     <     =     >     ?
+                    + "\u003C\u003D\u0042\u0042\u0042\u0040\u0042\u0042"
+                    //         @    A     B     C     D     E     F     G
+                    + "\u0042\u0000\u0001\u0002\u0003\u0004\u0005\u0006"
+                    //         H    I   J K   L     M   N   O
+                    + "\u0007\u0008\t\n\u000B\u000C\r\u000E"
+                    //         P    Q     R     S     T     U     V    W
+                    + "\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016"
+                    //         X    Y     Z     [     \     ]     ^    _
+                    + "\u0017\u0018\u0019\u0042\u0042\u0042\u0042\u0042"
+                    //         '    a     b     c     d     e     f     g
+                    + "\u0042\u001A\u001B\u001C\u001D\u001E\u001F\u0020"
+                    //        h   i   j     k     l     m     n     o    p
+                    + "\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028"
+                    //        p     q     r     s     t     u     v     w
+                    + "\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030"
+                    //        x     y     z
+                    + "\u0031\u0032\u0033").getBytes();
+
+    /**
+     * Decode the Sting from base64 into a byte array
+     *
+     * @param value the string to be decoded
+     * @return the decoded bytes as an array
+     */
+    public static byte[] decodeBase64(String value) {
+        int byteShift = 4;
+        int tmp = 0;
+        boolean done = false;
+        final StringBuffer buffer = new StringBuffer();
+
+        for (int i = 0; i != value.length(); i++) {
+            final char c = value.charAt(i);
+            final int sixBit = (c < 123) ? translateTable[c] : 66;
+
+            if (sixBit < 64) {
+                if (done)
+                    throw new RuntimeException("= character not at end of base64 value"); // TODO: change this exception type
+
+                tmp = (tmp << 6) | sixBit;
+
+                if (byteShift-- != 4) {
+                    buffer.append((char) ((tmp >> (byteShift * 2)) & 0XFF));
+                }
+
+            } else if (sixBit == 64) {
+
+                byteShift--;
+                done = true;
+
+            } else if (sixBit == 66) {
+                // RFC 2045 says that I'm allowed to take the presence of
+                // these characters as evedence of data corruption
+                // So I will
+                throw new RuntimeException("bad character in base64 value"); // TODO: change this exception type
+            }
+
+            if (byteShift == 0) byteShift = 4;
+        }
+
+        try {
+            return buffer.toString().getBytes("ISO-8859-1");
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException("Base 64 decode produced byte values > 255"); // TODO: change this exception type
+        }
+    }
+
+    /**
+     * Implements the getAt(int) method for primitve type arrays
+     */
+    protected static Object primitiveArrayGet(Object array, int idx) {
+        return Array.get(array, normaliseIndex(idx, Array.getLength(array)));
+    }
+
+    /**
+     * Implements the getAt(Range) method for primitve type arrays
+     */
+    protected static List primitiveArrayGet(Object array, Range range) {
+        List answer = new ArrayList();
+        for (Iterator iter = range.iterator(); iter.hasNext();) {
+            int idx = DefaultTypeTransformation.intUnbox(iter.next());
+            answer.add(primitiveArrayGet(array, idx));
+        }
+        return answer;
+    }
+
+    /**
+     * Implements the getAt(Collection) method for primitve type arrays
+     */
+    protected static List primitiveArrayGet(Object self, Collection indices) {
+        List answer = new ArrayList();
+        for (Iterator iter = indices.iterator(); iter.hasNext();) {
+            Object value = iter.next();
+            if (value instanceof Range) {
+                answer.addAll(primitiveArrayGet(self, (Range) value));
+            } else if (value instanceof List) {
+                answer.addAll(primitiveArrayGet(self, (List) value));
+            } else {
+                int idx = DefaultTypeTransformation.intUnbox(value);
+                answer.add(primitiveArrayGet(self, idx));
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * Implements the set(int idx) method for primitve type arrays
+     */
+    protected static void primitiveArrayPut(Object array, int idx, Object newValue) {
+        Array.set(array, normaliseIndex(idx, Array.getLength(array)), newValue);
+    }
+
+    // String methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Converts the given string into a Character object
+     * using the first character in the string
+     *
+     * @param self a String
+     * @return the first Character
+     */
+    public static Character toCharacter(String self) {
+        /** @todo use cache? */
+        return new Character(self.charAt(0));
+    }
+
+    /**
+     * Converts the given string into a Boolean object
+     * If the trimmed string is "true", "y" or "1" (ignoring case)
+     * then the result is true othewrwise it is false
+     *
+     * @param self a String
+     * @return The Boolean value
+     */
+    public static Boolean toBoolean(String self) {
+        final String trimmed = self.trim();
+
+        if ("true".equalsIgnoreCase(trimmed) || "y".equalsIgnoreCase(trimmed) || "1".equals(trimmed)) {
+            return Boolean.TRUE;
+        } else {
+            return Boolean.FALSE;
+        }
+    }
+
+    /**
+     * Tokenize a String
+     *
+     * @param self  a String
+     * @param token the delimiter
+     * @return a List of tokens
+     */
+    public static List tokenize(String self, String token) {
+        return InvokerHelper.asList(new StringTokenizer(self, token));
+    }
+
+    /**
+     * Tokenize a String (with a whitespace as delimiter)
+     *
+     * @param self a String
+     * @return a List of tokens
+     */
+    public static List tokenize(String self) {
+        return InvokerHelper.asList(new StringTokenizer(self));
+    }
+
+    /**
+     * Appends a String
+     *
+     * @param left  a String
+     * @param value any Object
+     * @return a String
+     */
+    public static String plus(String left, Object value) {
+        return left + toString(value);
+    }
+    
+    /**
+     * Appends a String
+     *
+     * @param value a Number
+     * @param right a String
+     * @return a String
+     */
+    public static String plus(Number value, String right) {
+        return toString(value) + right;
+    }
+
+    /**
+     * Appends a String
+     *
+     * @param left  a StringBuffer
+     * @param value a String
+     * @return a String
+     */
+    public static String plus(StringBuffer left, String value) {
+        return left + value;
+    }
+
+
+    /**
+     * Remove a part of a String
+     *
+     * @param left  a String
+     * @param value a String part to remove
+     * @return a String minus the part to be removed
+     */
+    public static String minus(String left, Object value) {
+        String text = toString(value);
+        return left.replaceFirst(text, "");
+    }
+
+    /**
+     * Provide an implementation of contains() like Collection to make Strings more polymorphic
+     * This method is not required on JDK 1.5 onwards
+     *
+     * @param self a String
+     * @param text a String to look for
+     * @return true if this string contains the given text
+     */
+    public static boolean contains(String self, String text) {
+        int idx = self.indexOf(text);
+        return idx >= 0;
+    }
+
+    /**
+     * Count the number of occurencies of a substring
+     *
+     * @param self a String
+     * @param text a substring
+     * @return the number of occurrencies of the given string inside this String
+     */
+    public static int count(String self, String text) {
+        int answer = 0;
+        for (int idx = 0; true; idx++) {
+            idx = self.indexOf(text, idx);
+            if (idx >= 0) {
+                ++answer;
+            } else {
+                break;
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * This method is called by the ++ operator for the class String.
+     * It increments the last character in the given string. If the
+     * character in the string is Character.MAX_VALUE a Character.MIN_VALUE
+     * will be appended. The empty string is incremented to a string
+     * consisting of the character Character.MIN_VALUE.
+     *
+     * @param self a String
+     * @return an incremented String
+     */
+    public static String next(String self) {
+        StringBuffer buffer = new StringBuffer(self);
+        if (buffer.length() == 0) {
+            buffer.append(Character.MIN_VALUE);
+        } else {
+            char last = buffer.charAt(buffer.length() - 1);
+            if (last == Character.MAX_VALUE) {
+                buffer.append(Character.MIN_VALUE);
+            } else {
+                char next = last;
+                next++;
+                buffer.setCharAt(buffer.length() - 1, next);
+            }
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * This method is called by the -- operator for the class String.
+     * It decrements the last character in the given string. If the
+     * character in the string is Character.MIN_VALUE it will be deleted.
+     * The empty string can't be decremented.
+     *
+     * @param self a String
+     * @return a String with a decremented digit at the end
+     */
+    public static String previous(String self) {
+        StringBuffer buffer = new StringBuffer(self);
+        if (buffer.length() == 0) throw new IllegalArgumentException("the string is empty");
+        char last = buffer.charAt(buffer.length() - 1);
+        if (last == Character.MIN_VALUE) {
+            buffer.deleteCharAt(buffer.length() - 1);
+        } else {
+            char next = last;
+            next--;
+            buffer.setCharAt(buffer.length() - 1, next);
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Executes the given string as a command line process. For more control
+     * over the process mechanism in JDK 1.5 you can use java.lang.ProcessBuilder.
+     *
+     * @param self a command line String
+     * @return the Process which has just started for this command line string
+     */
+    public static Process execute(String self) throws IOException {
+        return Runtime.getRuntime().exec(self);
+    }
+
+    /**
+     * Executes the command specified by the <code>String</code> array that is the parameter.
+     * The first item in the array is the command the others are the parameters. For more
+     * control over the process mechanism in JDK 1.5 you can use
+     * <code>java.lang.ProcessBuilder</code>.
+     *
+     * @param commandArray an array of <code>String<code> containing the command name and
+     *                     parameters as separate items in the array.
+     * @return the Process which has just started for this command line string.
+     */
+    public static Process execute(String[] commandArray) throws IOException {
+        return Runtime.getRuntime().exec(commandArray);
+    }
+
+    /**
+     * Executes the command specified by the <code>self</code> with environments <code>envp</code>
+     * under the working directory <code>dir</code>.
+     * For more control over the process mechanism in JDK 1.5 you can use <code>java.lang.ProcessBuilder</code>.
+     *
+     * @param self a command line String to be executed.
+     * @param envp an array of Strings, each element of which
+     *             has environment variable settings in the format
+     *             <i>name</i>=<i>value</i>, or
+     *             <tt>null</tt> if the subprocess should inherit
+     *             the environment of the current process.
+     * @param dir  the working directory of the subprocess, or
+     *             <tt>null</tt> if the subprocess should inherit
+     *             the working directory of the current process.
+     * @return the Process which has just started for this command line string.
+     */
+    public static Process execute(String self, final String[] envp, File dir) throws IOException {
+        return Runtime.getRuntime().exec(self, envp, dir);
+    }
+
+    /**
+     * Executes the command specified by the <code>String</code> list that is the parameter.
+     * The first item in the array is the command the others are the parameters. All entries
+     * must be <code>String</code>s.  For more control over the process mechanism in JDK 1.5 you
+     * can use <code>java.lang.ProcessBuilder</code>.
+     *
+     * @param commandList a list of <code>String<code> containing the command name and
+     *                    parameters as separate items in the list.
+     * @return the Process which has just started for this command line string.
+     */
+    public static Process execute(List commandList) throws IOException {
+        final String[] commandArray = new String[commandList.size()];
+        Iterator it = commandList.iterator();
+        for (int i = 0; it.hasNext(); ++i) {
+            commandArray[i] = it.next().toString();
+        }
+        return execute(commandArray);
+    }
+
+    /**
+     * Executes the command specified by the <code>self</code> with environments <code>envp</code>
+     * under the working directory <code>dir</code>.
+     * For more control over the process mechanism in JDK 1.5 you can use <code>java.lang.ProcessBuilder</code>.
+     *
+     * @param self a command line String to be executed.
+     * @param envp a List of Strings, each member of which
+     *             has environment variable settings in the format
+     *             <i>name</i>=<i>value</i>, or
+     *             <tt>null</tt> if the subprocess should inherit
+     *             the environment of the current process.
+     * @param dir  the working directory of the subprocess, or
+     *             <tt>null</tt> if the subprocess should inherit
+     *             the working directory of the current process.
+     * @return the Process which has just started for this command line string.
+     */
+    public static Process execute(String self, List envp, File dir) throws IOException {
+        if (envp==null) {
+            return execute(self, (String[]) null, dir);
+        }
+        String[] commandArray = new String[envp.size()];
+        if (envp != null) {
+        	Iterator it = envp.iterator();
+        	for (int i = 0; it.hasNext(); ++i) {
+            	commandArray[i] = it.next().toString();
+        	}
+        } else {
+        	commandArray = null;	
+        }
+        return execute(self, commandArray, dir);
+    }
+
+    /**
+     * Repeat a String a certain number of times
+     *
+     * @param self   a String to be repeated
+     * @param factor the number of times the String should be repeated
+     * @return a String composed of a repeatition
+     * @throws IllegalArgumentException if the number of repeatition is &lt; 0
+     */
+    public static String multiply(String self, Number factor) {
+        int size = factor.intValue();
+        if (size == 0)
+            return "";
+        else if (size < 0) {
+            throw new IllegalArgumentException("multiply() should be called with a number of 0 or greater not: " + size);
+        }
+        StringBuffer answer = new StringBuffer(self);
+        for (int i = 1; i < size; i++) {
+            answer.append(self);
+        }
+        return answer.toString();
+    }
+
+    /**
+     * Returns the string representation of the given map with bracket boundaries.
+     *
+     * @param self a Map
+     * @return the string representation
+     */
+    public static String toString(Map self) {
+        return toMapString(self);
+    }
+
+    /**
+     * Returns the string representation of the given map with bracket boundaries.
+     *
+     * @param self a Map
+     * @return the string representation
+     */
+    public static String toMapString(Map self) {
+        return (self == null) ? "null" : InvokerHelper.toMapString(self);
+    }
+
+    /**
+     * Returns the string representation of the given collection with the bracket boundaries.
+     *
+     * @param self a Collection
+     * @return the string representation
+     */
+    public static String toString(Collection self) {
+        return toListString(self);
+    }
+
+    /**
+     * Returns the string representation of the given collection with the bracket boundaries.
+     *
+     * @param self a Collection
+     * @return the string representation
+     */
+    public static String toListString(Collection self) {
+        return (self == null) ? "null" : InvokerHelper.toListString(self);
+    }
+
+    /**
+     * Returns the string representation of the given array with the brace boundaries.
+     *
+     * @param self an Object[]
+     * @return the string representation
+     */
+    public static String toString(Object[] self) {
+        return toArrayString(self);
+    }
+
+    /**
+     * Returns the string representation of the given array with the brace boundaries.
+     *
+     * @param self an Object[]
+     * @return the string representation
+     */
+    public static String toArrayString(Object[] self) {
+        return (self == null) ? "null" : InvokerHelper.toArrayString(self);
+    }
+
+
+    protected static String toString(Object value) {
+        if (value instanceof Map)
+            return toMapString((Map) value);
+        else if (value instanceof Collection)
+            return toListString((Collection) value);
+        else if (value instanceof Object[])
+            return toArrayString((Object[]) value);
+        return (value == null) ? "null" : value.toString();
+    }
+
+    // Number based methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Increment a Character by one
+     *
+     * @param self a Character
+     * @return an incremented Number
+     */
+    public static Number next(Character self) {
+        return plus(self, ONE);
+    }
+
+    /**
+     * Increment a Number by one
+     *
+     * @param self a Number
+     * @return an incremented Number
+     */
+    public static Number next(Number self) {
+        return plus(self, ONE);
+    }
+
+    /**
+     * Decrement a Character by one
+     *
+     * @param self a Character
+     * @return a decremented Number
+     */
+    public static Number previous(Character self) {
+        return minus(self, ONE);
+    }
+
+    /**
+     * Decrement a Number by one
+     *
+     * @param self a Number
+     * @return a decremented Number
+     */
+    public static Number previous(Number self) {
+        return minus(self, ONE);
+    }
+
+    /**
+     * Add a Character and a Number
+     *
+     * @param left  a Character
+     * @param right a Number
+     * @return the addition of the Character and the Number
+     */
+    public static Number plus(Character left, Number right) {
+        return plus(new Integer(left.charValue()), right);
+    }
+
+    /**
+     * Add a Number and a Character
+     *
+     * @param left  a Number
+     * @param right a Character
+     * @return the addition of the Character and the Number
+     */
+    public static Number plus(Number left, Character right) {
+        return plus(left, new Integer(right.charValue()));
+    }
+
+    /**
+     * Add two Characters
+     *
+     * @param left  a Character
+     * @param right a Character
+     * @return the addition of both Characters
+     */
+    public static Number plus(Character left, Character right) {
+        return plus(new Integer(left.charValue()), right);
+    }
+
+    /**
+     * Add two numbers and return the result.
+     *
+     * @param left  a Number
+     * @param right another Number to add
+     * @return the addition of both Numbers
+     */
+    public static Number plus(Number left, Number right) {
+        return NumberMath.add(left, right);
+    }
+
+    /**
+     * Compare a Character and a Number
+     *
+     * @param left  a Character
+     * @param right a Number
+     * @return the result of the comparison
+     */
+    public static int compareTo(Character left, Number right) {
+        return compareTo(new Integer(left.charValue()), right);
+    }
+
+    /**
+     * Compare a Number and a Character
+     *
+     * @param left  a Number
+     * @param right a Character
+     * @return the result of the comparison
+     */
+    public static int compareTo(Number left, Character right) {
+        return compareTo(left, new Integer(right.charValue()));
+    }
+
+    /**
+     * Compare two Characters
+     *
+     * @param left  a Character
+     * @param right a Character
+     * @return the result of the comparison
+     */
+    public static int compareTo(Character left, Character right) {
+        return compareTo(new Integer(left.charValue()), right);
+    }
+
+    /**
+     * Compare two Numbers
+     *
+     * @param left  a Number
+     * @param right another Number to compare to
+     * @return the comparision of both numbers
+     */
+    public static int compareTo(Number left, Number right) {
+        /** @todo maybe a double dispatch thing to handle new large numbers? */
+        return NumberMath.compareTo(left, right);
+    }
+
+    /**
+     * Subtract a Number from a Character
+     *
+     * @param left  a Character
+     * @param right a Number
+     * @return the addition of the Character and the Number
+     */
+    public static Number minus(Character left, Number right) {
+        return minus(new Integer(left.charValue()), right);
+    }
+
+    /**
+     * Subtract a Character from a Number
+     *
+     * @param left  a Number
+     * @param right a Character
+     * @return the addition of the Character and the Number
+     */
+    public static Number minus(Number left, Character right) {
+        return minus(left, new Integer(right.charValue()));
+    }
+
+    /**
+     * Subtraction two Characters
+     *
+     * @param left  a Character
+     * @param right a Character
+     * @return the addition of both Characters
+     */
+    public static Number minus(Character left, Character right) {
+        return minus(new Integer(left.charValue()), right);
+    }
+
+    /**
+     * Substraction of two Numbers
+     *
+     * @param left  a Number
+     * @param right another Number to substract to the first one
+     * @return the substraction
+     */
+    public static Number minus(Number left, Number right) {
+        return NumberMath.subtract(left, right);
+    }
+
+    /**
+     * Multiply a Character by a Number
+     *
+     * @param left  a Character
+     * @param right a Number
+     * @return the multiplication of both
+     */
+    public static Number multiply(Character left, Number right) {
+        return multiply(new Integer(left.charValue()), right);
+    }
+
+    /**
+     * Multiply a Number by a Character
+     *
+     * @param left  a Number
+     * @param right a Character
+     * @return the multiplication of both
+     */
+    public static Number multiply(Number left, Character right) {
+        return multiply(left, new Integer(right.charValue()));
+    }
+
+    /**
+     * Multiply two Characters
+     *
+     * @param left  a Character
+     * @param right another Character
+     * @return the multiplication of both
+     */
+    public static Number multiply(Character left, Character right) {
+        return multiply(new Integer(left.charValue()), right);
+    }
+
+    /**
+     * Multiply two Numbers
+     *
+     * @param left  a Number
+     * @param right another Number
+     * @return the multiplication of both
+     */
+    //Note:  This method is NOT called if left AND right are both BigIntegers or BigDecimals because
+    //those classes implement a method with a better exact match.
+    public static Number multiply(Number left, Number right) {
+        return NumberMath.multiply(left, right);
+    }
+
+    /**
+     * Multiply a BigDecimal and a Double.
+     * Note: This method was added to enforce the Groovy rule of
+     * BigDecimal*Double == Double. Without this method, the
+     * multiply(BigDecimal) method in BigDecimal would respond
+     * and return a BigDecimal instead. Since BigDecimal is prefered
+     * over Number, the Number*Number method is not choosen as in older
+     * versions of Groovy. 
+     *
+     * @param left  a BigDecimal
+     * @param right a Double
+     * @return the multiplication of both
+     */
+    public static Number multiply(BigDecimal left, Double right) {
+        return NumberMath.multiply(left, right);
+    }
+    
+    /**
+     * Multiply a BigDecimal and a BigInteger.
+     * Note: This method was added to enforce the Groovy rule of
+     * BigDecimal*long == long. Without this method, the
+     * multiply(BigDecimal) method in BigDecimal would respond
+     * and return a BigDecimal instead. Since BigDecimal is prefered
+     * over Number, the Number*Number method is not choosen as in older
+     * versions of Groovy. Biginteger is the fallback for all integer
+     * types in Groovy
+     *
+     * @param left  a BigDecimal
+     * @param right a BigInteger
+     * @return the multiplication of both
+     */
+    public static Number multiply(BigDecimal left, BigInteger right) {
+        return NumberMath.multiply(left, right);
+    }
+    
+    /**
+     * Power of a Number to a certain exponent
+     *
+     * @param self     a Number
+     * @param exponent a Number exponent
+     * @return a Number to the power of a certain exponent
+     */
+    public static Number power(Number self, Number exponent) {
+        double base, exp, answer;
+        base = self.doubleValue();
+        exp = exponent.doubleValue();
+
+        answer = Math.pow(base, exp);
+        if ((double) ((int) answer) == answer) {
+            return new Integer((int) answer);
+        } else if ((double) ((long) answer) == answer) {
+            return new Long((long) answer);
+        } else {
+            return new Double(answer);
+        }
+    }
+
+    /**
+     * Divide a Character by a Number
+     *
+     * @param left  a Character
+     * @param right a Number
+     * @return the multiplication of both
+     */
+    public static Number div(Character left, Number right) {
+        return div(new Integer(left.charValue()), right);
+    }
+
+    /**
+     * Divide a Number by a Character
+     *
+     * @param left  a Number
+     * @param right a Character
+     * @return the multiplication of both
+     */
+    public static Number div(Number left, Character right) {
+        return div(left, new Integer(right.charValue()));
+    }
+
+    /**
+     * Divide two Characters
+     *
+     * @param left  a Character
+     * @param right another Character
+     * @return the multiplication of both
+     */
+    public static Number div(Character left, Character right) {
+        return div(new Integer(left.charValue()), right);
+    }
+
+    /**
+     * Divide two Numbers
+     *
+     * @param left  a Number
+     * @param right another Number
+     * @return a Number resulting of the divide operation
+     */
+    //Method name changed from 'divide' to avoid collision with BigInteger method that has
+    //different semantics.  We want a BigDecimal result rather than a BigInteger.
+    public static Number div(Number left, Number right) {
+        return NumberMath.divide(left, right);
+    }
+
+    /**
+     * Integer Divide a Character by a Number
+     *
+     * @param left  a Character
+     * @param right a Number
+     * @return the integer division of both
+     */
+    public static Number intdiv(Character left, Number right) {
+        return intdiv(new Integer(left.charValue()), right);
+    }
+
+    /**
+     * Integer Divide a Number by a Character
+     *
+     * @param left  a Number
+     * @param right a Character
+     * @return the integer division of both
+     */
+    public static Number intdiv(Number left, Character right) {
+        return intdiv(left, new Integer(right.charValue()));
+    }
+
+    /**
+     * Integer Divide two Characters
+     *
+     * @param left  a Character
+     * @param right another Character
+     * @return the integer division of both
+     */
+    public static Number intdiv(Character left, Character right) {
+        return intdiv(new Integer(left.charValue()), right);
+    }
+
+    /**
+     * Integer Divide two Numbers
+     *
+     * @param left  a Number
+     * @param right another Number
+     * @return a Number (an Integer) resulting of the integer division operation
+     */
+    public static Number intdiv(Number left, Number right) {
+        return NumberMath.intdiv(left, right);
+    }
+
+    /**
+     * Bitwise OR together two numbers
+     *
+     * @param left  a Number
+     * @param right another Number to bitwise OR
+     * @return the bitwise OR of both Numbers
+     */
+    public static Number or(Number left, Number right) {
+        return NumberMath.or(left, right);
+    }
+
+    /**
+     * Bitwise AND together two Numbers
+     *
+     * @param left  a Number
+     * @param right another Number to bitwse AND
+     * @return the bitwise AND of both Numbers
+     */
+    public static Number and(Number left, Number right) {
+        return NumberMath.and(left, right);
+    }
+
+    /**
+     * Bitwise XOR together two Numbers
+     *
+     * @param left  a Number
+     * @param right another Number to bitwse XOR
+     * @return the bitwise XOR of both Numbers
+     */
+    public static Number xor(Number left, Number right) {
+        return NumberMath.xor(left, right);
+    }
+
+    /**
+     * Performs a division modulus operation
+     *
+     * @param left  a Number
+     * @param right another Number to mod
+     * @return the modulus result
+     */
+    public static Number mod(Number left, Number right) {
+        return NumberMath.mod(left, right);
+    }
+
+    /**
+     * Negates the number
+     *
+     * @param left a Number
+     * @return the negation of the number
+     */
+    public static Number negate(Number left) {
+        return NumberMath.negate(left);
+    }
+
+
+    /**
+     * Iterates a number of times
+     *
+     * @param self    a Number
+     * @param closure the closure to call a number of times
+     */
+    public static void times(Number self, Closure closure) {
+        for (int i = 0, size = self.intValue(); i < size; i++) {
+            closure.call(new Integer(i));
+            if (closure.getDirective() == Closure.DONE) {
+                break;
+            }
+        }
+    }
+
+    /**
+     * Iterates from this number up to the given number
+     *
+     * @param self    a Number
+     * @param to      another Number to go up to
+     * @param closure the closure to call
+     */
+    public static void upto(Number self, Number to, Closure closure) {
+        int self1 = self.intValue();
+        int to1 = to.intValue();
+        if (self1 <= to1) {
+            for (int i = self1; i <= to1; i++) {
+                closure.call(new Integer(i));
+            }
+        } else
+            throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to + ")");
+    }
+
+    public static void upto(long self, Number to, Closure closure) {
+        long to1 = to.longValue();
+        if (self <= to1) {
+            for (long i = self; i <= to1; i++) {
+                closure.call(new Long(i));
+            }
+        } else
+            throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to + ")");
+    }
+
+    public static void upto(Long self, Number to, Closure closure) {
+        long self1 = self.longValue();
+        long to1 = to.longValue();
+        if (self1 <= to1) {
+            for (long i = self1; i <= to1; i++) {
+                closure.call(new Long(i));
+            }
+        } else
+            throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to + ")");
+    }
+
+    public static void upto(float self, Number to, Closure closure) {
+        float to1 = to.floatValue();
+        if (self <= to1) {
+            for (float i = self; i <= to1; i++) {
+                closure.call(new Float(i));
+            }
+        } else
+            throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to + ")");
+    }
+
+    public static void upto(Float self, Number to, Closure closure) {
+        float self1 = self.floatValue();
+        float to1 = to.floatValue();
+        if (self1 <= to1) {
+            for (float i = self1; i <= to1; i++) {
+                closure.call(new Float(i));
+            }
+        } else
+            throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to + ")");
+    }
+
+    public static void upto(Double self, Number to, Closure closure) {
+        double self1 = self.doubleValue();
+        double to1 = to.doubleValue();
+        if (self1 <= to1) {
+            for (double i = self1; i <= to1; i++) {
+                closure.call(new Double(i));
+            }
+        } else
+            throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to + ")");
+    }
+
+    public static void upto(BigInteger self, Number to, Closure closure) {
+        if (to instanceof BigDecimal) {
+            final BigDecimal one = new BigDecimal("1.0");
+            BigDecimal self1 = new BigDecimal(self);
+            BigDecimal to1 = (BigDecimal) to;
+            if (self1.compareTo(to1) <= 0) {
+                for (BigDecimal i = self1; i.compareTo(to1) <= 0; i = i.add(one)) {
+                    closure.call(i);
+                }
+            } else
+                throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to + ")");
+        } else if (to instanceof BigInteger) {
+            final BigInteger one = new BigInteger("1");
+            BigInteger to1 = (BigInteger) to;
+            if (self.compareTo(to1) <= 0) {
+                for (BigInteger i = self; i.compareTo(to1) <= 0; i = i.add(one)) {
+                    closure.call(i);
+                }
+            } else
+                throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to + ")");
+        } else {
+            final BigInteger one = new BigInteger("1");
+            BigInteger to1 = new BigInteger("" + to);
+            if (self.compareTo(to1) <= 0) {
+                for (BigInteger i = self; i.compareTo(to1) <= 0; i = i.add(one)) {
+                    closure.call(i);
+                }
+            } else
+                throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to + ")");
+        }
+    }
+
+    public static void upto(BigDecimal self, Number to, Closure closure) {
+        final BigDecimal one = new BigDecimal("1.0");
+        if (to instanceof BigDecimal) {
+            BigDecimal to1 = (BigDecimal) to;
+            if (self.compareTo(to1) <= 0) {
+                for (BigDecimal i = self; i.compareTo(to1) <= 0; i = i.add(one)) {
+                    closure.call(i);
+                }
+            } else
+                throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to + ")");
+        } else if (to instanceof BigInteger) {
+            BigDecimal to1 = new BigDecimal((BigInteger) to);
+            if (self.compareTo(to1) <= 0) {
+                for (BigDecimal i = self; i.compareTo(to1) <= 0; i = i.add(one)) {
+                    closure.call(i);
+                }
+            } else
+                throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to + ")");
+        } else {
+            BigDecimal to1 = new BigDecimal("" + to);
+            if (self.compareTo(to1) <= 0) {
+                for (BigDecimal i = self; i.compareTo(to1) <= 0; i = i.add(one)) {
+                    closure.call(i);
+                }
+            } else
+                throw new GroovyRuntimeException("Infinite loop in " + self + ".upto(" + to + ")");
+        }
+    }
+
+    /**
+     * Iterates from this number down to the given number
+     *
+     * @param self    a Number
+     * @param to      another Number to go down to
+     * @param closure the closure to call
+     */
+    public static void downto(Number self, Number to, Closure closure) {
+        int self1 = self.intValue();
+        int to1 = to.intValue();
+        if (self1 >= to1) {
+            for (int i = self1; i >= to1; i--) {
+                closure.call(new Integer(i));
+            }
+        } else
+            throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to + ")");
+    }
+
+    public static void downto(long self, Number to, Closure closure) {
+        long to1 = to.longValue();
+        if (self >= to1) {
+            for (long i = self; i >= to1; i--) {
+                closure.call(new Long(i));
+            }
+        } else
+            throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to + ")");
+    }
+
+    public static void downto(Long self, Number to, Closure closure) {
+        long self1 = self.longValue();
+        long to1 = to.longValue();
+        if (self1 >= to1) {
+            for (long i = self1; i >= to1; i--) {
+                closure.call(new Long(i));
+            }
+        } else
+            throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to + ")");
+    }
+
+    public static void downto(float self, Number to, Closure closure) {
+        float to1 = to.floatValue();
+        if (self >= to1) {
+            for (float i = self; i >= to1; i--) {
+                closure.call(new Float(i));
+            }
+        } else
+            throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to + ")");
+    }
+
+    public static void downto(Float self, Number to, Closure closure) {
+        float self1 = self.floatValue();
+        float to1 = to.floatValue();
+        if (self1 >= to1) {
+            for (float i = self1; i >= to1; i--) {
+                closure.call(new Float(i));
+            }
+        } else
+            throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to + ")");
+    }
+
+    public static void downto(double self, Number to, Closure closure) {
+        double to1 = to.doubleValue();
+        if (self >= to1) {
+            for (double i = self; i >= to1; i--) {
+                closure.call(new Double(i));
+            }
+        } else
+            throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to + ")");
+    }
+
+    public static void downto(Double self, Number to, Closure closure) {
+        double self1 = self.doubleValue();
+        double to1 = to.doubleValue();
+        if (self1 >= to1) {
+            for (double i = self1; i >= to1; i--) {
+                closure.call(new Double(i));
+            }
+        } else
+            throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to + ")");
+    }
+
+    public static void downto(BigInteger self, Number to, Closure closure) {
+        if (to instanceof BigDecimal) {
+            final BigDecimal one = new BigDecimal("1.0");
+            final BigDecimal to1 = (BigDecimal) to;
+            final BigDecimal selfD = new BigDecimal(self);
+            if (selfD.compareTo(to1) >= 0) {
+                for (BigDecimal i = selfD; i.compareTo(to1) >= 0; i = i.subtract(one)) {
+                    closure.call(i.toBigInteger());
+                }
+            } else
+                throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to + ")");
+        } else if (to instanceof BigInteger) {
+            final BigInteger one = new BigInteger("1");
+            final BigInteger to1 = (BigInteger) to;
+            if (self.compareTo(to1) >= 0) {
+                for (BigInteger i = self; i.compareTo(to1) >= 0; i = i.subtract(one)) {
+                    closure.call(i);
+                }
+            } else
+                throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to + ")");
+        } else {
+            final BigInteger one = new BigInteger("1");
+            final BigInteger to1 = new BigInteger("" + to);
+            if (self.compareTo(to1) >= 0) {
+                for (BigInteger i = self; i.compareTo(to1) >= 0; i = i.subtract(one)) {
+                    closure.call(i);
+                }
+            } else
+                throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to + ")");
+        }
+    }
+
+    public static void downto(BigDecimal self, Number to, Closure closure) {
+        final BigDecimal one = new BigDecimal("1.0");
+        if (to instanceof BigDecimal) {
+            BigDecimal to1 = (BigDecimal) to;
+            if (self.compareTo(to1) >= 0) {
+                for (BigDecimal i = self; i.compareTo(to1) >= 0; i = i.subtract(one)) {
+                    closure.call(i);
+                }
+            } else
+                throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to + ")");
+        } else if (to instanceof BigInteger) {
+            BigDecimal to1 = new BigDecimal((BigInteger) to);
+            if (self.compareTo(to1) >= 0) {
+                for (BigDecimal i = self; i.compareTo(to1) >= 0; i = i.subtract(one)) {
+                    closure.call(i);
+                }
+            } else
+                throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to + ")");
+        } else {
+            BigDecimal to1 = new BigDecimal("" + to);
+            if (self.compareTo(to1) >= 0) {
+                for (BigDecimal i = self; i.compareTo(to1) >= 0; i = i.subtract(one)) {
+                    closure.call(i);
+                }
+            } else
+                throw new GroovyRuntimeException("Infinite loop in " + self + ".downto(" + to + ")");
+        }
+    }
+
+    /**
+     * Iterates from this number up to the given number using a step increment
+     *
+     * @param self       a Number to start with
+     * @param to         a Number to go up to
+     * @param stepNumber a Number representing the step increment
+     * @param closure    the closure to call
+     */
+    public static void step(Number self, Number to, Number stepNumber, Closure closure) {
+        if (self instanceof BigDecimal || to instanceof BigDecimal || stepNumber instanceof BigDecimal) {
+            final BigDecimal zero = new BigDecimal("0.0");
+            BigDecimal self1 = (self instanceof BigDecimal) ? (BigDecimal) self : new BigDecimal("" + self);
+            BigDecimal to1 = (to instanceof BigDecimal) ? (BigDecimal) to : new BigDecimal("" + to);
+            BigDecimal stepNumber1 = (stepNumber instanceof BigDecimal) ? (BigDecimal) stepNumber : new BigDecimal("" + stepNumber);
+            if (stepNumber1.compareTo(zero) > 0 && to1.compareTo(self1) > 0) {
+                for (BigDecimal i = self1; i.compareTo(to1) < 0; i = i.add(stepNumber1)) {
+                    closure.call(i);
+                }
+            } else if (stepNumber1.compareTo(zero) < 0 && to1.compareTo(self1) < 0) {
+                for (BigDecimal i = self1; i.compareTo(to1) > 0; i = i.add(stepNumber1)) {
+                    closure.call(i);
+                }
+            } else
+                throw new GroovyRuntimeException("Infinite loop in " + self1 + ".step(" + to1 + ", " + stepNumber1 + ")");
+        } else if (self instanceof BigInteger || to instanceof BigInteger || stepNumber instanceof BigInteger) {
+            final BigInteger zero = new BigInteger("0");
+            BigInteger self1 = (self instanceof BigInteger) ? (BigInteger) self : new BigInteger("" + self);
+            BigInteger to1 = (to instanceof BigInteger) ? (BigInteger) to : new BigInteger("" + to);
+            BigInteger stepNumber1 = (stepNumber instanceof BigInteger) ? (BigInteger) stepNumber : new BigInteger("" + stepNumber);
+            if (stepNumber1.compareTo(zero) > 0 && to1.compareTo(self1) > 0) {
+                for (BigInteger i = self1; i.compareTo(to1) < 0; i = i.add(stepNumber1)) {
+                    closure.call(i);
+                }
+            } else if (stepNumber1.compareTo(zero) < 0 && to1.compareTo(self1) < 0) {
+                for (BigInteger i = self1; i.compareTo(to1) > 0; i = i.add(stepNumber1)) {
+                    closure.call(i);
+                }
+            } else
+                throw new GroovyRuntimeException("Infinite loop in " + self1 + ".step(" + to1 + ", " + stepNumber1 + ")");
+        } else {
+            int self1 = self.intValue();
+            int to1 = to.intValue();
+            int stepNumber1 = stepNumber.intValue();
+            if (stepNumber1 > 0 && to1 > self1) {
+                for (int i = self1; i < to1; i += stepNumber1) {
+                    closure.call(new Integer(i));
+                }
+            } else if (stepNumber1 < 0 && to1 < self1) {
+                for (int i = self1; i > to1; i += stepNumber1) {
+                    closure.call(new Integer(i));
+                }
+            } else
+                throw new GroovyRuntimeException("Infinite loop in " + self1 + ".step(" + to1 + ", " + stepNumber1 + ")");
+        }
+    }
+
+    /**
+     * Get the absolute value
+     *
+     * @param number a Number
+     * @return the absolute value of that Number
+     */
+    //Note:  This method is NOT called if number is a BigInteger or BigDecimal because
+    //those classes implement a method with a better exact match.
+    public static int abs(Number number) {
+        return Math.abs(number.intValue());
+    }
+
+    /**
+     * Get the absolute value
+     *
+     * @param number a Long
+     * @return the absolute value of that Long
+     */
+    public static long abs(Long number) {
+        return Math.abs(number.longValue());
+    }
+
+    /**
+     * Get the absolute value
+     *
+     * @param number a Float
+     * @return the absolute value of that Float
+     */
+    public static float abs(Float number) {
+        return Math.abs(number.floatValue());
+    }
+
+    /**
+     * Get the absolute value
+     *
+     * @param number a Double
+     * @return the absolute value of that Double
+     */
+    public static double abs(Double number) {
+        return Math.abs(number.doubleValue());
+    }
+
+    /**
+     * Get the absolute value
+     *
+     * @param number a Float
+     * @return the absolute value of that Float
+     */
+    public static int round(Float number) {
+        return Math.round(number.floatValue());
+    }
+
+    /**
+     * Round the value
+     *
+     * @param number a Double
+     * @return the absolute value of that Double
+     */
+    public static long round(Double number) {
+        return Math.round(number.doubleValue());
+    }
+
+    /**
+     * Parse a String into an Integer
+     *
+     * @param self a String
+     * @return an Integer
+     */
+    public static Integer toInteger(String self) {
+        return Integer.valueOf(self.trim());
+    }
+
+    /**
+     * Parse a String into a Long
+     *
+     * @param self a String
+     * @return a Long
+     */
+    public static Long toLong(String self) {
+        return Long.valueOf(self.trim());
+    }
+
+    /**
+     * Parse a String into a Float
+     *
+     * @param self a String
+     * @return a Float
+     */
+    public static Float toFloat(String self) {
+        return Float.valueOf(self.trim());
+    }
+
+    /**
+     * Parse a String into a Double
+     *
+     * @param self a String
+     * @return a Double
+     */
+    public static Double toDouble(String self) {
+        return Double.valueOf(self.trim());
+    }
+
+    /**
+     * Parse a String into a BigInteger
+     *
+     * @param self a String
+     * @return a BigInteger
+     */
+    public static BigInteger toBigInteger(String self) {
+        return new BigInteger(self.trim());
+    }
+
+    /**
+     * Parse a String into a BigDecimal
+     *
+     * @param self a String
+     * @return a BigDecimal
+     */
+    public static BigDecimal toBigDecimal(String self) {
+        return new BigDecimal(self.trim());
+    }
+
+    /**
+     * Transform a Number into an Integer
+     *
+     * @param self a Number
+     * @return an Integer
+     */
+    public static Integer toInteger(Number self) {
+        return new Integer(self.intValue());
+    }
+
+    /**
+     * Transform a Number into a Long
+     *
+     * @param self a Number
+     * @return an Long
+     */
+    public static Long toLong(Number self) {
+        return new Long(self.longValue());
+    }
+
+    /**
+     * Transform a Number into a Float
+     *
+     * @param self a Number
+     * @return an Float
+     */
+    public static Float toFloat(Number self) {
+        return new Float(self.floatValue());
+    }
+
+    /**
+     * Transform a Number into a Double
+     *
+     * @param self a Number
+     * @return an Double
+     */
+    public static Double toDouble(Number self) {
+        return new Double(self.doubleValue());
+    }
+
+    /**
+     * Transform a Number into a BigDecimal
+     *
+     * @param self a Number
+     * @return an BigDecimal
+     */
+    public static BigDecimal toBigDecimal(Number self) {
+        return new BigDecimal(self.doubleValue());
+    }
+
+    public static Object asType(Number self, Class c) {
+        if (c == BigDecimal.class) {
+            return toBigDecimal(self);
+        } else if (c == BigInteger.class) {
+            return toBigInteger(self);
+        } else if (c == Double.class) {
+            return toDouble(self);
+        } else if (c == Float.class) {
+            return toFloat(self);
+        }
+        return asType((Object) self, c);
+    }
+
+    /**
+     * Transform a Number into a BigInteger
+     *
+     * @param self a Number
+     * @return an BigInteger
+     */
+    public static BigInteger toBigInteger(Number self) {
+        return new BigInteger(Long.toString(self.longValue()));
+    }
+
+    // Date methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Increments a Date by a day
+     *
+     * @param self a Date
+     * @return the next days date
+     */
+    public static Date next(Date self) {
+        return plus(self, 1);
+    }
+
+    /**
+     * Increments a java.sql.Date by a day
+     *
+     * @param self a java.sql.Date
+     * @return the next days date
+     */
+    public static java.sql.Date next(java.sql.Date self) {
+        return new java.sql.Date(next((Date) self).getTime());
+    }
+
+    /**
+     * Decrement a Date by a day
+     *
+     * @param self a Date
+     * @return the previous days date
+     */
+    public static Date previous(Date self) {
+        return minus(self, 1);
+    }
+
+    /**
+     * Decrement a java.sql.Date by a day
+     *
+     * @param self a java.sql.Date
+     * @return the previous days date
+     */
+    public static java.sql.Date previous(java.sql.Date self) {
+        return new java.sql.Date(previous((Date) self).getTime());
+    }
+
+    /**
+     * Adds a number of days to this date and returns the new date
+     *
+     * @param self a Date
+     * @param days the number of days to increase
+     * @return the new date
+     */
+    public static Date plus(Date self, int days) {
+        Calendar calendar = (Calendar) Calendar.getInstance().clone();
+        calendar.setTime(self);
+        calendar.add(Calendar.DAY_OF_YEAR, days);
+        return calendar.getTime();
+    }
+
+    /**
+     * Adds a number of days to this date and returns the new date
+     *
+     * @param self a java.sql.Date
+     * @param days the number of days to increase
+     * @return the new date
+     */
+    public static java.sql.Date plus(java.sql.Date self, int days) {
+        return new java.sql.Date(plus((Date) self, days).getTime());
+    }
+
+    /**
+     * Subtracts a number of days from this date and returns the new date
+     *
+     * @param self a Date
+     * @return the new date
+     */
+    public static Date minus(Date self, int days) {
+        return plus(self, -days);
+    }
+
+    /**
+     * Subtracts a number of days from this date and returns the new date
+     *
+     * @param self a java.sql.Date
+     * @return the new date
+     */
+    public static java.sql.Date minus(java.sql.Date self, int days) {
+        return new java.sql.Date(minus((Date) self, days).getTime());
+    }
+
+    // Boolean based methods
+    //-------------------------------------------------------------------------
+
+    public static Boolean and(Boolean left, Boolean right) {
+        return Boolean.valueOf(left.booleanValue() & right.booleanValue());
+    }
+
+    public static Boolean or(Boolean left, Boolean right) {
+        return Boolean.valueOf(left.booleanValue() | right.booleanValue());
+    }
+
+    public static Boolean xor(Boolean left, Boolean right) {
+        return Boolean.valueOf(left.booleanValue() ^ right.booleanValue());
+    }
+
+//    public static Boolean negate(Boolean left) {
+//        return Boolean.valueOf(!left.booleanValue());
+//    }
+
+    // File and stream based methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Helper method to create an object input stream from the given file.
+     *
+     * @param file a file
+     * @return an object input stream
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    public static ObjectInputStream newObjectInputStream(File file) throws FileNotFoundException, IOException {
+        return new ObjectInputStream(new FileInputStream(file));
+    }
+
+    /**
+     * Iterates through the given file object by object
+     *
+     * @param self    a File
+     * @param closure a closure
+     * @throws IOException
+     * @throws ClassNotFoundException
+     */
+    public static void eachObject(File self, Closure closure) throws IOException, ClassNotFoundException {
+        eachObject(newObjectInputStream(self), closure);
+    }
+
+    /**
+     * Iterates through the given object stream object by object. The
+     * ObjectInputStream is closed afterwards.
+     *
+     * @param ois     an ObjectInputStream, closed after the operation
+     * @param closure a closure
+     * @throws IOException
+     * @throws ClassNotFoundException
+     */
+    public static void eachObject(ObjectInputStream ois, Closure closure) throws IOException, ClassNotFoundException {
+        try {
+            while (true) {
+                try {
+                    Object obj = ois.readObject();
+                    // we allow null objects in the object stream
+                    closure.call(obj);
+                } catch (EOFException e) {
+                    break;
+                }
+            }
+            InputStream temp = ois;
+            ois = null;
+            temp.close();
+        } finally {
+            if (ois != null) {
+                try {
+                    ois.close();
+                }
+                catch (Exception e) {
+                    // ignore this exception since there
+                    // has to be another already
+                    LOG.warning("Caught exception closing ObjectInputStream: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Iterates through the given file line by line
+     *
+     * @param self    a File
+     * @param closure a closure
+     * @throws IOException
+     */
+    public static void eachLine(File self, Closure closure) throws IOException {
+        eachLine(newReader(self), closure);
+    }
+
+    /**
+     * Iterates through the given reader line by line. The
+     * Reader is closed afterwards
+     *
+     * @param self    a Reader, closed after the method returns
+     * @param closure a closure
+     * @throws IOException
+     */
+    public static void eachLine(Reader self, Closure closure) throws IOException {
+        BufferedReader br /* = null */;
+
+        if (self instanceof BufferedReader)
+            br = (BufferedReader) self;
+        else
+            br = new BufferedReader(self);
+
+        try {
+            while (true) {
+                String line = br.readLine();
+                if (line == null) {
+                    break;
+                } else {
+                    closure.call(line);
+                }
+            }
+            Reader temp = self;
+            self = null;
+            temp.close();
+        } finally {
+            if (self != null) {
+                try {
+                    self.close();
+                }
+                catch (Exception e) {
+                    // ignore this exception since there
+                    // has to be another already
+                    LOG.warning("Caught exception closing Reader: " + e);
+                }
+            }
+            if (br != null) {
+                try {
+                    br.close();
+                }
+                catch (Exception e) {
+                    // ignore this exception since this
+                    // is only our internal problem
+                    LOG.warning("Caught exception closing Reader: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Iterates through the given file line by line, splitting on the seperator
+     *
+     * @param self    a File
+     * @param sep     a String separator
+     * @param closure a closure
+     * @throws IOException
+     */
+    public static void splitEachLine(File self, String sep, Closure closure) throws IOException {
+        splitEachLine(newReader(self), sep, closure);
+    }
+
+    /**
+     * Iterates through the given reader line by line, splitting on the separator.
+     * The Reader is closed afterwards.
+     *
+     * @param self    a Reader, closed after the method returns
+     * @param sep     a String separator
+     * @param closure a closure
+     * @throws IOException
+     */
+    public static void splitEachLine(Reader self, String sep, Closure closure) throws IOException {
+        BufferedReader br /* = null */;
+
+        if (self instanceof BufferedReader)
+            br = (BufferedReader) self;
+        else
+            br = new BufferedReader(self);
+
+        try {
+            while (true) {
+                String line = br.readLine();
+                if (line == null) {
+                    break;
+                } else {
+                    List vals = Arrays.asList(line.split(sep));
+                    closure.call(vals);
+                }
+            }
+            Reader temp = self;
+            self = null;
+            temp.close();
+        } finally {
+            if (self != null) {
+                try {
+                    self.close();
+                } catch (Exception e) {
+                    // ignore this exception since there
+                    // has to be another already
+                    LOG.warning("Caught exception closing Reader: " + e);
+                }
+            }
+            if (br != null) {
+                try {
+                    br.close();
+                } catch (Exception e) {
+                    // ignore this exception since this
+                    // is only our internal problem
+                    LOG.warning("Caught exception closing Reader: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Read a single, whole line from the given Reader
+     *
+     * @param self a Reader
+     * @return a line
+     * @throws IOException
+     */
+    public static String readLine(Reader self) throws IOException {
+        BufferedReader br /* = null */;
+
+        if (self instanceof BufferedReader) {
+            br = (BufferedReader) self;
+        } else {
+            br = new BufferedReader(self); // todo dk: bug! will return null on second call
+        }
+        return br.readLine();
+    }
+
+    /**
+     * Read a single, whole line from the given InputStream
+     *
+     * @param stream an InputStream
+     * @return a line
+     * @throws IOException
+     */
+    public static String readLine(InputStream stream) throws IOException {
+        return readLine(new InputStreamReader(stream));
+    }
+
+    /**
+     * Reads the file into a list of Strings for each line
+     *
+     * @param file a File
+     * @return a List of lines
+     * @throws IOException
+     */
+    public static List readLines(File file) throws IOException {
+        IteratorClosureAdapter closure = new IteratorClosureAdapter(file);
+        eachLine(file, closure);
+        return closure.asList();
+    }
+
+    /**
+     * Reads the content of the File opened with the specified encoding and returns it as a String
+     *
+     * @param file    the file whose content we want to read
+     * @param charset the charset used to read the content of the file
+     * @return a String containing the content of the file
+     * @throws IOException
+     */
+    public static String getText(File file, String charset) throws IOException {
+        BufferedReader reader = newReader(file, charset);
+        return getText(reader);
+    }
+
+    /**
+     * Reads the content of the File and returns it as a String
+     *
+     * @param file the file whose content we want to read
+     * @return a String containing the content of the file
+     * @throws IOException
+     */
+    public static String getText(File file) throws IOException {
+        BufferedReader reader = newReader(file);
+        return getText(reader);
+    }
+
+    /**
+     * Reads the content of this URL and returns it as a String
+     *
+     * @param url URL to read content from
+     * @return the text from that URL
+     * @throws IOException
+     */
+    public static String getText(URL url) throws IOException {
+        return getText(url, CharsetToolkit.getDefaultSystemCharset().toString());
+    }
+
+    /**
+     * Reads the content of this URL and returns it as a String
+     *
+     * @param url     URL to read content from
+     * @param charset opens the stream with a specified charset
+     * @return the text from that URL
+     * @throws IOException
+     */
+    public static String getText(URL url, String charset) throws IOException {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(url.openConnection().getInputStream(), charset));
+        return getText(reader);
+    }
+
+    /**
+     * Reads the content of this InputStream and returns it as a String
+     *
+     * @param is an input stream
+     * @return the text from that URL
+     * @throws IOException
+     */
+    public static String getText(InputStream is) throws IOException {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+        return getText(reader);
+    }
+
+    /**
+     * Reads the content of this InputStream with a specified charset and returns it as a String
+     *
+     * @param is      an input stream
+     * @param charset opens the stream with a specified charset
+     * @return the text from that URL
+     * @throws IOException
+     */
+    public static String getText(InputStream is, String charset) throws IOException {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(is, charset));
+        return getText(reader);
+    }
+
+    /**
+     * Reads the content of the Reader and returns it as a String
+     *
+     * @param reader a Reader whose content we want to read
+     * @return a String containing the content of the buffered reader
+     * @throws IOException
+     */
+    public static String getText(Reader reader) throws IOException {
+        BufferedReader bufferedReader = new BufferedReader(reader);
+        return getText(bufferedReader);
+    }
+
+    /**
+     * Reads the content of the BufferedReader and returns it as a String.
+     * The BufferedReader is closed afterwards.
+     *
+     * @param reader a BufferedReader whose content we want to read
+     * @return a String containing the content of the buffered reader
+     * @throws IOException
+     */
+    public static String getText(BufferedReader reader) throws IOException {
+        StringBuffer answer = new StringBuffer();
+        // reading the content of the file within a char buffer 
+        // allow to keep the correct line endings
+        char[] charBuffer = new char[4096];
+        int nbCharRead /* = 0*/;
+        try {
+            while ((nbCharRead = reader.read(charBuffer)) != -1) {
+                // appends buffer
+                answer.append(charBuffer, 0, nbCharRead);
+            }
+            Reader temp = reader;
+            reader = null;
+            temp.close();
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (Exception e) {
+                    // ignore since there has to be an exception already
+                    LOG.warning("Caught exception closing Reader: " + e);
+                }
+            }
+        }
+        return answer.toString();
+    }
+
+    /**
+     * Write the text and append a new line (depending on the platform
+     * line-ending)
+     *
+     * @param writer a BufferedWriter
+     * @param line   the line to write
+     * @throws IOException
+     */
+    public static void writeLine(BufferedWriter writer, String line) throws IOException {
+        writer.write(line);
+        writer.newLine();
+    }
+
+    /**
+     * Write the text to the File.
+     *
+     * @param file a File
+     * @param text the text to write to the File
+     * @throws IOException
+     */
+    public static void write(File file, String text) throws IOException {
+        BufferedWriter writer = null;
+        try {
+            writer = newWriter(file);
+            writer.write(text);
+            writer.flush();
+
+            Writer temp = writer;
+            writer = null;
+            temp.close();
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (Exception e) {
+                    // ignore since there has to be an exception already
+                    LOG.warning("Caught exception closing Writer: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Write the text to the File.
+     *
+     * @param file a File
+     * @param text the text to write to the File
+     * @throws IOException
+     */
+    public static File leftShift(File file, Object text) throws IOException {
+        append(file, text);
+        return file;
+    }
+
+    /**
+     * Write the text to the File with a specified encoding.
+     *
+     * @param file    a File
+     * @param text    the text to write to the File
+     * @param charset the charset used
+     * @throws IOException
+     */
+    public static void write(File file, String text, String charset) throws IOException {
+        BufferedWriter writer = null;
+        try {
+            writer = newWriter(file, charset);
+            writer.write(text);
+            writer.flush();
+
+            Writer temp = writer;
+            writer = null;
+            temp.close();
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (Exception e) {
+                    // ignore since there has to be an exception already
+                    LOG.warning("Caught exception closing Writer: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Append the text at the end of the File
+     *
+     * @param file a File
+     * @param text the text to append at the end of the File
+     * @throws IOException
+     */
+    public static void append(File file, Object text) throws IOException {
+        BufferedWriter writer = null;
+        try {
+            writer = newWriter(file, true);
+            InvokerHelper.write(writer, text);
+            writer.flush();
+
+            Writer temp = writer;
+            writer = null;
+            temp.close();
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (Exception e) {
+                    // ignore since there has to be an exception already
+                    LOG.warning("Caught exception closing Writer: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Append the text at the end of the File with a specified encoding
+     *
+     * @param file    a File
+     * @param text    the text to append at the end of the File
+     * @param charset the charset used
+     * @throws IOException
+     */
+    public static void append(File file, Object text, String charset) throws IOException {
+        BufferedWriter writer = null;
+        try {
+            writer = newWriter(file, charset, true);
+            InvokerHelper.write(writer, text);
+            writer.flush();
+
+            Writer temp = writer;
+            writer = null;
+            temp.close();
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (Exception e) {
+                    // ignore since there has to be an exception already
+                    LOG.warning("Caught exception closing Writer: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Reads the reader into a list of Strings for each line
+     *
+     * @param reader a Reader
+     * @return a List of lines
+     * @throws IOException
+     */
+    public static List readLines(Reader reader) throws IOException {
+        IteratorClosureAdapter closure = new IteratorClosureAdapter(reader);
+        eachLine(reader, closure);
+        return closure.asList();
+    }
+
+    /**
+     * This method is used to throw useful exceptions when the eachFile* and eachDir closure methods
+     * are used incorrectly.
+     *
+     * @param dir The directory to check
+     * @throws FileNotFoundException    Thrown if the given directory does not exist
+     * @throws IllegalArgumentException Thrown if the provided File object does not represent a directory
+     */
+    private static void checkDir(File dir) throws FileNotFoundException, IllegalArgumentException {
+        if (!dir.exists())
+            throw new FileNotFoundException(dir.getAbsolutePath());
+        if (!dir.isDirectory())
+            throw new IllegalArgumentException("The provided File object is not a directory: " + dir.getAbsolutePath());
+    }
+
+    /**
+     * Invokes the closure for each file in the given directory
+     *
+     * @param self    a File
+     * @param closure a closure
+     * @throws FileNotFoundException    Thrown if the given directory does not exist
+     * @throws IllegalArgumentException Thrown if the provided File object does not represent a directory
+     */
+    public static void eachFile(File self, Closure closure) throws FileNotFoundException, IllegalArgumentException {
+        checkDir(self);
+        File[] files = self.listFiles();
+        for (int i = 0; i < files.length; i++) {
+            closure.call(files[i]);
+        }
+    }
+
+    /**
+     * Invokes the closure for each file in the given directory and recursively.
+     * It is a depth-first exploration, directories are included in the search.
+     *
+     * @param self    a File
+     * @param closure a closure
+     * @throws FileNotFoundException    Thrown if the given directory does not exist
+     * @throws IllegalArgumentException Thrown if the provided File object does not represent a directory
+     */
+    public static void eachFileRecurse(File self, Closure closure) throws FileNotFoundException, IllegalArgumentException {
+        checkDir(self);
+        File[] files = self.listFiles();
+        for (int i = 0; i < files.length; i++) {
+            if (files[i].isDirectory()) {
+                closure.call(files[i]);
+                eachFileRecurse(files[i], closure);
+            } else {
+                closure.call(files[i]);
+            }
+        }
+    }
+
+    /**
+     * Invokes the closure for each directory in the given directory,
+     * ignoring regular files.
+     *
+     * @param self    a directory
+     * @param closure a closure
+     * @throws FileNotFoundException    Thrown if the given directory does not exist
+     * @throws IllegalArgumentException Thrown if the provided File object does not represent a directory
+     */
+    public static void eachDir(File self, Closure closure) throws FileNotFoundException, IllegalArgumentException {
+        checkDir(self);
+        File[] files = self.listFiles();
+        for (int i = 0; i < files.length; i++) {
+            if (files[i].isDirectory()) {
+                closure.call(files[i]);
+            }
+        }
+    }
+
+    /**
+     * Invokes the closure for each file matching the given filter in the given directory
+     * - calling the isCase() method used by switch statements.  This method can be used
+     * with different kinds of filters like regular expresions, classes, ranges etc.
+     *
+     * @param self    a file
+     * @param filter  the filter to perform on the directory (using the isCase(object) method)
+     * @param closure
+     * @throws FileNotFoundException    Thrown if the given directory does not exist
+     * @throws IllegalArgumentException Thrown if the provided File object does not represent a directory
+     */
+    public static void eachFileMatch(File self, Object filter, Closure closure) throws FileNotFoundException, IllegalArgumentException {
+        checkDir(self);
+        File[] files = self.listFiles();
+        MetaClass metaClass = InvokerHelper.getMetaClass(filter);
+        for (int i = 0; i < files.length; i++) {
+            if (DefaultTypeTransformation.castToBoolean(metaClass.invokeMethod(filter, "isCase", files[i].getName()))) {
+                closure.call(files[i]);
+            }
+        }
+    }
+
+    /**
+     * Allow simple syntax for using timers.
+     *
+     * @param timer   a timer object
+     * @param delay   the delay in milliseconds before running the closure code
+     * @param closure
+     */
+    public static void runAfter(Timer timer, int delay, final Closure closure) {
+        TimerTask timerTask = new TimerTask() {
+            public void run() {
+                closure.call();
+            }
+        };
+        timer.schedule(timerTask, delay);
+    }
+
+    /**
+     * Helper method to create a buffered reader for a file
+     *
+     * @param file a File
+     * @return a BufferedReader
+     * @throws IOException
+     */
+    public static BufferedReader newReader(File file) throws IOException {
+        CharsetToolkit toolkit = new CharsetToolkit(file);
+        return toolkit.getReader();
+    }
+
+    /**
+     * Helper method to create a buffered reader for a file, with a specified charset
+     *
+     * @param file    a File
+     * @param charset the charset with which we want to write in the File
+     * @return a BufferedReader
+     * @throws FileNotFoundException        if the File was not found
+     * @throws UnsupportedEncodingException if the encoding specified is not supported
+     */
+    public static BufferedReader newReader(File file, String charset)
+            throws FileNotFoundException, UnsupportedEncodingException {
+        return new BufferedReader(new InputStreamReader(new FileInputStream(file), charset));
+    }
+
+    /**
+     * Provides a reader for an arbitrary input stream
+     *
+     * @param self an input stream
+     * @return a reader
+     */
+    public static BufferedReader newReader(InputStream self) {
+        return new BufferedReader(new InputStreamReader(self));
+    }
+
+    /**
+     * Helper method to create a new BufferedReader for a file and then
+     * passes it into the closure and ensures its closed again afterwords
+     *
+     * @param file
+     * @throws FileNotFoundException
+     */
+    public static void withReader(File file, Closure closure) throws IOException {
+        withReader(newReader(file), closure);
+    }
+
+    /**
+     * Helper method to create a buffered output stream for a file
+     *
+     * @param file
+     * @throws FileNotFoundException
+     */
+    public static BufferedOutputStream newOutputStream(File file) throws IOException {
+        return new BufferedOutputStream(new FileOutputStream(file));
+    }
+
+    /**
+     * Helper method to create a new OutputStream for a file and then
+     * passes it into the closure and ensures its closed again afterwords
+     *
+     * @param file a File
+     * @throws FileNotFoundException
+     */
+    public static void withOutputStream(File file, Closure closure) throws IOException {
+        withStream(newOutputStream(file), closure);
+    }
+
+    /**
+     * Helper method to create a new InputStream for a file and then
+     * passes it into the closure and ensures its closed again afterwords
+     *
+     * @param file a File
+     * @throws FileNotFoundException
+     */
+    public static void withInputStream(File file, Closure closure) throws IOException {
+        withStream(newInputStream(file), closure);
+    }
+
+    /**
+     * Helper method to create a buffered writer for a file
+     *
+     * @param file a File
+     * @return a BufferedWriter
+     * @throws FileNotFoundException
+     */
+    public static BufferedWriter newWriter(File file) throws IOException {
+        return new BufferedWriter(new FileWriter(file));
+    }
+
+    /**
+     * Helper method to create a buffered writer for a file in append mode
+     *
+     * @param file   a File
+     * @param append true if in append mode
+     * @return a BufferedWriter
+     * @throws FileNotFoundException
+     */
+    public static BufferedWriter newWriter(File file, boolean append) throws IOException {
+        return new BufferedWriter(new FileWriter(file, append));
+    }
+
+    /**
+     * Helper method to create a buffered writer for a file
+     *
+     * @param file    a File
+     * @param charset the name of the encoding used to write in this file
+     * @param append  true if in append mode
+     * @return a BufferedWriter
+     * @throws FileNotFoundException
+     */
+    public static BufferedWriter newWriter(File file, String charset, boolean append) throws IOException {
+        if (append) {
+            return new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, append), charset));
+        } else {
+            // first write the Byte Order Mark for Unicode encodings
+            FileOutputStream stream = new FileOutputStream(file);
+            if ("UTF-16BE".equals(charset)) {
+                writeUtf16Bom(stream, true);
+            } else if ("UTF-16LE".equals(charset)) {
+                writeUtf16Bom(stream, false);
+            }
+            return new BufferedWriter(new OutputStreamWriter(stream, charset));
+        }
+    }
+
+    /**
+     * Helper method to create a buffered writer for a file
+     *
+     * @param file    a File
+     * @param charset the name of the encoding used to write in this file
+     * @return a BufferedWriter
+     * @throws FileNotFoundException
+     */
+    public static BufferedWriter newWriter(File file, String charset) throws IOException {
+        return newWriter(file, charset, false);
+    }
+
+    /**
+     * Write a Byte Order Mark at the begining of the file
+     *
+     * @param stream    the FileOuputStream to write the BOM to
+     * @param bigEndian true if UTF 16 Big Endian or false if Low Endian
+     * @throws IOException
+     */
+    private static void writeUtf16Bom(FileOutputStream stream, boolean bigEndian) throws IOException {
+        if (bigEndian) {
+            stream.write(-2);
+            stream.write(-1);
+        } else {
+            stream.write(-1);
+            stream.write(-2);
+        }
+    }
+
+    /**
+     * Helper method to create a new BufferedWriter for a file and then
+     * passes it into the closure and ensures it is closed again afterwords
+     *
+     * @param file    a File
+     * @param closure a closure
+     * @throws FileNotFoundException
+     */
+    public static void withWriter(File file, Closure closure) throws IOException {
+        withWriter(newWriter(file), closure);
+    }
+
+    /**
+     * Helper method to create a new BufferedWriter for a file in a specified encoding
+     * and then passes it into the closure and ensures it is closed again afterwords
+     *
+     * @param file    a File
+     * @param charset the charset used
+     * @param closure a closure
+     * @throws FileNotFoundException
+     */
+    public static void withWriter(File file, String charset, Closure closure) throws IOException {
+        withWriter(newWriter(file, charset), closure);
+    }
+
+    /**
+     * Helper method to create a new BufferedWriter for a file in a specified encoding
+     * in append mode and then passes it into the closure and ensures it is closed again afterwords
+     *
+     * @param file    a File
+     * @param charset the charset used
+     * @param closure a closure
+     * @throws FileNotFoundException
+     */
+    public static void withWriterAppend(File file, String charset, Closure closure) throws IOException {
+        withWriter(newWriter(file, charset, true), closure);
+    }
+
+    /**
+     * Helper method to create a new PrintWriter for a file
+     *
+     * @param file a File
+     * @throws FileNotFoundException
+     */
+    public static PrintWriter newPrintWriter(File file) throws IOException {
+        return new PrintWriter(newWriter(file));
+    }
+
+    /**
+     * Helper method to create a new PrintWriter for a file with a specified charset
+     *
+     * @param file    a File
+     * @param charset the charset
+     * @return a PrintWriter
+     * @throws FileNotFoundException
+     */
+    public static PrintWriter newPrintWriter(File file, String charset) throws IOException {
+        return new PrintWriter(newWriter(file, charset));
+    }
+
+    /**
+     * Helper method to create a new PrintWriter for a file and then
+     * passes it into the closure and ensures its closed again afterwords
+     *
+     * @param file a File
+     * @throws FileNotFoundException
+     */
+    public static void withPrintWriter(File file, Closure closure) throws IOException {
+        withWriter(newPrintWriter(file), closure);
+    }
+
+    /**
+     * Allows a writer to be used, calling the closure with the writer
+     * and then ensuring that the writer is closed down again irrespective
+     * of whether exceptions occur or the
+     *
+     * @param writer  the writer which is used and then closed
+     * @param closure the closure that the writer is passed into
+     * @throws IOException
+     */
+    public static void withWriter(Writer writer, Closure closure) throws IOException {
+        try {
+            closure.call(writer);
+            writer.flush();
+
+            Writer temp = writer;
+            writer = null;
+            temp.close();
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (Exception e) {
+                    // ignore since there has to be an exception already
+                    LOG.warning("Caught exception closing Writer: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Allows a Reader to be used, calling the closure with the reader
+     * and then ensuring that the reader is closed down again irrespective
+     * of whether exceptions occur or the
+     *
+     * @param reader  the reader which is used and then closed
+     * @param closure the closure that the writer is passed into
+     * @throws IOException
+     */
+    public static void withReader(Reader reader, Closure closure) throws IOException {
+        try {
+            closure.call(reader);
+
+            Reader temp = reader;
+            reader = null;
+            temp.close();
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (Exception e) {
+                    // ignore since there has to be an exception already
+                    LOG.warning("Caught exception closing Reader: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Allows a InputStream to be used, calling the closure with the stream
+     * and then ensuring that the stream is closed down again irrespective
+     * of whether exceptions occur or the
+     *
+     * @param stream  the stream which is used and then closed
+     * @param closure the closure that the stream is passed into
+     * @throws IOException
+     */
+    public static void withStream(InputStream stream, Closure closure) throws IOException {
+        try {
+            closure.call(stream);
+
+            InputStream temp = stream;
+            stream = null;
+            temp.close();
+        } finally {
+            if (stream != null) {
+                try {
+                    stream.close();
+                } catch (Exception e) {
+                    // ignore since there has to be an exception already
+                    LOG.warning("Caught exception closing InputStream: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Reads the stream into a list of Strings for each line
+     *
+     * @param stream a stream
+     * @return a List of lines
+     * @throws IOException
+     */
+    public static List readLines(InputStream stream) throws IOException {
+        return readLines(new BufferedReader(new InputStreamReader(stream)));
+    }
+
+    /**
+     * Iterates through the given stream line by line
+     *
+     * @param stream  a stream
+     * @param closure a closure
+     * @throws IOException
+     */
+    public static void eachLine(InputStream stream, Closure closure) throws IOException {
+        eachLine(new InputStreamReader(stream), closure);
+    }
+
+    /**
+     * Iterates through the lines read from the URL's associated input stream
+     *
+     * @param url     a URL to open and read
+     * @param closure a closure to apply on each line
+     * @throws IOException
+     */
+    public static void eachLine(URL url, Closure closure) throws IOException {
+        eachLine(url.openConnection().getInputStream(), closure);
+    }
+
+    /**
+     * Helper method to create a new BufferedReader for a URL and then
+     * passes it into the closure and ensures its closed again afterwords
+     *
+     * @param url a URL
+     * @throws FileNotFoundException
+     */
+    public static void withReader(URL url, Closure closure) throws IOException {
+        withReader(url.openConnection().getInputStream(), closure);
+    }
+
+    /**
+     * Helper method to create a new BufferedReader for a stream and then
+     * passes it into the closure and ensures its closed again afterwords
+     *
+     * @param in a stream
+     * @throws FileNotFoundException
+     */
+    public static void withReader(InputStream in, Closure closure) throws IOException {
+        withReader(new InputStreamReader(in), closure);
+    }
+
+    /**
+     * Allows an output stream to be used, calling the closure with the output stream
+     * and then ensuring that the output stream is closed down again irrespective
+     * of whether exceptions occur
+     *
+     * @param stream  the stream which is used and then closed
+     * @param closure the closure that the writer is passed into
+     * @throws IOException
+     */
+    public static void withWriter(OutputStream stream, Closure closure) throws IOException {
+        withWriter(new OutputStreamWriter(stream), closure);
+    }
+
+    /**
+     * Allows an output stream to be used, calling the closure with the output stream
+     * and then ensuring that the output stream is closed down again irrespective
+     * of whether exceptions occur.
+     *
+     * @param stream  the stream which is used and then closed
+     * @param charset the charset used
+     * @param closure the closure that the writer is passed into
+     * @throws IOException
+     */
+    public static void withWriter(OutputStream stream, String charset, Closure closure) throws IOException {
+        withWriter(new OutputStreamWriter(stream, charset), closure);
+    }
+
+    /**
+     * Allows a OutputStream to be used, calling the closure with the stream
+     * and then ensuring that the stream is closed down again irrespective
+     * of whether exceptions occur.
+     *
+     * @param os      the stream which is used and then closed
+     * @param closure the closure that the stream is passed into
+     * @throws IOException
+     */
+    public static void withStream(OutputStream os, Closure closure) throws IOException {
+        try {
+            closure.call(os);
+            os.flush();
+
+            OutputStream temp = os;
+            os = null;
+            temp.close();
+        } finally {
+            if (os != null) {
+                try {
+                    os.close();
+                } catch (IOException e) {
+                    LOG.warning("Caught exception closing OutputStream: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper method to create a buffered input stream for a file
+     *
+     * @param file a File
+     * @return a BufferedInputStream of the file
+     * @throws FileNotFoundException
+     */
+    public static BufferedInputStream newInputStream(File file) throws FileNotFoundException {
+        return new BufferedInputStream(new FileInputStream(file));
+    }
+
+    /**
+     * Traverse through each byte of the specified File
+     *
+     * @param self    a File
+     * @param closure a closure
+     */
+    public static void eachByte(File self, Closure closure) throws IOException {
+        BufferedInputStream is = newInputStream(self);
+        eachByte(is, closure);
+    }
+
+    /**
+     * Traverse through each byte of the specified stream. The
+     * stream is closed afterwards.
+     *
+     * @param is      stream to iterate over, closed after the method call
+     * @param closure closure to apply to each byte
+     * @throws IOException
+     */
+    public static void eachByte(InputStream is, Closure closure) throws IOException {
+        try {
+            while (true) {
+                int b = is.read();
+                if (b == -1) {
+                    break;
+                } else {
+                    closure.call(new Byte((byte) b));
+                }
+            }
+
+            InputStream temp = is;
+            is = null;
+            temp.close();
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                    LOG.warning("Caught exception closing InputStream: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Traverse through each byte of the specified URL
+     *
+     * @param url     url to iterate over
+     * @param closure closure to apply to each byte
+     * @throws IOException
+     */
+    public static void eachByte(URL url, Closure closure) throws IOException {
+        InputStream is = url.openConnection().getInputStream();
+        eachByte(is, closure);
+    }
+
+    /**
+     * Transforms the characters from a reader with a Closure and
+     * write them to a writer.
+     *
+     * @param reader
+     * @param writer
+     * @param closure
+     */
+    public static void transformChar(Reader reader, Writer writer, Closure closure) throws IOException {
+        int c;
+        try {
+            char[] chars = new char[1];
+            while ((c = reader.read()) != -1) {
+                chars[0] = (char) c;
+                writer.write((String) closure.call(new String(chars)));
+            }
+            writer.flush();
+
+            Writer temp2 = writer;
+            writer = null;
+            temp2.close();
+            Reader temp1 = reader;
+            reader = null;
+            temp1.close();
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    LOG.warning("Caught exception closing Reader: " + e);
+                }
+            }
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (IOException e) {
+                    LOG.warning("Caught exception closing Writer: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Transforms the lines from a reader with a Closure and
+     * write them to a writer. Both Reader and Writer are
+     * closed after the operation
+     *
+     * @param reader  Lines of text to be transformed. Reader is closed afterwards.
+     * @param writer  Where transformed lines are written. Writer is closed afterwards.
+     * @param closure Single parameter closure that is called to transform each line of
+     *                text from the reader, before writing it to the writer.
+     */
+    public static void transformLine(Reader reader, Writer writer, Closure closure) throws IOException {
+        BufferedReader br = new BufferedReader(reader);
+        BufferedWriter bw = new BufferedWriter(writer);
+        String line;
+        try {
+            while ((line = br.readLine()) != null) {
+                Object o = closure.call(line);
+                if (o != null) {
+                    bw.write(o.toString());
+                    bw.newLine();
+                }
+            }
+            bw.flush();
+
+            Writer temp2 = writer;
+            writer = null;
+            temp2.close();
+            Reader temp1 = reader;
+            reader = null;
+            temp1.close();
+        } finally {
+            if (br != null) {
+                try {
+                    br.close();
+                } catch (IOException e) {
+                    LOG.warning("Caught exception closing Reader: " + e);
+                }
+            }
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    LOG.warning("Caught exception closing Reader: " + e);
+                }
+            }
+            if (bw != null) {
+                try {
+                    bw.close();
+                } catch (IOException e) {
+                    LOG.warning("Caught exception closing Writer: " + e);
+                }
+            }
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (IOException e) {
+                    LOG.warning("Caught exception closing Writer: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Filter the lines from a reader and write them on the writer,
+     * according to a closure which returns true or false.
+     * Both Reader and Writer are closed after the operation.
+     *
+     * @param reader  a reader, closed after the call
+     * @param writer  a writer, closed after the call
+     * @param closure the closure which returns booleans
+     * @throws IOException
+     */
+    public static void filterLine(Reader reader, Writer writer, Closure closure) throws IOException {
+        BufferedReader br = new BufferedReader(reader);
+        BufferedWriter bw = new BufferedWriter(writer);
+        String line;
+        try {
+            while ((line = br.readLine()) != null) {
+                if (DefaultTypeTransformation.castToBoolean(closure.call(line))) {
+                    bw.write(line);
+                    bw.newLine();
+                }
+            }
+            bw.flush();
+
+            Writer temp2 = writer;
+            writer = null;
+            temp2.close();
+            Reader temp1 = reader;
+            reader = null;
+            temp1.close();
+        } finally {
+            if (br != null) {
+                try {
+                    br.close();
+                } catch (IOException e) {
+                    LOG.warning("Caught exception closing Reader: " + e);
+                }
+            }
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    LOG.warning("Caught exception closing Reader: " + e);
+                }
+            }
+            if (bw != null) {
+                try {
+                    bw.close();
+                } catch (IOException e) {
+                    LOG.warning("Caught exception closing Writer: " + e);
+                }
+            }
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (IOException e) {
+                    LOG.warning("Caught exception closing Writer: " + e);
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Filters the lines of a File and creates a Writeable in return to
+     * stream the filtered lines
+     *
+     * @param self    a File
+     * @param closure a closure which returns a boolean indicating to filter
+     *                the line or not
+     * @return a Writable closure
+     * @throws IOException if <code>self</code> is not readable
+     */
+    public static Writable filterLine(File self, Closure closure) throws IOException {
+        return filterLine(newReader(self), closure);
+    }
+
+    /**
+     * Filter the lines from a File and write them on a writer, according to a closure
+     * which returns true or false
+     *
+     * @param self    a File
+     * @param writer  a writer
+     * @param closure a closure which returns a boolean value and takes a line as input
+     * @throws IOException if <code>self</code> is not readable
+     */
+    public static void filterLine(File self, Writer writer, Closure closure) throws IOException {
+        filterLine(newReader(self), writer, closure);
+    }
+
+    /**
+     * Filter the lines of a Reader and create a Writable in return to stream
+     * the filtered lines.
+     *
+     * @param reader  a reader
+     * @param closure a closure returning a boolean indicating to filter or not a line
+     * @return a Writable closure
+     */
+    public static Writable filterLine(Reader reader, final Closure closure) {
+        final BufferedReader br = new BufferedReader(reader);
+        return new Writable() {
+            public Writer writeTo(Writer out) throws IOException {
+                BufferedWriter bw = new BufferedWriter(out);
+                String line;
+                while ((line = br.readLine()) != null) {
+                    if (DefaultTypeTransformation.castToBoolean(closure.call(line))) {
+                        bw.write(line);
+                        bw.newLine();
+                    }
+                }
+                bw.flush();
+                return out;
+            }
+
+            public String toString() {
+                StringWriter buffer = new StringWriter();
+                try {
+                    writeTo(buffer);
+                } catch (IOException e) {
+                    throw new StringWriterIOException(e);
+                }
+                return buffer.toString();
+            }
+        };
+    }
+
+    /**
+     * Filter lines from an input stream using a closure predicate
+     *
+     * @param self      an input stream
+     * @param predicate a closure which returns boolean and takes a line
+     * @return a filtered writer
+     */
+    public static Writable filterLine(InputStream self, Closure predicate) {
+        return filterLine(newReader(self), predicate);
+    }
+
+    /**
+     * Filters lines from an input stream, writing to a writer, using a closure which
+     * returns boolean and takes a line.
+     *
+     * @param self      an InputStream
+     * @param writer    a writer to write output to
+     * @param predicate a closure which returns a boolean and takes a line as input
+     */
+    public static void filterLine(InputStream self, Writer writer, Closure predicate)
+            throws IOException {
+        filterLine(newReader(self), writer, predicate);
+    }
+
+    /**
+     * Reads the content of the file into an array of byte
+     *
+     * @param file a File
+     * @return a List of Bytes
+     */
+    public static byte[] readBytes(File file) throws IOException {
+        byte[] bytes = new byte[(int) file.length()];
+        FileInputStream fileInputStream = new FileInputStream(file);
+        DataInputStream dis = new DataInputStream(fileInputStream);
+        try {
+            dis.readFully(bytes);
+
+            InputStream temp = dis;
+            dis = null;
+            temp.close();
+        } finally {
+            if (dis != null) {
+                try {
+                    dis.close();
+                } catch (IOException e) {
+                    LOG.warning("Caught exception closing DataInputStream: " + e);
+                }
+            }
+        }
+        return bytes;
+    }
+
+    // ================================
+    // Socket and ServerSocket methods
+
+    /**
+     * Allows an InputStream and an OutputStream from a Socket to be used,
+     * calling the closure with the streams and then ensuring that the streams
+     * are closed down again irrespective of whether exceptions occur.
+     *
+     * @param socket  a Socket
+     * @param closure a Closure
+     * @throws IOException
+     */
+    public static void withStreams(Socket socket, Closure closure) throws IOException {
+        InputStream input = socket.getInputStream();
+        OutputStream output = socket.getOutputStream();
+        try {
+            closure.call(new Object[]{input, output});
+
+            InputStream temp1 = input;
+            input = null;
+            temp1.close();
+            OutputStream temp2 = output;
+            output = null;
+            temp2.close();
+        } finally {
+            if (input != null) {
+                try {
+                    input.close();
+                } catch (IOException e) {
+                    LOG.warning("Caught exception closing InputStream: " + e);
+                }
+            }
+            if (output != null) {
+                try {
+                    output.close();
+                } catch (IOException e) {
+                    LOG.warning("Caught exception closing OutputStream: " + e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Overloads the left shift operator to provide an append mechanism to
+     * add things to the output stream of a socket
+     *
+     * @param self  a Socket
+     * @param value a value to append
+     * @return a Writer
+     */
+    public static Writer leftShift(Socket self, Object value) throws IOException {
+        return leftShift(self.getOutputStream(), value);
+    }
+
+    /**
+     * Overloads the left shift operator to provide an append mechanism
+     * to add bytes to the output stream of a socket
+     *
+     * @param self  a Socket
+     * @param value a value to append
+     * @return an OutputStream
+     */
+    public static OutputStream leftShift(Socket self, byte[] value) throws IOException {
+        return leftShift(self.getOutputStream(), value);
+    }
+
+    /**
+     * Allow to pass a Closure to the accept methods of ServerSocket
+     *
+     * @param serverSocket a ServerSocket
+     * @param closure      a Closure
+     * @return a Socket
+     * @throws IOException
+     */
+    public static Socket accept(ServerSocket serverSocket, final Closure closure) throws IOException {
+        final Socket socket = serverSocket.accept();
+        new Thread(new Runnable() {
+            public void run() {
+                try {
+                    closure.call(socket);
+                } finally {
+                    try {
+                        socket.close();
+                    } catch (IOException e) {
+                        LOG.warning("Caught exception closing socket: " + e);
+                    }
+                }
+            }
+        }).start();
+        return socket;
+    }
+
+
+    /**
+     * @param file a File
+     * @return a File which wraps the input file and which implements Writable
+     */
+    public static File asWritable(File file) {
+        return new WritableFile(file);
+    }
+
+    public static Object asType(File f, Class c) {
+        if (c == Writable.class) {
+            return asWritable(f);
+        }
+        return asType((Object) f, c);
+    }
+
+    /**
+     * @param file     a File
+     * @param encoding the encoding to be used when reading the file's contents
+     * @return File which wraps the input file and which implements Writable
+     */
+    public static File asWritable(File file, String encoding) {
+        return new WritableFile(file, encoding);
+    }
+
+    /**
+     * Converts the given String into a List of strings of one character
+     *
+     * @param self a String
+     * @return a List of characters (a 1-character String)
+     */
+    public static List toList(String self) {
+        int size = self.length();
+        List answer = new ArrayList(size);
+        for (int i = 0; i < size; i++) {
+            answer.add(self.substring(i, i + 1));
+        }
+        return answer;
+    }
+
+    public static Object asType(String self, Class c) {
+        if (c == List.class) {
+            return toList(self);
+        } else if (c == BigDecimal.class) {
+            return toBigDecimal(self);
+        } else if (c == BigInteger.class) {
+            return toBigInteger(self);
+        } else if (c == Character.class) {
+            return toCharacter(self);
+        } else if (c == Double.class) {
+            return toDouble(self);
+        } else if (c == Float.class) {
+            return toFloat(self);
+        }
+        return asType((Object) self, c);
+    }
+
+    // Process methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * An alias method so that a process appears similar to System.out, System.in, System.err;
+     * you can use process.in, process.out, process.err in a similar way
+     *
+     * @return an InputStream
+     */
+    public static InputStream getIn(Process self) {
+        return self.getInputStream();
+    }
+
+    /**
+     * Read the text of the output stream of the Process.
+     *
+     * @param self a Process
+     * @return the text of the output
+     * @throws IOException
+     */
+    public static String getText(Process self) throws IOException {
+        return getText(new BufferedReader(new InputStreamReader(self.getInputStream())));
+    }
+
+    /**
+     * An alias method so that a process appears similar to System.out, System.in, System.err;
+     * you can use process.in, process.out, process.err in a similar way
+     *
+     * @return an InputStream
+     */
+    public static InputStream getErr(Process self) {
+        return self.getErrorStream();
+    }
+
+    /**
+     * An alias method so that a process appears similar to System.out, System.in, System.err;
+     * you can use process.in, process.out, process.err in a similar way
+     *
+     * @return an OutputStream
+     */
+    public static OutputStream getOut(Process self) {
+        return self.getOutputStream();
+    }
+
+    /**
+     * Overloads the left shift operator to provide an append mechanism
+     * to pipe into a Process
+     *
+     * @param self  a Process
+     * @param value a value to append
+     * @return a Writer
+     */
+    public static Writer leftShift(Process self, Object value) throws IOException {
+        return leftShift(self.getOutputStream(), value);
+    }
+
+    /**
+     * Overloads the left shift operator to provide an append mechanism
+     * to pipe into a Process
+     *
+     * @param self  a Process
+     * @param value a value to append
+     * @return an OutputStream
+     */
+    public static OutputStream leftShift(Process self, byte[] value) throws IOException {
+        return leftShift(self.getOutputStream(), value);
+    }
+
+    /**
+     * Wait for the process to finish during a certain amount of time, otherwise stops the process.
+     *
+     * @param self           a Process
+     * @param numberOfMillis the number of milliseconds to wait before stopping the process
+     */
+    public static void waitForOrKill(Process self, long numberOfMillis) {
+        ProcessRunner runnable = new ProcessRunner(self);
+        Thread thread = new Thread(runnable);
+        thread.start();
+        runnable.waitForOrKill(numberOfMillis);
+    }
+
+    /**
+     * gets the input and error streams from a process and reads them
+     * to avoid the process to block due to a full ouput buffer. For this
+     * two Threads are started, so this method will return immediately
+     *
+     * @param self a Process
+     */
+    public static void consumeProcessOutput(Process self) {
+        Dumper d = new Dumper(self.getErrorStream());
+        Thread t = new Thread(d);
+        t.start();
+        d = new Dumper(self.getInputStream());
+        t = new Thread(d);
+        t.start();
+    }
+
+    /**
+     * Process each regex group matched substring of the given string. If the closure
+     * parameter takes one argument an array with all match groups is passed to it.
+     * If the closure takes as many arguments as there are match groups, then each
+     * parameter will be one match group.
+     *
+     * @param self    the source string
+     * @param regex   a Regex string
+     * @param closure a closure with one parameter or as much parameters as groups
+     */
+    public static void eachMatch(String self, String regex, Closure closure) {
+        Pattern p = Pattern.compile(regex);
+        Matcher m = p.matcher(self);
+        while (m.find()) {
+            int count = m.groupCount();
+            ArrayList groups = new ArrayList();
+            for (int i = 0; i <= count; i++) {
+                groups.add(m.group(i));
+            }
+            if (groups.size() == 1 || closure.getMaximumNumberOfParameters() < groups.size()) {
+                // not enough parameters there to give each group part
+                // it's own parameter, so try a closure with one parameter
+                // and give it all groups as a array
+                closure.call((Object) groups.toArray());
+            } else {
+                closure.call((Object[]) groups.toArray());
+            }
+        }
+    }
+
+    /**
+     * Process each matched substring of the given group matcher. The object
+     * passed to the closure is an array of strings, matched per a successful match.
+     *
+     * @param self    the source matcher
+     * @param closure a closure
+     */
+    public static void each(Matcher self, Closure closure) {
+        Matcher m = self;
+        while (m.find()) {
+            int count = m.groupCount();
+            ArrayList groups = new ArrayList();
+            for (int i = 0; i <= count; i++) {
+                groups.add(m.group(i));
+            }
+            closure.call((Object[]) groups.toArray());
+        }
+    }
+
+    /**
+     * Iterates over every element of the collection and return the index of the first object
+     * that matches the condition specified in the closure
+     *
+     * @param self    the iteration object over which we iterate
+     * @param closure the filter to perform a match on the collection
+     * @return an integer that is the index of the first macthed object.
+     */
+    public static int findIndexOf(Object self, Closure closure) {
+        int i = 0;
+        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext(); i++) {
+            Object value = iter.next();
+            if (DefaultTypeTransformation.castToBoolean(closure.call(value))) {
+                break;
+            }
+        }
+        return i;
+    }
+
+    /**
+     * Iterates through the class loader parents until it finds a loader with a class
+     * named equal to org.codehaus.groovy.tools.RootLoader. If there is no such class
+     * null will be returned. The name has to be used because a direct compare with
+     * == may fail as the class may be loaded through different classloaders.
+     *
+     * @see org.codehaus.groovy.tools.RootLoader
+     */
+    public static ClassLoader getRootLoader(ClassLoader cl) {
+        while (true) {
+            if (cl == null) return null;
+            if (cl.getClass().getName().equals(RootLoader.class.getName())) return cl;
+            cl = cl.getParent();
+        }
+    }
+
+    /**
+     * Converts a given object to a type. This method is used through
+     * the "as" operator and is overloadable as any other operator.
+     *
+     * @param obj  the object to convert
+     * @param type the goal type
+     * @return the resulting object
+     */
+    public static Object asType(Object obj, Class type) {
+        return DefaultTypeTransformation.castToType(obj, type);
+    }
+    
+    public static Object newInstance(Class c) {
+        return InvokerHelper.getInstance().invokeConstructorOf(c,null);        
+    }
+    
+    public static Object newInstance(Class c, Object[] args) {
+        if (args==null) args=new Object[]{null};
+        return InvokerHelper.getInstance().invokeConstructorOf(c,args);
+    }
+
+    /**
+     * A Runnable which waits for a process to complete together with a notification scheme
+     * allowing another thread to wait a maximum number of seconds for the process to complete
+     * before killing it.
+     */
+    protected static class ProcessRunner implements Runnable {
+        Process process;
+        private boolean finished;
+
+        public ProcessRunner(Process process) {
+            this.process = process;
+        }
+
+        public void run() {
+            try {
+                process.waitFor();
+            } catch (InterruptedException e) {
+            }
+            synchronized (this) {
+                notifyAll();
+                finished = true;
+            }
+        }
+
+        public synchronized void waitForOrKill(long millis) {
+            if (!finished) {
+                try {
+                    wait(millis);
+                } catch (InterruptedException e) {
+                }
+                if (!finished) {
+                    process.destroy();
+                }
+            }
+        }
+    }
+
+    protected static class RangeInfo {
+        protected int from, to;
+        protected boolean reverse;
+
+        public RangeInfo(int from, int to, boolean reverse) {
+            this.from = from;
+            this.to = to;
+            this.reverse = reverse;
+        }
+    }
+
+    private static class Dumper implements Runnable {
+        InputStream in;
+
+        public Dumper(InputStream in) {
+            this.in = in;
+        }
+
+        public void run() {
+            InputStreamReader isr = new InputStreamReader(in);
+            BufferedReader br = new BufferedReader(isr);
+            try {
+                while (br.readLine() != null) {
+                }
+            } catch (IOException e) {
+                throw new GroovyRuntimeException("exception while reading process stream", e);
+            }
+        }
+    }
+
+    public static Iterator iterator(Object o) {
+        return DefaultTypeTransformation.asCollection(o).iterator();
+    }
+
+    /**
+     * @return an Iterator for an Enumeration
+     */
+    public static Iterator iterator(final Enumeration enumeration) {
+        return new Iterator() {
+            private Object last;
+
+            public boolean hasNext() {
+                return enumeration.hasMoreElements();
+            }
+
+            public Object next() {
+                last = enumeration.nextElement();
+                return last;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException("Cannot remove() from an Enumeration");
+            }
+        };
+    }
+
+    // TODO move into DOMCategory once we can make use of optional categories transparent
+
+    /**
+     * @return an Iterator for a NodeList
+     */
+    public static Iterator iterator(final NodeList nodeList) {
+        return new Iterator() {
+            private int current /* = 0 */;
+
+            public boolean hasNext() {
+                return current < nodeList.getLength();
+            }
+
+            public Object next() {
+                return nodeList.item(current++);
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException("Cannot remove() from a NodeList iterator");
+            }
+        };
+    }
+
+    /**
+     * @return an Iterator for a Matcher
+     */
+    public static Iterator iterator(final Matcher matcher) {
+        return new Iterator() {
+            private boolean found /* = false */;
+            private boolean done /* = false */;
+
+            public boolean hasNext() {
+                if (done) {
+                    return false;
+                }
+                if (!found) {
+                    found = matcher.find();
+                    if (!found) {
+                        done = true;
+                    }
+                }
+                return found;
+            }
+
+            public Object next() {
+                if (!found) {
+                    if (!hasNext()) {
+                        throw new NoSuchElementException();
+                    }
+                }
+                found = false;
+                return matcher.group();
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    /**
+     * @return an Iterator for a Reader
+     */
+    public static Iterator iterator(Reader value) {
+        final BufferedReader bufferedReader;
+        if (value instanceof BufferedReader)
+            bufferedReader = (BufferedReader) value;
+        else
+            bufferedReader = new BufferedReader(value);
+        return new Iterator() {
+            String nextVal /* = null */;
+            boolean nextMustRead = true;
+            boolean hasNext = true;
+
+            public boolean hasNext() {
+                if (nextMustRead && hasNext) {
+                    try {
+                        nextVal = readNext();
+                        nextMustRead = false;
+                    } catch (IOException e) {
+                        hasNext = false;
+                    }
+                }
+                return hasNext;
+            }
+
+            public Object next() {
+                String retval = null;
+                if (nextMustRead) {
+                    try {
+                        retval = readNext();
+                    } catch (IOException e) {
+                        hasNext = false;
+                    }
+                } else
+                    retval = nextVal;
+                nextMustRead = true;
+                return retval;
+            }
+
+            private String readNext() throws IOException {
+                String nv = bufferedReader.readLine();
+                if (nv == null)
+                    hasNext = false;
+                return nv;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException("Cannot remove() from a Reader Iterator");
+            }
+        };
+    }
+
+    /**
+     * Standard iterator for a input stream which iterates through the stream content in a byte-based fashion.
+     *
+     * @param is
+     * @return
+     */
+    public static Iterator iterator(InputStream is) {
+        return iterator(new DataInputStream(is));
+    }
+
+    /**
+     * Standard iterator for a data input stream which iterates through the stream content in a byte-based fashion.
+     *
+     * @param dis
+     * @return
+     */
+    public static Iterator iterator(final DataInputStream dis) {
+        return new Iterator() {
+            Byte nextVal;
+            boolean nextMustRead = true;
+            boolean hasNext = true;
+
+            public boolean hasNext() {
+                if (nextMustRead && hasNext) {
+                    try {
+                        byte bPrimitive = dis.readByte();
+                        nextVal = new Byte(bPrimitive);
+                        nextMustRead = false;
+                    } catch (IOException e) {
+                        hasNext = false;
+                    }
+                }
+                return hasNext;
+            }
+
+            public Object next() {
+                Byte retval = null;
+                if (nextMustRead) {
+                    try {
+                        byte b = dis.readByte();
+                        retval = new Byte(b);
+                    } catch (IOException e) {
+                        hasNext = false;
+                    }
+                } else
+                    retval = nextVal;
+                nextMustRead = true;
+                return retval;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException("Cannot remove() from an InputStream Iterator");
+            }
+        };
+    }
+
+    /**
+     * Standard iterator for a file which iterates through the file content in a line-based fashion.
+     *
+     * @param f
+     * @return
+     * @throws IOException
+     */
+    public static Iterator iterator(File f) throws IOException {
+        return iterator(newReader(f));
+    }
+
+    public static Iterator iterator(Iterator it) {
+        return it;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java b/groovy-core/src/main/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
new file mode 100644
index 0000000..3312efc
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
@@ -0,0 +1,120 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.Closure;
+
+import java.util.regex.Matcher;
+
+/**
+ * This class defines all the new static groovy methods which appear on normal JDK
+ * classes inside the Groovy environment. Static methods are used with the
+ * first parameter as the destination class.
+ *
+ * @author Guillaume Laforge
+ * @author Dierk Koenig
+ * @version $Revision$
+ */
+public class DefaultGroovyStaticMethods {
+
+    /**
+     * Start a Thread with the given closure as a Runnable instance.
+     *
+     * @param closure the Runnable closure
+     * @return the started thread
+     */
+    public static Thread start(Thread self, Closure closure) {
+        Thread thread = new Thread(closure);
+        thread.start();
+        return thread;
+    }
+
+    /**
+     * Start a daemon Thread with the given closure as a Runnable instance.
+     *
+     * @param closure the Runnable closure
+     * @return the started thread
+     */
+    public static Thread startDaemon(Thread self, Closure closure) {
+        Thread thread = new Thread(closure);
+        thread.setDaemon(true);
+        thread.start();
+        return thread;
+    }
+
+    /**
+     * Get the last hidden matcher that system used to do a match.
+     * 
+     * @param matcher
+     * @return the last regex matcher
+     */
+    public static Matcher getLastMatcher(Matcher matcher) {
+        return RegexSupport.getLastMatcher();
+    }
+
+    /**
+     * Sleep for so many milliseconds, even if interrupted.
+     * @param object receiver
+     * @param milliseconds the number of milliseconds to sleep
+     */
+    public static void sleep(Object object, long milliseconds){
+        sleepImpl(object, milliseconds);
+    }
+
+    protected static void sleepImpl(Object object, long millis) {
+        long start = System.currentTimeMillis();
+        try {
+            Thread.sleep(millis);
+        } catch (InterruptedException e) {
+            long slept = System.currentTimeMillis() - start;
+            long rest  = millis - slept;
+            if (rest > 0) sleepImpl(object, rest);    // recursion to sleep the rest
+        }
+    }
+
+    /**
+     * Sleep for so many milliseconds
+     * @param object receiver
+     * @param milliseconds the number of milliseconds to sleep
+     * @param onInterrupt interrupt handler, InterruptedException is passed to the Closure
+     */
+    public static void sleep(Object object, long milliseconds, Closure onInterrupt){
+        try {
+            Thread.sleep(milliseconds);
+        } catch (InterruptedException e) {
+            onInterrupt.call(e);
+        }
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/DefaultMethodKey.java b/groovy-core/src/main/org/codehaus/groovy/runtime/DefaultMethodKey.java
new file mode 100644
index 0000000..464b7d8
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/DefaultMethodKey.java
@@ -0,0 +1,61 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package org.codehaus.groovy.runtime;
+
+/**
+ * A default implementation of MethodKey
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class DefaultMethodKey extends MethodKey{
+
+    private Class[] parameterTypes;
+
+    public DefaultMethodKey(Class sender, String name, Class[] parameterTypes, boolean isCallToSuper) {
+        super(sender, name,isCallToSuper);
+        this.parameterTypes = parameterTypes;
+    }
+
+    public int getParameterCount() {
+        return parameterTypes.length;
+    }
+
+    public Class getParameterType(int index) {
+        Class c = parameterTypes[index];
+        if (c==null) return Object.class;
+        return c;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/FlushingStreamWriter.java b/groovy-core/src/main/org/codehaus/groovy/runtime/FlushingStreamWriter.java
new file mode 100644
index 0000000..b914143
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/FlushingStreamWriter.java
@@ -0,0 +1,67 @@
+/*
+ * $Id$
+ *
+ * Copyright 2005 (C) Guillaume Laforge. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package org.codehaus.groovy.runtime;
+
+import java.io.OutputStreamWriter;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * Stream writer which flushes after each write operation.
+ *
+ * @author Guillaume Laforge
+ * @cvs.date $Date$
+ */
+public class FlushingStreamWriter extends OutputStreamWriter {
+
+    public FlushingStreamWriter(OutputStream out) {
+        super(out);
+    }
+
+    public void write(char[] cbuf, int off, int len) throws IOException {
+        super.write(cbuf, off, len);
+        flush();
+    }
+
+    public void write(int c) throws IOException {
+        super.write(c);
+        flush();
+    }
+
+    public void write(String str, int off, int len) throws IOException {
+        super.write(str, off, len);
+        flush();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/GroovyCategorySupport.java b/groovy-core/src/main/org/codehaus/groovy/runtime/GroovyCategorySupport.java
new file mode 100644
index 0000000..b144ea8
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/GroovyCategorySupport.java
@@ -0,0 +1,249 @@
+/*
+ * $Id$version Apr 26, 2004 4:22:50 PM $user Exp $
+ * 
+ * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.Closure;
+import groovy.lang.MetaMethod;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.*;
+
+/**
+ * @author sam
+ * @author Paul King
+ */
+public class GroovyCategorySupport {
+    
+    private static long categoriesInUse = 0; 
+
+    /**
+     * This method is used to pull all the new methods out of the local thread context with a particular name.
+     * 
+     * @param categorizedClass a class subject to the category methods in the thread context
+     * @param name the method name of interest
+     * @return the list of methods
+     */
+    public static List getCategoryMethods(Class categorizedClass, String name) {
+        Map properties = getProperties();
+        List methodList = new ArrayList();
+        for (Iterator i = properties.keySet().iterator(); i.hasNext(); ) {
+            Class current = (Class) i.next();
+            if (current.isAssignableFrom(categorizedClass)) {
+                Map metaMethodsMap = (Map) properties.get(current);
+                List newMethodList = (List) metaMethodsMap.get(name);
+                if (newMethodList != null) {
+                    methodList.addAll(newMethodList);
+                }
+            }
+        }
+        if (methodList.size() == 0) return null;
+        return methodList;
+    }
+
+    /**
+     * This method is used to pull all the new methods out of the local thread context.
+     *
+     * @param categorizedClass a class subject to the category methods in the thread context
+     * @return the list of methods
+     */
+    public static List getCategoryMethods(Class categorizedClass) {
+        Map properties = getProperties();
+        List methodList = new ArrayList();
+        for (Iterator i = properties.keySet().iterator(); i.hasNext(); ) {
+            Class current = (Class) i.next();
+            if (current.isAssignableFrom(categorizedClass)) {
+                Map metaMethodsMap = (Map) properties.get(current);
+                Collection collection = metaMethodsMap.values();
+                for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
+                    List newMethodList = (List) iterator.next();
+                    if (newMethodList != null) {
+                        methodList.addAll(newMethodList);
+                    }                    
+                }
+            }
+        }
+        if (methodList.size() == 0) return null;
+        return methodList;
+    }
+
+    private static class CategoryMethod extends NewInstanceMetaMethod implements Comparable {
+        private Class metaClass;
+
+        public CategoryMethod(MetaMethod metaMethod, Class metaClass) {
+            super(metaMethod);
+            this.metaClass = metaClass;
+        }
+
+        public boolean isCacheable() { return false; }
+
+        /**
+         * Sort by most specific to least specific.
+         *
+         * @param o the object to compare against
+         */
+        public int compareTo(Object o) {
+            CategoryMethod thatMethod = (CategoryMethod) o;
+            Class thisClass = metaClass;
+            Class thatClass = thatMethod.metaClass;
+            if (thisClass == thatClass) return 0;
+            Class loop = thisClass;
+            while(loop != Object.class) {
+                loop = thisClass.getSuperclass();
+                if (loop == thatClass) {
+                    return -1;
+                }
+            }
+            loop = thatClass;
+            while (loop != Object.class) {
+                loop = thatClass.getSuperclass();
+                if (loop == thisClass) {
+                    return 1;
+                }
+            }
+            return 0;
+        }
+    }
+
+    /**
+     * Create a scope based on given categoryClass and invoke closure within that scope.
+     *
+     * @param categoryClass the class containing category methods
+	 * @param closure the closure during which to make the category class methods available
+	 */
+	public static void use(Class categoryClass, Closure closure) {
+		newScope();
+		try {
+			use(categoryClass);
+			closure.call();
+		} finally {
+			endScope();
+		}
+	}
+
+    /**
+     * Create a scope based on given categoryClasses and invoke closure within that scope.
+     *
+     * @param categoryClasses the list of classes containing category methods
+     * @param closure the closure during which to make the category class methods available
+     */
+    public static void use(List categoryClasses, Closure closure) {
+        newScope();
+        try {
+            for (Iterator i = categoryClasses.iterator(); i.hasNext(); ) {
+                Class clazz = (Class) i.next();
+                use(clazz);
+            }
+            closure.call();
+        } finally {
+            endScope();
+        }
+    }
+
+    /**
+     * Delegated to from the global use(CategoryClass) method.  It scans the Category class for static methods
+     * that take 1 or more parameters.  The first parameter is the class you are adding the category method to,
+     * additional parameters are those paramteres needed by that method.  A use statement cannot be undone and
+     * is valid only for the current thread.
+     *
+     * @param categoryClass the class containing category methods
+     */
+    private static void use(Class categoryClass) {
+        Map properties = getProperties();
+        Method[] methods = categoryClass.getMethods();
+        for (int i = 0; i < methods.length; i++) {
+            Method method = methods[i];
+            if (Modifier.isStatic(method.getModifiers())) {
+                Class[] paramTypes = method.getParameterTypes();
+                if (paramTypes.length > 0) {
+                    Class metaClass = paramTypes[0];
+                    Map metaMethodsMap = getMetaMethods(properties, metaClass);
+                    List methodList = getMethodList(metaMethodsMap, method.getName());
+                    MetaMethod mmethod = new CategoryMethod(new MetaMethod(method), metaClass);
+                    methodList.add(mmethod);
+                    Collections.sort(methodList);
+                }
+            }
+        }
+    }
+
+    private static ThreadLocal local = new ThreadLocal() {
+        protected Object initialValue() {
+        		List stack = new ArrayList();
+        		stack.add(Collections.EMPTY_MAP);
+        		return stack;
+        	}
+    };
+    
+    private static void newScope() {
+        categoriesInUse++;
+        List stack = (List) local.get();
+    	Map properties = new WeakHashMap(getProperties());
+    	stack.add(properties);
+    }
+    
+    private static void endScope() {
+        List stack = (List) local.get();
+    	stack.remove(stack.size() - 1);
+        categoriesInUse--;
+    }
+    
+    private static Map getProperties() {
+        List stack = (List) local.get();
+        return (Map) stack.get(stack.size() - 1);
+    }
+    
+    public static boolean hasCategoryInAnyThread() {
+        return categoriesInUse!=0;
+    }
+    
+    private static List getMethodList(Map metaMethodsMap, String name) {
+        List methodList = (List) metaMethodsMap.get(name);
+        if (methodList == null) {
+            methodList = new ArrayList(1);
+            metaMethodsMap.put(name, methodList);
+        }
+        return methodList;
+    }
+
+    private static Map getMetaMethods(Map properties, Class metaClass) {
+        Map metaMethodsMap = (Map) properties.get(metaClass);
+        if (metaMethodsMap == null) {
+            metaMethodsMap = new HashMap();
+            properties.put(metaClass, metaMethodsMap);
+        }
+        return metaMethodsMap;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/Invoker.java b/groovy-core/src/main/org/codehaus/groovy/runtime/Invoker.java
new file mode 100644
index 0000000..bd3f4db
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/Invoker.java
@@ -0,0 +1,293 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyInterceptable;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.MetaClass;
+import groovy.lang.MetaClassRegistry;
+import groovy.lang.MissingMethodException;
+
+import java.util.Map;
+
+/**
+ * A helper class to invoke methods or extract properties on arbitrary Java objects dynamically
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class Invoker {
+
+    protected static final Object[] EMPTY_ARGUMENTS = {
+    };
+    protected static final Class[] EMPTY_TYPES = {
+    };
+
+    public MetaClassRegistry getMetaRegistry() {
+        return metaRegistry;
+    }
+
+    private MetaClassRegistry metaRegistry = new MetaClassRegistry();
+
+    public MetaClass getMetaClass(Object object) {
+        return metaRegistry.getMetaClass(object.getClass());
+    }
+
+    /**
+     * Invokes the given method on the object.
+     *
+     * @param object
+     * @param methodName
+     * @param arguments
+     * @return
+     */
+    public Object invokeMethod(Object object, String methodName, Object arguments) {
+        /*
+        System
+            .out
+            .println(
+                "Invoker - Invoking method on object: "
+                    + object
+                    + " method: "
+                    + methodName
+                    + " arguments: "
+                    + InvokerHelper.toString(arguments));
+                    */
+
+        if (object == null) {
+            object = NullObject.getNullObject();
+            //throw new NullPointerException("Cannot invoke method " + methodName + "() on null object");
+        }
+        
+        // if the object is a Class, call a static method from that class
+        if (object instanceof Class) {
+            Class theClass = (Class) object;
+            MetaClass metaClass = metaRegistry.getMetaClass(theClass);
+            return metaClass.invokeStaticMethod(object, methodName, asArray(arguments));
+        }
+        else // it's an instance
+        {
+            // if it's not an object implementing GroovyObject (thus not builder, nor a closure)
+            if (!(object instanceof GroovyObject)) {
+                Class theClass = object.getClass();
+                MetaClass metaClass = metaRegistry.getMetaClass(theClass);
+                return metaClass.invokeMethod(object, methodName, asArray(arguments));
+            }
+            // it's an object implementing GroovyObject
+            else {
+                GroovyObject groovy = (GroovyObject) object;
+                try {
+                    // if it's a pure interceptable object (even intercepting toString(), clone(), ...)
+                    if (groovy instanceof GroovyInterceptable) {
+                        return groovy.invokeMethod(methodName, asArray(arguments));
+                    }
+                    //else if there's a statically typed method or a GDK method
+                    else {
+                        return groovy.getMetaClass().invokeMethod(object, methodName, asArray(arguments));
+                    }
+                } catch (MissingMethodException e) {
+                    if (e.getMethod().equals(methodName) && object.getClass() == e.getType()) {
+                        // in case there's nothing else, invoke the object's own invokeMethod()
+                        return groovy.invokeMethod(methodName, asArray(arguments));
+                    } else {
+                        throw e;
+                    }
+                }
+            }
+        }
+    }
+
+    public Object invokeSuperMethod(Object object, String methodName, Object arguments) {
+        if (object == null) {
+            throw new NullPointerException("Cannot invoke method " + methodName + "() on null object");
+        }
+
+        Class theClass = object.getClass();
+
+        MetaClass metaClass = metaRegistry.getMetaClass(theClass.getSuperclass());
+        return metaClass.invokeMethod(object, methodName, asArray(arguments));
+    }
+
+    public Object invokeStaticMethod(Class type, String method, Object arguments) {
+        MetaClass metaClass = metaRegistry.getMetaClass(type);
+        return metaClass.invokeStaticMethod(type, method, asArray(arguments));
+    }
+
+    public Object invokeConstructorOf(Class type, Object arguments) {
+        MetaClass metaClass = metaRegistry.getMetaClass(type);
+        return metaClass.invokeConstructor(asArray(arguments));
+    }
+
+    /**
+     * Converts the given object into an array; if its an array then just
+     * cast otherwise wrap it in an array
+     */
+    public Object[] asArray(Object arguments) {
+        if (arguments == null) {
+            return EMPTY_ARGUMENTS;
+        } else if (arguments instanceof Object[]) {
+            return (Object[]) arguments;
+        } else {
+            return new Object[]{arguments};
+        }
+    }
+
+    /**
+     * Looks up the given property of the given object
+     */
+    public Object getProperty(Object object, String property) {
+        if (object == null) {
+            throw new NullPointerException("Cannot get property: " + property + " on null object");
+        }
+        else if (object instanceof GroovyObject) {
+            GroovyObject pogo = (GroovyObject) object;
+            return pogo.getProperty(property);
+        }
+        else if (object instanceof Map) {
+            Map map = (Map) object;
+            return map.get(property);
+        }
+        else if (object instanceof Class) {
+            Class c = (Class) object;
+            return metaRegistry.getMetaClass(c).getProperty(object, property);
+        }
+        else {
+            return metaRegistry.getMetaClass(object.getClass()).getProperty(object, property);
+        }
+    }
+    
+    /**
+     * Sets the property on the given object
+     */
+    public void setProperty(Object object, String property, Object newValue) {
+        if (object == null) {
+            throw new GroovyRuntimeException("Cannot set property on null object");
+        }
+        else if (object instanceof GroovyObject) {
+            GroovyObject pogo = (GroovyObject) object;
+            pogo.setProperty(property, newValue);
+        }
+        else if (object instanceof Map) {
+            Map map = (Map) object;
+            map.put(property, newValue);
+        }
+        else {
+            if (object instanceof Class)
+                metaRegistry.getMetaClass((Class) object).setProperty((Class) object, property, newValue);
+            else
+                metaRegistry.getMetaClass(object.getClass()).setProperty(object, property, newValue);
+        }
+    }
+
+    /**
+     * Looks up the given attribute (field) on the given object
+     */
+    public Object getAttribute(Object object, String attribute) {
+        if (object == null) {
+            throw new NullPointerException("Cannot get attribute: " + attribute + " on null object");
+
+            /**
+             } else if (object instanceof GroovyObject) {
+             GroovyObject pogo = (GroovyObject) object;
+             return pogo.getAttribute(attribute);
+             } else if (object instanceof Map) {
+             Map map = (Map) object;
+             return map.get(attribute);
+             */
+        }
+        else {
+            if (object instanceof Class) {
+                return metaRegistry.getMetaClass((Class) object).getAttribute(object, attribute);
+            } else if (object instanceof GroovyObject) {
+                return ((GroovyObject)object).getMetaClass().getAttribute(object, attribute);
+            } else {
+                return metaRegistry.getMetaClass(object.getClass()).getAttribute(object, attribute);
+            }
+	}
+    }
+
+    /**
+     * Sets the given attribute (field) on the given object
+     */
+    public void setAttribute(Object object, String attribute, Object newValue) {
+        if (object == null) {
+            throw new GroovyRuntimeException("Cannot set attribute on null object");
+            /*
+        } else if (object instanceof GroovyObject) {
+            GroovyObject pogo = (GroovyObject) object;
+            pogo.setProperty(attribute, newValue);
+        } else if (object instanceof Map) {
+            Map map = (Map) object;
+            map.put(attribute, newValue);
+            */
+        }
+        else {
+            if (object instanceof Class) {
+                metaRegistry.getMetaClass((Class) object).setAttribute(object, attribute, newValue);
+            } else if (object instanceof GroovyObject) {
+                ((GroovyObject)object).getMetaClass().setAttribute(object, attribute, newValue);
+            } else {
+                metaRegistry.getMetaClass(object.getClass()).setAttribute(object, attribute, newValue);
+            }
+	}
+    }
+
+    /**
+     * Returns the method pointer for the given object name
+     */
+    public Closure getMethodPointer(Object object, String methodName) {
+        if (object == null) {
+            throw new NullPointerException("Cannot access method pointer for '" + methodName + "' on null object");
+        }
+        return MetaClassHelper.getMethodPointer(object, methodName);
+    }
+
+    public void removeMetaClass(Class clazz) {
+        getMetaRegistry().removeMetaClass(clazz);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/InvokerHelper.java b/groovy-core/src/main/org/codehaus/groovy/runtime/InvokerHelper.java
new file mode 100644
index 0000000..4aa4d33
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/InvokerHelper.java
@@ -0,0 +1,759 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.*;
+
+import java.beans.Introspector;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.xml.serialize.OutputFormat;
+import org.apache.xml.serialize.XMLSerializer;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.codehaus.groovy.runtime.typehandling.IntegerCache;
+import org.w3c.dom.Element;
+
+/**
+ * A static helper class to make bytecode generation easier and act as a facade over the Invoker
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class InvokerHelper {
+    public static final Object[] EMPTY_ARGS = {
+    };
+
+    private static final Object[] EMPTY_MAIN_ARGS = new Object[]{new String[0]};
+
+    private static final Invoker singleton = new Invoker();
+
+
+
+    public static MetaClass getMetaClass(Object object) {
+        return getInstance().getMetaClass(object);
+    }
+
+    public static void removeClass(Class clazz) {
+        getInstance().removeMetaClass(clazz);
+        Introspector.flushFromCaches(clazz);
+    }
+
+    public static Invoker getInstance() {
+        return singleton;
+    }
+
+    public static Object invokeNoArgumentsMethod(Object object, String methodName) {
+        return getInstance().invokeMethod(object, methodName, EMPTY_ARGS);
+    }
+
+    public static Object invokeMethod(Object object, String methodName, Object arguments) {
+        return getInstance().invokeMethod(object, methodName, arguments);
+    }
+
+    public static Object invokeSuperMethod(Object object, String methodName, Object arguments) {
+        return getInstance().invokeSuperMethod(object, methodName, arguments);
+    }
+
+    public static Object invokeMethodSafe(Object object, String methodName, Object arguments) {
+        if (object != null) {
+            return getInstance().invokeMethod(object, methodName, arguments);
+        }
+        return null;
+    }
+
+    public static Object invokeStaticMethod(Class type, String methodName, Object arguments) {
+        return getInstance().invokeStaticMethod(type, methodName, arguments);
+    }
+    
+    public static Object invokeStaticMethod(String klass, String methodName, Object arguments) throws ClassNotFoundException {
+        Class type = InvokerHelper.class.forName(klass);
+        return getInstance().invokeStaticMethod(type, methodName, arguments);
+    }
+    
+
+    public static Object invokeStaticNoArgumentsMethod(Class type, String methodName) {
+        return getInstance().invokeStaticMethod(type, methodName, EMPTY_ARGS);
+    }
+    
+    public static Object invokeConstructorOf(Class type, Object arguments) {
+        return getInstance().invokeConstructorOf(type, arguments);
+    }
+    
+    public static Object invokeConstructorOf(String klass, Object arguments) throws ClassNotFoundException {
+        Class type = InvokerHelper.class.forName(klass);
+        return getInstance().invokeConstructorOf(type, arguments);
+    }
+
+    public static Object invokeNoArgumentsConstructorOf(Class type) {
+        return getInstance().invokeConstructorOf(type, EMPTY_ARGS);
+    }
+
+    public static Object invokeClosure(Object closure, Object arguments) {
+        return getInstance().invokeMethod(closure, "doCall", arguments);
+    }
+
+    public static List asList(Object value) {
+        if (value == null) {
+            return Collections.EMPTY_LIST;
+        }
+        else if (value instanceof List) {
+            return (List) value;
+        }
+        else if (value.getClass().isArray()) {
+            return Arrays.asList((Object[]) value);
+        }
+        else if (value instanceof Enumeration) {
+            List answer = new ArrayList();
+            for (Enumeration e = (Enumeration) value; e.hasMoreElements();) {
+                answer.add(e.nextElement());
+            }
+            return answer;
+        }
+        else {
+            // lets assume its a collection of 1
+            return Collections.singletonList(value);
+        }
+    }
+
+    public static String toString(Object arguments) {
+        if (arguments instanceof Object[])
+            return toArrayString((Object[])arguments);
+        else if (arguments instanceof Collection)
+            return toListString((Collection)arguments);
+        else if (arguments instanceof Map)
+            return toMapString((Map)arguments);
+        else if (arguments instanceof Collection)
+            return format(arguments, true);
+        else
+            return format(arguments, false);
+    }
+
+    public static String inspect(Object self) {
+        return format(self, true);
+    }
+
+    public static Object getAttribute(Object object, String attribute) {
+        return getInstance().getAttribute(object, attribute);
+    }
+
+    public static void setAttribute(Object object, String attribute, Object newValue) {
+        getInstance().setAttribute(object, attribute, newValue);
+    }
+
+    public static Object getProperty(Object object, String property) {
+        return getInstance().getProperty(object, property);
+    }
+
+    public static Object getPropertySafe(Object object, String property) {
+        if (object != null) {
+            return getInstance().getProperty(object, property);
+        }
+        return null;
+    }
+
+    public static void setProperty(Object object, String property, Object newValue) {
+        getInstance().setProperty(object, property, newValue);
+    }
+
+    /**
+     * This is so we don't have to reorder the stack when we call this method.
+     * At some point a better name might be in order.
+     */
+    public static void setProperty2(Object newValue, Object object, String property) {
+        getInstance().setProperty(object, property, newValue);
+    }
+
+
+    /**
+     * This is so we don't have to reorder the stack when we call this method.
+     * At some point a better name might be in order.
+     */
+    public static void setGroovyObjectProperty(Object newValue, GroovyObject object, String property) {
+        object.setProperty(property, newValue);
+    }
+
+    public static Object getGroovyObjectProperty(GroovyObject object, String property) {
+        return object.getProperty(property);
+    }
+
+
+    /**
+     * This is so we don't have to reorder the stack when we call this method.
+     * At some point a better name might be in order.
+     */
+    public static void setPropertySafe2(Object newValue, Object object, String property) {
+        if (object != null) {
+            setProperty2(newValue, object, property);
+        }
+    }
+
+    /**
+     * Returns the method pointer for the given object name
+     */
+    public static Closure getMethodPointer(Object object, String methodName) {
+        return getInstance().getMethodPointer(object, methodName);
+    }
+
+    public static Object negate(Object value) {
+        if (value instanceof Integer) {
+            Integer number = (Integer) value;
+            return IntegerCache.integerValue(-number.intValue());
+        }
+        else if (value instanceof Long) {
+            Long number = (Long) value;
+            return new Long(-number.longValue());
+        }
+        else if (value instanceof BigInteger) {
+            return ((BigInteger) value).negate();
+        }
+        else if (value instanceof BigDecimal) {
+            return ((BigDecimal) value).negate();
+        }
+        else if (value instanceof Double) {
+            Double number = (Double) value;
+            return new Double(-number.doubleValue());
+        }
+        else if (value instanceof Float) {
+            Float number = (Float) value;
+            return new Float(-number.floatValue());
+        }
+        else if (value instanceof ArrayList) {
+            // value is an list.
+            ArrayList newlist = new ArrayList();
+            Iterator it = ((ArrayList) value).iterator();
+            for (; it.hasNext();) {
+                newlist.add(negate(it.next()));
+            }
+            return newlist;
+        }
+        else {
+            throw new GroovyRuntimeException("Cannot negate type " + value.getClass().getName() + ", value " + value);
+        }
+    }
+
+    /**
+     * Find the right hand regex within the left hand string and return a matcher.
+     *
+     * @param left  string to compare
+     * @param right regular expression to compare the string to
+     * @return
+     */
+    public static Matcher findRegex(Object left, Object right) {
+        String stringToCompare;
+        if (left instanceof String) {
+            stringToCompare = (String) left;
+        }
+        else {
+            stringToCompare = toString(left);
+        }
+        String regexToCompareTo;
+        if (right instanceof String) {
+            regexToCompareTo = (String) right;
+        }
+        else if (right instanceof Pattern) {
+            Pattern pattern = (Pattern) right;
+            return pattern.matcher(stringToCompare);
+        }
+        else {
+            regexToCompareTo = toString(right);
+        }
+        Matcher matcher = Pattern.compile(regexToCompareTo).matcher(stringToCompare);
+        return matcher;
+    }
+    
+    
+    /**
+     * Find the right hand regex within the left hand string and return a matcher.
+     *
+     * @param left  string to compare
+     * @param right regular expression to compare the string to
+     * @return
+     */
+    public static boolean matchRegex(Object left, Object right) {
+        Pattern pattern;
+        if (right instanceof Pattern) {
+            pattern = (Pattern) right;
+        }
+        else {
+            pattern = Pattern.compile(toString(right));
+        }
+        String stringToCompare = toString(left);
+        Matcher matcher = pattern.matcher(stringToCompare);
+        RegexSupport.setLastMatcher(matcher);
+        return matcher.matches();
+    }
+
+    public static Tuple createTuple(Object[] array) {
+        return new Tuple(array);
+    }
+
+    public static SpreadMap spreadMap(Object value) {
+        if (value instanceof Map) {
+            Object[] values = new Object[((Map) value).keySet().size() * 2];
+            int index = 0;
+            Iterator it = ((Map) value).keySet().iterator();
+            for (; it.hasNext();) {
+                Object key = it.next();
+                values[index++] = key;
+                values[index++] = ((Map) value).get(key);
+            }
+            return new SpreadMap(values);
+        }
+        else {
+            throw new SpreadMapEvaluatingException("Cannot spread the map " + value.getClass().getName() + ", value " + value);
+        }
+    }
+
+    public static List createList(Object[] values) {
+        ArrayList answer = new ArrayList(values.length);
+        for (int i = 0; i < values.length; i++) {
+            answer.add(values[i]);
+        }
+        return answer;
+    }
+
+    public static Map createMap(Object[] values) {
+        Map answer = new HashMap(values.length / 2);
+        int i = 0;
+        while (i < values.length - 1) {
+            if ((values[i] instanceof SpreadMap) && (values[i+1] instanceof Map)) {
+                Map smap = (Map) values[i+1];
+                Iterator iter = smap.keySet().iterator();
+                for (; iter.hasNext(); ) {
+                    Object key = (Object) iter.next();
+                    answer.put(key, smap.get(key));
+                }
+                i+=2;
+            }
+            else {
+                answer.put(values[i++], values[i++]);
+            }
+        }
+        return answer;
+    }
+
+    public static void assertFailed(Object expression, Object message) {
+        if (message == null || "".equals(message)) {
+            throw new AssertionError("Expression: " + expression);
+        }
+        else {
+            throw new AssertionError("" + message + ". Expression: " + expression);
+        }
+    }
+
+    public static Object runScript(Class scriptClass, String[] args) {
+        Binding context = new Binding(args);
+        Script script = createScript(scriptClass, context);
+        return invokeMethod(script, "run", EMPTY_ARGS);
+    }
+
+    public static Script createScript(Class scriptClass, Binding context) {
+        // for empty scripts
+        if (scriptClass == null) {
+            return new Script() {
+                public Object run() {
+                    return null;
+                }
+            };
+        }
+        try {
+            final GroovyObject object = (GroovyObject) scriptClass.newInstance();
+            Script script = null;
+            if (object instanceof Script) {
+                script = (Script) object;
+            }
+            else {
+                // it could just be a class, so lets wrap it in a Script wrapper
+                // though the bindings will be ignored
+                script = new Script() {
+                    public Object run() {
+                        object.invokeMethod("main", EMPTY_MAIN_ARGS);
+                        return null;
+                    }
+                };
+                setProperties(object, context.getVariables());
+            }
+            script.setBinding(context);
+            return script;
+        }
+        catch (Exception e) {
+            throw new GroovyRuntimeException("Failed to create Script instance for class: " + scriptClass + ". Reason: " + e,
+                    e);
+        }
+    }
+
+    /**
+     * Sets the properties on the given object
+     *
+     * @param object
+     * @param map
+     */
+    public static void setProperties(Object object, Map map) {
+        MetaClass mc = getInstance().getMetaClass(object);
+        for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            String key = entry.getKey().toString();
+
+            Object value = entry.getValue();
+            try {
+                mc.setProperty(object, key, value);
+            } catch (MissingPropertyException mpe) {}
+        }
+    }
+
+    public static String getVersion() {
+        String version = null;
+        Package p = Package.getPackage("groovy.lang");
+        if (p != null) {
+            version = p.getImplementationVersion();
+        }
+        if (version == null) {
+            version = "";
+        }
+        return version;
+    }
+
+    /**
+     * Writes the given object to the given stream
+     */
+    public static void write(Writer out, Object object) throws IOException {
+        if (object instanceof String) {
+            out.write((String) object);
+        }
+        else if (object instanceof Object[]) {
+            out.write(toArrayString((Object[]) object));
+        }
+        else if (object instanceof Map) {
+            out.write(toMapString((Map) object));
+        }
+        else if (object instanceof Collection) {
+            out.write(toListString((Collection) object));
+        }
+        else if (object instanceof Writable) {
+            Writable writable = (Writable) object;
+            writable.writeTo(out);
+        }
+        else if (object instanceof InputStream || object instanceof Reader) {
+            // Copy stream to stream
+            Reader reader;
+            if (object instanceof InputStream) {
+                reader = new InputStreamReader((InputStream) object);
+            }
+            else {
+                reader = (Reader) object;
+            }
+            char[] chars = new char[8192];
+            int i;
+            while ((i = reader.read(chars)) != -1) {
+                out.write(chars, 0, i);
+            }
+            reader.close();
+        }
+        else {
+            out.write(toString(object));
+        }
+    }
+    
+    public static Iterator asIterator(Object o) {
+        return (Iterator) invokeMethod(o,"iterator",EMPTY_ARGS);
+    }
+    
+    protected static String format(Object arguments, boolean verbose) {
+        if (arguments == null) {
+            return "null";
+        }
+        else if (arguments.getClass().isArray()) {
+            return format(DefaultTypeTransformation.asCollection(arguments), verbose);
+        }
+        else if (arguments instanceof Range) {
+            Range range = (Range) arguments;
+            if (verbose) {
+                return range.inspect();
+            }
+            else {
+                return range.toString();
+            }
+        }
+        else if (arguments instanceof List) {
+            List list = (List) arguments;
+            StringBuffer buffer = new StringBuffer("[");
+            boolean first = true;
+            for (Iterator iter = list.iterator(); iter.hasNext();) {
+                if (first) {
+                    first = false;
+                }
+                else {
+                    buffer.append(", ");
+                }
+                buffer.append(format(iter.next(), verbose));
+            }
+            buffer.append("]");
+            return buffer.toString();
+        }
+        else if (arguments instanceof Map) {
+            Map map = (Map) arguments;
+            if (map.isEmpty()) {
+                return "[:]";
+            }
+            StringBuffer buffer = new StringBuffer("[");
+            boolean first = true;
+            for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
+                if (first) {
+                    first = false;
+                }
+                else {
+                    buffer.append(", ");
+                }
+                Map.Entry entry = (Map.Entry) iter.next();
+                buffer.append(format(entry.getKey(), verbose));
+                buffer.append(":");
+                if (entry.getValue()==map) {
+                    buffer.append("this Map_");
+                } else {
+                    buffer.append(format(entry.getValue(), verbose));
+                }
+            }
+            buffer.append("]");
+            return buffer.toString();
+        }
+        else if (arguments instanceof Element) {
+            Element node = (Element) arguments;
+            OutputFormat format = new OutputFormat(node.getOwnerDocument());
+            format.setOmitXMLDeclaration(true);
+            format.setIndenting(true);
+            format.setLineWidth(0);
+            format.setPreserveSpace(true);
+            StringWriter sw = new StringWriter();
+            XMLSerializer serializer = new XMLSerializer(sw, format);
+            try {
+                serializer.asDOMSerializer();
+                serializer.serialize(node);
+            }
+            catch (IOException e) {
+            }
+            return sw.toString();
+        }
+        else if (arguments instanceof String) {
+            if (verbose) {
+                String arg = ((String)arguments).replaceAll("\\n", "\\\\n");    // line feed
+                arg = arg.replaceAll("\\r", "\\\\r");      // carriage return
+                arg = arg.replaceAll("\\t", "\\\\t");      // tab
+                arg = arg.replaceAll("\\f", "\\\\f");      // form feed
+                arg = arg.replaceAll("\\\"", "\\\\\"");    // double quotation amrk
+                arg = arg.replaceAll("\\\\", "\\\\");      // back slash
+                return "\"" + arg + "\"";
+            }
+            else {
+                return (String) arguments;
+            }
+        }
+        else {
+            return arguments.toString();
+        }
+    }
+    
+
+    /**
+     * A helper method to format the arguments types as a comma-separated list
+     */
+    public static String toTypeString(Object[] arguments) {
+        if (arguments == null) {
+            return "null";
+        }
+        StringBuffer argBuf = new StringBuffer();
+        for (int i = 0; i < arguments.length; i++) {
+            if (i > 0) {
+                argBuf.append(", ");
+            }
+            argBuf.append(arguments[i] != null ? arguments[i].getClass().getName() : "null");
+        }
+        return argBuf.toString();
+    }
+
+    /**
+     * A helper method to return the string representation of a map with bracket boundaries "[" and "]".
+     */
+    public static String toMapString(Map arg) {
+        return format(arg, true);
+        /*if (arg == null) {
+            return "null";
+        }
+        if (arg.isEmpty()) {
+            return "[:]";
+        }
+        String sbdry = "[";
+        String ebdry = "]";
+        StringBuffer buffer = new StringBuffer(sbdry);
+        boolean first = true;
+        for (Iterator iter = arg.entrySet().iterator(); iter.hasNext();) {
+            if (first)
+                first = false;
+            else
+                buffer.append(", ");
+            Map.Entry entry = (Map.Entry) iter.next();
+            buffer.append(format(entry.getKey(), true));
+            buffer.append(":");
+            buffer.append(format(entry.getValue(), true));
+        }
+        buffer.append(ebdry);
+        return buffer.toString();*/
+    }
+
+    /**
+     * A helper method to return the string representation of a list with bracket boundaries "[" and "]".
+     */
+    public static String toListString(Collection arg) {
+        if (arg == null) {
+            return "null";
+        }
+        if (arg.isEmpty()) {
+            return "[]";
+        }
+        String sbdry = "[";
+        String ebdry = "]";
+        StringBuffer buffer = new StringBuffer(sbdry);
+        boolean first = true;
+        for (Iterator iter = arg.iterator(); iter.hasNext();) {
+            if (first)
+                first = false;
+            else
+                buffer.append(", ");
+            Object elem = iter.next();
+            buffer.append(format(elem, true));
+        }
+        buffer.append(ebdry);
+        return buffer.toString();
+    }
+
+    /**
+     * A helper method to return the string representation of an arrray of objects
+     * with brace boundaries "{" and "}".
+     */
+    public static String toArrayString(Object[] arguments) {
+        if (arguments == null) {
+            return "null";
+        }
+        String sbdry = "{";
+        String ebdry = "}";
+        StringBuffer argBuf = new StringBuffer(sbdry);
+        for (int i = 0; i < arguments.length; i++) {
+            if (i > 0) {
+                argBuf.append(", ");
+            }
+            argBuf.append(format(arguments[i], true));
+        }
+        argBuf.append(ebdry);
+        return argBuf.toString();
+    }
+    
+    public static List createRange(Object from, Object to, boolean inclusive) {
+        try {
+            return ScriptBytecodeAdapter.createRange(from,to,inclusive);
+        } catch (RuntimeException re) {
+            throw re;
+        } catch (Error e) {
+            throw e;
+        } catch (Throwable t) {
+            throw new RuntimeException(t);
+        }
+    }
+    
+    public static Object bitNegate(Object value) {
+        if (value instanceof Integer) {
+            Integer number = (Integer) value;
+            return new Integer(~number.intValue());
+        }
+        else if (value instanceof Long) {
+            Long number = (Long) value;
+            return new Long(~number.longValue());
+        }
+        else if (value instanceof BigInteger) {
+            return ((BigInteger) value).not();
+
+        }
+        else if (value instanceof String) {
+            // value is a regular expression.
+            return DefaultGroovyMethods.negate(value.toString());
+        }
+        else if (value instanceof GString) {
+            // value is a regular expression.
+            return DefaultGroovyMethods.negate(value.toString());
+        }
+        else if (value instanceof ArrayList) {
+            // value is an list.
+            ArrayList newlist = new ArrayList();
+            Iterator it = ((ArrayList) value).iterator();
+            for (; it.hasNext();) {
+                newlist.add(bitNegate(it.next()));
+            }
+            return newlist;
+        }
+        else {
+            throw new BitwiseNegateEvaluatingException("Cannot bitwise negate type " + value.getClass().getName() + ", value " + value);
+        }
+
+
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/InvokerInvocationException.java b/groovy-core/src/main/org/codehaus/groovy/runtime/InvokerInvocationException.java
new file mode 100644
index 0000000..518e5b9
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/InvokerInvocationException.java
@@ -0,0 +1,68 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.*;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * An exception thrown if a method is called and an exception occurred
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class InvokerInvocationException extends GroovyRuntimeException {
+
+    public InvokerInvocationException(InvocationTargetException e) {
+        super(e.getTargetException().toString(), e.getTargetException());
+    }
+
+    public InvokerInvocationException(Throwable cause) {
+        super((cause==null)?"java.lang.NullPointerException":cause.getMessage(),cause);
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/IteratorClosureAdapter.java b/groovy-core/src/main/org/codehaus/groovy/runtime/IteratorClosureAdapter.java
new file mode 100644
index 0000000..eded14e
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/IteratorClosureAdapter.java
@@ -0,0 +1,41 @@
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.Closure;
+import groovy.lang.MetaClass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A closure which stores calls in a List so that method calls 
+ * can be iterated over in a 'yield' style way
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class IteratorClosureAdapter extends Closure {
+
+    private List list = new ArrayList();
+    private MetaClass metaClass = InvokerHelper.getMetaClass(this);
+    
+    public IteratorClosureAdapter(Object delegate) {
+        super(delegate);
+    }
+
+    public MetaClass getMetaClass() {
+        return metaClass;
+    }
+
+    public void setMetaClass(MetaClass metaClass) {
+        this.metaClass = metaClass;
+    }
+    
+    public List asList() {
+        return list;
+    }
+
+    protected Object doCall(Object argument) {
+        list.add(argument);
+        return null;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/MetaClassHelper.java b/groovy-core/src/main/org/codehaus/groovy/runtime/MetaClassHelper.java
new file mode 100644
index 0000000..cbd360d
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/MetaClassHelper.java
@@ -0,0 +1,984 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.runtime;
+
+import groovy.lang.Closure;
+import groovy.lang.GString;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.MetaMethod;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Iterator;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.codehaus.groovy.runtime.wrappers.Wrapper;
+
+/**
+ * @author John Wilson
+ * @author Jochen Theodorou
+ */
+public class MetaClassHelper {
+
+    public static final Object[] EMPTY_ARRAY = {};
+    public static Class[] EMPTY_TYPE_ARRAY = {};
+    protected static final Object[] ARRAY_WITH_NULL = { null };
+    protected static final Logger log = Logger.getLogger(MetaClassHelper.class.getName());
+    private static final int MAX_ARG_LEN = 12;
+    
+    public static boolean accessibleToConstructor(final Class at, final Constructor constructor) {
+        boolean accessible = false;
+        if (Modifier.isPublic(constructor.getModifiers())) {
+            accessible = true;
+        }
+        else if (Modifier.isPrivate(constructor.getModifiers())) {
+            accessible = at.getName().equals(constructor.getName());
+        }
+        else if ( Modifier.isProtected(constructor.getModifiers()) ) {
+            if ( at.getPackage() == null && constructor.getDeclaringClass().getPackage() == null ) {
+                accessible = true;
+            }
+            else if ( at.getPackage() == null && constructor.getDeclaringClass().getPackage() != null ) {
+                accessible = false;
+            }
+            else if ( at.getPackage() != null && constructor.getDeclaringClass().getPackage() == null ) {
+                accessible = false;
+            }
+            else if ( at.getPackage().equals(constructor.getDeclaringClass().getPackage()) ) {
+                accessible = true;
+            }
+            else {
+                boolean flag = false;
+                Class clazz = at;
+                while ( !flag && clazz != null ) {
+                    if (clazz.equals(constructor.getDeclaringClass()) ) {
+                        flag = true;
+                        break;
+                    }
+                    if (clazz.equals(Object.class) ) {
+                        break;
+                    }
+                    clazz = clazz.getSuperclass();
+                }
+                accessible = flag;
+            }
+        }
+        else {
+            if ( at.getPackage() == null && constructor.getDeclaringClass().getPackage() == null ) {
+                accessible = true;
+            }
+            else if ( at.getPackage() == null && constructor.getDeclaringClass().getPackage() != null ) {
+                accessible = false;
+            }
+            else if ( at.getPackage() != null && constructor.getDeclaringClass().getPackage() == null ) {
+                accessible = false;
+            }
+            else if ( at.getPackage().equals(constructor.getDeclaringClass().getPackage()) ) {
+                accessible = true;
+            }
+        }
+        return accessible;
+    }
+    
+    public static Object[] asWrapperArray(Object parameters, Class componentType) {
+        Object[] ret=null;
+        if (componentType == boolean.class) {
+            boolean[] array = (boolean[]) parameters;
+            ret = new Object[array.length];
+            for (int i=0; i<array.length; i++) {
+                ret[i] = new Boolean(array[i]);
+            }
+        } else if (componentType == char.class) {
+            char[] array = (char[]) parameters;
+            ret = new Object[array.length];
+            for (int i=0; i<array.length; i++) {
+                ret[i] = new Character(array[i]);
+            }
+        } else if (componentType == byte.class) {
+            byte[] array = (byte[]) parameters;
+            ret = new Object[array.length];
+            for (int i=0; i<array.length; i++) {
+                ret[i] = new Byte(array[i]);
+            }
+        } else if (componentType == int.class) {
+            int[] array = (int[]) parameters;
+            ret = new Object[array.length];
+            for (int i=0; i<array.length; i++) {
+                ret[i] = new Integer(array[i]);
+            }
+        } else if (componentType == short.class) {
+            short[] array = (short[]) parameters;
+            ret = new Object[array.length];
+            for (int i=0; i<array.length; i++) {
+                ret[i] = new Short(array[i]);
+            }
+        } else if (componentType == long.class) {
+            long[] array = (long[]) parameters;
+            ret = new Object[array.length];
+            for (int i=0; i<array.length; i++) {
+                ret[i] = new Long(array[i]);
+            }
+        } else if (componentType == double.class) {
+            double[] array = (double[]) parameters;
+            ret = new Object[array.length];
+            for (int i=0; i<array.length; i++) {
+                ret[i] = new Double(array[i]);
+            }
+        } else if (componentType == float.class) {
+            float[] array = (float[]) parameters;
+            ret = new Object[array.length];
+            for (int i=0; i<array.length; i++) {
+                ret[i] = new Float(array[i]);
+            }
+        }
+        
+        return ret;
+    }
+    
+    
+    /**
+     * @param list
+     * @param parameterType
+     */
+    public static Object asPrimitiveArray(List list, Class parameterType) {
+        Class arrayType = parameterType.getComponentType();
+        Object objArray = Array.newInstance(arrayType, list.size());
+        for (int i = 0; i < list.size(); i++) {
+            Object obj = list.get(i);
+            if (arrayType.isPrimitive()) {
+                if (obj instanceof Integer) {
+                    Array.setInt(objArray, i, ((Integer) obj).intValue());
+                }
+                else if (obj instanceof Double) {
+                    Array.setDouble(objArray, i, ((Double) obj).doubleValue());
+                }
+                else if (obj instanceof Boolean) {
+                    Array.setBoolean(objArray, i, ((Boolean) obj).booleanValue());
+                }
+                else if (obj instanceof Long) {
+                    Array.setLong(objArray, i, ((Long) obj).longValue());
+                }
+                else if (obj instanceof Float) {
+                    Array.setFloat(objArray, i, ((Float) obj).floatValue());
+                }
+                else if (obj instanceof Character) {
+                    Array.setChar(objArray, i, ((Character) obj).charValue());
+                }
+                else if (obj instanceof Byte) {
+                    Array.setByte(objArray, i, ((Byte) obj).byteValue());
+                }
+                else if (obj instanceof Short) {
+                    Array.setShort(objArray, i, ((Short) obj).shortValue());
+                }
+            }
+            else {
+                Array.set(objArray, i, obj);
+            }
+        }
+        return objArray;
+    }
+    
+    protected static Class autoboxType(Class type) {
+        if (type.isPrimitive()) {
+            if (type == int.class) {
+                return Integer.class;
+            }
+            else if (type == double.class) {
+                return Double.class;
+            }
+            else if (type == long.class) {
+                return Long.class;
+            }
+            else if (type == boolean.class) {
+                return Boolean.class;
+            }
+            else if (type == float.class) {
+                return Float.class;
+            }
+            else if (type == char.class) {
+                return Character.class;
+            }
+            else if (type == byte.class) {
+                return Byte.class;
+            }
+            else if (type == short.class) {
+                return Short.class;
+            }
+        }
+        return type;
+    }
+    
+    private static Class[] primitives = {
+        byte.class, Byte.class, short.class, Short.class, 
+        int.class, Integer.class, long.class, Long.class, 
+        BigInteger.class, float.class, Float.class, 
+        double.class, Double.class, BigDecimal.class,
+        Number.class, Object.class
+    };
+    private static int[][] primitiveDistanceTable = {
+        //              byte    Byte    short   Short   int     Integer     long    Long    BigInteger  float   Float   double  Double  BigDecimal, Number, Object 
+        /* byte*/{      0,      1,      2,      3,      4,      5,          6,      7,      8,          9,      10,     11,     12,     13,         14,     15,         },
+        /*Byte*/{       1,      0,      2,      3,      4,      5,          6,      7,      8,          9,      10,     11,     12,     13,         14,     15,         },
+        /*short*/{      14,     15,     0,      1,      2,      3,          4,      5,      6,          7,      8,      9,      10,     11,         12,     13,         },
+        /*Short*/{      14,     15,     1,      0,      2,      3,          4,      5,      6,          7,      8,      9,      10,     11,         12,     13,         },
+        /*int*/{        14,     15,     12,     13,     0,      1,          2,      3,      4,          5,      6,      7,      8,      9,          10,     11,         },
+        /*Integer*/{    14,     15,     12,     13,     1,      0,          2,      3,      4,          5,      6,      7,      8,      9,          10,     11,         },
+        /*long*/{       14,     15,     12,     13,     10,     11,         0,      1,      2,          3,      4,      5,      6,      7,          8,      9,          },
+        /*Long*/{       14,     15,     12,     13,     10,     11,         1,      0,      2,          3,      4,      5,      6,      7,          8,      9,          },
+        /*BigInteger*/{ 14,     15,     12,     13,     10,     11,         8,      9,      0,          1,      2,      3,      4,      5,          6,      7,          },
+        /*float*/{      14,     15,     12,     13,     10,     11,         8,      9,      7,          0,      1,      2,      3,      4,          5,      6,          },
+        /*Float*/{      14,     15,     12,     13,     10,     11,         8,      9,      7,          1,      0,      2,      3,      4,          5,      6,          },
+        /*double*/{     14,     15,     12,     13,     10,     11,         8,      9,      7,          5,      6,      0,      1,      2,          3,      4,          },
+        /*Double*/{     14,     15,     12,     13,     10,     11,         8,      9,      7,          5,      6,      1,      0,      2,          3,      4,          },
+        /*BigDecimal*/{ 14,     15,     12,     13,     10,     11,         8,      9,      7,          5,      6,      3,      4,      0,          1,      2,          },
+        /*Numer*/{      14,     15,     12,     13,     10,     11,         8,      9,      7,          5,      6,      3,      4,      2,          0,      1,          },
+        /*Object*/{     14,     15,     12,     13,     10,     11,         8,      9,      7,          5,      6,      3,      4,      2,          1,      0,          },
+    };
+    
+    private static int getPrimitiveIndex(Class c) {
+        for (byte i=0; i< primitives.length; i++) {
+            if (primitives[i] == c) return i;
+        }
+        return -1;
+    }
+    
+    private static int getPrimitiveDistance(Class from, Class to) {
+        // we know here that from!=to, so a distance of 0 is never valid
+        // get primitive type indexes
+        int fromIndex = getPrimitiveIndex(from);
+        int toIndex = getPrimitiveIndex(to);
+        if (fromIndex==-1 || toIndex==-1) return -1;
+        return primitiveDistanceTable[toIndex][fromIndex];
+    }
+    
+    private static int getMaximumInterfaceDistance(Class c, Class interfaceClass) {
+        if (c==interfaceClass) return 0;
+        Class[] interfaces = c.getInterfaces();
+        int max = 0;
+        for (int i=0; i<interfaces.length; i++) {
+            int sub = 0;
+            if (interfaces[i].isAssignableFrom(c)) {
+                sub = 1+ getMaximumInterfaceDistance(interfaces[i],interfaceClass);
+            }
+            max = Math.max(max,sub);
+        }
+        return max;
+    }
+    
+    public static long calculateParameterDistance(Class[] arguments, Class[] parameters) {
+        int objectDistance=0, interfaceDistance=0;
+        for (int i=0; i<arguments.length; i++) {
+            if (parameters[i]==arguments[i]) continue;
+            
+            if (parameters[i].isInterface()) {
+                objectDistance+=primitives.length;
+                interfaceDistance += getMaximumInterfaceDistance(arguments[i],parameters[i]);
+                continue;
+            }
+            
+            if (arguments[i]!=null) {
+                int pd = getPrimitiveDistance(parameters[i],arguments[i]);
+                if (pd!=-1) {
+                    objectDistance += pd;
+                    continue;
+                }
+                
+                // add one to dist to be sure interfaces are prefered
+                objectDistance += primitives.length+1;
+                Class clazz = autoboxType(arguments[i]);
+                while (clazz!=null) {
+                    if (clazz==parameters[i]) break;
+                    if (clazz==GString.class && parameters[i]==String.class) {
+                        objectDistance+=2;
+                        break;
+                    }
+                    clazz = clazz.getSuperclass();
+                    objectDistance+=3;
+                }
+            } else {
+                // choose the distance to Object if a parameter is null
+                // this will mean that Object is prefered over a more
+                // specific type
+                // remove one to dist to be sure Object is prefered
+                objectDistance--;
+                Class clazz = parameters[i];
+                if (clazz.isPrimitive()) {
+                    objectDistance+=2;
+                } else {
+                    while (clazz!=Object.class) {
+                        clazz = clazz.getSuperclass();
+                        objectDistance+=2;
+                    }
+                }
+            }
+        }
+        long ret = objectDistance;
+        ret <<= 32;
+        ret |= interfaceDistance;
+        return ret;
+    }
+    
+    public static String capitalize(String property) {
+        return property.substring(0, 1).toUpperCase() + property.substring(1, property.length());
+    }
+    
+    /**
+     * @return the method with 1 parameter which takes the most general type of
+     *         object (e.g. Object)
+     */
+    public static Object chooseEmptyMethodParams(List methods) {
+        for (Iterator iter = methods.iterator(); iter.hasNext();) {
+            Object method = iter.next();
+            Class[] paramTypes = getParameterTypes(method);
+            int paramLength = paramTypes.length;
+            if (paramLength == 0) {
+                return method;
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * @return the method with 1 parameter which takes the most general type of
+     *         object (e.g. Object) ignoring primitve types
+     */
+    public static Object chooseMostGeneralMethodWith1NullParam(List methods) {
+        // lets look for methods with 1 argument which matches the type of the
+        // arguments
+        Class closestClass = null;
+        Object answer = null;
+        
+        for (Iterator iter = methods.iterator(); iter.hasNext();) {
+            Object method = iter.next();
+            Class[] paramTypes = getParameterTypes(method);
+            int paramLength = paramTypes.length;
+            if (paramLength == 1) {
+                Class theType = paramTypes[0];
+                if (theType.isPrimitive()) continue;
+                if (closestClass == null || isAssignableFrom(theType, closestClass)) {
+                    closestClass = theType;
+                    answer = method;
+                }
+            }
+        }
+        return answer;
+    }
+    
+    /**
+     * Coerces a GString instance into String if needed
+     *
+     * @return the coerced argument
+     */
+    protected static Object coerceGString(Object argument, Class clazz) {
+        if (clazz!=String.class) return argument;
+        if (!(argument instanceof GString)) return argument;
+        return argument.toString();
+    }
+    
+    protected static Object coerceNumber(Object argument, Class param) {
+        if ((Number.class.isAssignableFrom(param) || param.isPrimitive()) && argument instanceof Number) { // Number types
+            Object oldArgument = argument;
+            boolean wasDouble = false;
+            boolean wasFloat = false;
+            if (param == Byte.class || param == Byte.TYPE ) {
+                argument = new Byte(((Number)argument).byteValue());
+            } else if (param == Double.class || param == Double.TYPE) {
+                wasDouble = true;
+                argument = new Double(((Number)argument).doubleValue());
+            } else if (param == Float.class || param == Float.TYPE) {
+                wasFloat = true;
+                argument = new Float(((Number)argument).floatValue());
+            } else if (param == Integer.class || param == Integer.TYPE) {
+                argument = new Integer(((Number)argument).intValue());
+            } else if (param == Long.class || param == Long.TYPE) {
+                argument = new Long(((Number)argument).longValue());
+            } else if (param == Short.class || param == Short.TYPE) {
+                argument = new Short(((Number)argument).shortValue());
+            } else if (param == BigDecimal.class ) {
+                argument = new BigDecimal(String.valueOf((Number)argument));
+            } else if (param == BigInteger.class) {
+                argument = new BigInteger(String.valueOf((Number)argument));
+            }
+            
+            if (oldArgument instanceof BigDecimal) {
+                BigDecimal oldbd = (BigDecimal) oldArgument;
+                boolean throwException = false;
+                if (wasDouble) {
+                    Double d = (Double) argument;
+                    if (d.isInfinite()) throwException = true;
+                } else if (wasFloat) {
+                    Float f = (Float) argument;
+                    if (f.isInfinite()) throwException = true;
+                } else {
+                    BigDecimal newbd = new BigDecimal(String.valueOf((Number)argument));
+                    throwException = !oldArgument.equals(newbd);
+                }
+                
+                if (throwException) throw new IllegalArgumentException(param+" out of range while converting from BigDecimal");
+            }
+
+        }
+        return argument;
+    }
+        
+     protected static Object coerceArray(Object argument, Class param) {
+         if (!param.isArray()) return argument;
+         Class argumentClass = argument.getClass();
+         if (!argumentClass.isArray()) return argument;
+            
+         Class paramComponent = param.getComponentType();
+         if (paramComponent.isPrimitive()) {
+             if (paramComponent == boolean.class && argumentClass==Boolean[].class) {
+                 argument = DefaultTypeTransformation.convertToBooleanArray(argument);
+             } else if (paramComponent == byte.class && argumentClass==Byte[].class) {
+                 argument = DefaultTypeTransformation.convertToByteArray(argument);
+             } else if (paramComponent == char.class && argumentClass==Character[].class) {
+                 argument = DefaultTypeTransformation.convertToCharArray(argument);
+             } else if (paramComponent == short.class && argumentClass==Short[].class) {
+                 argument = DefaultTypeTransformation.convertToShortArray(argument);
+             } else if (paramComponent == int.class && argumentClass==Integer[].class) {
+                 argument = DefaultTypeTransformation.convertToIntArray(argument);
+             } else if (paramComponent == long.class &&
+                        (argumentClass == Long[].class || argumentClass  == Integer[].class))
+             {
+                 argument = DefaultTypeTransformation.convertToLongArray(argument);
+             } else if (paramComponent == float.class &&
+                        (argumentClass == Float[].class || argumentClass == Integer[].class))
+             {
+                 argument = DefaultTypeTransformation.convertToFloatArray(argument);
+             } else if (paramComponent == double.class &&
+                        (argumentClass == Double[].class || argumentClass==Float[].class  
+                         || BigDecimal.class.isAssignableFrom(argumentClass)))
+             {
+                 argument = DefaultTypeTransformation.convertToDoubleArray(argument);
+             }
+         } else if (paramComponent==String.class && argument instanceof GString[]) {
+             GString[] strings = (GString[]) argument;
+             String[] ret = new String[strings.length];
+             for (int i=0; i<strings.length; i++) {
+                 ret[i] = strings[i].toString();
+             }
+             argument = ret;
+         }
+         return argument;
+    }
+    
+    /**
+     * @return true if a method of the same matching prototype was found in the
+     *         list
+     */
+    public static boolean containsMatchingMethod(List list, MetaMethod method) {
+        for (Iterator iter = list.iterator(); iter.hasNext();) {
+            MetaMethod aMethod = (MetaMethod) iter.next();
+            Class[] params1 = aMethod.getParameterTypes();
+            Class[] params2 = method.getParameterTypes();
+            if (params1.length == params2.length) {
+                boolean matches = true;
+                for (int i = 0; i < params1.length; i++) {
+                    if (params1[i] != params2[i]) {
+                        matches = false;
+                        break;
+                    }
+                }
+                if (matches) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * param instance array to the type array
+     * @param args
+     */
+    public static Class[] convertToTypeArray(Object[] args) {
+        if (args == null)
+            return null;
+        int s = args.length;
+        Class[] ans = new Class[s];
+        for (int i = 0; i < s; i++) {
+            Object o = args[i];
+            if (o == null) {
+                ans[i] = null;
+            } else if (o instanceof Wrapper) {
+                ans[i] = ((Wrapper) o).getType();
+            } else {
+                ans[i] = o.getClass();
+            } 
+        }
+        return ans;
+    }
+    
+    /**
+     * @param listenerType
+     *            the interface of the listener to proxy
+     * @param listenerMethodName
+     *            the name of the method in the listener API to call the
+     *            closure on
+     * @param closure
+     *            the closure to invoke on the listenerMethodName method
+     *            invocation
+     * @return a dynamic proxy which calls the given closure on the given
+     *         method name
+     */
+    public static Object createListenerProxy(Class listenerType, final String listenerMethodName, final Closure closure) {
+        InvocationHandler handler = new ClosureListener(listenerMethodName, closure);
+        return Proxy.newProxyInstance(listenerType.getClassLoader(), new Class[] { listenerType }, handler);
+    }
+    
+    public static Object doConstructorInvoke(Constructor constructor, Object[] argumentArray) {
+        if (log.isLoggable(Level.FINER)){
+            logMethodCall(constructor.getDeclaringClass(), constructor.getName(), argumentArray);
+        }
+        argumentArray = coerceArgumentsToClasses(argumentArray,constructor.getParameterTypes());
+        try {
+            return constructor.newInstance(argumentArray);
+        } catch (InvocationTargetException e) {
+            throw new InvokerInvocationException(e);
+        } catch (IllegalArgumentException e) {
+            throw createExceptionText("failed to invoke constructor: ", constructor, argumentArray, e, false);
+        } catch (IllegalAccessException e) {
+            throw createExceptionText("could not access constructor: ", constructor, argumentArray, e, false);
+        } catch (Exception e) {
+            throw createExceptionText("failed to invoke constructor: ", constructor, argumentArray, e, true);
+        }
+    }
+    
+    private static GroovyRuntimeException createExceptionText(String init, Constructor constructor, Object[] argumentArray, Throwable e, boolean setReason) {
+        throw new GroovyRuntimeException(
+                init
+                + constructor
+                + " with arguments: "
+                + InvokerHelper.toString(argumentArray)
+                + " reason: "
+                + e,
+                setReason?e:null);
+    }
+
+    public static Object[] coerceArgumentsToClasses(Object[] argumentArray, Class[] paramTypes) {
+        // correct argumentArray's length
+        if (argumentArray == null) {
+            argumentArray = EMPTY_ARRAY;
+        } else if (paramTypes.length == 1 && argumentArray.length == 0) {
+            if (isVargsMethod(paramTypes,argumentArray))
+                argumentArray = new Object[]{Array.newInstance(paramTypes[0].getComponentType(),0)};
+            else
+                argumentArray = ARRAY_WITH_NULL;
+        } else if (isVargsMethod(paramTypes,argumentArray)) {
+            argumentArray = fitToVargs(argumentArray, paramTypes);
+        }
+        
+        //correct Type
+        for (int i=0; i<argumentArray.length; i++) {
+            Object argument = argumentArray[i];
+            if (argument==null) continue;
+            Class parameterType = paramTypes[i];
+            if (parameterType.isInstance(argument)) continue;
+            
+            argument = coerceGString(argument,parameterType);
+            argument = coerceNumber(argument,parameterType);
+            argument = coerceArray(argument,parameterType);
+            argumentArray[i] = argument;
+        }
+        return argumentArray;
+    }
+
+    private static Object makeCommonArray(Object[] arguments, int offset, Class fallback) {
+    	// arguments.leght>0 && !=null
+    	Class baseClass = null;
+    	for (int i = offset; i < arguments.length; i++) {
+			if (arguments[i]==null) continue;
+			Class argClass = arguments[i].getClass();
+			if (baseClass==null) {
+				baseClass = argClass;
+			} else {
+				for (;baseClass!=Object.class; baseClass=baseClass.getSuperclass()){
+					if (baseClass.isAssignableFrom(argClass)) break;
+				}
+			}
+		}
+        if (baseClass==null) {
+            // all arguments were null
+            baseClass = fallback;
+        }
+    	Object result = makeArray(null,baseClass,arguments.length-offset);
+    	System.arraycopy(arguments,offset,result,0,arguments.length-offset);
+    	return result;
+    }
+    
+    private static Object makeArray(Object obj, Class secondary, int length) {
+    	Class baseClass = secondary;
+    	if (obj!=null) {
+    		baseClass = obj.getClass();
+    	}
+    	/*if (GString.class.isAssignableFrom(baseClass)) {
+    		baseClass = GString.class;
+    	}*/
+    	return Array.newInstance(baseClass,length);
+    }
+    
+    /**
+     * this method is called when the number of arguments to a method is greater than 1
+     * and if the method is a vargs method. This method will then transform the given
+     * arguments to make the method callable
+     * 
+     * @param argumentArray the arguments used to call the method
+     * @param paramTypes the types of the paramters the method takes
+     */
+    private static Object[] fitToVargs(Object[] argumentArray, Class[] paramTypes) {
+    	Class vargsClass = autoboxType(paramTypes[paramTypes.length-1].getComponentType());
+    	
+        if (argumentArray.length == paramTypes.length-1) {
+            // the vargs argument is missing, so fill it with an empty array
+            Object[] newArgs = new Object[paramTypes.length];
+            System.arraycopy(argumentArray,0,newArgs,0,argumentArray.length);
+            Object vargs = makeArray(null,vargsClass,0);
+            newArgs[newArgs.length-1] = vargs;
+            return newArgs;
+        } else if (argumentArray.length==paramTypes.length) {
+            // the number of arguments is correct, but if the last argument 
+            // is no array we have to wrap it in a array. if the last argument
+            // is null, then we don't have to do anything
+            Object lastArgument = argumentArray[argumentArray.length-1];
+            if (lastArgument!=null && !lastArgument.getClass().isArray()) {
+                // no array so wrap it
+                Object vargs = makeArray(lastArgument,vargsClass,1);
+                System.arraycopy(argumentArray,argumentArray.length-1,vargs,0,1);
+                argumentArray[argumentArray.length-1]=vargs;
+                return argumentArray;
+            } else {
+                // we may have to box the arguemnt!
+                return argumentArray;
+            } 
+        } else if (argumentArray.length>paramTypes.length) {
+            // the number of arguments is too big, wrap all exceeding elements
+            // in an array, but keep the old elements that are no vargs
+            Object[] newArgs = new Object[paramTypes.length];
+            // copy arguments that are not a varg
+            System.arraycopy(argumentArray,0,newArgs,0,paramTypes.length-1);
+            // create a new array for the vargs and copy them
+            int numberOfVargs = argumentArray.length-paramTypes.length;
+            Object vargs = makeCommonArray(argumentArray,paramTypes.length-1,vargsClass);
+            newArgs[newArgs.length-1] = vargs;
+            return newArgs;
+        } else {
+            throw new GroovyBugError("trying to call a vargs method without enough arguments");
+        }
+    }
+    
+    private static GroovyRuntimeException createExceptionText(String init, MetaMethod method, Object object, Object[] args, Throwable reason, boolean setReason) {
+        return new GroovyRuntimeException(
+                init
+                + method
+                + " on: "
+                + object
+                + " with arguments: "
+                + InvokerHelper.toString(args)
+                + " reason: "
+                + reason,
+                setReason?reason:null);
+    }
+    
+    public static Object doMethodInvoke(Object object, MetaMethod method, Object[] argumentArray) {
+        Class[] paramTypes = method.getParameterTypes();
+        argumentArray = coerceArgumentsToClasses(argumentArray,paramTypes);
+        try {
+            return method.invoke(object, argumentArray);
+        } catch (IllegalArgumentException e) {
+            //TODO: test if this is ok with new MOP, should be changed!
+            // we don't want the exception being unwrapped if it is a IllegalArgumentException
+            // but in the case it is for example a IllegalThreadStateException, we want the unwrapping
+            // from the runtime
+            //Note: the reason we want unwrapping sometimes and sometimes not is that the method
+            // invokation tries to invoke the method with and then reacts with type transformation
+            // if the invokation failed here. This is ok for IllegalArgumentException, but it is
+            // possible that a Reflector will be used to execute the call and then an Exception from inside
+            // the method is not wrapped in a InvocationTargetException and we will end here.
+            boolean setReason = e.getClass() != IllegalArgumentException.class;
+            throw createExceptionText("failed to invoke method: ", method, object, argumentArray, e, setReason);
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw createExceptionText("failed to invoke method: ", method, object, argumentArray, e, true);
+        }
+    }
+    
+    protected static String getClassName(Object object) {
+        if (object==null) return null;
+        return (object instanceof Class) ? ((Class)object).getName() : object.getClass().getName();
+    }
+    
+    /**
+     * Returns a callable object for the given method name on the object.
+     * The object acts like a Closure in that it can be called, like a closure
+     * and passed around - though really its a method pointer, not a closure per se.
+     */
+    public static Closure getMethodPointer(Object object, String methodName) {
+        return new MethodClosure(object, methodName);
+    }
+    
+    public static Class[] getParameterTypes(Object methodOrConstructor) {
+        if (methodOrConstructor instanceof MetaMethod) {
+            MetaMethod method = (MetaMethod) methodOrConstructor;
+            return method.getParameterTypes();
+        }
+        if (methodOrConstructor instanceof Method) {
+            Method method = (Method) methodOrConstructor;
+            return method.getParameterTypes();
+        }
+        if (methodOrConstructor instanceof Constructor) {
+            Constructor constructor = (Constructor) methodOrConstructor;
+            return constructor.getParameterTypes();
+        }
+        throw new IllegalArgumentException("Must be a Method or Constructor");
+    }
+   
+    public static boolean isAssignableFrom(Class classToTransformTo, Class classToTransformFrom) {
+        if (classToTransformFrom==null) return true;
+        classToTransformTo = autoboxType(classToTransformTo);
+        classToTransformFrom = autoboxType(classToTransformFrom);
+        
+        if (classToTransformTo == classToTransformFrom) {
+        	return true;
+        }
+        // note: there is not coercion for boolean and char. Range matters, precision doesn't
+        else if (classToTransformTo == Integer.class) {
+        	if (	classToTransformFrom == Integer.class
+        			|| classToTransformFrom == Short.class
+        			|| classToTransformFrom == Byte.class
+                    || classToTransformFrom == BigInteger.class)
+        	return true;
+        }
+        else if (classToTransformTo == Double.class) {
+        	if (	classToTransformFrom == Double.class
+        			|| classToTransformFrom == Integer.class
+        			|| classToTransformFrom == Long.class
+        			|| classToTransformFrom == Short.class
+        			|| classToTransformFrom == Byte.class
+        			|| classToTransformFrom == Float.class
+                    || classToTransformFrom == BigDecimal.class
+                    || classToTransformFrom == BigInteger.class)
+        	return true;
+        }
+        else if (classToTransformTo == BigDecimal.class) {
+            if (    classToTransformFrom == Double.class
+                    || classToTransformFrom == Integer.class
+                    || classToTransformFrom == Long.class
+                    || classToTransformFrom == Short.class
+                    || classToTransformFrom == Byte.class
+                    || classToTransformFrom == Float.class
+                    || classToTransformFrom == BigDecimal.class
+                    || classToTransformFrom == BigInteger.class)
+            return true;
+        }
+        else if (classToTransformTo == BigInteger.class) {
+            if (    classToTransformFrom == Integer.class
+                    || classToTransformFrom == Long.class
+                    || classToTransformFrom == Short.class
+                    || classToTransformFrom == Byte.class
+                    || classToTransformFrom == BigInteger.class)
+            return true;
+        }
+        else if (classToTransformTo == Long.class) {
+        	if (	classToTransformFrom == Long.class
+        			|| classToTransformFrom == Integer.class
+        			|| classToTransformFrom == Short.class
+        			|| classToTransformFrom == Byte.class)
+        	return true;
+        }
+        else if (classToTransformTo == Float.class) {
+        	if (	classToTransformFrom == Float.class
+        			|| classToTransformFrom == Integer.class
+        			|| classToTransformFrom == Long.class
+        			|| classToTransformFrom == Short.class
+        			|| classToTransformFrom == Byte.class)
+        	return true;
+        }
+        else if (classToTransformTo == Short.class) {
+        	if (	classToTransformFrom == Short.class
+        			|| classToTransformFrom == Byte.class)
+        	return true;
+        }
+        else if (classToTransformTo==String.class) {
+            if (	classToTransformFrom == String.class ||
+            		GString.class.isAssignableFrom(classToTransformFrom)) {
+                return true;
+            }
+        }
+
+        return classToTransformTo.isAssignableFrom(classToTransformFrom);
+    }
+    
+    public static boolean isGenericSetMethod(MetaMethod method) {
+        return (method.getName().equals("set"))
+        && method.getParameterTypes().length == 2;
+    }
+    
+    protected static boolean isSuperclass(Class claszz, Class superclass) {
+        while (claszz!=null) {
+            if (claszz==superclass) return true;
+            claszz = claszz.getSuperclass();
+        }
+        return false;
+    }
+    
+    public static boolean isValidMethod(Class[] paramTypes, Class[] arguments, boolean includeCoerce) {
+        if (arguments == null) {
+            return true;
+        }
+        int size = arguments.length;
+        
+        if (   (size>=paramTypes.length || size==paramTypes.length-1)
+                && paramTypes.length>0
+                && paramTypes[paramTypes.length-1].isArray())
+        {
+            // first check normal number of parameters
+            for (int i = 0; i < paramTypes.length-1; i++) {
+                if (isAssignableFrom(paramTypes[i], arguments[i])) continue;
+                return false;
+            }
+            // check varged
+            Class clazz = paramTypes[paramTypes.length-1].getComponentType();
+            for (int i=paramTypes.length; i<size; i++) {
+                if (isAssignableFrom(clazz, arguments[i])) continue;
+                return false;
+            }
+            return true;
+        } else if (paramTypes.length == size) {
+            // lets check the parameter types match
+            for (int i = 0; i < size; i++) {
+                if (isAssignableFrom(paramTypes[i], arguments[i])) continue;
+                return false;
+            }
+            return true;
+        } else if (paramTypes.length == 1 && size == 0) {
+            return true;
+        }
+        return false;
+        
+    }
+    
+    public static boolean isValidMethod(Object method, Class[] arguments, boolean includeCoerce) {
+        Class[] paramTypes = getParameterTypes(method);
+        return isValidMethod(paramTypes, arguments, includeCoerce);
+    }
+    
+    public static boolean isVargsMethod(Class[] paramTypes, Object[] arguments) {
+        if (paramTypes.length==0) return false;
+        if (!paramTypes[paramTypes.length-1].isArray()) return false;
+        // -1 because the varg part is optional
+        if (paramTypes.length-1==arguments.length) return true;
+        if (paramTypes.length-1>arguments.length) return false;
+        if (arguments.length>paramTypes.length) return true;
+        
+        // only case left is arguments.length==paramTypes.length
+        Object last = arguments[arguments.length-1];
+        if (last==null) return true;
+        Class clazz = last.getClass();
+        if (clazz.equals(paramTypes[paramTypes.length-1])) return false;
+        
+        return true;
+    }
+    
+    public static void logMethodCall(Object object, String methodName, Object[] arguments) {
+        String className = getClassName(object);
+        String logname = "methodCalls." + className + "." + methodName;
+        Logger objLog = Logger.getLogger(logname);
+        if (! objLog.isLoggable(Level.FINER)) return;
+        StringBuffer msg = new StringBuffer(methodName);
+        msg.append("(");
+        if (arguments != null){
+            for (int i = 0; i < arguments.length;) {
+                msg.append(normalizedValue(arguments[i]));
+                if (++i < arguments.length) { msg.append(","); }
+            }
+        }
+        msg.append(")");
+        objLog.logp(Level.FINER, className, msg.toString(), "called from MetaClass.invokeMethod");
+    }
+    
+    protected static String normalizedValue(Object argument) {
+        String value;
+        try {
+            value = argument.toString();
+            if (value.length() > MAX_ARG_LEN){
+                value = value.substring(0,MAX_ARG_LEN-2) + "..";
+            }
+            if (argument instanceof String){
+                value = "\'"+value+"\'";
+            }
+        } catch (Exception e) {
+            value = shortName(argument);
+        }
+        return value;
+    }
+    
+    public static boolean parametersAreCompatible(Class[] arguments, Class[] parameters) {
+        if (arguments.length!=parameters.length) return false;
+        for (int i=0; i<arguments.length; i++) {
+            if (!isAssignableFrom(parameters[i],arguments[i])) return false;
+        }
+        return true;
+    }
+    
+    protected static String shortName(Object object) {
+        if (object == null || object.getClass()==null) return "unknownClass";
+        String name = getClassName(object);
+        if (name == null) return "unknownClassName"; // *very* defensive...
+        int lastDotPos = name.lastIndexOf('.');
+        if (lastDotPos < 0 || lastDotPos >= name.length()-1) return name;
+        return name.substring(lastDotPos+1);
+    }
+    
+    public static Class[] wrap(Class[] classes) {
+        Class[] wrappedArguments = new Class[classes.length];
+        for (int i = 0; i < wrappedArguments.length; i++) {
+            Class c = classes[i];
+            if (c==null) continue;
+            if (c.isPrimitive()) {
+                if (c==Integer.TYPE) {
+                    c=Integer.class;
+                } else if (c==Byte.TYPE) {
+                    c=Byte.class;
+                } else if (c==Long.TYPE) {
+                    c=Long.class;
+                } else if (c==Double.TYPE) {
+                    c=Double.class;
+                } else if (c==Float.TYPE) {
+                    c=Float.class;
+                }
+            } else if (isSuperclass(c,GString.class)) {
+                c = String.class;
+            }
+            wrappedArguments[i]=c;
+        }
+        return wrappedArguments;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/MethodClosure.java b/groovy-core/src/main/org/codehaus/groovy/runtime/MethodClosure.java
new file mode 100644
index 0000000..1fa3165
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/MethodClosure.java
@@ -0,0 +1,65 @@
+package org.codehaus.groovy.runtime;
+
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import groovy.lang.Closure;
+
+
+/**
+ * Represents a method on an object using a closure which can be invoked
+ * at any time
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MethodClosure extends Closure {
+
+    private String method;
+    
+    public MethodClosure(Object owner, String method) {
+        super(owner);
+        this.method = method;
+
+        final Class clazz = owner.getClass()==Class.class?(Class) owner:owner.getClass();
+        
+        maximumNumberOfParameters = 0;
+
+        Method[] methods = (Method[]) AccessController.doPrivileged(new  PrivilegedAction() {
+            public Object run() {
+                return clazz.getMethods();
+            }
+        });
+        for (int j = 0; j < methods.length; j++) {
+            if (method.equals(methods[j].getName()) && methods[j].getParameterTypes().length > maximumNumberOfParameters) {
+                maximumNumberOfParameters = methods[j].getParameterTypes().length;
+            }
+        }        
+        methods = (Method[]) AccessController.doPrivileged(new  PrivilegedAction() {
+            public Object run() {
+                return clazz.getDeclaredMethods();
+            }
+        });
+        for (int j = 0; j < methods.length; j++) {
+            if (method.equals(methods[j].getName()) && methods[j].getParameterTypes().length > maximumNumberOfParameters) {
+                maximumNumberOfParameters = methods[j].getParameterTypes().length;
+            }
+        }
+
+    }
+    
+    public String getMethod() {
+        return method;
+    }
+
+    protected Object doCall(Object arguments) {
+        return InvokerHelper.invokeMethod(getDelegate(), method, arguments);
+    }
+    
+    public Object getProperty(String property) {
+        if ("method".equals(property)) {
+            return getMethod();
+        } else  return super.getProperty(property);        
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/MethodHelper.java b/groovy-core/src/main/org/codehaus/groovy/runtime/MethodHelper.java
new file mode 100644
index 0000000..b9d1d23
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/MethodHelper.java
@@ -0,0 +1,68 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.runtime;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+/**
+ * Some reflection helper methods
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MethodHelper {
+ 
+    public static boolean isStatic(Method method) {
+        int flags = Modifier.STATIC;
+        return (method.getModifiers() & (flags)) == flags;
+    }
+
+    public static boolean isPublic(Method method) {
+        int flags = Modifier.PUBLIC;
+        return (method.getModifiers() & (flags)) == flags;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/MethodKey.java b/groovy-core/src/main/org/codehaus/groovy/runtime/MethodKey.java
new file mode 100644
index 0000000..71e63d1
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/MethodKey.java
@@ -0,0 +1,149 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package org.codehaus.groovy.runtime;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * An abstract base class for a key used for comparators and Map keys to lookup a method by
+ * name and parameter types
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public abstract class MethodKey {
+
+    private int hash;
+    private String name;
+    private Class sender;
+    private boolean isCallToSuper;
+    
+    public MethodKey(Class sender, String name, boolean isCallToSuper) {
+        this.sender = sender;
+        this.name = name;
+        this.isCallToSuper = isCallToSuper;
+    }
+
+    /**
+     * Creates an immutable copy that we can cache. 
+     */
+    public MethodKey createCopy() {
+        int size = getParameterCount();
+        Class[] paramTypes = new Class[size];
+        for (int i = 0; i < size; i++) {
+            paramTypes[i] = getParameterType(i);
+        }
+        return new DefaultMethodKey(sender, name, paramTypes, isCallToSuper);
+    }
+
+    public boolean equals(Object that) {
+        if (this == that) {
+            return true;
+        }
+        else if (hashCode() == that.hashCode() && that instanceof MethodKey) {
+            return equals((MethodKey) that);
+        }
+        return false;
+    }
+
+    public boolean equals(MethodKey that) {
+        int size = getParameterCount();
+        if (sender!=that.sender) return false;
+        if (isCallToSuper!=that.isCallToSuper) return false;
+        if (name.equals(that.name) && size == that.getParameterCount()) {
+            for (int i = 0; i < size; i++) {
+                if (!getParameterType(i).equals(that.getParameterType(i))) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public int hashCode() {
+        if (hash == 0) {
+            hash = createHashCode();
+            if (hash == 0) {
+                hash = 0xcafebabe;
+            }
+        }
+        return hash;
+    }
+
+    public String toString() {
+        return super.toString() + "[name:" + name + "; params:" + getParamterTypes();
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public List getParamterTypes() {
+        int size = getParameterCount();
+        if (size <= 0) {
+            return Collections.EMPTY_LIST;
+        }
+        List params = new ArrayList(size);
+        for (int i = 0; i < size; i++) {
+            params.add(getParameterType(i));
+        }
+        return params;
+    }
+
+    public abstract int getParameterCount();
+    public abstract Class getParameterType(int index);
+
+    protected int createHashCode() {
+        int answer = name.hashCode();
+        int size = getParameterCount();
+
+        /** @todo we should use the real Josh Bloch algorithm here */
+
+        // can't remember the exact Josh Bloch algorithm and I've not got the book handy
+        // but its something like this IIRC
+        for (int i = 0; i < size; i++) {
+            answer *= 37;
+            answer += 1 + getParameterType(i).hashCode();
+        }
+        answer *= 37;
+        answer += isCallToSuper?1:0;
+        answer *= 37;
+        answer += 1 + sender.hashCode();
+        return answer;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/NewInstanceMetaMethod.java b/groovy-core/src/main/org/codehaus/groovy/runtime/NewInstanceMetaMethod.java
new file mode 100644
index 0000000..2fc43ca
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/NewInstanceMetaMethod.java
@@ -0,0 +1,115 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.MetaMethod;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * A MetaMethod implementation where the underlying method is really a static
+ * helper method on some class but it appears to be an instance method on a class.
+ * 
+ * This implementation is used to add new methods to the JDK writing them as normal
+ * static methods with the first parameter being the class on which the method is added.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class NewInstanceMetaMethod extends MetaMethod {
+
+    private static final Class[] EMPTY_TYPE_ARRAY = {};
+    
+    private MetaMethod metaMethod;
+    private Class[] logicalParameterTypes;
+
+    
+    public NewInstanceMetaMethod(MetaMethod metaMethod) {
+        super(metaMethod);
+        this.metaMethod = metaMethod;
+        init();
+    }
+    
+    public NewInstanceMetaMethod(String name, Class declaringClass, Class[] parameterTypes, Class returnType, int modifiers) {
+        super(name, declaringClass, parameterTypes, returnType, modifiers);
+        this.metaMethod = new MetaMethod(name, declaringClass, parameterTypes,returnType, modifiers);
+        init();
+    }
+    
+    private void init() {
+        Class[] realParameterTypes = metaMethod.getParameterTypes();
+        int size = realParameterTypes!=null ? realParameterTypes.length : 0;
+        if (size <= 1) {
+            logicalParameterTypes = EMPTY_TYPE_ARRAY;
+        } else {
+            logicalParameterTypes = new Class[--size];
+            System.arraycopy(realParameterTypes, 1, logicalParameterTypes, 0, size);
+        }
+    }
+    
+    public Class getDeclaringClass() {
+        return getBytecodeParameterTypes()[0];
+    }
+
+    public boolean isStatic() {
+        return false;
+    }
+
+    public int getModifiers() {
+        // lets clear the static bit
+        return super.getModifiers() ^ Modifier.STATIC;
+    }
+
+    public Class[] getParameterTypes() {
+        return logicalParameterTypes;
+    }
+
+    public Class[] getBytecodeParameterTypes() {
+        return super.getParameterTypes();
+    }
+
+    public Object invoke(Object object, Object[] arguments)  {
+        // we need to cheat using the type
+        int size = arguments.length;
+        Object[] newArguments = new Object[size + 1];
+        newArguments[0] = object;
+        System.arraycopy(arguments, 0, newArguments, 1, size);
+        return metaMethod.invoke(null, newArguments);
+    }
+    
+    public Class getOwnerClass() {
+        return getBytecodeParameterTypes()[0];
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/NewStaticMetaMethod.java b/groovy-core/src/main/org/codehaus/groovy/runtime/NewStaticMetaMethod.java
new file mode 100644
index 0000000..4582798
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/NewStaticMetaMethod.java
@@ -0,0 +1,106 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.MetaMethod;
+
+/**
+ * A MetaMethod implementation where the underlying method is really a static
+ * helper method on some class.
+ * 
+ * This implementation is used to add new static methods to the JDK writing them as normal
+ * static methods with the first parameter being the class on which the method is added.
+ * 
+ * @author Guillaume Laforge
+ * @version $Revision$
+ */
+public class NewStaticMetaMethod extends MetaMethod {
+
+    private static final Class[] EMPTY_TYPE_ARRAY = {};
+    
+    private MetaMethod metaMethod;
+    private Class[] logicalParameterTypes;
+    
+    public NewStaticMetaMethod(MetaMethod metaMethod) {
+        super(metaMethod);
+        this.metaMethod = metaMethod;
+        init();
+    }
+    
+    public NewStaticMetaMethod(String name, Class declaringClass, Class[] parameterTypes, Class returnType, int modifiers) {
+        super(name, declaringClass, parameterTypes, returnType, modifiers);
+        this.metaMethod = new MetaMethod(name, declaringClass, parameterTypes,returnType, modifiers);
+        init();
+    }
+    
+    private void init() {
+        Class[] realParameterTypes = metaMethod.getParameterTypes();
+        int size = realParameterTypes!=null ? realParameterTypes.length : 0;
+        if (size <= 1) {
+            logicalParameterTypes = EMPTY_TYPE_ARRAY;
+        } else {
+            logicalParameterTypes = new Class[--size];
+            System.arraycopy(realParameterTypes, 1, logicalParameterTypes, 0, size);
+        }
+    }
+
+    public Class getDeclaringClass() {
+        return getBytecodeParameterTypes()[0];
+    }
+
+    public boolean isStatic() {
+        return true;
+    }
+
+    public int getModifiers() {
+        return super.getModifiers();
+    }
+
+    public Class[] getParameterTypes() {
+        return logicalParameterTypes;
+    }
+
+    public Class[] getBytecodeParameterTypes() {
+        return super.getParameterTypes();
+    }
+
+    public Object invoke(Object object, Object[] arguments) {
+        int size = arguments.length;
+        Object[] newArguments = new Object[size + 1];
+        System.arraycopy(arguments, 0, newArguments, 1, size);
+        newArguments[0] = null;
+        return metaMethod.invoke(null, newArguments);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/NullObject.java b/groovy-core/src/main/org/codehaus/groovy/runtime/NullObject.java
new file mode 100644
index 0000000..c863aba
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/NullObject.java
@@ -0,0 +1,126 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.runtime;
+
+import java.util.Collections;
+import java.util.Iterator;
+
+import groovy.lang.GroovyObjectSupport;
+
+public class NullObject extends GroovyObjectSupport {
+  private static NullObject ref;
+
+  /**
+   * private constructor
+   **/
+  private NullObject() {
+  }
+
+  /**
+   * get the NullObject reference
+   **/
+  public synchronized static NullObject getNullObject() {
+    if (ref == null)
+      ref = new NullObject();
+    return ref;
+  }
+
+  /**
+   * Since this is implemented as a singleton, we should avoid the 
+   * use of the clone method
+   **/
+  public Object clone() throws CloneNotSupportedException {
+    throw new CloneNotSupportedException();
+  }
+
+  /**
+   * @param property - the property to get
+   * @returns a NPE
+   **/
+  public Object getProperty(String property) {
+    throw new NullPointerException("Cannot get property " + property + "() on null object");
+  }
+
+  /**
+   * @param property - the property to set
+   * @returns a NPE
+   **/
+  public Object setProperty(String property) {
+    throw new NullPointerException("Cannot set property " + property + "() on null object");
+  }
+
+  /**
+   * @param name the name of the method to invoke
+   * @param args - arguments to the method
+   * @returns a NPE
+   * 
+   **/
+  public Object invokeMethod(String name, Object args) {
+    throw new NullPointerException("Cannot invoke method " + name + "() on null object");
+  }
+
+  /**
+   * @param to - the reference object with which to compare
+   * @returns - true if this object is the same as the to argument
+   **/
+  public boolean equals(Object to) {
+    return to == null;
+  }
+
+  /**
+   * iterator() method to be able to iterate on null. 
+   * Note: this part is from Invoker
+   * @return an iterator for an empty list
+   */
+  public Iterator iterator() {
+      return Collections.EMPTY_LIST.iterator();
+  }
+  
+  public Object plus(String s){
+      return "null"+s;
+  }
+  
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/ReferenceMap.java b/groovy-core/src/main/org/codehaus/groovy/runtime/ReferenceMap.java
new file mode 100644
index 0000000..5af915c
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/ReferenceMap.java
@@ -0,0 +1,95 @@
+/*

+ * WeakValueMap.java created on 31.10.2006

+ *

+ * To change this generated comment go to 

+ * Window>Preferences>Java>Code Generation>Code and Comments

+ */

+package org.codehaus.groovy.runtime;

+

+import java.lang.ref.ReferenceQueue;

+import java.lang.ref.SoftReference;

+import java.util.ArrayList;

+import java.util.Collection;

+import java.util.Iterator;

+import java.util.Set;

+import java.util.WeakHashMap;

+

+public class ReferenceMap extends WeakHashMap {

+    

+    private static class HardReference extends SoftReference {

+        private Object value;

+        public HardReference(Object arg) {

+            super(null);

+            value = arg;

+        }

+        public Object get() {

+            return value;

+        }        

+    }

+    

+    private ReferenceQueue queue = new ReferenceQueue();

+    

+    public ReferenceMap() {

+        super();

+    }

+

+    public boolean containsValue(Object value) {

+        throw new UnsupportedOperationException();

+    }

+    

+    public Set entrySet() {

+        throw new UnsupportedOperationException();

+    }

+    

+    public Object get(Object key) {

+        Object ret = super.get(key);

+        if (ret!=null) {

+            SoftReference weak = (SoftReference) ret;

+            ret = weak.get();

+            if (ret==null) remove(key);

+        }        

+        return ret;

+    }

+    

+    public Object put(Object key, Object value) {

+        removeDereferencedEntries();

+        if (value!=null) {

+            value = new SoftReference(value,queue);

+        }        

+        return super.put(key, value);

+    }

+    

+    public Object putStrong(Object key, Object value) {

+        removeDereferencedEntries();

+        if (value!=null) {

+            value = new HardReference(value);

+        }        

+        return super.put(key, value);

+    }

+    

+    public Collection values() {

+        removeDereferencedEntries();

+        Collection origColl = super.values();

+        ArrayList newColl = new ArrayList(origColl.size());

+        for (Iterator iter = origColl.iterator(); iter.hasNext();) {

+            SoftReference element = (SoftReference) iter.next();

+            if (element!=null) {

+                Object strong = element.get();

+                if (strong==null) continue;

+                newColl.add(strong);

+            } else {

+                newColl.add(null);

+            }            

+        }        

+        return newColl;

+    }

+    

+    private void removeDereferencedEntries(){

+        SoftReference e;

+        while ( (e = (SoftReference) queue.poll()) != null) {

+            Object strong = e.get();

+            if (strong==null) continue;

+            remove(strong);

+        }

+    }

+}

diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/ReflectionMetaMethod.java b/groovy-core/src/main/org/codehaus/groovy/runtime/ReflectionMetaMethod.java
new file mode 100644
index 0000000..d3ee1c7
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/ReflectionMetaMethod.java
@@ -0,0 +1,78 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.MetaMethod;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+public class ReflectionMetaMethod extends MetaMethod {
+    private Method method;
+    boolean alreadySetAccessible;
+
+    public ReflectionMetaMethod(Method method) {
+        super(method);
+        this.method = method;
+    }
+
+    public Object invoke(Object object, Object[] arguments) {
+    	if ( !alreadySetAccessible ) {
+	    	AccessController.doPrivileged(new PrivilegedAction() {
+	    		public Object run() {
+	    			method.setAccessible(true);
+	                return null;
+	    		}
+	    	});
+	    	alreadySetAccessible = true;
+    	}
+
+        //        System.out.println("About to invoke method: " + method);
+        //        System.out.println("Object: " + object);
+        //        System.out.println("Using arguments: " + InvokerHelper.toString(arguments));
+
+        try {
+            return method.invoke(object, arguments);
+        } catch (IllegalArgumentException e) {
+            throw new InvokerInvocationException(e);
+        } catch (IllegalAccessException e) {
+            throw new InvokerInvocationException(e);
+        } catch (InvocationTargetException e) {
+            throw new InvokerInvocationException(e);
+        }
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/ReflectionMethodInvoker.java b/groovy-core/src/main/org/codehaus/groovy/runtime/ReflectionMethodInvoker.java
new file mode 100644
index 0000000..5f0f2cf
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/ReflectionMethodInvoker.java
@@ -0,0 +1,82 @@
+/*
+ $Id$
+
+ Copyright 2005 (C) Guillaume Laforge. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.runtime;
+
+import java.lang.reflect.Method;
+
+/**
+ * Utility class to call methods through reflection, and falls through using the <code>Invoker</code> to call the method if it fails.
+ * The class is particularly useful for Groovy classes implementing <code>GroovyIntercpetable</code>,
+ * since it is not possible to call any method from this class,
+ * because it is intercepted by the <code>invokeMethod()</code> method.
+ *
+ * @author Guillaume Laforge
+ */
+public class ReflectionMethodInvoker {
+
+    /**
+     * Invoke a method through reflection.
+     * Falls through to using the Invoker to call the method in case the reflection call fails..
+     *
+     * @param object the object on which to invoke a method
+     * @param methodName the name of the method to invoke
+     * @param parameters the parameters of the method call
+     * @return the result of the method call
+     */
+    public static Object invoke(Object object, String methodName, Object[] parameters) {
+        try {
+            Class[] classTypes = new Class[parameters.length];
+            for (int i = 0; i < classTypes.length; i++) {
+                classTypes[i] = parameters[i].getClass();
+            }
+            Method method = object.getClass().getMethod(methodName, classTypes);
+            return method.invoke(object, parameters);
+        } catch (Throwable t) {
+            return InvokerHelper.invokeMethod(object, methodName,  parameters);
+        }
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/Reflector.java b/groovy-core/src/main/org/codehaus/groovy/runtime/Reflector.java
new file mode 100644
index 0000000..ca5c720
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/Reflector.java
@@ -0,0 +1,56 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.MetaMethod;
+import groovy.lang.MissingMethodException;
+
+
+
+/**
+ * Provides as alternative to reflection using bytecode generation.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class Reflector {
+
+    public Object invoke(MetaMethod method, Object object, Object[] arguments) {
+        return noSuchMethod(method, object, arguments);
+    }
+
+    protected Object noSuchMethod(MetaMethod method, Object object, Object[] arguments) {
+        throw new MissingMethodException(method.getName(), method.getCallClass(), arguments, false);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/ReflectorLoader.java b/groovy-core/src/main/org/codehaus/groovy/runtime/ReflectorLoader.java
new file mode 100644
index 0000000..ca7ff7d
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/ReflectorLoader.java
@@ -0,0 +1,93 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) Jochen Theodorou. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package org.codehaus.groovy.runtime;
+
+import java.security.ProtectionDomain;
+import java.util.HashMap;
+
+/**
+ * Reflector creation helper. This class is used to define the Refloctor classes.
+ * For each ClassLoader such a Loader will be created by the MetaClass.
+ * The only special about this loader is, that it knows the class Reflector, 
+ * which is the base class of all runtime created Reflectors. 
+ * 
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * @version $Revision$
+ */
+public class ReflectorLoader extends ClassLoader {
+    private HashMap loadedClasses = new HashMap();
+    
+    /**
+     * returns the Reflector class.
+     * 
+     * @return the Reflector class if the name matches
+     * @throws ClassNotFoundException if the name is not matching Reflector
+     * @see Reflector
+     */
+    protected Class findClass(String name) throws ClassNotFoundException {
+        if (delegatationLoader==null) return super.loadClass(name);
+        return delegatationLoader.loadClass(name);
+    }
+    
+    /**
+     * helper method to define Reflector classes
+     * @param name of the Reflector
+     * @param bytecode the bytecode
+     * @param domain  the protection domain
+     * @return the generated class
+     */
+    public Class defineClass(String name, byte[] bytecode, ProtectionDomain domain) {
+        Class c = defineClass(name, bytecode, 0, bytecode.length, domain);
+        synchronized(loadedClasses) { loadedClasses.put(name,c); }
+        resolveClass(c);
+        return c;
+    }
+    
+    /**
+     * creates a RelfectorLoader. 
+     * @param parent the parent loader. This should never be null!
+     */
+    public ReflectorLoader(ClassLoader parent) {
+        super(parent);
+        delegatationLoader = getClass().getClassLoader();
+    }
+    
+    public Class getLoadedClass(String name) {
+        synchronized (loadedClasses) {
+            return (Class)loadedClasses.get(name);
+        }
+    }
+    
+    private ClassLoader delegatationLoader; 
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/RegexSupport.java b/groovy-core/src/main/org/codehaus/groovy/runtime/RegexSupport.java
new file mode 100644
index 0000000..74e91c8
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/RegexSupport.java
@@ -0,0 +1,23 @@
+package org.codehaus.groovy.runtime;
+
+import java.util.regex.Matcher;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: sam
+ * Date: May 17, 2004
+ * Time: 9:04:28 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class RegexSupport {
+
+    private static ThreadLocal currentMatcher = new ThreadLocal();
+
+    public static Matcher getLastMatcher() {
+        return (Matcher) currentMatcher.get();
+    }
+
+    public static void setLastMatcher(Matcher matcher) {
+        currentMatcher.set(matcher);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java b/groovy-core/src/main/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
new file mode 100644
index 0000000..190ae9f
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
@@ -0,0 +1,833 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.*;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.codehaus.groovy.runtime.wrappers.GroovyObjectWrapper;
+import org.codehaus.groovy.runtime.wrappers.PojoWrapper;
+import org.codehaus.groovy.runtime.wrappers.Wrapper;
+
+/**
+ * A static helper class to interface bytecode and runtime 
+ *
+ * @author Jochen Theodorou
+ * @version $Revision$
+ */
+public class ScriptBytecodeAdapter {
+    public static final Object[] EMPTY_ARGS = {};
+    private static final Integer ZERO = new Integer(0);
+    private static final Integer MINUS_ONE = new Integer(-1);
+    private static final Integer ONE = new Integer(1);
+
+    //  --------------------------------------------------------
+    //                   exception handling
+    //  --------------------------------------------------------
+    private static Object unwrap(GroovyRuntimeException gre) throws Throwable{
+        Throwable th = gre;
+        if (th.getCause()!=null && th.getCause()!=gre) th=th.getCause();
+        if (th!=gre && (th instanceof GroovyRuntimeException)) unwrap((GroovyRuntimeException) th);
+        throw th;
+    }
+    
+    //  --------------------------------------------------------
+    //                       methods for this
+    //  --------------------------------------------------------
+    public static Object invokeMethodOnCurrentN(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable{
+        Object result=null;
+        try {
+            try {
+                // if it's a pure interceptable object (even intercepting toString(), clone(), ...)
+                if (receiver instanceof GroovyInterceptable) {
+                    result = receiver.invokeMethod(messageName, messageArguments);
+                }
+                //else if there's a statically typed method or a GDK method
+                else {
+                    result = receiver.getMetaClass().invokeMethod(senderClass, receiver, messageName, messageArguments, false, true);
+                }
+            } catch (MissingMethodException e) {
+                if (receiver.getClass() == e.getType() && e.getMethod().equals(messageName)) {
+                    // in case there's nothing else, invoke the object's own invokeMethod()
+                    result = receiver.invokeMethod(messageName, messageArguments);
+                } else {
+                    throw e;
+                }
+            }
+        } catch (GroovyRuntimeException t) {
+            unwrap(t);
+        }
+        return result;
+    }
+    
+    public static Object invokeMethodOnCurrentNSafe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable{
+        return invokeMethodOnCurrentN(senderClass,receiver,messageName,messageArguments);
+    }
+    
+    public static Object invokeMethodOnCurrentNSpreadSafe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable{
+        if (! (receiver instanceof List)) return invokeMethodOnCurrentN(senderClass,receiver,messageName, messageArguments);
+        
+        List list = (List) receiver;
+        List answer = new ArrayList();
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            answer.add(invokeMethodNSafe(senderClass, it.next(), messageName, messageArguments));
+        }
+        return answer;
+    }
+    
+    public static Object invokeMethodOnCurrent0(Class senderClass, GroovyObject receiver, String messageName)  throws Throwable{
+        return invokeMethodOnCurrentN(senderClass,receiver,messageName,EMPTY_ARGS);
+    }
+    
+    public static Object invokeMethodOnCurrent0Safe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable{
+        return invokeMethodOnCurrentNSafe(senderClass,receiver,messageName,EMPTY_ARGS);
+    }
+    
+    public static Object invokeMethodOnCurrent0SpreadSafe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable{
+        return invokeMethodOnCurrentNSpreadSafe(senderClass,receiver,messageName,EMPTY_ARGS);
+    }
+    
+    //  --------------------------------------------------------
+    //                       methods for super
+    //  --------------------------------------------------------
+    public static Object invokeMethodOnSuperN(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable{
+        MetaClass metaClass = receiver.getMetaClass();
+        // ignore interception and missing method fallback
+        Object result=null;
+        try {
+            result = metaClass.invokeMethod(senderClass, receiver, messageName, messageArguments, true, true);
+        } catch (GroovyRuntimeException t) {
+            unwrap(t);
+        }
+        return result;        
+    }
+    
+    public static Object invokeMethodOnSuperNSafe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable{
+        return invokeMethodOnSuperN(senderClass,receiver,messageName,messageArguments);
+    }
+    
+    public static Object invokeMethodOnSuperNSpreadSafe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable{
+        if (! (receiver instanceof List)) return invokeMethodOnSuperN(senderClass,receiver,messageName, messageArguments);
+        
+        List list = (List) receiver;
+        List answer = new ArrayList();
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            answer.add(invokeMethodNSafe(senderClass,it.next(), messageName, messageArguments));
+        }
+        return answer;
+    }
+    
+    public static Object invokeMethodOnSuper0(Class senderClass, GroovyObject receiver, String messageName)  throws Throwable{
+        return invokeMethodOnSuperN(senderClass,receiver,messageName,EMPTY_ARGS);
+    }
+    
+    public static Object invokeMethodOnSuper0Safe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable{
+        return invokeMethodOnSuperNSafe(senderClass,receiver,messageName,EMPTY_ARGS);
+    }
+    
+    public static Object invokeMethodOnSuper0SpreadSafe(Class senderClass, GroovyObject receiver, String messageName, Object[] messageArguments) throws Throwable{
+        return invokeMethodOnSuperNSpreadSafe(senderClass,receiver,messageName,EMPTY_ARGS);
+    }
+
+    //  --------------------------------------------------------
+    //              normal method invocation
+    //  --------------------------------------------------------       
+    public static Object invokeMethodN(Class senderClass, Object receiver, String messageName, Object[] messageArguments) throws Throwable{
+        try {
+            return InvokerHelper.invokeMethod(receiver, messageName, messageArguments);
+        } catch (GroovyRuntimeException gre) {
+            return unwrap(gre);
+        }
+    }
+    
+    public static Object invokeMethodNSafe(Class senderClass, Object receiver, String messageName, Object[] messageArguments) throws Throwable{
+        if (receiver==null) return null;
+        return invokeMethodN(senderClass,receiver,messageName,messageArguments);
+    }
+    
+    public static Object invokeMethodNSpreadSafe(Class senderClass, Object receiver, String messageName, Object[] messageArguments) throws Throwable{
+        if (receiver==null) return null;
+        if (! (receiver instanceof List)) return invokeMethodN(senderClass,receiver,messageName, messageArguments);
+        
+        List list = (List) receiver;
+        List answer = new ArrayList();
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            answer.add(invokeMethodNSafe(senderClass, it.next(), messageName, messageArguments));
+        }
+        return answer;
+    }
+    
+    public static Object invokeMethod0(Class senderClass, Object receiver, String messageName)  throws Throwable{
+        return invokeMethodN(senderClass,receiver,messageName,EMPTY_ARGS);
+    }
+    
+    public static Object invokeMethod0Safe(Class senderClass, Object receiver, String messageName) throws Throwable{
+        if (receiver==null) return null;
+        return invokeMethodNSafe(senderClass,receiver,messageName,EMPTY_ARGS);
+    }
+    
+    public static Object invokeMethod0SpreadSafe(Class senderClass, Object receiver, String messageName) throws Throwable{
+        return invokeMethodNSpreadSafe(senderClass,receiver,messageName,EMPTY_ARGS);
+    }
+    
+    //  --------------------------------------------------------
+    //                static normal method invocation
+    //  --------------------------------------------------------       
+    public static Object invokeStaticMethodN(Class senderClass, Class receiver, String messageName, Object[] messageArguments) throws Throwable{
+        try {
+            return InvokerHelper.invokeStaticMethod(receiver, messageName, messageArguments);
+        } catch (GroovyRuntimeException gre) {
+            return unwrap(gre);
+        }
+    }
+    
+    public static Object invokeStaticMethod0(Class senderClass, Class receiver, String messageName)  throws Throwable{
+        return invokeStaticMethodN(senderClass,receiver,messageName,EMPTY_ARGS);
+    }
+    
+    //  --------------------------------------------------------
+    //              normal constructor invocation (via new)
+    //  --------------------------------------------------------       
+    public static Object invokeNewN(Class senderClass, Class receiver, Object arguments) throws Throwable{
+        try {
+            return InvokerHelper.invokeConstructorOf(receiver, arguments);
+        } catch (GroovyRuntimeException gre) {
+            return unwrap(gre);
+        }  
+    }
+    
+    public static Object invokeNew0(Class senderClass, Class receiver) throws Throwable {
+        return invokeNewN(senderClass, receiver, EMPTY_ARGS);
+    }
+
+    //  --------------------------------------------------------
+    //       special constructor invocation (via this/super)
+    //  --------------------------------------------------------       
+
+    public static int selectConstructorAndTransformArguments(Object[] arguments, int numberOfCosntructors, Class which) {
+        MetaClassImpl metaClass = (MetaClassImpl) InvokerHelper.getInstance().getMetaRegistry().getMetaClass(which);
+        return metaClass.selectConstructorAndTransformArguments(numberOfCosntructors, arguments);
+    }
+
+    //  --------------------------------------------------------
+    //              field handling super: get
+    //  --------------------------------------------------------       
+
+    public static Object getFieldOnSuper(Class senderClass, Object receiver, String messageName) throws Throwable{
+        try {
+            if (receiver instanceof Class) {
+                return InvokerHelper.getAttribute(receiver,messageName); 
+            } else {            
+                MetaClass mc = ((GroovyObject) receiver).getMetaClass();
+                return mc.getAttribute(senderClass, receiver, messageName, true);
+            }
+        } catch (GroovyRuntimeException gre) {
+            return unwrap(gre);
+        }
+    }
+    
+    public static Object getFieldOnSuperSafe(Class senderClass, Object receiver, String messageName) throws Throwable{
+        return getFieldOnSuper(senderClass,receiver,messageName);
+    }
+    
+    public static Object getFieldOnSuperSpreadSafe(Class senderClass, Object receiver, String messageName) throws Throwable{
+        if (! (receiver instanceof List)) return getFieldOnSuper(senderClass,receiver,messageName);
+        
+        List list = (List) receiver;
+        List answer = new ArrayList();
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            answer.add(getFieldOnSuper(senderClass, it.next(), messageName));
+        }
+        return answer;
+    }
+
+    //  --------------------------------------------------------
+    //              field handling super: set
+    //  --------------------------------------------------------       
+
+    public static void setFieldOnSuper(Object messageArgument,Class senderClass, Object receiver, String messageName) throws Throwable{
+        try {
+            if (receiver instanceof Class) {
+                InvokerHelper.setAttribute(receiver,messageName,messageArgument); 
+            } else {          
+                MetaClass mc = ((GroovyObject) receiver).getMetaClass();
+                mc.setAttribute(senderClass, receiver, messageName, messageArgument, true, true);
+            }
+        } catch (GroovyRuntimeException gre) {
+            unwrap(gre);
+        }
+    }
+    
+    public static void setFieldOnSuperSafe(Object messageArgument,Class senderClass, Object receiver, String messageName) throws Throwable{
+        setFieldOnSuper(messageArgument,senderClass,receiver,messageName);
+    }
+    
+    public static void setFieldOnSuperSpreadSafe(Object messageArgument,Class senderClass, Object receiver, String messageName) throws Throwable{
+        if (! (receiver instanceof List)) {
+            setFieldOnSuper(messageArgument,senderClass,receiver,messageName);
+            return;
+        }
+        
+        List list = (List) receiver;
+        List answer = new ArrayList();
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            setFieldOnSuper(messageArgument,senderClass, it.next(), messageName);
+        }
+    }
+
+    
+    //  --------------------------------------------------------
+    //              normal field handling : get
+    //  --------------------------------------------------------       
+
+    public static Object getField(Class senderClass, Object receiver, String messageName) throws Throwable{
+        try {
+            return InvokerHelper.getAttribute(receiver, messageName);
+        } catch (GroovyRuntimeException gre) {
+            return unwrap(gre);
+        }
+    }
+    
+    public static Object getFieldSafe(Class senderClass, Object receiver, String messageName) throws Throwable{
+        if (receiver==null) return null;
+        return getField(senderClass,receiver,messageName);
+    }
+    
+    public static Object getFieldSpreadSafe(Class senderClass, Object receiver, String messageName) throws Throwable{
+        if (receiver==null) return null;
+        if (! (receiver instanceof List)) return getField(senderClass,receiver,messageName);
+        
+        List list = (List) receiver;
+        List answer = new ArrayList();
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            answer.add(getFieldSafe(senderClass, it.next(), messageName));
+        }
+        return answer;
+    }
+
+    //  --------------------------------------------------------
+    //              normal field handling : set
+    //  --------------------------------------------------------       
+
+    public static void setField(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable{
+        try {
+            InvokerHelper.setAttribute(receiver, messageName,messageArgument);
+        } catch (GroovyRuntimeException gre) {
+            unwrap(gre);
+        }
+    }
+    
+    public static void setFieldSafe(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable{
+        if (receiver==null) return;
+        setField(messageArgument,senderClass,receiver,messageName);
+    }
+    
+    public static void setFieldSpreadSafe(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable{
+        if (receiver==null) return;
+        if (! (receiver instanceof List)) {
+            setField(messageArgument,senderClass,receiver,messageName);
+            return;
+        }
+        
+        List list = (List) receiver;
+        List answer = new ArrayList();
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            setFieldSafe(messageArgument,senderClass, it.next(), messageName);
+        }
+    }
+    
+    //  --------------------------------------------------------
+    //              normal GroovyObject field handling : get
+    //  --------------------------------------------------------       
+
+    public static Object getGroovyObjectField(Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        return receiver.getMetaClass().getAttribute(receiver,messageName);
+    }
+    
+    public static Object getGroovyObjectFieldSafe(Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        if (receiver==null) return null;
+        return receiver.getMetaClass().getAttribute(receiver,messageName);
+    }
+    
+    public static Object getGroovyObjectFieldSpreadSafe(Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        if (receiver==null) return null;
+        if (! (receiver instanceof List)) return getGroovyObjectField(senderClass,receiver,messageName);
+        
+        List list = (List) receiver;
+        List answer = new ArrayList();
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            answer.add(getFieldSafe(senderClass, it.next(), messageName));
+        }
+        return answer;
+    }
+
+    //  --------------------------------------------------------
+    //              normal field handling : set
+    //  --------------------------------------------------------       
+
+    public static void setGroovyObjectField(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        receiver.getMetaClass().setAttribute(receiver,messageName,messageArgument);
+    }
+    
+    public static void setGroovyObjectFieldSafe(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        if (receiver==null) return;
+        receiver.getMetaClass().setAttribute(receiver,messageName,messageArgument);
+    }
+    
+    public static void setGroovyObjectFieldSpreadSafe(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        if (receiver==null) return;
+        if (! (receiver instanceof List)) {
+            setGroovyObjectField(messageArgument,senderClass,receiver,messageName);
+            return;
+        }
+        
+        List list = (List) receiver;
+        List answer = new ArrayList();
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            setFieldSafe(messageArgument,senderClass, it.next(), messageName);
+        }
+    }
+
+    //  --------------------------------------------------------
+    //              Property handling super: get
+    //  --------------------------------------------------------       
+
+    public static Object getPropertyOnSuper(Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        return invokeMethodOnSuperN(senderClass, receiver, "getProperty", new Object[]{messageName});
+    }
+    
+    public static Object getPropertyOnSuperSafe(Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        return getPropertyOnSuper(senderClass,receiver,messageName);
+    }
+    
+    public static Object getPropertyOnSuperSpreadSafe(Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        if (! (receiver instanceof List)) return getPropertyOnSuper(senderClass,receiver,messageName);
+        
+        List list = (List) receiver;
+        List answer = new ArrayList();
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            answer.add(getPropertySafe(senderClass, it.next(), messageName));
+        }
+        return answer;
+    }
+
+    //  --------------------------------------------------------
+    //              Property handling super: set
+    //  --------------------------------------------------------       
+
+    public static void setPropertyOnSuper(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        try {
+            InvokerHelper.setAttribute(receiver, messageName,messageArgument);
+        } catch (GroovyRuntimeException gre) {
+            unwrap(gre);
+        }
+    }
+    
+    public static void setPropertyOnSuperSafe(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        setPropertyOnSuper(messageArgument, senderClass,receiver,messageName);
+    }
+    
+    public static void setPropertyOnSuperSpreadSafe(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        if (! (receiver instanceof List)) {
+            setPropertyOnSuper(messageArgument, senderClass,receiver,messageName);
+            return;
+        }
+        
+        List list = (List) receiver;
+        List answer = new ArrayList();
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            setPropertySafe(messageArgument, senderClass, it.next(), messageName);
+        }
+    }
+
+    
+    //  --------------------------------------------------------
+    //              normal Property handling : get
+    //  --------------------------------------------------------       
+
+    public static Object getProperty(Class senderClass, Object receiver, String messageName) throws Throwable{
+        try {
+            return InvokerHelper.getProperty(receiver, messageName);
+        } catch (GroovyRuntimeException gre) {
+            return unwrap(gre);
+        }
+    }
+    
+    public static Object getPropertySafe(Class senderClass, Object receiver, String messageName) throws Throwable{
+        if (receiver==null) return null;
+        return getProperty(senderClass,receiver,messageName);
+    }
+    
+    public static Object getPropertySpreadSafe(Class senderClass, Object receiver, String messageName) throws Throwable{
+        if (receiver==null) return null;
+        if (! (receiver instanceof List)) return getProperty(senderClass,receiver,messageName);
+        
+        List list = (List) receiver;
+        List answer = new ArrayList();
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            answer.add(getPropertySafe(senderClass, it.next(), messageName));
+        }
+        return answer;
+    }
+    
+    //  --------------------------------------------------------
+    //              normal Property handling : set
+    //  --------------------------------------------------------       
+
+    public static void setProperty(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable{
+        try {
+            InvokerHelper.setProperty(receiver, messageName,messageArgument);
+        } catch (GroovyRuntimeException gre) {
+            unwrap(gre);
+        }
+    }
+    
+    public static void setPropertySafe(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable{
+        if (receiver==null) return;
+        setProperty(messageArgument,senderClass,receiver,messageName);
+    }
+    
+    public static void setPropertySpreadSafe(Object messageArgument, Class senderClass, Object receiver, String messageName) throws Throwable{
+        if (receiver==null) return;
+        if (! (receiver instanceof List)) {
+            setProperty(messageArgument, senderClass, receiver, messageName);
+            return;
+        }
+        
+        List list = (List) receiver;
+        List answer = new ArrayList();
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            setPropertySafe(messageArgument, senderClass, it.next(), messageName);
+        }
+    }
+    
+    
+    //  --------------------------------------------------------
+    //              normal GroovyObject Property handling : get
+    //  --------------------------------------------------------       
+
+    public static Object getGroovyObjectProperty(Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        return receiver.getProperty(messageName);
+    }
+    
+    public static Object getGroovyObjectPropertySafe(Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        if (receiver==null) return null;
+        return receiver.getProperty(messageName);
+    }
+    
+    public static Object getGroovyObjectPropertySpreadSafe(Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        if (receiver==null) return null;
+        if (! (receiver instanceof List)) return getGroovyObjectProperty(senderClass,receiver,messageName);
+        
+        List list = (List) receiver;
+        List answer = new ArrayList();
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            answer.add(getPropertySafe(senderClass, it.next(), messageName));
+        }
+        return answer;
+    }
+
+    //  --------------------------------------------------------
+    //              normal GroovyObject Property handling : set
+    //  --------------------------------------------------------       
+
+    public static void setGroovyObjectProperty(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        receiver.setProperty(messageName,messageArgument);
+    }
+    
+    public static void setGroovyObjectPropertySafe(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        if (receiver==null) return;
+        receiver.setProperty(messageName,messageArgument);
+    }
+    
+    public static void setGroovyObjectPropertySpreadSafe(Object messageArgument, Class senderClass, GroovyObject receiver, String messageName) throws Throwable{
+        if (receiver==null) return;
+        if (! (receiver instanceof List)) {
+            setProperty(messageArgument, senderClass, receiver, messageName);
+            return;
+        }
+        
+        List list = (List) receiver;
+        List answer = new ArrayList();
+        for (Iterator it = list.iterator(); it.hasNext();) {
+            setPropertySafe(messageArgument, senderClass, it.next(), messageName);
+        }
+    }
+    
+    //  **********************************************************************************
+    //  **********************************************************************************
+    //  **************          methods not covered by the new MOP          **************
+    //  **********************************************************************************
+    //  **********************************************************************************
+    
+    //  --------------------------------------------------------
+    //                     Closures
+    //  --------------------------------------------------------           
+    
+    /**
+     * Returns the method pointer for the given object name
+     */
+    public static Closure getMethodPointer(Object object, String methodName) {
+        return InvokerHelper.getMethodPointer(object, methodName);
+    }
+    
+    // TODO: set sender class
+    public static Object invokeClosure(Object closure, Object[] arguments) throws Throwable {
+        return invokeMethodN(closure.getClass(), closure, "doCall", arguments);
+    } 
+        
+
+    //  --------------------------------------------------------
+    //                     type conversion
+    //  --------------------------------------------------------           
+          
+    /**
+     * Provides a hook for type coercion of the given object to the required type
+     *
+     * @param type   of object to convert the given object to
+     * @param object the object to be converted
+     * @return the original object or a new converted value
+     * @throws Throwable 
+     */
+    public static Object asType(Object object, Class type) throws Throwable {
+        return invokeMethodN(object.getClass(),object,"asType",new Object[]{type});
+    }
+    
+    /**
+     * Provides a hook for type casting of the given object to the required type
+     * 
+     * @param type   of object to convert the given object to
+     * @param object the object to be converted
+     * @return the original object or a new converted value
+     * @throws Throwable 
+     */
+    public static Object castToType(Object object, Class type) throws Throwable{
+        try {
+            return DefaultTypeTransformation.castToType(object,type);
+        } catch (GroovyRuntimeException gre) {
+            return (Matcher) unwrap(gre);
+        }
+    }    
+
+    public static Tuple createTuple(Object[] array) {
+        return new Tuple(array);
+    }
+
+    public static List createList(Object[] values) {
+        return InvokerHelper.createList(values);
+    }
+    
+    public static Wrapper createPojoWrapper(Object val, Class clazz) {
+        return new PojoWrapper(val,clazz);
+    }
+
+    public static Wrapper createGroovyObjectWrapper(GroovyObject val, Class clazz) {
+        return new GroovyObjectWrapper(val,clazz);
+    }
+    
+    public static Map createMap(Object[] values) {
+        return InvokerHelper.createMap(values);
+    }
+    
+
+    //TODO: refactor
+    public static List createRange(Object from, Object to, boolean inclusive) throws Throwable {
+        if (!inclusive) {
+            if (compareEqual(from,to)){
+                return new EmptyRange((Comparable)from);
+            }
+            if (compareGreaterThan(from, to)) {
+                to = invokeMethod0(ScriptBytecodeAdapter.class, to, "next");
+            }
+            else {
+                to = invokeMethod0(ScriptBytecodeAdapter.class, to, "previous");
+            }
+        }
+        if (from instanceof Integer && to instanceof Integer) {
+            return new IntRange(DefaultTypeTransformation.intUnbox(from), DefaultTypeTransformation.intUnbox(to));
+        }
+        else {
+            return new ObjectRange((Comparable) from, (Comparable) to);
+        }
+    }
+    
+    //assert
+    public static void assertFailed(Object expression, Object message) {
+        InvokerHelper.assertFailed(expression,message);
+    }
+
+    //isCase
+    //TODO: set sender class
+    public static boolean isCase(Object switchValue, Object caseExpression) throws Throwable{
+        if (caseExpression == null) {
+            return switchValue == null;
+        }
+        return DefaultTypeTransformation.castToBoolean(invokeMethodN(caseExpression.getClass(), caseExpression, "isCase", new Object[]{switchValue}));
+    }
+    
+    //compare
+    public static boolean compareIdentical(Object left, Object right) {
+        return left == right;
+    }
+    
+    public static boolean compareEqual(Object left, Object right) {
+        return DefaultTypeTransformation.compareEqual(left, right);
+    }
+    
+    public static boolean compareNotEqual(Object left, Object right) {
+        return !compareEqual(left, right);
+    }
+    
+    public static Integer compareTo(Object left, Object right) {
+        int answer = DefaultTypeTransformation.compareTo(left, right);
+        if (answer == 0) {
+            return ZERO;
+        }
+        else {
+            return answer > 0 ? ONE : MINUS_ONE;
+        }
+    }    
+
+    public static boolean compareLessThan(Object left, Object right) {
+        return compareTo(left, right).intValue() < 0;
+    }
+    
+    public static boolean compareLessThanEqual(Object left, Object right){
+        return compareTo(left, right).intValue() <= 0;
+    }
+    
+    public static boolean compareGreaterThan(Object left, Object right){
+        return compareTo(left, right).intValue() > 0;
+    }
+
+    public static boolean compareGreaterThanEqual(Object left, Object right){
+        return compareTo(left, right).intValue() >= 0;
+    }
+
+    //regexpr
+    public static Pattern regexPattern(Object regex) {
+        return DefaultGroovyMethods.negate(regex.toString());
+    }
+    
+    public static Matcher findRegex(Object left, Object right) throws Throwable{
+        try {
+            return InvokerHelper.findRegex(left, right);
+        } catch (GroovyRuntimeException gre) {
+            return (Matcher) unwrap(gre);
+        }
+    }
+    
+    public static boolean matchRegex(Object left, Object right) {
+        return InvokerHelper.matchRegex(left, right);
+    }
+    
+    
+    //spread expressions
+    public static Object[] despreadList(Object[] args, Object[] spreads, int[] positions) {
+        ArrayList ret = new ArrayList();
+        int argsPos = 0;
+        int spreadPos = 0;
+        for (int pos = 0; pos<positions.length; pos++) {
+            for (;argsPos<positions[pos];argsPos++) {
+                ret.add(args[argsPos]);
+            }
+            Object value = spreads[spreadPos];
+            if (value==null) {
+                ret.add(null);
+            } else if (value instanceof List) {
+                ret.addAll((List) value);
+            } else if (value.getClass().isArray()) {
+                ret.addAll(DefaultTypeTransformation.primitiveArrayToList(value));
+            } else {
+                throw new IllegalArgumentException("connot spread the type "+ value.getClass().getName()+" with value "+value);
+            }
+            spreadPos++;
+        }
+        for (;argsPos<args.length;argsPos++) {
+            ret.add(args[argsPos]);
+        }
+        return ret.toArray();
+    }
+    
+    public static Object spreadMap(Object value) {
+        return InvokerHelper.spreadMap(value);
+    }
+    
+    //negation
+    public static Object negate(Object value) throws Throwable {
+        try {
+            return InvokerHelper.negate(value);
+        } catch (GroovyRuntimeException gre) {
+            return unwrap(gre);
+        }
+    }
+    
+    public static Object bitNegate(Object value) {
+        return InvokerHelper.bitNegate(value);
+    }
+
+    public static MetaClass initMetaClass(Object object) {
+        return InvokerHelper.getMetaClass(object);
+    }
+    
+    private static MetaClass getMetaClassObjectNotNull(Object object) {
+        if (!(object instanceof GroovyObject)) {
+            return initMetaClass(object);
+        } else {
+            return ((GroovyObject) object).getMetaClass();
+        }        
+    }
+    
+    
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/ScriptReference.java b/groovy-core/src/main/org/codehaus/groovy/runtime/ScriptReference.java
new file mode 100644
index 0000000..d36ab7a
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/ScriptReference.java
@@ -0,0 +1,74 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.Reference;
+import groovy.lang.Script;
+
+/**
+ * Represents a reference to a variable in a script
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ScriptReference extends Reference {
+
+    private Script script;
+    private String variable;
+
+    public ScriptReference(Script script, String variable) {
+        this.script = script;
+        this.variable = variable;
+    }
+
+    public Object get() {
+        return script.getBinding().getVariable(variable);
+    }
+
+    public void set(Object value) {
+        script.getBinding().setVariable(variable, value);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/ScriptTestAdapter.java b/groovy-core/src/main/org/codehaus/groovy/runtime/ScriptTestAdapter.java
new file mode 100644
index 0000000..c958ee6
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/ScriptTestAdapter.java
@@ -0,0 +1,58 @@
+/**
+ *
+ * Copyright 2004 James Strachan
+ *
+ * Licensed 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.runtime;
+
+import junit.framework.Test;
+import junit.framework.TestResult;
+
+/**
+ * An adapter to make any Groovy Script class an instance of a JUnit Test
+ *
+ * @version $Revision$
+ */
+public class ScriptTestAdapter implements Test {
+    private Class scriptClass;
+    private String[] arguments;
+
+    public ScriptTestAdapter(Class scriptClass, String[] arguments) {
+        this.scriptClass = scriptClass;
+        this.arguments = arguments;
+    }
+
+    public int countTestCases() {
+        return 1;
+    }
+
+    public void run(TestResult result) {
+        try {
+            result.startTest(this);
+
+            // lets run the script
+            InvokerHelper.runScript(scriptClass, arguments);
+            result.endTest(this);
+        }
+        catch (Exception e) {
+            result.addError(this, e);
+        }
+    }
+
+    public String toString() {
+        return "TestCase for script: " + scriptClass.getName();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/StringBufferWriter.java b/groovy-core/src/main/org/codehaus/groovy/runtime/StringBufferWriter.java
new file mode 100644
index 0000000..4ffb7e0
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/StringBufferWriter.java
@@ -0,0 +1,120 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package org.codehaus.groovy.runtime;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * This class codes around a silly limiation of StringWriter which doesn't allow a StringBuffer
+ * to be passed in as a constructor for some bizzare reason.
+ * So we replicate the behaviour of StringWriter here but allow a StringBuffer to be passed in.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class StringBufferWriter extends Writer {
+
+    private StringBuffer buffer;
+
+    /**
+     * Create a new string writer which will append the text to the given StringBuffer
+     */
+    public StringBufferWriter(StringBuffer buffer) {
+        this.buffer = buffer;
+    }
+
+    /**
+     * Write a single character.
+     */
+    public void write(int c) {
+        buffer.append((char) c);
+    }
+
+    /**
+     * Write a portion of an array of characters.
+     *
+     * @param text Array of characters
+     * @param offset Offset from which to start writing characters
+     * @param length Number of characters to write
+     */
+    public void write(char text[], int offset, int length) {
+        if ((offset < 0) || (offset > text.length) || (length < 0) || ((offset + length) > text.length) || ((offset + length) < 0)) {
+            throw new IndexOutOfBoundsException();
+        }
+        else if (length == 0) {
+            return;
+        }
+        buffer.append(text, offset, length);
+    }
+
+    /**
+     * Write a string.
+     */
+    public void write(String text) {
+        buffer.append(text);
+    }
+
+    /**
+     * Write a portion of a string.
+     *
+     * @param text the text to be written
+     * @param offset offset from which to start writing characters
+     * @param length Number of characters to write
+     */
+    public void write(String text, int offset, int length) {
+        buffer.append(text.substring(offset, offset + length));
+    }
+
+    /**
+     * Return the buffer's current value as a string.
+     */
+    public String toString() {
+        return buffer.toString();
+    }
+
+    /**
+     * Flush the stream.
+     */
+    public void flush() {
+    }
+
+    /**
+     * Closing a <tt>StringWriter</tt> has no effect. The methods in this
+     * class can be called after the stream has been closed without generating
+     * an <tt>IOException</tt>.
+     */
+    public void close() throws IOException {
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/TemporaryMethodKey.java b/groovy-core/src/main/org/codehaus/groovy/runtime/TemporaryMethodKey.java
new file mode 100644
index 0000000..bb0cd87
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/TemporaryMethodKey.java
@@ -0,0 +1,73 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package org.codehaus.groovy.runtime;
+
+
+/**
+ * A temporary implementation of MethodKey used to perform a fast lookup
+ * for a method using a set of arguments to a method
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class TemporaryMethodKey extends MethodKey {
+
+    private Object[] parameterValues;
+
+    public TemporaryMethodKey(Class sender, String name, Object[] parameterValues, boolean isCallToSuper) {
+        super(sender, name, isCallToSuper);
+        if (parameterValues == null) {
+            parameterValues = MetaClassHelper.EMPTY_ARRAY;
+        }
+        this.parameterValues = parameterValues;
+    }
+
+    public int getParameterCount() {
+        return parameterValues.length;
+    }
+
+    public Class getParameterType(int index) {
+        Object value = parameterValues[index];
+
+        if (value != null ) {
+            Class type = (Class)((value.getClass() == java.lang.Class.class) ?
+                    value :
+                    value.getClass());
+            return type;
+        }
+
+        return Object.class;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/TransformMetaMethod.java b/groovy-core/src/main/org/codehaus/groovy/runtime/TransformMetaMethod.java
new file mode 100644
index 0000000..a7ae0e4
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/TransformMetaMethod.java
@@ -0,0 +1,58 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.MetaMethod;
+
+/**
+ * A MetaMethod implementation useful for implementing coercion based invocations
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+
+public class TransformMetaMethod extends MetaMethod {
+    
+    private MetaMethod metaMethod;
+
+    public TransformMetaMethod(MetaMethod metaMethod) {
+        super(metaMethod);
+        this.metaMethod = metaMethod;
+    }
+
+    public Object invoke(Object object, Object[] arguments) {
+        return metaMethod.invoke(object, arguments);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/WritableFile.java b/groovy-core/src/main/org/codehaus/groovy/runtime/WritableFile.java
new file mode 100644
index 0000000..1e5903d
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/WritableFile.java
@@ -0,0 +1,82 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) John Wilson. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.Writable;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+
+/**
+ * A Writable File.
+ *
+ * @author John Wilson
+ *
+ */
+public class WritableFile extends File implements Writable {
+    private final String encoding;
+
+    public WritableFile(final File delegate) {
+        this(delegate, null);
+    }
+
+    public WritableFile(final File delegate, final String encoding) {
+        super(delegate.toURI());
+        this.encoding = encoding;
+    }
+
+    public Writer writeTo(final Writer out) throws IOException {
+        final Reader reader =
+            (this.encoding == null)
+                ? DefaultGroovyMethods.newReader(this)
+                : DefaultGroovyMethods.newReader(this, this.encoding);
+
+        try {
+            int c = reader.read();
+
+            while (c != -1) {
+                out.write(c);
+                c = reader.read();
+            }
+        }
+        finally {
+            reader.close();
+        }
+        return out;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/package.html b/groovy-core/src/main/org/codehaus/groovy/runtime/package.html
new file mode 100644
index 0000000..0c86cdc
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/package.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>package org.codehaus.groovy.runtime.*</title>
+  </head>
+  <body>
+    <p>Runtime classes for Groovy - whether the dynamic interpreter is being used, the compiler or the bytecode generator.</p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/BigDecimalMath.java b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/BigDecimalMath.java
new file mode 100644
index 0000000..3df4a6f
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/BigDecimalMath.java
@@ -0,0 +1,72 @@
+package org.codehaus.groovy.runtime.typehandling;
+
+import java.math.BigDecimal;
+
+/**
+ * BigDecimal NumberMath operations
+ * 
+ * @author Steve Goetze
+ */
+public class BigDecimalMath extends NumberMath {
+
+	//This is an arbitrary value, picked as a reasonable choice for a rounding point
+	//for typical user math.
+	public static final int MAX_DIVISION_SCALE = 10;
+	
+	protected static BigDecimalMath instance = new BigDecimalMath();
+	
+	private BigDecimalMath() {}
+
+	protected Number absImpl(Number number) {
+		return toBigDecimal(number).abs();
+	}
+	
+	protected Number addImpl(Number left, Number right) {
+		return toBigDecimal(left).add(toBigDecimal(right));
+	}
+
+	protected Number subtractImpl(Number left, Number right) {
+		return toBigDecimal(left).subtract(toBigDecimal(right));
+	}
+
+	protected Number multiplyImpl(Number left, Number right) {
+		return toBigDecimal(left).multiply(toBigDecimal(right));
+	}
+
+	protected Number divideImpl(Number left, Number right) {
+		//Hack until Java 1.5 BigDecimal is available.  For now, pick
+		//a result scale which is the maximum of the scale of the
+		//two operands and an arbitrary maximum (similar to what a
+		//handheld calculator would do).  Then, normalize the result
+		//by removing any trailing zeros.
+		BigDecimal bigLeft = toBigDecimal(left);
+		BigDecimal bigRight = toBigDecimal(right);
+		int scale = Math.max(bigLeft.scale(), bigRight.scale());
+		return normalize(bigLeft.divide(bigRight, Math.max(scale, MAX_DIVISION_SCALE), BigDecimal.ROUND_HALF_UP));
+	}
+	
+	protected int compareToImpl(Number left, Number right) {
+		return toBigDecimal(left).compareTo(toBigDecimal(right));
+	}
+	
+	private BigDecimal normalize(BigDecimal number) {
+        // we have to take care of the case number==0, because 0 can have every
+        // scale and the test in the while loop would never end
+        if (number.signum()==0) {
+            // the smallest scale for 0 is 0
+            return number.setScale(0);
+        }
+        // rescale until we found the smallest possible scale
+		try {
+			while (true) {
+				number = number.setScale(number.scale()-1);
+			} 
+		} catch (ArithmeticException e) {
+			return number;
+		}
+	}
+
+    protected Number negateImpl(Number left) {
+        return toBigDecimal(left).negate();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/BigIntegerMath.java b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/BigIntegerMath.java
new file mode 100644
index 0000000..f62ef36
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/BigIntegerMath.java
@@ -0,0 +1,64 @@
+package org.codehaus.groovy.runtime.typehandling;
+
+/**
+ * BigInteger NumberMath operations
+ * 
+ * @author Steve Goetze
+ */
+public class BigIntegerMath extends NumberMath {
+
+	protected static BigIntegerMath instance = new BigIntegerMath();
+	
+	private BigIntegerMath() {}
+
+	protected Number absImpl(Number number) {
+		return toBigInteger(number).abs();
+	}
+	
+	protected Number addImpl(Number left, Number right) {
+		return toBigInteger(left).add(toBigInteger(right));
+	}
+	protected Number subtractImpl(Number left, Number right) {
+		return toBigInteger(left).subtract(toBigInteger(right));
+	}
+
+	protected Number multiplyImpl(Number left, Number right) {
+		return toBigInteger(left).multiply(toBigInteger(right));
+	}
+
+	protected Number divideImpl(Number left, Number right) {
+		return BigDecimalMath.instance.divideImpl(left, right);
+	}
+	
+	protected int compareToImpl(Number left, Number right) {
+		return toBigInteger(left).compareTo(toBigInteger(right));
+	}
+
+    protected Number intdivImpl(Number left, Number right) {
+        return toBigInteger(left).divide(toBigInteger(right));
+    }
+    
+    protected Number modImpl(Number left, Number right) {
+        return toBigInteger(left).mod(toBigInteger(right));
+    }
+    
+    protected Number negateImpl(Number left) {
+        return toBigInteger(left).negate();
+    }
+
+    protected Number bitNegateImpl(Number left) {
+        return toBigInteger(left).not();
+    }
+
+    protected Number orImpl(Number left, Number right) {
+        return toBigInteger(left).or(toBigInteger(right));
+    }
+
+    protected Number andImpl(Number left, Number right) {
+        return toBigInteger(left).and(toBigInteger(right));
+    }
+    
+    protected Number xorImpl(Number left, Number right) {
+        return toBigInteger(left).xor(toBigInteger(right));
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/ClassDistance.java b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/ClassDistance.java
new file mode 100644
index 0000000..da63058
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/ClassDistance.java
@@ -0,0 +1,143 @@
+/*

+ * Class for calculating "distances" between classes. Such a distance

+ * is not a real distance to something but should be seen as the order

+ * classes and interfaces are choosen for method selection. The class

+ * will keep a weak cache and recalculate the distances on demand. 

+ */

+package org.codehaus.groovy.runtime.typehandling;

+

+import java.io.Serializable;

+import java.math.BigDecimal;

+import java.math.BigInteger;

+import java.util.WeakHashMap;

+

+public class ClassDistance {

+    private static WeakHashMap classDistances;

+    

+    private static class Entry {

+        

+    }

+    

+    private static class LinearEntry  extends Entry{

+        Class[] entries;

+        void concat(Class[] c,LinearEntry le){

+            entries = new Class[c.length+le.entries.length];

+            System.arraycopy(c,0,entries,0,c.length);

+            System.arraycopy(le.entries,0,entries,c.length,le.entries.length);

+        }

+        void concat(Class c,LinearEntry le){

+            entries = new Class[1+le.entries.length];

+            entries[0] = c;

+            System.arraycopy(le.entries,0,entries,1,le.entries.length);

+        }

+    }

+    

+    static {

+        classDistances = new WeakHashMap();

+        initialPopulate();

+    }

+    

+    private static void initialPopulate() {

+        // int, double, byte, float, BigInteger, BigDecimal, long, short

+        // GString, char

+        

+        

+        LinearEntry object = new LinearEntry();

+        object.entries = new Class[]{Object.class};

+        classDistances.put(Object.class,object);

+        

+        LinearEntry number = new LinearEntry();

+        number.concat(new Class[]{Number.class,Serializable.class},object);

+        classDistances.put(Number.class,number);

+

+        LinearEntry compareableNumber = new LinearEntry();

+        compareableNumber.concat(Comparable.class,number);

+        

+        LinearEntry binteger = new LinearEntry();

+        binteger.concat(new Class[]{BigInteger.class, BigDecimal.class}, compareableNumber);

+        classDistances.put(BigInteger.class,object);

+        

+        LinearEntry bdec = new LinearEntry();

+        binteger.concat(new Class[]{BigDecimal.class, BigInteger.class}, compareableNumber);

+        classDistances.put(BigDecimal.class,object);

+        

+        

+        

+        // byte:

+        LinearEntry start = new LinearEntry();

+        start.entries =  new Class[]{

+                byte.class, Byte.class, short.class, Short.class,

+                int.class, Integer.class, long.class, Long.class,

+                BigInteger.class,

+                float.class, Float.class,  double.class, Double.class, 

+                BigDecimal.class,

+                Number.class,Object.class};

+        classDistances.put(byte.class,start);

+        

+        // short:

+        start = new LinearEntry();

+        start.entries =  new Class[]{

+                short.class, Short.class,

+                int.class, Integer.class, long.class, Long.class,

+                BigInteger.class,

+                float.class, Float.class,  double.class, Double.class, 

+                BigDecimal.class,

+                Number.class,Object.class};

+        classDistances.put(short.class,start);

+        

+        // int:

+        start = new LinearEntry();

+        start.entries =  new Class[]{

+                int.class, Integer.class, long.class, Long.class,

+                BigInteger.class,

+                float.class, Float.class,  double.class, Double.class, 

+                BigDecimal.class,

+                Number.class,Object.class};

+        classDistances.put(int.class,start);

+        

+        // long:

+        start = new LinearEntry();

+        start.entries =  new Class[]{

+                long.class, Long.class,

+                BigInteger.class,

+                float.class, Float.class,  double.class, Double.class, 

+                BigDecimal.class,

+                Number.class,Object.class};

+        classDistances.put(long.class,start);

+        

+        // Biginteger:

+        start = new LinearEntry();

+        start.entries =  new Class[]{

+                BigInteger.class,

+                float.class, Float.class,  double.class, Double.class, 

+                BigDecimal.class,

+                Number.class,Object.class};

+        classDistances.put(long.class,start);

+        

+        // float:

+        start = new LinearEntry();

+        start.entries =  new Class[]{ 

+                byte.class, Byte.class, short.class, Short.class,

+                int.class, Integer.class, long.class, Long.class,

+                BigInteger.class,

+                float.class, Float.class,  double.class, Double.class, 

+                BigDecimal.class,

+                Number.class,Object.class};

+        classDistances.put(float.class,start);

+        

+        // double:

+        start = new LinearEntry();

+        start.entries =  new Class[]{ 

+                double.class,

+                Double.class, BigDecimal.class,

+                Number.class,Object.class};

+        classDistances.put(double.class,start);

+

+    }

+    

+    private synchronized static void popultate(Class clazz) {

+        if (classDistances.get(clazz) != null) return;

+        

+    }

+    

+}

diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
new file mode 100644
index 0000000..b536dd8
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
@@ -0,0 +1,822 @@
+/*
+ * AutoBoxing.java created on 13.09.2006
+ *
+ * To change this generated comment go to 
+ * Window>Preferences>Java>Code Generation>Code and Comments
+ */
+package org.codehaus.groovy.runtime.typehandling;
+
+import groovy.lang.GString;
+import groovy.lang.GroovyRuntimeException;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.lang.reflect.Modifier;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.InvokerInvocationException;
+import org.codehaus.groovy.runtime.IteratorClosureAdapter;
+import org.codehaus.groovy.runtime.MethodClosure;
+import org.codehaus.groovy.runtime.RegexSupport;
+
+public class DefaultTypeTransformation {
+    
+    protected static final Object[] EMPTY_ARGUMENTS = {};
+    protected static final BigInteger ONE_NEG = new BigInteger("-1");
+    
+    //  --------------------------------------------------------
+    //                  unboxing methods
+    //  --------------------------------------------------------       
+    
+    public static byte byteUnbox(Object value) {
+        Number n = castToNumber(value);
+        return n.byteValue();
+    }
+
+    public static char charUnbox(Object value) {
+        return castToChar(value);
+    }
+
+    public static short shortUnbox(Object value) {
+        Number n = castToNumber(value);
+        return n.shortValue();
+    }
+
+    public static int intUnbox(Object value) {
+        Number n = castToNumber(value);
+        return n.intValue();
+    }
+
+    public static boolean booleanUnbox(Object value) {
+        return castToBoolean(value);
+    }
+
+    public static long longUnbox(Object value) {
+        Number n = castToNumber(value);
+        return n.longValue();
+    }
+
+    public static float floatUnbox(Object value) {
+        Number n = castToNumber(value);
+        return n.floatValue();
+    }
+
+    public static double doubleUnbox(Object value) {
+        Number n = castToNumber(value);
+        return n.doubleValue();
+    } 
+
+    //  --------------------------------------------------------
+    //                  boxing methods
+    //  --------------------------------------------------------       
+    
+    public static Object box(boolean value) {
+        return value ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    public static Object box(byte value) {
+        return new Byte(value);
+    }
+
+    public static Object box(char value) {
+        return new Character(value);
+    }
+
+    public static Object box(short value) {
+        return new Short(value);
+    }
+
+    public static Object box(int value) {
+        return IntegerCache.integerValue(value);
+    }
+
+    public static Object box(long value) {
+        return new Long(value);
+    }
+
+    public static Object box(float value) {
+        return new Float(value);
+    }
+
+    public static Object box(double value) {
+        return new Double(value);
+    }
+    
+    public static Number castToNumber(Object object) {
+        if (object instanceof Number) return (Number) object;
+        if (object instanceof Character) {
+            return new Integer(((Character) object).charValue());
+        } else if (object instanceof String) {
+            String c = (String) object;
+            if (c.length() == 1) {
+                return new Integer(c.charAt(0));
+            }
+            else {
+                throw new GroovyCastException(c,Integer.class);
+            }
+        }
+        throw new GroovyCastException(object,Number.class);
+    }
+    
+    public static boolean castToBoolean(Object object) {
+        if (object instanceof Boolean) {
+            Boolean booleanValue = (Boolean) object;
+            return booleanValue.booleanValue();
+        }
+        else if (object instanceof Matcher) {
+            Matcher matcher = (Matcher) object;
+            RegexSupport.setLastMatcher(matcher);
+            return matcher.find();
+        }
+        else if (object instanceof Collection) {
+            Collection collection = (Collection) object;
+            return !collection.isEmpty();
+        }
+        else if (object instanceof Map) {
+            Map map = (Map) object;
+            return !map.isEmpty();
+        }
+        else if (object instanceof String || object instanceof GString) {
+            String string =  object.toString();
+            return string.length() > 0;
+        } 
+        else if (object instanceof Character) {
+            Character c = (Character) object;
+            return c.charValue() != 0;
+        }
+        else if (object instanceof Number) {
+            Number n = (Number) object;
+            return n.doubleValue() != 0;
+        }
+        else {
+            return object != null;
+        }
+    }
+    
+    public static char castToChar(Object object) {
+        if (object instanceof Character) {
+            return ((Character) object).charValue();            
+        } else if (object instanceof Number) {
+            Number value = (Number) object;
+            return (char) value.intValue();
+        } else {
+            String text = object.toString();
+            if (text.length() == 1) {
+                return text.charAt(0);
+            }
+            else {
+                throw new GroovyCastException(text,char.class);
+            }
+        }
+    }
+    
+    public static Object castToType(Object object, Class type) {
+        if (object == null) {
+            return null;
+        }
+        
+        if (type == object.getClass()) return object;
+        
+        // TODO we should move these methods to groovy method, like g$asType() so that
+        // we can use operator overloading to customize on a per-type basis
+        if (type.isArray()) {
+            return asArray(object, type);
+
+        }
+        if (type.isInstance(object)) {
+            return object;
+        }
+        if (Collection.class.isAssignableFrom(type)) {
+            if (object.getClass().isArray()) {
+                Collection answer;
+                int modifiers = type.getModifiers();
+                if (type.isAssignableFrom(ArrayList.class) && (Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers))) {
+                    answer = new ArrayList();
+                } else {
+                    // lets call the collections constructor
+                    // passing in the list wrapper
+                    try {
+                        answer = (Collection) type.newInstance();
+                    }
+                    catch (Exception e) {
+                        throw new GroovyCastException("Could not instantiate instance of: " + type.getName() + ". Reason: " + e);
+                    }
+                }
+
+                // we cannot just wrap in a List as we support primitive type arrays
+                int length = Array.getLength(object);
+                for (int i = 0; i < length; i++) {
+                    Object element = Array.get(object, i);
+                    answer.add(element);
+                }
+                return answer;
+            }
+        }
+        if (type == String.class) {
+            return object.toString();
+        } else if (type == Character.class) {
+            return box(castToChar(object));
+        } else if (type == Boolean.class) {
+            return box(castToBoolean(object));
+        } else if (Number.class.isAssignableFrom(type)) {
+            Number n = castToNumber(object);
+            if (type == Byte.class) {
+                return new Byte(n.byteValue());
+            } else if (type == Character.class) {
+                return new Character((char) n.intValue());
+            } else if (type == Short.class) {
+                return new Short(n.shortValue());
+            } else if (type == Integer.class) {
+                return new Integer(n.intValue());
+            } else if (type == Long.class) {
+                return new Long(n.longValue());
+            } else if (type == Float.class) {
+                return new Float(n.floatValue());
+            } else if (type == Double.class) {
+                Double answer = new Double(n.doubleValue());
+                //throw a runtime exception if conversion would be out-of-range for the type.
+                if (!(n instanceof Double) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
+                        || answer.doubleValue() == Double.POSITIVE_INFINITY)) {
+                    throw new GroovyRuntimeException("Automatic coercion of " + n.getClass().getName()
+                            + " value " + n + " to double failed.  Value is out of range.");
+                }
+                return answer;
+            } else if (type == BigDecimal.class) {
+                return new BigDecimal(n.toString());
+            } else if (type == BigInteger.class) {
+                if (object instanceof Float || object instanceof Double) {
+                    BigDecimal bd = new BigDecimal(n.doubleValue());
+                    return bd.toBigInteger();
+                } else if (object instanceof BigDecimal) {
+                    return ((BigDecimal) object).toBigInteger();
+                } else {
+                    return new BigInteger(n.toString());
+                }
+            }
+        } else if (type.isPrimitive()) {
+            if (type == boolean.class) {
+               return box(booleanUnbox(object)); 
+            } else if (type == byte.class) {
+                return box(byteUnbox(object));
+            } else if (type == char.class) {
+                return box(charUnbox(object));
+            } else if (type == short.class) {
+                return box(shortUnbox(object));
+            } else if (type == int.class) {
+                return box(intUnbox(object));
+            } else if (type == long.class) {
+                return box(longUnbox(object));
+            } else if (type == float.class) {
+                return box(floatUnbox(object));
+            } else if (type == double.class) {
+                Double answer = new Double(doubleUnbox(object));
+                //throw a runtime exception if conversion would be out-of-range for the type.
+                if (!(object instanceof Double) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
+                        || answer.doubleValue() == Double.POSITIVE_INFINITY)) {
+                    throw new GroovyRuntimeException("Automatic coercion of " + object.getClass().getName()
+                            + " value " + object + " to double failed.  Value is out of range.");
+                }
+                return answer;
+            }
+        }
+        Object[] args = null;
+        if (object instanceof Collection) {
+            Collection list = (Collection) object;
+            args = list.toArray();
+        } else if (object instanceof Object[]) {
+            args = (Object[]) object;
+        } else if (object instanceof Map) {
+            // emulate named params constructor
+            args = new Object[1];
+            args[0] = object;
+        }
+        if (args != null) {
+            // lets try invoke the constructor with the list as arguments
+            // such as for creating a Dimension, Point, Color etc.
+            try {
+                return InvokerHelper.invokeConstructorOf(type, args);
+            } catch (InvokerInvocationException iie){
+                throw iie;
+            } catch (Exception e) {
+                // lets ignore exception and return the original object
+                // as the caller has more context to be able to throw a more
+                // meaningful exception
+            }
+        }
+        throw new GroovyCastException(object,type);
+    }
+    
+    public static Object asArray(Object object, Class type) {
+        Collection list = asCollection(object);
+        int size = list.size();
+        Class elementType = type.getComponentType();
+        Object array = Array.newInstance(elementType, size);
+        int idx = 0;
+
+        if (boolean.class.equals(elementType)) {
+            for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
+                Object element = iter.next();
+                Array.setBoolean(array, idx, booleanUnbox(element));
+            }
+        }
+        else if (byte.class.equals(elementType)) {
+            for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
+                Object element = iter.next();
+                Array.setByte(array, idx, byteUnbox(element));
+            }
+        }
+        else if (char.class.equals(elementType)) {
+            for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
+                Object element = iter.next();
+                Array.setChar(array, idx, charUnbox(element));
+            }
+        }
+        else if (double.class.equals(elementType)) {
+            for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
+                Object element = iter.next();
+                Array.setDouble(array, idx, doubleUnbox(element));
+            }
+        }
+        else if (float.class.equals(elementType)) {
+            for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
+                Object element = iter.next();
+                Array.setFloat(array, idx, floatUnbox(element));
+            }
+        }
+        else if (int.class.equals(elementType)) {
+            for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
+                Object element = iter.next();
+                Array.setInt(array, idx, intUnbox(element));
+            }
+        }
+        else if (long.class.equals(elementType)) {
+            for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
+                Object element = iter.next();
+                Array.setLong(array, idx, longUnbox(element));
+            }
+        }
+        else if (short.class.equals(elementType)) {
+            for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
+                Object element = iter.next();
+                Array.setShort(array, idx, shortUnbox(element));
+            }
+        }
+        else {
+            for (Iterator iter = list.iterator(); iter.hasNext(); idx++) {
+                Object element = iter.next();
+                Object coercedElement = castToType(element, elementType);
+                Array.set(array, idx, coercedElement);
+            }
+        }
+        return array;
+    }
+    
+    public static Collection asCollection(Object value) {
+        if (value == null) {
+            return Collections.EMPTY_LIST;
+        }
+        else if (value instanceof Collection) {
+            return (Collection) value;
+        }
+        else if (value instanceof Map) {
+            Map map = (Map) value;
+            return map.entrySet();
+        }
+        else if (value.getClass().isArray()) {
+            if (value.getClass().getComponentType().isPrimitive()) {
+                return primitiveArrayToList(value);
+            }
+            return Arrays.asList((Object[]) value);
+        }
+        else if (value instanceof MethodClosure) {
+            MethodClosure method = (MethodClosure) value;
+            IteratorClosureAdapter adapter = new IteratorClosureAdapter(method.getDelegate());
+            method.call(adapter);
+            return adapter.asList();
+        }
+        else if (value instanceof String) {
+            return DefaultGroovyMethods.toList((String) value);
+        }
+        else if (value instanceof File) {
+            try {
+                return DefaultGroovyMethods.readLines((File) value);
+            }
+            catch (IOException e) {
+                throw new GroovyRuntimeException("Error reading file: " + value, e);
+            }
+        }
+        else {
+            // lets assume its a collection of 1
+            return Collections.singletonList(value);
+        }
+    }
+    
+    /**
+     * Allows conversion of arrays into a mutable List
+     *
+     * @return the array as a List
+     */
+    public static List primitiveArrayToList(Object array) {
+        int size = Array.getLength(array);
+        List list = new ArrayList(size);
+        for (int i = 0; i < size; i++) {
+            list.add(Array.get(array, i));
+        }
+        return list;
+    }
+    
+    /**
+     * Compares the two objects handling nulls gracefully and performing numeric type coercion if required
+     */
+    public static int compareTo(Object left, Object right) {
+        if (left == right) {
+            return 0;
+        }
+        if (left == null) {
+            return -1;
+        }
+        else if (right == null) {
+            return 1;
+        }
+        if (left instanceof Comparable) {
+            if (left instanceof Number) {
+                if (isValidCharacterString(right)) {
+                    return castToChar(left) - castToChar(right);
+                } else if (right instanceof Character || right instanceof Number) {
+                    return DefaultGroovyMethods.compareTo((Number) left, castToNumber(right));
+                }
+            }
+            else if (left instanceof Character) {
+                if (isValidCharacterString(right)) {
+                    return castToChar(left) - castToChar(right);
+                }
+                else if (right instanceof Number) {
+                    return castToChar(left) - castToChar(right);
+                }
+            }
+            else if (right instanceof Number) {
+                if (isValidCharacterString(left)) {
+                    return castToChar(left) - castToChar(right);
+                } 
+            }
+            else if (left instanceof String && right instanceof Character) {
+                return ((String) left).compareTo(right.toString());
+            }
+            else if (left instanceof String && right instanceof GString) {
+                return ((String) left).compareTo(right.toString());
+            }
+            Comparable comparable = (Comparable) left;
+            return comparable.compareTo(right);
+        }
+
+        if (left.getClass().isArray()) {
+            Collection leftList = asCollection(left);
+            if (right.getClass().isArray()) {
+                right = asCollection(right);
+            }
+            return ((Comparable) leftList).compareTo(right);
+        }
+        throw new GroovyRuntimeException("Cannot compare values: " + left + " and " + right);
+    }
+    
+    public static boolean compareEqual(Object left, Object right) {
+        if (left == right) return true;
+        if (left == null || right == null) return false;
+        if (left instanceof Comparable) {
+            return compareTo(left, right) == 0;
+        } else if (left instanceof List && right instanceof List) {
+            return DefaultGroovyMethods.equals((List) left, (List) right);
+        } else {
+            return left.equals(right);
+        }
+    }
+    
+    /**
+     * @return true if the given value is a valid character string (i.e. has length of 1)
+     */
+    private static boolean isValidCharacterString(Object value) {
+        if (value instanceof String) {
+            String s = (String) value;
+            if (s.length() == 1) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * @param a    array of primitives
+     * @param type component type of the array
+     * @return
+     */
+    public static Object[] convertPrimitiveArray(Object a, Class type) {
+//        System.out.println("a.getClass() = " + a.getClass());
+        Object[] ans = null;
+        String elemType = type.getName();
+        if (elemType.equals("int")) {
+            // conservative coding
+            if (a.getClass().getName().equals("[Ljava.lang.Integer;")) {
+                ans = (Integer[]) a;
+            }
+            else {
+                int[] ia = (int[]) a;
+                ans = new Integer[ia.length];
+                for (int i = 0; i < ia.length; i++) {
+                    int e = ia[i];
+                    ans[i] = IntegerCache.integerValue(e);
+                }
+            }
+        }
+        else if (elemType.equals("char")) {
+            if (a.getClass().getName().equals("[Ljava.lang.Character;")) {
+                ans = (Character[]) a;
+            }
+            else {
+                char[] ia = (char[]) a;
+                ans = new Character[ia.length];
+                for (int i = 0; i < ia.length; i++) {
+                    char e = ia[i];
+                    ans[i] = new Character(e);
+                }
+            }
+        }
+        else if (elemType.equals("boolean")) {
+            if (a.getClass().getName().equals("[Ljava.lang.Boolean;")) {
+                ans = (Boolean[]) a;
+            }
+            else {
+                boolean[] ia = (boolean[]) a;
+                ans = new Boolean[ia.length];
+                for (int i = 0; i < ia.length; i++) {
+                    boolean e = ia[i];
+                    ans[i] = new Boolean(e);
+                }
+            }
+        }
+        else if (elemType.equals("byte")) {
+            if (a.getClass().getName().equals("[Ljava.lang.Byte;")) {
+                ans = (Byte[]) a;
+            }
+            else {
+                byte[] ia = (byte[]) a;
+                ans = new Byte[ia.length];
+                for (int i = 0; i < ia.length; i++) {
+                    byte e = ia[i];
+                    ans[i] = new Byte(e);
+                }
+            }
+        }
+        else if (elemType.equals("short")) {
+            if (a.getClass().getName().equals("[Ljava.lang.Short;")) {
+                ans = (Short[]) a;
+            }
+            else {
+                short[] ia = (short[]) a;
+                ans = new Short[ia.length];
+                for (int i = 0; i < ia.length; i++) {
+                    short e = ia[i];
+                    ans[i] = new Short(e);
+                }
+            }
+        }
+        else if (elemType.equals("float")) {
+            if (a.getClass().getName().equals("[Ljava.lang.Float;")) {
+                ans = (Float[]) a;
+            }
+            else {
+                float[] ia = (float[]) a;
+                ans = new Float[ia.length];
+                for (int i = 0; i < ia.length; i++) {
+                    float e = ia[i];
+                    ans[i] = new Float(e);
+                }
+            }
+        }
+        else if (elemType.equals("long")) {
+            if (a.getClass().getName().equals("[Ljava.lang.Long;")) {
+                ans = (Long[]) a;
+            }
+            else {
+                long[] ia = (long[]) a;
+                ans = new Long[ia.length];
+                for (int i = 0; i < ia.length; i++) {
+                    long e = ia[i];
+                    ans[i] = new Long(e);
+                }
+            }
+        }
+        else if (elemType.equals("double")) {
+            if (a.getClass().getName().equals("[Ljava.lang.Double;")) {
+                ans = (Double[]) a;
+            }
+            else {
+                double[] ia = (double[]) a;
+                ans = new Double[ia.length];
+                for (int i = 0; i < ia.length; i++) {
+                    double e = ia[i];
+                    ans[i] = new Double(e);
+                }
+            }
+        }
+        return ans;
+    }
+
+    public static int[] convertToIntArray(Object a) {
+        int[] ans = null;
+
+        // conservative coding
+        if (a.getClass().getName().equals("[I")) {
+            ans = (int[]) a;
+        }
+        else {
+            Object[] ia = (Object[]) a;
+            ans = new int[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                if (ia[i] == null) {
+                    continue;
+                }
+                ans[i] = ((Number) ia[i]).intValue();
+            }
+        }
+        return ans;
+    }
+
+    public static boolean[] convertToBooleanArray(Object a) {
+        boolean[] ans = null;
+
+        // conservative coding
+        if (a.getClass().getName().equals("[Z")) {
+            ans = (boolean[]) a;
+        }
+        else {
+            Object[] ia = (Object[]) a;
+            ans = new boolean[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                if (ia[i] == null) {
+                    continue;
+                }
+                ans[i] = ((Boolean) ia[i]).booleanValue();
+            }
+        }
+        return ans;
+    }
+
+    public static byte[] convertToByteArray(Object a) {
+        byte[] ans = null;
+
+        // conservative coding
+        if (a.getClass().getName().equals("[B")) {
+            ans = (byte[]) a;
+        }
+        else {
+            Object[] ia = (Object[]) a;
+            ans = new byte[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                if (ia[i] != null) {
+                    ans[i] = ((Number) ia[i]).byteValue();
+                }
+            }
+        }
+        return ans;
+    }
+
+    public static short[] convertToShortArray(Object a) {
+        short[] ans = null;
+
+        // conservative coding
+        if (a.getClass().getName().equals("[S")) {
+            ans = (short[]) a;
+        }
+        else {
+            Object[] ia = (Object[]) a;
+            ans = new short[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                ans[i] = ((Number) ia[i]).shortValue();
+            }
+        }
+        return ans;
+    }
+
+    public static char[] convertToCharArray(Object a) {
+        char[] ans = null;
+
+        // conservative coding
+        if (a.getClass().getName().equals("[C")) {
+            ans = (char[]) a;
+        }
+        else {
+            Object[] ia = (Object[]) a;
+            ans = new char[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                if (ia[i] == null) {
+                    continue;
+                }
+                ans[i] = ((Character) ia[i]).charValue();
+            }
+        }
+        return ans;
+    }
+
+    public static long[] convertToLongArray(Object a) {
+        long[] ans = null;
+
+        // conservative coding
+        if (a.getClass().getName().equals("[J")) {
+            ans = (long[]) a;
+        }
+        else {
+            Object[] ia = (Object[]) a;
+            ans = new long[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                if (ia[i] == null) {
+                    continue;
+                }
+                ans[i] = ((Number) ia[i]).longValue();
+            }
+        }
+        return ans;
+    }
+
+    public static float[] convertToFloatArray(Object a) {
+        float[] ans = null;
+
+        // conservative coding
+        if (a.getClass().getName().equals("[F")) {
+            ans = (float[]) a;
+        }
+        else {
+            Object[] ia = (Object[]) a;
+            ans = new float[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                if (ia[i] == null) {
+                    continue;
+                }
+                ans[i] = ((Number) ia[i]).floatValue();
+            }
+        }
+        return ans;
+    }
+
+    public static double[] convertToDoubleArray(Object a) {
+        double[] ans = null;
+
+        // conservative coding
+        if (a.getClass().getName().equals("[D")) {
+            ans = (double[]) a;
+        }
+        else {
+            Object[] ia = (Object[]) a;
+            ans = new double[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                if (ia[i] == null) {
+                    continue;
+                }
+                ans[i] = ((Number) ia[i]).doubleValue();
+            }
+        }
+        return ans;
+    }
+
+    public static Object convertToPrimitiveArray(Object a, Class type) {
+        if (type == Byte.TYPE) {
+            return convertToByteArray(a);
+        }
+        if (type == Boolean.TYPE) {
+            return convertToBooleanArray(a);
+        }
+        if (type == Short.TYPE) {
+            return convertToShortArray(a);
+        }
+        if (type == Character.TYPE) {
+            return convertToCharArray(a);
+        }
+        if (type == Integer.TYPE) {
+            return convertToIntArray(a);
+        }
+        if (type == Long.TYPE) {
+            return convertToLongArray(a);
+        }
+        if (type == Float.TYPE) {
+            return convertToFloatArray(a);
+        }
+        if (type == Double.TYPE) {
+            return convertToDoubleArray(a);
+        }
+        else {
+            return a;
+        }
+    }
+    
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/FloatingPointMath.java b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/FloatingPointMath.java
new file mode 100644
index 0000000..02cc4d4
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/FloatingPointMath.java
@@ -0,0 +1,44 @@
+package org.codehaus.groovy.runtime.typehandling;
+
+/**
+ * FloatingPoint (Double and Float) NumberMath operations
+ * 
+ * @author Steve Goetze
+ */
+public class FloatingPointMath extends NumberMath {
+
+	protected static FloatingPointMath instance = new FloatingPointMath();
+	
+	private FloatingPointMath() {}
+				
+	protected Number absImpl(Number number) {
+		return new Double(Math.abs(number.doubleValue()));
+	}
+	
+	protected Number addImpl(Number left, Number right) {
+		return new Double(left.doubleValue() + right.doubleValue());
+	}
+
+	protected Number subtractImpl(Number left, Number right) {
+		return new Double(left.doubleValue() - right.doubleValue());
+	}
+
+	protected Number multiplyImpl(Number left, Number right) {
+		return new Double(left.doubleValue() * right.doubleValue());
+	}
+
+	protected Number divideImpl(Number left, Number right) {
+		return new Double(left.doubleValue() / right.doubleValue());
+	}
+	protected int compareToImpl(Number left, Number right) {
+		return Double.compare(left.doubleValue(), right.doubleValue());
+	}
+    
+    protected Number modImpl(Number left, Number right) {
+        return new Double(left.doubleValue() % right.doubleValue());
+    }
+    
+    protected Number negateImpl(Number left) {
+        return new Double(-left.doubleValue());
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/GroovyCastException.java b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/GroovyCastException.java
new file mode 100644
index 0000000..61620cc
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/GroovyCastException.java
@@ -0,0 +1,32 @@
+/*

+ * GroovyCastException.java created on 21.11.2006

+ *

+ * To change this generated comment go to 

+ * Window>Preferences>Java>Code Generation>Code and Comments

+ */

+package org.codehaus.groovy.runtime.typehandling;

+

+public class GroovyCastException extends ClassCastException {

+

+    public GroovyCastException(Object objectToCast, Class classToCastTo) {

+        super(makeMessage(objectToCast,classToCastTo));

+    }

+

+    public GroovyCastException(String string) {

+        super(string);

+    }

+

+    private static String makeMessage(Object objectToCast, Class classToCastTo) {

+       String classToCastFrom;

+       if (objectToCast!=null) {

+           classToCastFrom = objectToCast.getClass().getName();

+       } else {

+           objectToCast = "null";

+           classToCastFrom = "null";

+       }

+       return "Cannot cast object '" + objectToCast + "' " +

+              "with class '" + classToCastFrom + "' " +

+              "to class '" + classToCastTo.getName() + "'";

+    }

+

+}

diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/IntegerCache.java b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/IntegerCache.java
new file mode 100644
index 0000000..7e380d8
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/IntegerCache.java
@@ -0,0 +1,20 @@
+package org.codehaus.groovy.runtime.typehandling;

+

+public class IntegerCache {

+    private IntegerCache(){}

+    

+    static final Integer cache[] = new Integer[-(-128) + 127 + 1];

+    

+    static {

+        for(int i = 0; i < cache.length; i++)

+            cache[i] = new Integer(i - 128);

+    }

+    

+    public static Integer integerValue(int i) {

+        final int offset = 128;

+        if (i >= -128 && i <= 127) { // must cache 

+            return cache[i + offset];

+        }

+        return new Integer(i);

+    }

+}
\ No newline at end of file
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/IntegerMath.java b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/IntegerMath.java
new file mode 100644
index 0000000..5af4512
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/IntegerMath.java
@@ -0,0 +1,84 @@
+/*
+ * Created on Mar 5, 2004
+ *
+ */
+package org.codehaus.groovy.runtime.typehandling;
+
+
+/**
+ * Integer NumberMath operations
+ * 
+ * @author Steve Goetze
+ */
+public class IntegerMath extends NumberMath {
+
+	protected static IntegerMath instance = new IntegerMath();
+
+	private IntegerMath() {}
+					
+	protected Number absImpl(Number number) {
+		return new Integer(Math.abs(number.intValue()));
+	}
+	
+	protected Number addImpl(Number left, Number right) {
+		return new Integer(left.intValue() + right.intValue());
+	}
+
+	protected Number subtractImpl(Number left, Number right) {
+		return new Integer(left.intValue() - right.intValue());
+	}
+
+	protected Number multiplyImpl(Number left, Number right) {
+		return new Integer(left.intValue() * right.intValue());
+	}
+
+	protected Number divideImpl(Number left, Number right) {
+		return BigDecimalMath.instance.divideImpl(left, right);
+	}
+	
+	protected int compareToImpl(Number left, Number right) {
+		int leftVal = left.intValue();
+		int rightVal = right.intValue();
+		return (leftVal<rightVal ? -1 : (leftVal==rightVal ? 0 : 1));
+	}
+
+    protected Number orImpl(Number left, Number right) {
+        return new Integer(left.intValue() | right.intValue());
+    }
+
+    protected Number andImpl(Number left, Number right) {
+        return new Integer(left.intValue() & right.intValue());
+    }
+
+    protected Number xorImpl(Number left, Number right) {
+        return new Integer(left.intValue() ^ right.intValue());
+    }
+
+    protected Number intdivImpl(Number left, Number right) {
+        return new Integer(left.intValue() / right.intValue());
+    }
+	
+    protected Number modImpl(Number left, Number right) {
+        return new Integer(left.intValue() % right.intValue());
+    }
+
+    protected Number negateImpl(Number left) {
+        return new Integer(-left.intValue());
+    }
+
+    protected Number bitNegateImpl(Number left) {
+        return new Integer(~left.intValue());
+    }
+
+    protected Number leftShiftImpl(Number left, Number right) {
+        return new Integer(left.intValue() << right.intValue());
+    }
+
+    protected Number rightShiftImpl(Number left, Number right) {
+        return new Integer(left.intValue() >> right.intValue());
+    }
+
+    protected Number rightShiftUnsignedImpl(Number left, Number right) {
+        return new Integer(left.intValue() >>> right.intValue());
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/LongMath.java b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/LongMath.java
new file mode 100644
index 0000000..325d660
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/LongMath.java
@@ -0,0 +1,87 @@
+/*
+ * Created on Mar 5, 2004
+ *
+ */
+package org.codehaus.groovy.runtime.typehandling;
+
+/**
+ * Long NumberMath operations
+ * 
+ * @author Steve Goetze
+ */
+public class LongMath extends NumberMath {
+
+	protected static LongMath instance = new LongMath();
+
+	private LongMath() {}
+					
+	protected Number absImpl(Number number) {
+		return new Long(Math.abs(number.longValue()));
+	}
+	
+	protected Number addImpl(Number left, Number right) {
+		return new Long(left.longValue() + right.longValue());
+	}
+
+	protected Number subtractImpl(Number left, Number right) {
+		return new Long(left.longValue() - right.longValue());
+	}
+
+	protected Number multiplyImpl(Number left, Number right) {
+		return new Long(left.longValue() * right.longValue());
+	}
+
+	protected Number divideImpl(Number left, Number right) {
+		return BigDecimalMath.instance.divideImpl(left, right);
+	}
+	
+	protected int compareToImpl(Number left, Number right) {
+		long leftVal = left.longValue();
+		long rightVal = right.longValue();
+		return (leftVal<rightVal ? -1 : (leftVal==rightVal ? 0 : 1));
+	}
+
+	protected Number intdivImpl(Number left, Number right) {
+        return new Long(left.longValue() / right.longValue());
+	}
+	
+    protected Number modImpl(Number left, Number right) {
+        return new Long(left.longValue() % right.longValue());
+    }
+    
+    protected Number negateImpl(Number left) {
+        return new Long(-left.longValue());
+    }
+    
+    protected Number bitNegateImpl(Number left) {
+        return new Long(~left.longValue());
+    }
+    
+    protected Number orImpl(Number left, Number right) {
+        return new Long(left.longValue() | right.longValue());
+    }
+
+    protected Number andImpl(Number left, Number right) {
+        return new Long(left.longValue() & right.longValue());
+    }
+    
+    protected Number xorImpl(Number left, Number right) {
+        return new Long(left.longValue() ^ right.longValue());
+    }
+    
+    protected Number leftShiftImpl(Number left, Number right) {
+        return new Long(left.longValue() << right.longValue());
+    }
+
+    protected Number rightShiftImpl(Number left, Number right) {
+        return new Long(left.longValue() >> right.longValue());
+    }
+
+    protected Number rightShiftUnsignedImpl(Number left, Number right) {
+        return new Long(left.longValue() >>> right.longValue());
+    }
+
+    protected Number bitAndImpl(Number left, Number right) {
+        return new Long(left.longValue() & right.longValue());
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/NumberMath.java b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/NumberMath.java
new file mode 100644
index 0000000..0074dd2
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/NumberMath.java
@@ -0,0 +1,250 @@
+/*
+ * Created on Mar 7, 2004
+ *
+ */
+package org.codehaus.groovy.runtime.typehandling;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+
+/**
+ * Stateless objects used to perform math on the various Number subclasses.
+ * Instances are required so that polymorphic calls work properly, but each
+ * subclass creates a singleton instance to minimize garbage.  All methods
+ * must be thread-safe.
+ * 
+ * The design goals of this class are as follows:
+ * <ol>
+ * <li>Support a 'least surprising' math model to scripting language users.  This
+ * means that exact, or decimal math should be used for default calculations.  This
+ * scheme assumes that by default, groovy literals with decimal points are instantiated
+ * as BigDecimal objects rather than binary floating points (Float, Double). 
+ * <li>Do not force the appearance of exactness on a number that is by definition not 
+ * guaranteed to be exact.  In particular this means that if an operand in a NumberMath 
+ * operation is a binary floating point number, ensure that the result remains a binary floating point 
+ * number (i.e. never automatically promote a binary floating point number to a BigDecimal).  
+ * This has the effect of preserving the expectations of binary floating point users and helps performance.
+ * <li>Provide an implementation that is as close as practical to the Java 1.5 BigDecimal math model 
+ * which implements precision based floating point decimal math (ANSI X3.274-1996 and 
+ * ANSI X3.274-1996/AM 1-2000 (section 7.4).  
+ * </ol>
+ * 
+ * @author Steve Goetze
+ */
+public abstract class NumberMath extends Object {
+		
+	public static Number abs(Number number) {
+		return getMath(number).absImpl(number);
+	}
+	
+	public static Number add(Number left, Number right) {
+		return getMath(left, right).addImpl(left,right);
+	}
+	
+	public static Number subtract(Number left, Number right) {
+		return getMath(left,right).subtractImpl(left,right);
+	}
+	
+	public static Number multiply(Number left, Number right) {
+		return getMath(left,right).multiplyImpl(left,right);
+	}
+	
+	public static Number divide(Number left, Number right) {
+		return getMath(left,right).divideImpl(left,right);
+ 	}
+ 	 
+	public static int compareTo(Number left, Number right) {
+		return getMath(left,right).compareToImpl(left, right);
+	}
+	
+    public static Number or(Number left, Number right) {
+        return getMath(left,right).orImpl(left, right);
+    }
+    
+    public static Number and(Number left, Number right) {
+        return getMath(left,right).andImpl(left, right);
+    }
+    
+    public static Number xor(Number left, Number right) {
+        return getMath(left,right).xorImpl(left, right);
+    }
+    
+	public static Number intdiv(Number left, Number right) {
+		return getMath(left,right).intdivImpl(left,right);
+ 	}
+
+	public static Number mod(Number left, Number right) {
+        return getMath(left,right).modImpl(left, right);
+    }
+
+    /**
+     * For this operation, consider the operands independently.  Throw an exception if the right operand
+     * (shift distance) is not an integral type.  For the left operand (shift value) also require an integral
+     * type, but do NOT promote from Integer to Long.  This is consistent with Java, and makes sense for the
+     * shift operators.
+     */
+    public static Number leftShift(Number left, Number right) {
+		if (isFloatingPoint(right) || isBigDecimal(right)) {
+	        throw new UnsupportedOperationException("Shift distance must be an integral type, but " +  right + " (" + right.getClass().getName() + ") was supplied");
+		}
+    	return getMath(left).leftShiftImpl(left,right);
+    }
+    
+    /**
+     * For this operation, consider the operands independently.  Throw an exception if the right operand
+     * (shift distance) is not an integral type.  For the left operand (shift value) also require an integral
+     * type, but do NOT promote from Integer to Long.  This is consistent with Java, and makes sense for the
+     * shift operators.
+     */
+    public static Number rightShift(Number left, Number right) {
+		if (isFloatingPoint(right) || isBigDecimal(right)) {
+	        throw new UnsupportedOperationException("Shift distance must be an integral type, but " +  right + " (" + right.getClass().getName() + ") was supplied");
+		}
+    	return getMath(left).rightShiftImpl(left,right);
+    }
+    
+    /**
+     * For this operation, consider the operands independently.  Throw an exception if the right operand
+     * (shift distance) is not an integral type.  For the left operand (shift value) also require an integral
+     * type, but do NOT promote from Integer to Long.  This is consistent with Java, and makes sense for the
+     * shift operators.
+     */
+    public static Number rightShiftUnsigned(Number left, Number right) {
+		if (isFloatingPoint(right) || isBigDecimal(right)) {
+	        throw new UnsupportedOperationException("Shift distance must be an integral type, but " +  right + " (" + right.getClass().getName() + ") was supplied");
+		}
+    	return getMath(left).rightShiftUnsignedImpl(left,right);
+    }
+    
+    public static Number negate(Number left) {
+        return getMath(left).negateImpl(left);
+    }
+    
+    public static boolean isFloatingPoint(Number number) {
+		return number instanceof Double || number instanceof Float;
+	}
+
+	public static boolean isInteger(Number number) {
+		return number instanceof Integer;
+	}
+
+	public static boolean isLong(Number number) {
+		return number instanceof Long;
+	}
+
+	public static boolean isBigDecimal(Number number) {
+		return number instanceof BigDecimal;
+	}
+
+	public static boolean isBigInteger(Number number) {
+		return number instanceof BigInteger;
+	}
+
+	public static BigDecimal toBigDecimal(Number n) {
+		return (n instanceof BigDecimal ? (BigDecimal) n : new BigDecimal(n.toString()));
+	}
+				
+	public static BigInteger toBigInteger(Number n) {
+		return (n instanceof BigInteger ? (BigInteger) n : new BigInteger(n.toString()));
+	}
+					
+	/**
+	 * Determine which NumberMath instance to use, given the supplied operands.  This method implements
+	 * the type promotion rules discussed in the documentation.  Note that by the time this method is
+	 * called, any Byte, Character or Short operands will have been promoted to Integer.  For reference,
+	 * here is the promotion matrix:
+	 *    bD bI  D  F  L  I
+	 * bD bD bD  D  D bD bD
+	 * bI bD bI  D  D bI bI
+	 *  D  D  D  D  D  D  D
+	 *  F  D  D  D  D  D  D
+	 *  L bD bI  D  D  L  L
+	 *  I bD bI  D  D  L  I
+	 * 
+	 * Note that for division, if either operand isFloatingPoint, the result will be floating.  Otherwise,
+	 * the result is BigDecimal
+	 */
+	private static NumberMath getMath(Number left, Number right) {
+		if (isFloatingPoint(left) || isFloatingPoint(right)) {
+			return FloatingPointMath.instance;
+		}
+		else if (isBigDecimal(left) || isBigDecimal(right)) {
+			return BigDecimalMath.instance;
+		}
+		else if (isBigInteger(left) || isBigInteger(right)) {
+			return BigIntegerMath.instance;
+		}
+		else if (isLong(left) || isLong(right)){
+			return LongMath.instance;
+		}
+		return IntegerMath.instance;
+	}
+
+	private static NumberMath getMath(Number number) {
+		if (isInteger(number)) {
+			return IntegerMath.instance;
+		}
+		else if (isLong(number)) {
+			return LongMath.instance;
+		}
+		else if (isFloatingPoint(number)) {
+			return FloatingPointMath.instance;
+		}			
+		else if (isBigDecimal(number)) {
+			return BigDecimalMath.instance;
+		}
+		else if (isBigInteger(number)) {
+			return BigIntegerMath.instance;
+		}
+		else {
+			throw new IllegalArgumentException("An unexpected Number subclass was supplied.");
+		}
+	}
+	
+	//Subclasses implement according to the type promotion hierarchy rules
+	protected abstract Number absImpl(Number number);
+	protected abstract Number addImpl(Number left, Number right);
+	protected abstract Number subtractImpl(Number left, Number right);
+	protected abstract Number multiplyImpl(Number left, Number right);
+	protected abstract Number divideImpl(Number left, Number right);
+	protected abstract int compareToImpl(Number left, Number right);
+    protected abstract Number negateImpl(Number left);
+
+
+    protected Number orImpl(Number left, Number right) {
+        throw createUnsupportedException("or()", left);
+    }
+    
+    protected Number andImpl(Number left, Number right) {
+        throw createUnsupportedException("and()", left);
+    }
+
+    protected Number xorImpl(Number left, Number right) {
+        throw createUnsupportedException("xor()", left);
+    }
+    
+    protected Number modImpl(Number left, Number right) {
+        throw createUnsupportedException("mod()", left);
+    }
+    
+    protected Number intdivImpl(Number left, Number right) {
+        throw createUnsupportedException("intdiv()", left);
+    }
+    
+    protected Number leftShiftImpl(Number left, Number right) {
+        throw createUnsupportedException("leftShift()", left);
+    }
+
+    protected Number rightShiftImpl(Number left, Number right) {
+        throw createUnsupportedException("rightShift()", left);
+    }
+
+    protected Number rightShiftUnsignedImpl(Number left, Number right) {
+        throw createUnsupportedException("rightShiftUnsigned()", left);
+    }
+
+    protected UnsupportedOperationException createUnsupportedException(String operation, Number left) {
+        return new UnsupportedOperationException("Cannot use " + operation + " on this number type: " + left.getClass().getName() + " with value: " + left);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/package.html b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/package.html
new file mode 100644
index 0000000..9ee7a92
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/typehandling/package.html
@@ -0,0 +1,10 @@
+<html>

+  <head>

+    <title>package org.codehaus.groovy.runtime.typehandling*</title>

+  </head>

+  <body>

+    <p>Classes used to execute special actions based on the type. 

+    This includes mathematic operations and wrapper classes.

+    </p>

+  </body>

+</html>

diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/BooleanWrapper.java b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/BooleanWrapper.java
new file mode 100644
index 0000000..df55cfb
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/BooleanWrapper.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2006 John G. Wilson
+ *
+ * Licensed 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.runtime.wrappers;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class BooleanWrapper extends PojoWrapper {
+  public BooleanWrapper(final boolean wrapped) {
+    super(wrapped ? Boolean.TRUE : Boolean.FALSE, boolean.class);
+  }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/ByteWrapper.java b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/ByteWrapper.java
new file mode 100644
index 0000000..1416e86
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/ByteWrapper.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2006 John G. Wilson
+ *
+ * Licensed 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.runtime.wrappers;
+
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class ByteWrapper extends PojoWrapper {
+  public ByteWrapper(final byte wrapped) {
+    super(new Byte(wrapped), byte.class);
+  }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/CharWrapper.java b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/CharWrapper.java
new file mode 100644
index 0000000..3fa9766
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/CharWrapper.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2006 John G. Wilson
+ *
+ * Licensed 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.runtime.wrappers;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class CharWrapper extends PojoWrapper {
+  public CharWrapper(final char wrapped) {
+    super(new Character(wrapped), char.class);
+  }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/DoubleWrapper.java b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/DoubleWrapper.java
new file mode 100644
index 0000000..8879502
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/DoubleWrapper.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2006 John G. Wilson
+ *
+ * Licensed 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.runtime.wrappers;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class DoubleWrapper extends PojoWrapper {
+  public DoubleWrapper(final double wrapped) {
+    super(new Double(wrapped), double.class);
+  }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/FloatWrapper.java b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/FloatWrapper.java
new file mode 100644
index 0000000..8068766
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/FloatWrapper.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2006 John G. Wilson
+ *
+ * Licensed 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.runtime.wrappers;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class FloatWrapper extends PojoWrapper {
+  public FloatWrapper(final float wrapped) {
+    super(new Float(wrapped), float.class);
+  }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/GroovyObjectWrapper.java b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/GroovyObjectWrapper.java
new file mode 100644
index 0000000..018a7b1
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/GroovyObjectWrapper.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2006 John G. Wilson
+ *
+ * Licensed 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.runtime.wrappers;
+
+import groovy.lang.GroovyObject;
+import groovy.lang.MetaClass;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class GroovyObjectWrapper extends Wrapper {
+  protected final GroovyObject wrapped;
+  
+  public GroovyObjectWrapper(final GroovyObject wrapped, final Class constrainedType) {
+    super(constrainedType);
+    this.wrapped = wrapped;
+  }
+  
+  public Object unwrap() {
+    return this.wrapped;
+  }
+  
+  /**
+   * Note the rest of these method will only be used post 1.0
+   */
+
+  /* (non-Javadoc)
+   * @see groovy.lang.GroovyObject#getProperty(java.lang.String)
+   */
+  public Object getProperty(final String property) {
+    return this.wrapped.getProperty(property);
+  }
+
+  /* (non-Javadoc)
+   * @see groovy.lang.GroovyObject#invokeMethod(java.lang.String, java.lang.Object)
+   */
+  public Object invokeMethod(final String name, final Object args) {
+    return this.wrapped.invokeMethod(name, args);
+  }
+
+  /* (non-Javadoc)
+   * @see groovy.lang.GroovyObject#setMetaClass(groovy.lang.MetaClass)
+   */
+  public void setMetaClass(final MetaClass metaClass) {
+    this.wrapped.setMetaClass(metaClass);
+  }
+
+  /* (non-Javadoc)
+   * @see groovy.lang.GroovyObject#setProperty(java.lang.String, java.lang.Object)
+   */
+  public void setProperty(final String property, final Object newValue) {
+    this.wrapped.setProperty(property, newValue);
+  }
+
+  protected Object getWrapped() {
+    return this.wrapped;
+  }
+
+  protected MetaClass getDelegatedMetaClass() {
+    return this.wrapped.getMetaClass();
+  }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/IntWrapper.java b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/IntWrapper.java
new file mode 100644
index 0000000..b6ae250
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/IntWrapper.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2006 John G. Wilson
+ *
+ * Licensed 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.runtime.wrappers;
+
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class IntWrapper extends PojoWrapper {
+  public IntWrapper(final int wrapped) {
+    super(new Integer(wrapped), int.class);
+  }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/LongWrapper.java b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/LongWrapper.java
new file mode 100644
index 0000000..af7e663
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/LongWrapper.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2006 John G. Wilson
+ *
+ * Licensed 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.runtime.wrappers;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class LongWrapper extends PojoWrapper {
+  public LongWrapper(final long wrapped) {
+    super(new Long(wrapped), long.class);
+  }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/PojoWrapper.java b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/PojoWrapper.java
new file mode 100644
index 0000000..ac4232b
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/PojoWrapper.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2006 John G. Wilson
+ *
+ * Licensed 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.runtime.wrappers;
+
+import groovy.lang.MetaClass;
+
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class PojoWrapper extends Wrapper {
+  protected MetaClass delegate;
+  protected final Object wrapped;
+  
+  public PojoWrapper(final Object wrapped, final Class constrainedType) {
+    super(constrainedType);
+    this.wrapped = wrapped;
+    
+    /*
+     * This check is temporary - remove before 1.0 release
+     */
+//    if (wrapped instanceof GroovyObject) {
+//      throw new RuntimeException("trying to wrap the groovyObject "
+//                                 + wrapped.getClass().getName()
+//                                 + " in a PojoWrapper");
+//    }
+  }
+  
+  public Object unwrap() {
+    return this.wrapped;
+  }
+  
+  /**
+   * Note the rest of these method will only be used post 1.0
+   */
+
+  /* (non-Javadoc)
+   * @see groovy.lang.GroovyObject#getProperty(java.lang.String)
+   */
+  public Object getProperty(final String property) {
+    return this.delegate.getProperty(this.wrapped, property);
+  }
+
+  /* (non-Javadoc)
+   * @see groovy.lang.GroovyObject#invokeMethod(java.lang.String, java.lang.Object)
+   */
+  public Object invokeMethod(final String methodName, final Object arguments) {
+    return this.delegate.invokeMethod(this.wrapped, methodName, arguments);
+  }
+
+  /* (non-Javadoc)
+   * @see groovy.lang.GroovyObject#setMetaClass(groovy.lang.MetaClass)
+   */
+  public void setMetaClass(final MetaClass metaClass) {
+    this.delegate = metaClass;
+  }
+
+  /* (non-Javadoc)
+   * @see groovy.lang.GroovyObject#setProperty(java.lang.String, java.lang.Object)
+   */
+  public void setProperty(final String property, final Object newValue) {
+    this.delegate.setProperty(this.wrapped, property, newValue);
+  }
+
+  protected Object getWrapped() {
+    return this.wrapped;
+  }
+
+  protected MetaClass getDelegatedMetaClass() {
+    return this.delegate;
+  }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/ShortWrapper.java b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/ShortWrapper.java
new file mode 100644
index 0000000..7a9e96b
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/ShortWrapper.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2006 John G. Wilson
+ *
+ * Licensed 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.runtime.wrappers;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class ShortWrapper extends PojoWrapper {
+  public ShortWrapper(final short wrapped) {
+    super(new Short(wrapped), short.class);
+  }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/Wrapper.java b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/Wrapper.java
new file mode 100644
index 0000000..768c9b3
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/runtime/wrappers/Wrapper.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2006 John G. Wilson
+ *
+ * Licensed 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.runtime.wrappers;
+
+//import java.lang.reflect.Constructor;
+//import java.lang.reflect.Method;
+//import java.util.List;
+//import java.util.Map;
+//
+//import org.codehaus.groovy.ast.ClassNode;
+
+import groovy.lang.GroovyObject;
+import groovy.lang.MetaClass;
+//import groovy.lang.MetaMethod;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public abstract class Wrapper implements GroovyObject {
+    protected MetaClass delegatingMetaClass;
+    
+//  protected MetaClass delegatingMetaClass = new MetaClass(Object.class) {
+//    /**
+//     * @param obj
+//     * @see java.lang.Object#equals(java.lang.Object)
+//     */
+//    public boolean equals(Object obj) {
+//      return Wrapper.this.getDelegatedMetaClass().equals(obj);
+//    }
+//
+//    /**
+//     * @param object
+//     * @param attribute
+//     * @see groovy.lang.MetaClass#getAttribute(java.lang.Object, java.lang.String)
+//     */
+//    public Object getAttribute(Object object, String attribute) {
+//      return Wrapper.this.getDelegatedMetaClass().getAttribute(Wrapper.this.getWrapped(), attribute);
+//    }
+//
+//    /**
+//     * @see groovy.lang.MetaClass#getClassNode()
+//     */
+//    public ClassNode getClassNode() {
+//      return Wrapper.this.getDelegatedMetaClass().getClassNode();
+//    }
+//
+//    /**
+//     * @see groovy.lang.MetaClass#getMetaMethods()
+//     */
+//    public List getMetaMethods() {
+//      return Wrapper.this.getDelegatedMetaClass().getMetaMethods();
+//    }
+//
+//    /**
+//     * @see groovy.lang.MetaClass#getMethods()
+//     */
+//    public List getMethods() {
+//      return Wrapper.this.getDelegatedMetaClass().getMethods();
+//    }
+//
+//    /**
+//     * @see groovy.lang.MetaClass#getProperties()
+//     */
+//    public List getProperties() {
+//      return Wrapper.this.getDelegatedMetaClass().getProperties();
+//    }
+//
+//    /**
+//     * @param object
+//     * @param property
+//     * @see groovy.lang.MetaClass#getProperty(java.lang.Object, java.lang.String)
+//     */
+//    public Object getProperty(Object object, String property) {
+//      return Wrapper.this.getDelegatedMetaClass().getProperty(Wrapper.this.getWrapped(), property);
+//    }
+//
+//    /**
+//     * @see java.lang.Object#hashCode()
+//     */
+//    public int hashCode() {
+//      return Wrapper.this.getDelegatedMetaClass().hashCode();
+//    }
+//
+//    /**
+//     * @param arguments
+//     * @see groovy.lang.MetaClass#invokeConstructor(java.lang.Object[])
+//     */
+//    public Object invokeConstructor(Object[] arguments) {
+//      return Wrapper.this.getDelegatedMetaClass().invokeConstructor(arguments);
+//    }
+//
+//    /**
+//     * @param at
+//     * @param arguments
+//     * @see groovy.lang.MetaClass#invokeConstructorAt(java.lang.Class, java.lang.Object[])
+//     */
+//    public Object invokeConstructorAt(Class at, Object[] arguments) {
+//      return Wrapper.this.getDelegatedMetaClass().invokeConstructorAt(at, arguments);
+//    }
+//
+//    /**
+//     * @param object
+//     * @param methodName
+//     * @param arguments
+//     * @see groovy.lang.MetaClass#invokeMethod(java.lang.Object, java.lang.String, java.lang.Object)
+//     */
+//    public Object invokeMethod(Object object, String methodName, Object arguments) {
+//      return Wrapper.this.getDelegatedMetaClass().invokeMethod(Wrapper.this.getWrapped(), methodName, arguments);
+//    }
+//
+//    /**
+//     * @param object
+//     * @param methodName
+//     * @param arguments
+//     * @see groovy.lang.MetaClass#invokeMethod(java.lang.Object, java.lang.String, java.lang.Object[])
+//     */
+//    public Object invokeMethod(Object object, String methodName, Object[] arguments) {
+//      return Wrapper.this.getDelegatedMetaClass().invokeMethod(Wrapper.this.getWrapped(), methodName, arguments);
+//    }
+//
+//    /**
+//     * @param object
+//     * @param methodName
+//     * @param arguments
+//     * @see groovy.lang.MetaClass#invokeStaticMethod(java.lang.Object, java.lang.String, java.lang.Object[])
+//     */
+//    public Object invokeStaticMethod(Object object, String methodName, Object[] arguments) {
+//      return Wrapper.this.getDelegatedMetaClass().invokeStaticMethod(Wrapper.this.getWrapped(), methodName, arguments);
+//    }
+//
+//    /**
+//     * @param arguments
+//     * @see groovy.lang.MetaClass#retrieveConstructor(java.lang.Class[])
+//     */
+//    public Constructor retrieveConstructor(Class[] arguments) {
+//      return Wrapper.this.getDelegatedMetaClass().retrieveConstructor(arguments);
+//    }
+//
+//    /**
+//     * @param owner
+//     * @param methodName
+//     * @param arguments
+//     * @see groovy.lang.MetaClass#retrieveMethod(java.lang.Object, java.lang.String, java.lang.Object[])
+//     */
+//    public MetaMethod retrieveMethod(Object owner, String methodName, Object[] arguments) {
+//      return Wrapper.this.getDelegatedMetaClass().retrieveMethod(owner, methodName, arguments);
+//    }
+//
+//    /**
+//     * @param methodName
+//     * @param arguments
+//     * @see groovy.lang.MetaClass#retrieveMethod(java.lang.String, java.lang.Class[])
+//     */
+//    public MetaMethod retrieveMethod(String methodName, Class[] arguments) {
+//      return Wrapper.this.getDelegatedMetaClass().retrieveMethod(methodName, arguments);
+//    }
+//
+//    /**
+//     * @param methodName
+//     * @param arguments
+//     * @see groovy.lang.MetaClass#retrieveStaticMethod(java.lang.String, java.lang.Class[])
+//     */
+//    public MetaMethod retrieveStaticMethod(String methodName, Class[] arguments) {
+//      return Wrapper.this.getDelegatedMetaClass().retrieveStaticMethod(methodName, arguments);
+//    }
+//
+//    /**
+//     * @param object
+//     * @param attribute
+//     * @param newValue
+//     * @see groovy.lang.MetaClass#setAttribute(java.lang.Object, java.lang.String, java.lang.Object)
+//     */
+//    public void setAttribute(Object object, String attribute, Object newValue) {
+//      Wrapper.this.getDelegatedMetaClass().setAttribute(Wrapper.this.getWrapped(), attribute, newValue);
+//    }
+//
+//    /**
+//     * @param bean
+//     * @param map
+//     * @see groovy.lang.MetaClass#setProperties(java.lang.Object, java.util.Map)
+//     */
+//    public void setProperties(Object bean, Map map) {
+//      Wrapper.this.getDelegatedMetaClass().setProperties(Wrapper.this.getWrapped(), map);
+//    }
+//
+//    /**
+//     * @param object
+//     * @param property
+//     * @param newValue
+//     * @see groovy.lang.MetaClass#setProperty(java.lang.Object, java.lang.String, java.lang.Object)
+//     */
+//    public void setProperty(Object object, String property, Object newValue) {
+//      Wrapper.this.getDelegatedMetaClass().setProperty(Wrapper.this.getWrapped(), property, newValue);
+//    }
+//
+//    /**
+//     * @see java.lang.Object#toString()
+//     */
+//    public String toString() {
+//      return Wrapper.this.getDelegatedMetaClass().toString();
+//    }
+//
+//    /* (non-Javadoc)
+//     * @see groovy.lang.MetaClass#addNewInstanceMethod(java.lang.reflect.Method)
+//     */
+//    public void addNewInstanceMethod(Method method) {
+//      Wrapper.this.getDelegatedMetaClass().addNewInstanceMethod(method);
+//    }
+//
+//    /* (non-Javadoc)
+//     * @see groovy.lang.MetaClass#addNewStaticMethod(java.lang.reflect.Method)
+//     */
+//    public void addNewStaticMethod(Method method) {
+//      Wrapper.this.getDelegatedMetaClass().addNewStaticMethod(method);
+//    }
+//
+//    /* (non-Javadoc)
+//     * @see groovy.lang.MetaClass#checkInitialised()
+//     */
+//    public void checkInitialised() {
+//      Wrapper.this.getDelegatedMetaClass().checkInitialised();
+//    }
+//
+//    /* (non-Javadoc)
+//     * @see groovy.lang.MetaClass#pickMethod(java.lang.Object, java.lang.String, java.lang.Object[])
+//     */
+//    public MetaMethod pickMethod(Object object, String methodName, Object[] arguments) {
+//      return Wrapper.this.getDelegatedMetaClass().pickMethod(object, methodName, arguments);
+//    }
+//
+//    /* (non-Javadoc)
+//     * @see groovy.lang.MetaClass#pickMethod(java.lang.String, java.lang.Class[])
+//     */
+//    public MetaMethod pickMethod(String methodName, Class[] arguments) {
+//      return Wrapper.this.getDelegatedMetaClass().pickMethod(methodName, arguments);
+//    }
+//  };
+  
+  protected final Class constrainedType;
+  
+  public Wrapper(final Class constrainedType) {
+    this.constrainedType = constrainedType;
+  }
+
+  /* (non-Javadoc)
+   * @see groovy.lang.GroovyObject#getMetaClass()
+   * 
+   * This will only be useful post 1.0
+   */
+  public MetaClass getMetaClass() {
+    return this.delegatingMetaClass;
+  }
+  
+  public abstract Object unwrap();
+  
+  public Class getType() {
+    return this.constrainedType;
+  }
+  
+  protected abstract Object getWrapped();
+  protected abstract MetaClass getDelegatedMetaClass();
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/sandbox/ui/Completer.java b/groovy-core/src/main/org/codehaus/groovy/sandbox/ui/Completer.java
new file mode 100644
index 0000000..49c0077
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/sandbox/ui/Completer.java
@@ -0,0 +1,7 @@
+package org.codehaus.groovy.sandbox.ui;
+
+import java.util.List;
+
+public interface Completer {
+  List findCompletions(String token);
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/sandbox/ui/JavaPrompt.java b/groovy-core/src/main/org/codehaus/groovy/sandbox/ui/JavaPrompt.java
new file mode 100644
index 0000000..a7c900b
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/sandbox/ui/JavaPrompt.java
@@ -0,0 +1,64 @@
+package org.codehaus.groovy.sandbox.ui;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+/**
+ * Pure Java prompt using just System.in.
+ */
+public class JavaPrompt implements Prompt
+{
+    private String prompt;
+    private BufferedReader input;
+    private final PrintStream out;
+    private final PrintStream err;
+
+    public JavaPrompt(InputStream in, PrintStream out, PrintStream err)
+    {
+        this.out = out;
+        this.err = err;
+        this.input = new BufferedReader(new InputStreamReader(in));
+    }
+
+    public JavaPrompt()
+    {
+        this(System.in, System.out, System.err);
+    }
+
+    public String readLine() throws IOException
+    {
+        out.print(prompt);
+        out.flush();
+        return input.readLine();
+    }
+
+    public String getPrompt()
+    {
+        return prompt;
+    }
+
+    public void setPrompt(String prompt)
+    {
+        this.prompt = prompt;
+    }
+
+    public void setCompleter(Completer completer)
+    {
+        // completer not supported
+    }
+
+    public void close()
+    {
+        try
+        {
+            input.close();
+        }
+        catch (IOException e)
+        {
+            e.printStackTrace(err);
+        }
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/sandbox/ui/Prompt.java b/groovy-core/src/main/org/codehaus/groovy/sandbox/ui/Prompt.java
new file mode 100644
index 0000000..3258951
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/sandbox/ui/Prompt.java
@@ -0,0 +1,13 @@
+package org.codehaus.groovy.sandbox.ui;
+
+import java.io.IOException;
+
+public interface Prompt {
+  String readLine() throws IOException;
+  
+  void setCompleter(Completer completer);
+  
+  void setPrompt(String prompt);
+  
+  void close();
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/sandbox/ui/PromptFactory.java b/groovy-core/src/main/org/codehaus/groovy/sandbox/ui/PromptFactory.java
new file mode 100644
index 0000000..f69077e
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/sandbox/ui/PromptFactory.java
@@ -0,0 +1,31 @@
+package org.codehaus.groovy.sandbox.ui;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+
+/**
+ * Factory to build a command line prompt.  Should build the most featureful
+ * prompt available.
+ * <p/>
+ * Currently readline prompt will be looked up dynamically, and defaults to
+ * normal System.in prompt.
+ */
+public class PromptFactory
+{
+    public static Prompt buildPrompt(InputStream in, PrintStream out, PrintStream err)
+    {
+        try
+        {
+            return (Prompt) Class.forName("org.codehaus.groovy.sandbox.ui.ReadlinePrompt").newInstance();
+        }
+        catch (ClassNotFoundException e)
+        {
+            return new JavaPrompt(in, out, err);
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+            return new JavaPrompt(in, out, err);
+        }
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/syntax/ASTHelper.java b/groovy-core/src/main/org/codehaus/groovy/syntax/ASTHelper.java
new file mode 100644
index 0000000..8668117
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/syntax/ASTHelper.java
@@ -0,0 +1,309 @@
+/**
+ *
+ * Copyright 2004 James Strachan
+ *
+ * Licensed 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.syntax;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.control.SourceUnit;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A common base class of AST helper methods which can be shared across the classic and new parsers
+ *
+ * @author Jochen Theodorou
+ * @author James Strachan
+ * @author Bob McWhirter
+ * @author Sam Pullara
+ * @author Chris Poirier
+ * @version $Revision$
+ */
+public class ASTHelper {
+
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+    /** The SourceUnit controlling us */
+    private SourceUnit controller;
+
+    /** Our ClassLoader, which provides information on external types */
+    private ClassLoader classLoader;
+
+    /** Our imports, simple name => fully qualified name */
+    private Map imports;
+    protected ModuleNode output;
+
+    /** The package name in which the module sits */
+    private String packageName;   //
+
+    // TODO should this really be static???
+    protected static HashMap resolutions = new HashMap();  // cleared on build(), to be safe
+
+    private static String NOT_RESOLVED = new String();
+
+    /** temporarily store the class names that the current modulenode contains */
+    private List newClasses = new ArrayList();
+
+    public ASTHelper(SourceUnit controller, ClassLoader classLoader) {
+        this();
+        this.controller = controller;
+        this.classLoader = classLoader;
+    }
+
+    public ASTHelper() {
+        imports = new HashMap();
+    }
+
+    public String getPackageName() {
+        return packageName;
+    }
+
+    public void setPackageName(String packageName) {
+        this.packageName = packageName;
+        if (packageName!=null && packageName.length()>0){
+            packageName+='.';
+        }
+        output.setPackageName(packageName);
+    }
+
+
+    /**
+     * Returns our class loader (as supplied on construction).
+     */
+    public ClassLoader getClassLoader() {
+        return classLoader;
+    }
+
+    public void setClassLoader(ClassLoader classLoader) {
+        this.classLoader = classLoader;
+    }
+
+    public SourceUnit getController() {
+        return controller;
+    }
+
+    public void setController(SourceUnit controller) {
+        this.controller = controller;
+    }
+    
+    /**
+     * Returns a fully qualified name for any given potential type
+     * name.  Returns null if no qualified name could be determined.
+     */
+/*    protected String resolveName(String name, boolean safe) {
+        //
+        // Use our cache of resolutions, if possible
+
+        String resolution = (String) resolutions.get(name);
+        if (NOT_RESOLVED.equals(resolution)) {
+            return (safe ? name : null);
+        }
+        else if (resolution != null) {
+            return (String) resolution;
+        }
+
+        try {
+            getClassLoader().loadClass(name);
+            resolutions.put(name,name);
+            return name;
+        } catch (ClassNotFoundException cnfe){
+            if (cnfe.getCause() instanceof MultipleCompilationErrorsException) {
+                MultipleCompilationErrorsException mcee = (MultipleCompilationErrorsException) cnfe.getCause();
+                controller.getErrorCollector().addCollectorContents(mcee.getErrorCollector());
+                resolutions.put(name,name);
+                return name;
+            }
+        } catch (NoClassDefFoundError ncdfe) {
+            //fall through
+        }
+
+        do {
+            //
+            // If the type name contains a ".", it's probably fully
+            // qualified, and we don't take it to verification here.
+
+            if (name.indexOf(".") >= 0) {
+                resolution = name;
+                break;                                            // <<< FLOW CONTROL <<<<<<<<<
+            }
+
+
+            //
+            // Otherwise, we'll need the scalar type for checking, and
+            // the postfix for reassembly.
+
+            String scalar = name, postfix = "";
+            while (scalar.endsWith("[]")) {
+                scalar = scalar.substring(0, scalar.length() - 2);
+                postfix += "[]";
+            }
+
+
+            //
+            // Primitive types are all valid...
+
+            if (Types.ofType(Types.lookupKeyword(scalar), Types.PRIMITIVE_TYPE)) {
+                resolution = name;
+                break;                                            // <<< FLOW CONTROL <<<<<<<<<
+            }
+
+
+            //
+            // Next, check our imports and return the qualified name,
+            // if available.
+
+            if (this.imports.containsKey(scalar)) {
+                resolution = ((String) this.imports.get(scalar)) + postfix;
+                break;                                            // <<< FLOW CONTROL <<<<<<<<<
+            }
+
+
+            //
+            // Next, see if our class loader can resolve it in the current package.
+
+            if (packageName != null && packageName.length() > 0) {
+                try {
+                    getClassLoader().loadClass(dot(packageName, scalar));
+                    resolution = dot(packageName, name);
+
+                    break;                                        // <<< FLOW CONTROL <<<<<<<<<
+                } catch (ClassNotFoundException cnfe){
+                    if (cnfe.getCause() instanceof CompilationFailedException) {
+                        resolution = dot(packageName, name);
+                        break;
+                    }
+                } catch (NoClassDefFoundError ncdfe) {
+                    //fall through
+                }
+            }
+
+            // search the package imports path
+            List packageImports = output.getImportPackages();
+            for (int i = 0; i < packageImports.size(); i++) {
+                String pack = (String) packageImports.get(i);
+                String clsName = pack + name;
+                try {
+                    getClassLoader().loadClass(clsName);
+                    resolution = clsName;
+                    break;
+                } catch (ClassNotFoundException cnfe){
+                    if (cnfe.getCause() instanceof CompilationFailedException) {
+                        resolution = clsName;
+                        break;
+                    }
+                } catch (NoClassDefFoundError ncdfe) {
+                    //fall through
+                }
+            }
+            if (resolution != null) {
+                break;
+            }
+
+            //
+            // Last chance, check the default imports.
+
+            for (int i = 0; i < DEFAULT_IMPORTS.length; i++) {
+                String qualified = DEFAULT_IMPORTS[i] + scalar;
+                try {
+                    getClassLoader().loadClass(qualified);
+
+                    resolution = qualified + postfix;
+                    break;                                        // <<< FLOW CONTROL <<<<<<<<<
+                } catch (ClassNotFoundException cnfe){
+                    if (cnfe.getCause() instanceof CompilationFailedException) {
+                        resolution = qualified + postfix;
+                        break;
+                    }
+                } catch (NoClassDefFoundError ncdfee) {
+                    // fall through
+                }
+            }
+
+        }
+        while (false);
+
+
+        //
+        // Cache the solution and return it
+
+        if (resolution == null) {
+            resolutions.put(name, NOT_RESOLVED);
+            return (safe ? name : null);
+        }
+        else {
+            resolutions.put(name, resolution);
+            return resolution;
+        }
+    }
+*/
+    
+    /**
+     * Returns two names joined by a dot.  If the base name is
+     * empty, returns the name unchanged.
+     */
+    public static String dot(String base, String name) {
+        if (base != null && base.length() > 0) {
+            return base + "." + name;
+        }
+
+        return name;
+    }
+
+    protected void makeModule() {
+        this.newClasses.clear();
+        this.output = new ModuleNode(controller);
+        resolutions.clear();
+    }
+
+    /**
+     * A synonym for <code>dot( base, "" )</code>.
+     */
+    protected String dot(String base) {
+        return dot(base, "");
+    }
+
+    /*protected String resolveNewClassOrName(String name, boolean safe) {
+        if (this.newClasses.contains(name)) {
+            return dot(packageName, name);
+        }
+        else {
+            return resolveName(name, safe);
+        }
+    }*/
+
+    protected void addNewClassName(String name) {
+        this.newClasses.add(name);
+    }
+
+    protected void importClass(ClassNode type, String name, String as) {
+        if (as==null) as=name;
+
+        output.addImport(as, type); 
+        imports.put(as, type);
+    }
+
+    protected void importPackageWithStar(String importPackage) {
+        String[] classes = output.addImportPackage( dot(importPackage) );
+        for( int i = 0; i < classes.length; i++ )
+        {
+            imports.put( classes[i], dot(importPackage, classes[i]) );
+        }
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/syntax/CSTNode.java b/groovy-core/src/main/org/codehaus/groovy/syntax/CSTNode.java
new file mode 100644
index 0000000..991f0dd
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/syntax/CSTNode.java
@@ -0,0 +1,616 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.syntax;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
+import org.codehaus.groovy.syntax.Reduction;
+
+import java.io.StringWriter;
+import java.io.PrintWriter;
+
+
+/**
+ *  An abstract base class for nodes in the concrete syntax tree that is
+ *  the result of parsing.  Note that the CSTNode is inextricably linked
+ *  with the Token in that every CSTNode has a Token as it's root.
+ *
+ *  @see antlr.Parser
+ *  @see Token
+ *  @see org.codehaus.groovy.syntax.Reduction
+ *  @see org.codehaus.groovy.syntax.Types
+ *
+ *  @author <a href="mailto:bob@werken.com">bob mcwhirter</a>
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public abstract class CSTNode
+{
+
+  //---------------------------------------------------------------------------
+  // NODE IDENTIFICATION AND MEANING
+
+
+   /**
+    *  Returns the meaning of this node.  If the node isEmpty(), returns
+    *  the type of Token.NULL.
+    */
+
+    public int getMeaning()
+    {
+        return getRoot( true ).getMeaning();
+    }
+
+
+
+   /**
+    *  Sets the meaning for this node (and it's root Token).  Not
+    *  valid if the node isEmpty().  Returns the node, for convenience.
+    */
+
+    public CSTNode setMeaning( int meaning )
+    {
+        getRoot().setMeaning( meaning );
+        return this;
+    }
+
+
+
+   /**
+    *  Returns the actual type of the node.  If the node isEmpty(), returns
+    *  the type of Token.NULL.
+    */
+
+    public int getType()
+    {
+        return getRoot( true ).getType();
+    }
+
+
+
+   /**
+    *  Returns true if the node can be coerced to the specified type.
+    */
+
+    public boolean canMean( int type )
+    {
+        return Types.canMean( getMeaning(), type );
+    }
+
+
+
+   /**
+    *  Returns true if the node's meaning matches the specified type.
+    */
+
+    public boolean isA( int type )
+    {
+        return Types.ofType( getMeaning(), type );
+    }
+
+
+
+   /**
+    *  Returns true if the node's meaning matches any of the specified types.
+    */
+
+    public boolean isOneOf( int[] types )
+    {
+        int meaning = getMeaning();
+        for( int i = 0; i < types.length; i++ )
+        {
+            if( Types.ofType(meaning, types[i]) )
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+
+
+   /**
+    *  Returns true if the node's meaning matches all of the specified types.
+    */
+
+    public boolean isAllOf( int[] types )
+    {
+        int meaning = getMeaning();
+        for( int i = 0; i < types.length; i++ )
+        {
+            if( !Types.ofType(meaning, types[i]) )
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
+
+   /**
+    *  Returns the first matching meaning of the specified types.
+    *  Returns Types.UNKNOWN if there are no matches.
+    */
+
+    public int getMeaningAs( int[] types )
+    {
+
+        for( int i = 0; i < types.length; i++ )
+        {
+            if( isA(types[i]) )
+            {
+                return types[i];
+            }
+        }
+
+        return Types.UNKNOWN;
+    }
+
+
+
+
+  //---------------------------------------------------------------------------
+  // TYPE SUGAR
+
+
+   /**
+    *  Returns true if the node matches the specified type.  Effectively
+    *  a synonym for <code>isA()</code>.  Missing nodes are Token.NULL.
+    */
+
+    boolean matches( int type )
+    {
+        return isA(type);
+    }
+
+
+
+   /**
+    *  Returns true if the node and it's first child match the specified
+    *  types.  Missing nodes are Token.NULL.
+    */
+
+    boolean matches( int type, int child1 )
+    {
+        return isA(type) && get(1, true).isA(child1);
+    }
+
+
+
+   /**
+    *  Returns true if the node and it's first and second child match the
+    *  specified types.  Missing nodes are Token.NULL.
+    */
+
+    boolean matches( int type, int child1, int child2 )
+    {
+        return matches( type, child1 ) && get(2, true).isA(child2);
+    }
+
+
+
+   /**
+    *  Returns true if the node and it's first three children match the
+    *  specified types.  Missing nodes are Token.NULL.
+    */
+
+    boolean matches( int type, int child1, int child2, int child3 )
+    {
+        return matches( type, child1, child2 ) && get(3, true).isA(child3);
+    }
+
+
+
+   /**
+    *  Returns true if the node an it's first four children match the
+    *  specified types.  Missing nodes have type Types.NULL.
+    */
+
+    boolean matches( int type, int child1, int child2, int child3, int child4 )
+    {
+        return matches( type, child1, child2, child3 ) && get(4, true).isA(child4);
+    }
+
+
+
+
+
+  //---------------------------------------------------------------------------
+  // MEMBER ACCESS
+
+
+   /**
+    *  Returns true if the node is completely empty (no root, even).
+    */
+
+    public boolean isEmpty()
+    {
+        return false;
+    }
+
+
+
+   /**
+    *  Returns the number of elements in the node (including root).
+    */
+
+    public abstract int size();
+
+
+
+   /**
+    *  Returns true if the node has any non-root elements.
+    */
+
+    public boolean hasChildren()
+    {
+        return children() > 0;
+    }
+
+
+
+   /**
+    *  Returns the number of non-root elements in the node.
+    */
+
+    public int children()
+    {
+        int size = size();
+        if( size > 1 )
+        {
+            return size - 1;
+        }
+        return 0;
+    }
+
+
+
+   /**
+    *  Returns the specified element, or null.
+    */
+
+    public abstract CSTNode get( int index );
+
+
+
+   /**
+    *  Returns the specified element, or Token.NULL if
+    *  safe is set and the specified element is null (or doesn't
+    *  exist).
+    */
+
+    public CSTNode get( int index, boolean safe )
+    {
+        CSTNode element = get( index );
+
+        if( element == null && safe )
+        {
+            element = Token.NULL;
+        }
+
+        return element;
+    }
+
+
+
+   /**
+    *  Returns the root of the node.  By convention, all nodes have
+    *  a Token as the first element (or root), which indicates the type
+    *  of the node.  May return null if the node <code>isEmpty()</code>.
+    */
+
+    public abstract Token getRoot();
+
+
+
+   /**
+    *  Returns the root of the node, the Token that indicates it's
+    *  type.  Returns a Token.NULL if safe and the actual root is null.
+    */
+
+    public Token getRoot( boolean safe )
+    {
+        Token root = getRoot();
+
+        if( root == null && safe )
+        {
+            root = Token.NULL;
+        }
+
+        return root;
+    }
+
+
+
+   /**
+    *  Returns the text of the root.  Uses <code>getRoot(true)</code>
+    *  to get the root, so you will only receive null in return if the
+    *  root token returns it.
+    */
+
+    public String getRootText()
+    {
+        Token root = getRoot( true );
+        return root.getText();
+    }
+
+
+
+   /**
+    *  Returns a description of the node.
+    */
+
+    public String getDescription()
+    {
+        return Types.getDescription( getMeaning() );
+    }
+
+
+
+   /**
+    *  Returns the starting line of the node.  Returns -1
+    *  if not known.
+    */
+
+    public int getStartLine()
+    {
+        return getRoot(true).getStartLine();
+    }
+
+
+
+   /**
+    *  Returns the starting column of the node.  Returns -1
+    *  if not known.
+    */
+
+    public int getStartColumn()
+    {
+        return getRoot(true).getStartColumn();
+    }
+
+
+
+   /**
+    *  Marks the node a complete expression.  Not all nodes support
+    *  this operation!
+    */
+
+    public void markAsExpression()
+    {
+        throw new GroovyBugError( "markAsExpression() not supported for this CSTNode type" );
+    }
+
+
+
+   /**
+    *  Returns true if the node is a complete expression.
+    */
+
+    public boolean isAnExpression()
+    {
+        return isA(Types.SIMPLE_EXPRESSION);
+    }
+
+
+
+
+
+  //---------------------------------------------------------------------------
+  // OPERATIONS
+
+
+   /**
+    *  Adds an element to the node.  Returns the element for convenience.
+    *  Not all nodes support this operation!
+    */
+
+    public CSTNode add( CSTNode element )
+    {
+        throw new GroovyBugError( "add() not supported for this CSTNode type" );
+    }
+
+
+
+   /**
+    *  Adds all children of the specified node to this one.  Not all
+    *  nodes support this operation!
+    */
+
+    public void addChildrenOf( CSTNode of )
+    {
+        for( int i = 1; i < of.size(); i++ )
+        {
+            add( of.get(i) );
+        }
+    }
+
+
+
+   /**
+    *  Sets an element node in at the specified index.  Returns the element
+    *  for convenience.  Not all nodes support this operation!
+    */
+
+    public CSTNode set( int index, CSTNode element )
+    {
+        throw new GroovyBugError( "set() not supported for this CSTNode type" );
+    }
+
+
+
+   /**
+    *  Creates a <code>Reduction</code> from this node.  Returns self if the
+    *  node is already a <code>Reduction</code>.
+    */
+
+    public abstract Reduction asReduction();
+
+
+
+
+  //---------------------------------------------------------------------------
+  // STRING CONVERSION
+
+
+   /**
+    *  Formats the node as a <code>String</code> and returns it.
+    */
+
+    public String toString()
+    {
+        StringWriter string = new StringWriter();
+        write( new PrintWriter(string) );
+
+        string.flush();
+        return string.toString();
+    }
+
+
+   /**
+    *  Formats the node and writes it to the specified <code>Writer</code>.
+    */
+
+    public void write( PrintWriter writer )
+    {
+        write( writer, "" );
+    }
+
+
+   /**
+    *  Formats the node and writes it to the specified <code>Writer</code>.
+    *  The indent is prepended to each output line, and is increased for each
+    *  recursion.
+    */
+
+    protected void write( PrintWriter writer, String indent )
+    {
+        writer.print( "(" );
+
+        if( !isEmpty() )
+        {
+            Token  root = getRoot( true );
+            int    type = root.getType();
+            int meaning = root.getMeaning();
+
+
+            //
+            // Display our type, text, and (optional) meaning
+
+            writer.print( Types.getDescription(type) );
+
+            if( meaning != type )
+            {
+                writer.print( " as " );
+                writer.print( Types.getDescription(meaning) );
+            }
+
+            if( getStartLine() > -1 )
+            {
+                writer.print( " at " + getStartLine() + ":" + getStartColumn() );
+            }
+
+            String text = root.getText();
+            int  length = text.length();
+            if( length > 0 )
+            {
+                writer.print( ": " );
+                if( length > 40 )
+                {
+                   text = text.substring( 0, 17 ) + "..." + text.substring( length - 17, length );
+                }
+
+                writer.print( " \"" );
+                writer.print( text );
+                writer.print( "\" " );
+            }
+            else if( children() > 0 )
+            {
+                writer.print( ": " );
+            }
+
+
+
+            //
+            // Recurse to display the children.
+
+            int count = size();
+            if( count > 1 )
+            {
+                writer.println( "" );
+
+                String indent1 = indent + "  ";
+                String indent2 = indent + "   ";
+                for( int i = 1; i < count; i++ )
+                {
+                    writer.print( indent1 );
+                    writer.print( i );
+                    writer.print( ": " );
+
+                    get( i, true ).write( writer, indent2 );
+                }
+
+                writer.print( indent );
+            }
+        }
+
+        if( indent.length() > 0 )
+        {
+            writer.println( ")" );
+        }
+        else
+        {
+            writer.print( ")" );
+        }
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/syntax/ClassSource.java b/groovy-core/src/main/org/codehaus/groovy/syntax/ClassSource.java
new file mode 100644
index 0000000..75ff46e
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/syntax/ClassSource.java
@@ -0,0 +1,57 @@
+/*
+ $Id$
+
+ Copyright 2005 (C) Jeremy Rayner. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.syntax;
+
+/**
+ * Provides a reflection style facade over the underlying source code for a class.
+ */
+public interface ClassSource {
+    public String getName();
+    //public List getMethods();
+    //public List getFields();
+    //public void add(MethodSource methodSource);
+    //public void add(FieldSource fieldSource);
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/syntax/Numbers.java b/groovy-core/src/main/org/codehaus/groovy/syntax/Numbers.java
new file mode 100644
index 0000000..d85f9f4
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/syntax/Numbers.java
@@ -0,0 +1,325 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.syntax;
+
+import java.math.BigInteger;
+import java.math.BigDecimal;
+
+/**
+ *  Helper class for processing Groovy numeric literals.
+ *
+ *  @author Brian Larson
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class Numbers
+{
+
+
+
+  //---------------------------------------------------------------------------
+  // LEXING SUPPORT
+
+
+   /**
+    *  Returns true if the specified character is a base-10 digit.
+    */
+
+    public static boolean isDigit( char c )
+    {
+        return c >= '0' && c <= '9';
+    }
+
+
+   /**
+    *  Returns true if the specific character is a base-8 digit.
+    */
+
+    public static boolean isOctalDigit( char c )
+    {
+        return c >= '0' && c <= '7';
+    }
+
+
+   /**
+    *  Returns true if the specified character is a base-16 digit.
+    */
+
+    public static boolean isHexDigit( char c )
+    {
+        return isDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
+    }
+
+
+
+   /**
+    *  Returns true if the specified character is a valid type specifier
+    *  for a numeric value.
+    */
+
+    public static boolean isNumericTypeSpecifier( char c, boolean isDecimal )
+    {
+        if( isDecimal )
+        {
+            switch( c )
+            {
+                case 'G':
+                case 'g':
+                case 'D':
+                case 'd':
+                case 'F':
+                case 'f':
+                    return true;
+            }
+        }
+        else
+        {
+            switch( c )
+            {
+                case 'G':
+                case 'g':
+                case 'I':
+                case 'i':
+                case 'L':
+                case 'l':
+                    return true;
+            }
+        }
+
+        return false;
+    }
+
+
+
+
+
+  //---------------------------------------------------------------------------
+  // PARSING SUPPORT
+
+
+    private static final BigInteger MAX_LONG    = BigInteger.valueOf(Long.MAX_VALUE);
+    private static final BigInteger MIN_LONG    = BigInteger.valueOf(Long.MIN_VALUE);
+
+    private static final BigInteger MAX_INTEGER = BigInteger.valueOf(Integer.MAX_VALUE);
+    private static final BigInteger MIN_INTEGER = BigInteger.valueOf(Integer.MIN_VALUE);
+
+    private static final BigDecimal MAX_DOUBLE  = new BigDecimal(String.valueOf(Double.MAX_VALUE));
+    private static final BigDecimal MIN_DOUBLE  = MAX_DOUBLE.negate();
+
+    private static final BigDecimal MAX_FLOAT   = new BigDecimal(String.valueOf(Float.MAX_VALUE));
+    private static final BigDecimal MIN_FLOAT   = MAX_FLOAT.negate();
+
+
+
+   /**
+    *  Builds a Number from the given integer descriptor.  Creates the narrowest
+    *  type possible, or a specific type, if specified.
+    *
+    *  @param  text literal text to parse
+    *  @return instantiated Number object
+    *  @throws NumberFormatException if the number does not fit within the type
+    *          requested by the type specifier suffix (invalid numbers don't make
+    *          it here)
+    */
+
+    public static Number parseInteger( String text )
+    {
+        char c = ' ';
+        int length = text.length();
+
+
+        //
+        // Strip off the sign, if present
+
+        boolean negative = false;
+        if( (c = text.charAt(0)) == '-' || c == '+' )
+        {
+            negative = (c == '-');
+            text = text.substring( 1, length );
+            length -= 1;
+        }
+
+
+        //
+        // Determine radix (default is 10).
+
+        int radix = 10;
+        if( text.charAt(0) == '0' && length > 1 )
+        {
+            if( (c = text.charAt(1)) == 'X' || c == 'x' )
+            {
+                radix = 16;
+                text = text.substring( 2, length);
+                length -= 2;
+            }
+            else
+            {
+                radix = 8;
+            }
+        }
+
+
+        //
+        // Strip off any type specifier and convert it to lower
+        // case, if present.
+
+        char type = 'x';  // pick best fit
+        if( isNumericTypeSpecifier(text.charAt(length-1), false) )
+        {
+            type = Character.toLowerCase( text.charAt(length-1) );
+            text = text.substring( 0, length-1);
+
+            length -= 1;
+        }
+
+
+        //
+        // Add the sign back, if necessary
+
+        if( negative )
+        {
+            text = "-" + text;
+        }
+
+
+        //
+        // Build the specified type or, if no type was specified, the
+        // smallest type in which the number will fit.
+
+        switch (type)
+        {
+            case 'i':
+                return new Integer( Integer.parseInt(text, radix) );
+
+            case 'l':
+                return new Long( Long.parseLong(text, radix) );
+
+            case 'g':
+                return new BigInteger( text, radix );
+
+            default:
+
+                //
+                // If not specified, we will return the narrowest possible
+                // of Integer, Long, and BigInteger.
+
+                BigInteger value = new BigInteger( text, radix );
+
+                if( value.compareTo(MAX_INTEGER) <= 0 && value.compareTo(MIN_INTEGER) >= 0 )
+                {
+                    return new Integer(value.intValue());
+                }
+                else if( value.compareTo(MAX_LONG) <= 0 && value.compareTo(MIN_LONG) >= 0 )
+                {
+                    return new Long(value.longValue());
+                }
+
+                return value;
+        }
+    }
+
+
+
+   /**
+    *  Builds a Number from the given decimal descriptor.  Uses BigDecimal,
+    *  unless, Double or Float is requested.
+    *
+    *  @param  text literal text to parse
+    *  @return instantiated Number object
+    *  @throws NumberFormatException if the number does not fit within the type
+    *          requested by the type specifier suffix (invalid numbers don't make
+    *          it here)
+    */
+
+    public static Number parseDecimal( String text )
+    {
+        int length = text.length();
+
+
+        //
+        // Strip off any type specifier and convert it to lower
+        // case, if present.
+
+        char type = 'x';
+        if( isNumericTypeSpecifier(text.charAt(length-1), true) )
+        {
+            type = Character.toLowerCase( text.charAt(length-1) );
+            text = text.substring( 0, length-1 );
+
+            length -= 1;
+        }
+
+
+        //
+        // Build the specified type or default to BigDecimal
+
+        BigDecimal value = new BigDecimal( text );
+        switch( type )
+        {
+            case 'f':
+                if( value.compareTo(MAX_FLOAT) <= 0 && value.compareTo(MIN_FLOAT) >= 0)
+                {
+                    return new Float( text );
+                }
+                throw new NumberFormatException( "out of range" );
+
+            case 'd':
+                if( value.compareTo(MAX_DOUBLE) <= 0 && value.compareTo(MIN_DOUBLE) >= 0)
+                {
+                    return new Double( text );
+                }
+                throw new NumberFormatException( "out of range" );
+
+            case 'g':
+            default:
+                return value;
+        }
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/syntax/ParserException.java b/groovy-core/src/main/org/codehaus/groovy/syntax/ParserException.java
new file mode 100644
index 0000000..3035093
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/syntax/ParserException.java
@@ -0,0 +1,15 @@
+package org.codehaus.groovy.syntax;
+
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.TokenException;
+
+public class ParserException extends TokenException {
+    public ParserException(String message, Token token) {
+        super(message, token);
+    }
+
+    public ParserException(String message, Throwable cause, int lineNumber, int columnNumber) {
+        super(message, cause, lineNumber, columnNumber);
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/syntax/ReadException.java b/groovy-core/src/main/org/codehaus/groovy/syntax/ReadException.java
new file mode 100644
index 0000000..5f9059d
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/syntax/ReadException.java
@@ -0,0 +1,40 @@
+package org.codehaus.groovy.syntax;
+
+import org.codehaus.groovy.GroovyException;
+
+import java.io.IOException;
+
+/**
+ * Encapsulates non-specific i/o exceptions.
+ */
+
+public class ReadException extends GroovyException {
+    private IOException cause = null;
+
+    public ReadException(IOException cause) {
+        super();
+        this.cause = cause;
+    }
+
+    public ReadException(String message, IOException cause) {
+        super(message);
+        this.cause = cause;
+    }
+
+    public IOException getIOCause() {
+        return this.cause;
+    }
+
+    public String toString() {
+        String message = super.getMessage();
+        if (message == null || message.trim().equals("")) {
+            message = cause.getMessage();
+        }
+
+        return message;
+    }
+
+    public String getMessage() {
+        return toString();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/syntax/Reduction.java b/groovy-core/src/main/org/codehaus/groovy/syntax/Reduction.java
new file mode 100644
index 0000000..1e52b50
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/syntax/Reduction.java
@@ -0,0 +1,297 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.syntax;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.syntax.Token;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+
+
+/** 
+ *  A syntax reduction, produced by the <code>Parser</code>.
+ *
+ *  @see antlr.Parser
+ *  @see Token
+ *  @see CSTNode
+ *  @see Types
+ *
+ *  @author <a href="mailto:bob@werken.com">bob mcwhirter</a>
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class Reduction extends CSTNode
+{
+    public static final Reduction EMPTY = new Reduction();
+
+
+  //---------------------------------------------------------------------------
+  // INITIALIZATION AND SUCH
+
+    private List    elements  = null;    // The set of child nodes   
+    private boolean marked    = false;   // Used for completion marking by some parts of the parser
+
+
+   /**
+    *  Initializes the <code>Reduction</code> with the specified root.
+    */
+
+    public Reduction( Token root ) 
+    {
+        elements = new ArrayList();
+        set( 0, root );
+    }
+
+
+   /**
+    *  Initializes the <code>Reduction</code> to empty.
+    */
+
+    private Reduction() 
+    {
+        elements = Collections.EMPTY_LIST;
+    }
+
+
+   /**
+    *  Creates a new <code>Reduction</code> with <code>Token.NULL</code>
+    *  as it's root.
+    */
+
+    public static Reduction newContainer() 
+    {
+        return new Reduction( Token.NULL );
+    }
+
+
+
+
+  //---------------------------------------------------------------------------
+  // MEMBER ACCESS
+
+
+   /**
+    *  Returns true if the node is completely empty (no root, even).
+    */
+
+    public boolean isEmpty() 
+    {
+        return size() == 0;
+    }
+
+
+
+   /**
+    *  Returns the number of elements in the node.
+    */
+
+    public int size() 
+    {
+        return elements.size();
+    }
+
+
+
+   /**
+    *  Returns the specified element, or null.
+    */
+
+    public CSTNode get( int index ) 
+    {
+        CSTNode element = null;
+
+        if( index < size() ) 
+        {
+            element = (CSTNode)elements.get( index );
+        }
+
+        return element;
+    }
+
+
+
+   /**
+    *  Returns the root of the node, the Token that indicates it's
+    *  type.  Returns null if there is no root (usually only if the
+    *  node is a placeholder of some kind -- see isEmpty()).
+    */
+
+    public Token getRoot() 
+    {
+        if( size() > 0 )
+        {
+            return (Token)elements.get(0);
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+
+   /**
+    *  Marks the node a complete expression.
+    */
+
+    public void markAsExpression() 
+    {
+        marked = true;
+    }
+
+
+
+   /**
+    *  Returns true if the node is a complete expression.
+    */
+
+    public boolean isAnExpression() 
+    {
+        if( isA(Types.COMPLEX_EXPRESSION) ) 
+        {
+            return true;
+        }
+
+        return marked;
+    }
+
+
+
+
+  //---------------------------------------------------------------------------
+  // OPERATIONS
+
+
+   /**
+    *  Adds an element to the node.
+    */
+
+    public CSTNode add( CSTNode element ) 
+    {
+        return set( size(), element );
+    }
+
+
+
+   /**
+    *  Sets an element in at the specified index.
+    */
+
+    public CSTNode set( int index, CSTNode element ) 
+    {
+        
+        if( elements == null ) 
+        {
+            throw new GroovyBugError( "attempt to set() on a EMPTY Reduction" );
+        }
+
+        if( index == 0 && !(element instanceof Token) ) 
+        {
+
+            //
+            // It's not the greatest of design that the interface allows this, but it
+            // is a tradeoff with convenience, and the convenience is more important.
+
+            throw new GroovyBugError( "attempt to set() a non-Token as root of a Reduction" );
+        }
+
+
+        //
+        // Fill slots with nulls, if necessary.
+
+        int count = elements.size();
+        if( index >= count ) 
+        {
+            for( int i = count; i <= index; i++ ) 
+            {
+                elements.add( null );
+            }
+        }
+
+        //
+        // Then set in the element.
+
+        elements.set( index, element );
+
+        return element;
+    }
+
+
+
+   /**
+    *  Removes a node from the <code>Reduction</code>.  You cannot remove 
+    *  the root node (index 0).
+    */
+
+    public CSTNode remove( int index )
+    {
+        if( index < 1 ) 
+        {
+            throw new GroovyBugError( "attempt to remove() root node of Reduction" );
+        }
+
+        return (CSTNode)elements.remove( index );
+    }
+
+
+
+   /**
+    *  Creates a <code>Reduction</code> from this node.  Returns self if the
+    *  node is already a <code>Reduction</code>.
+    */
+
+    public Reduction asReduction() 
+    {
+        return this;
+    }
+
+}
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/syntax/RuntimeParserException.java b/groovy-core/src/main/org/codehaus/groovy/syntax/RuntimeParserException.java
new file mode 100644
index 0000000..2324a46
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/syntax/RuntimeParserException.java
@@ -0,0 +1,41 @@
+package org.codehaus.groovy.syntax;
+
+import groovy.lang.GroovyRuntimeException;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.syntax.SyntaxException;
+
+/** 
+ * A helper class to allow parser exceptions to be thrown anywhere in the code. 
+ * Should be replaced when no longer required.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */ 
+public class RuntimeParserException extends GroovyRuntimeException {
+    
+    public RuntimeParserException(String message, ASTNode node) {
+        super(message + ".\nNode: " + node.getClass().getName(), node);
+    }
+
+    public void throwParserException() throws SyntaxException {
+        throw new SyntaxException(getMessage(), getNode().getLineNumber(), getNode().getColumnNumber());
+    }
+    
+    /*
+    private Token token;
+
+    public RuntimeParserException(String message, Token token) {
+        super(message);
+        this.token = token;
+    }
+
+    public Token getToken() {
+        return token;
+    }
+
+    public void throwParserException() throws SyntaxException {
+        throw new TokenException(getMessage(), token);
+    }
+    */
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/syntax/SourceSummary.java b/groovy-core/src/main/org/codehaus/groovy/syntax/SourceSummary.java
new file mode 100644
index 0000000..e6e6098
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/syntax/SourceSummary.java
@@ -0,0 +1,61 @@
+/*
+ $Id$
+
+ Copyright 2005 (C) Jeremy Rayner. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.syntax;
+
+import java.util.List;
+
+/** Provides a facade over parser CST, representing one source unit (i.e 0 or more classes)
+ *
+ *  @author <a href="groovy@ross-rayner.com">jeremy rayner</a>
+ *
+ *  @version $Id$
+ */
+
+
+public interface SourceSummary {
+    void addPublic(ClassSource classSource);
+    List getPublicClassSources();
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/syntax/SyntaxException.java b/groovy-core/src/main/org/codehaus/groovy/syntax/SyntaxException.java
new file mode 100644
index 0000000..62e29ed
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/syntax/SyntaxException.java
@@ -0,0 +1,122 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.syntax;
+
+import org.codehaus.groovy.GroovyException;
+
+/** Base exception indicating a syntax error.
+ *
+ *  @author <a href="bob@werken.com">bob mcwhirter</a>
+ *
+ *  @version $Id$
+ */
+public class SyntaxException extends GroovyException {
+
+    /** Line upon which the error occurred. */
+    private int line;
+
+    /** Column upon which the error occurred. */
+    private int column;
+
+    private String sourceLocator;
+
+    public SyntaxException(String message, int line, int column) {
+        super(message, false);
+        this.line = line;
+        this.column = column;
+    }
+
+    public SyntaxException(String message, Throwable cause, int line, int column) {
+        super(message, cause);
+        this.line = line;
+        this.column = column;
+    }
+
+    // Properties
+    // ----------------------------------------------------------------------
+    public void setSourceLocator(String sourceLocator) {
+        this.sourceLocator = sourceLocator;
+    }
+
+    public String getSourceLocator() {
+        return this.sourceLocator;
+    }
+
+    /** Retrieve the line upon which the error occurred.
+     *
+     *  @return The line.
+     */
+    public int getLine() {
+        return line;
+    }
+
+    /** Retrieve the column upon which the error occurred.
+     *
+     *  @return The column.
+     */
+    public int getStartColumn() {
+        return column;
+    }
+    
+    /** 
+     * @return the end of the line on which the error occurs
+     */
+    public int getStartLine() {
+        return getLine();
+    }
+
+    /**
+     * @return the end column on which the error occurs
+     */
+    public int getEndColumn() {
+        return getStartColumn() + 1;
+    }
+
+    public String getMessage() {
+        String msg = super.getMessage() + " @ line " + line + ", column " + column + ".";
+        return msg;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/syntax/Token.java b/groovy-core/src/main/org/codehaus/groovy/syntax/Token.java
new file mode 100644
index 0000000..ce0860e
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/syntax/Token.java
@@ -0,0 +1,423 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.syntax;
+
+import org.codehaus.groovy.GroovyBugError;
+
+
+/**
+ *  A <code>CSTNode</code> produced by the <code>Lexer</code>.
+ *
+ *  @see antlr.Parser
+ *  @see antlr.Token
+ *  @see Reduction
+ *  @see Types
+ *
+ *  @author <a href="mailto:bob@werken.com">bob mcwhirter</a>
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class Token extends CSTNode
+{
+    public static final Token NULL = new Token();
+    public static final Token EOF  = new Token( Types.EOF, "", -1, -1 );
+
+
+  //---------------------------------------------------------------------------
+  // TOKEN INITIALIZATION AND SUCH
+
+    private int type        = Types.UNKNOWN;  // the actual type identified by the lexer
+    private int meaning     = Types.UNKNOWN;  // an interpretation applied to the token after the fact
+
+    private String     text = "";             // the text of the token
+    private int   startLine = -1;             // the source line on which the token begins
+    private int startColumn = -1;             // the source column on which the token begins
+
+
+   /**
+    *  Initializes the Token with the specified information.
+    */
+
+    public Token( int type, String text, int startLine, int startColumn )
+    {
+        this.type        = type;
+        this.meaning     = type;
+        this.text        = text;
+        this.startLine   = startLine;
+        this.startColumn = startColumn;
+    }
+
+
+   /**
+    *  Initializes the NULL Token.
+    */
+
+    private Token() { }
+
+
+
+   /**
+    *  Returns a copy of this Token.
+    */
+
+    public Token dup()
+    {
+        Token token = new Token( this.type, this.text, this.startLine, this.startColumn );
+        token.setMeaning( this.meaning );
+
+        return token;
+    }
+
+
+
+
+  //---------------------------------------------------------------------------
+  // NODE IDENTIFICATION AND MEANING
+
+
+   /**
+    *  Returns the meaning of this node.  If the node isEmpty(), returns
+    *  the type of Token.NULL.
+    */
+
+    public int getMeaning()
+    {
+        return meaning;
+    }
+
+
+
+   /**
+    *  Sets the meaning for this node (and it's root Token).  Not
+    *  valid if the node isEmpty().  Returns this token, for
+    *  convenience.
+    */
+
+    public CSTNode setMeaning( int meaning )
+    {
+        this.meaning = meaning;
+        return this;
+    }
+
+
+
+   /**
+    *  Returns the actual type of the node.  If the node isEmpty(), returns
+    *  the type of Token.NULL.
+    */
+
+    public int getType()
+    {
+        return type;
+    }
+
+
+
+
+  //---------------------------------------------------------------------------
+  // MEMBER ACCESS
+
+
+   /**
+    *  Returns the number of elements in the node (including root).
+    */
+
+    public int size()
+    {
+        return 1;
+    }
+
+
+
+   /**
+    *  Returns the specified element, or null.
+    */
+
+    public CSTNode get( int index )
+    {
+        if( index > 0 )
+        {
+            throw new GroovyBugError( "attempt to access Token element other than root" );
+        }
+
+        return this;
+    }
+
+
+
+   /**
+    *  Returns the root of the node.  By convention, all nodes have
+    *  a Token as the first element (or root), which indicates the type
+    *  of the node.  May return null if the node <code>isEmpty()</code>.
+    */
+
+    public Token getRoot()
+    {
+        return this;
+    }
+
+
+
+   /**
+    *  Returns the text of the root node.  Uses <code>getRoot(true)</code>
+    *  to get the root, so you will only receive null in return if the
+    *  root token returns it.
+    */
+
+    public String getRootText()
+    {
+        return text;
+    }
+
+
+
+   /**
+    *  Returns the text of the token.  Equivalent to
+    *  <code>getRootText()</code> when called directly.
+    */
+
+    public String getText()
+    {
+        return text;
+    }
+
+
+
+   /**
+    *  Not advisable, but if you need to adjust the token's text, this
+    *  will do it.
+    */
+
+    public void setText( String text )
+    {
+        this.text = text;
+    }
+
+
+
+   /**
+    *  Returns the starting line of the node.  Returns -1
+    *  if not known.
+    */
+
+    public int getStartLine()
+    {
+        return startLine;
+    }
+
+
+
+   /**
+    *  Returns the starting column of the node.  Returns -1
+    *  if not known.
+    */
+
+    public int getStartColumn()
+    {
+        return startColumn;
+    }
+
+
+
+
+  //---------------------------------------------------------------------------
+  // OPERATIONS
+
+
+   /**
+    *  Creates a <code>Reduction</code> from this token.  Returns self if the
+    *  node is already a <code>Reduction</code>.
+    */
+
+    public Reduction asReduction()
+    {
+        return new Reduction( this );
+    }
+
+
+
+   /**
+    *  Creates a <code>Reduction</code> from this token, adding the supplied
+    *  node as the second element.
+    */
+
+    public Reduction asReduction( CSTNode second )
+    {
+        Reduction created = asReduction();
+        created.add( second );
+        return created;
+    }
+
+
+
+   /**
+    *  Creates a <code>Reduction</code> from this token, adding the supplied
+    *  nodes as the second and third element, respectively.
+    */
+
+    public Reduction asReduction( CSTNode second, CSTNode third )
+    {
+        Reduction created = asReduction( second );
+        created.add( third );
+        return created;
+    }
+
+
+
+   /**
+    *  Creates a <code>Reduction</code> from this token, adding the supplied
+    *  nodes as the second, third, and fourth element, respectively.
+    */
+
+    public Reduction asReduction( CSTNode second, CSTNode third, CSTNode fourth )
+    {
+        Reduction created = asReduction( second, third );
+        created.add( fourth );
+        return created;
+    }
+
+
+
+
+  //---------------------------------------------------------------------------
+  // TOKEN FACTORIES
+
+
+   /**
+    *  Creates a token that represents a keyword.  Returns null if the
+    *  specified text isn't a keyword.
+    */
+
+    public static Token newKeyword( String text, int startLine, int startColumn )
+    {
+
+        int type = Types.lookupKeyword( text );
+        if( type != Types.UNKNOWN )
+        {
+            return new Token( type, text, startLine, startColumn );
+        }
+
+        return null;
+
+    }
+
+
+   /**
+    *  Creates a token that represents a double-quoted string.
+    */
+
+    public static Token newString( String text, int startLine, int startColumn )
+    {
+        return new Token( Types.STRING, text, startLine, startColumn );
+    }
+
+
+   /**
+    *  Creates a token that represents an identifier.
+    */
+
+    public static Token newIdentifier( String text, int startLine, int startColumn )
+    {
+        return new Token( Types.IDENTIFIER, text, startLine, startColumn );
+    }
+
+
+   /**
+    *  Creates a token that represents an integer.
+    */
+
+    public static Token newInteger( String text, int startLine, int startColumn )
+    {
+        return new Token( Types.INTEGER_NUMBER, text, startLine, startColumn );
+    }
+
+
+   /**
+    *  Creates a token that represents a decimal number.
+    */
+
+    public static Token newDecimal( String text, int startLine, int startColumn )
+    {
+        return new Token( Types.DECIMAL_NUMBER, text, startLine, startColumn );
+    }
+
+
+   /**
+    *  Creates a token that represents a symbol, using a library for the text.
+    */
+
+    public static Token newSymbol( int type, int startLine, int startColumn )
+    {
+        return new Token( type, Types.getText(type), startLine, startColumn );
+    }
+
+
+   /**
+    *  Creates a token that represents a symbol, using a library for the type.
+    */
+
+    public static Token newSymbol( String type, int startLine, int startColumn )
+    {
+        return new Token( Types.lookupSymbol(type), type, startLine, startColumn );
+    }
+
+
+   /**
+    *  Creates a token with the specified meaning.
+    */
+
+    public static Token newPlaceholder( int type )
+    {
+        Token token = new Token( Types.UNKNOWN, "", -1, -1 );
+        token.setMeaning( type );
+
+        return token;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/syntax/TokenException.java b/groovy-core/src/main/org/codehaus/groovy/syntax/TokenException.java
new file mode 100644
index 0000000..cdc3c32
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/syntax/TokenException.java
@@ -0,0 +1,39 @@
+package org.codehaus.groovy.syntax;
+
+
+public class TokenException extends SyntaxException {
+    private Token token;
+
+    public TokenException(String message, Token token) {
+        super(
+            (token == null)
+                ? message + ". No token"
+                : message,
+            getLine(token),
+            getColumn(token));
+    }
+
+    public TokenException(String message, Throwable cause, int line, int column) {
+        super(message, cause, line, column);
+    }
+
+    public int getEndColumn() {
+        int length = 1;
+        if (token != null) { 
+            length = token.getText().length();
+        }
+        return getStartColumn() + length;
+    }
+
+
+    // Implementation methods
+    // ----------------------------------------------------------------------
+    private static int getColumn(Token token) {
+        return (token != null) ? token.getStartColumn() : -1;
+    }
+
+    private static int getLine(Token token) {
+        return (token != null) ? token.getStartLine() : -1;
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/syntax/TokenMismatchException.java b/groovy-core/src/main/org/codehaus/groovy/syntax/TokenMismatchException.java
new file mode 100644
index 0000000..7753ba0
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/syntax/TokenMismatchException.java
@@ -0,0 +1,20 @@
+package org.codehaus.groovy.syntax;
+
+public class TokenMismatchException extends TokenException {
+    private Token unexpectedToken;
+    private int expectedType;
+
+    public TokenMismatchException(Token token, int expectedType) {
+        super("Expected token: " + expectedType + " but found: " + token, token);
+        this.unexpectedToken = token;
+        this.expectedType = expectedType;
+    }
+
+    public Token getUnexpectedToken() {
+        return this.unexpectedToken;
+    }
+
+    public int getExpectedType() {
+        return this.expectedType;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/syntax/Types.java b/groovy-core/src/main/org/codehaus/groovy/syntax/Types.java
new file mode 100644
index 0000000..0cffa63
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/syntax/Types.java
@@ -0,0 +1,1471 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.syntax;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.codehaus.groovy.GroovyBugError;
+
+
+/**
+ *  Typing information for the CST system.  The types here are those
+ *  used by CSTNode, Token, and Reduction.
+ *
+ *  @author <a href="mailto:bob@werken.com">bob mcwhirter</a>
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class Types
+{
+
+
+  //---------------------------------------------------------------------------
+  // TYPES: NOTE THAT ORDERING AND VALUES ARE IMPORTANT TO LOCAL ROUTINES!
+
+
+    //
+    // SPECIAL TOKENS
+
+    public static final int EOF                         = -1;    // end of file
+    public static final int UNKNOWN                     = 0;     // the unknown token
+
+
+    //
+    // RELEVANT WHITESPACE
+
+    public static final int NEWLINE                     = 5;     // \n
+
+
+    //
+    // OPERATORS AND OTHER MARKERS
+
+    public static final int LEFT_CURLY_BRACE            = 10;    // {
+    public static final int RIGHT_CURLY_BRACE           = 20;    // }
+    public static final int LEFT_SQUARE_BRACKET         = 30;    // [
+    public static final int RIGHT_SQUARE_BRACKET        = 40;    // ]
+    public static final int LEFT_PARENTHESIS            = 50;    // (
+    public static final int RIGHT_PARENTHESIS           = 60;    // )
+
+    public static final int DOT                         = 70;    // .
+    public static final int DOT_DOT                     = 75;    // ..
+    public static final int DOT_DOT_DOT                 = 77;    // ...
+
+    public static final int NAVIGATE                    = 80;    // ->
+
+    public static final int FIND_REGEX                  = 90;    // =~
+    public static final int MATCH_REGEX                 = 94;    // ==~
+    public static final int REGEX_PATTERN               = 97;    // ~
+
+    public static final int EQUAL                       = 100;   // =
+    public static final int EQUALS                      = EQUAL;
+    public static final int ASSIGN                      = EQUAL;
+
+    public static final int COMPARE_NOT_EQUAL           = 120;   // !=
+    public static final int COMPARE_IDENTICAL           = 121;   // ===
+    public static final int COMPARE_NOT_IDENTICAL       = 122;   // !==
+    public static final int COMPARE_EQUAL               = 123;   // ==
+    public static final int COMPARE_LESS_THAN           = 124;   // <
+    public static final int COMPARE_LESS_THAN_EQUAL     = 125;   // <=
+    public static final int COMPARE_GREATER_THAN        = 126;   // >
+    public static final int COMPARE_GREATER_THAN_EQUAL  = 127;   // >=
+    public static final int COMPARE_TO                  = 128;   // <=>
+
+    public static final int NOT                         = 160;   // !
+    public static final int LOGICAL_OR                  = 162;   // ||
+    public static final int LOGICAL_AND                 = 164;   // &&
+
+    public static final int LOGICAL_OR_EQUAL            = 166;   // ||=
+    public static final int LOGICAL_AND_EQUAL           = 168;   // &&=
+
+    public static final int PLUS                        = 200;   // +
+    public static final int MINUS                       = 201;   // -
+    public static final int MULTIPLY                    = 202;   // *
+    public static final int DIVIDE                      = 203;   // /
+    public static final int INTDIV                      = 204;   // \
+    public static final int MOD                         = 205;   // %
+    public static final int STAR_STAR                   = 206;   // **
+    public static final int POWER                       = STAR_STAR;   // **
+
+    public static final int PLUS_EQUAL                  = 210;   // +=
+    public static final int MINUS_EQUAL                 = 211;   // -=
+    public static final int MULTIPLY_EQUAL              = 212;   // *=
+    public static final int DIVIDE_EQUAL                = 213;   // /=
+    public static final int INTDIV_EQUAL                = 214;   // \=
+    public static final int MOD_EQUAL                   = 215;   // %=
+    public static final int POWER_EQUAL                 = 216;   // **=
+
+    public static final int PLUS_PLUS                   = 250;   // ++
+    public static final int PREFIX_PLUS_PLUS            = 251;   // ++
+    public static final int POSTFIX_PLUS_PLUS           = 252;   // ++
+    public static final int PREFIX_PLUS                 = 253;   // +
+
+    public static final int MINUS_MINUS                 = 260;   // --
+    public static final int PREFIX_MINUS_MINUS          = 261;   // --
+    public static final int POSTFIX_MINUS_MINUS         = 262;   // --
+    public static final int PREFIX_MINUS                = 263;   // - (negation)
+
+    public static final int LEFT_SHIFT                  = 280;   // <<
+    public static final int RIGHT_SHIFT                 = 281;   // >>
+    public static final int RIGHT_SHIFT_UNSIGNED        = 282;   // >>>
+
+    public static final int LEFT_SHIFT_EQUAL            = 285;   // <<=
+    public static final int RIGHT_SHIFT_EQUAL           = 286;   // >>=
+    public static final int RIGHT_SHIFT_UNSIGNED_EQUAL  = 287;   // >>>=
+
+    public static final int STAR                        = MULTIPLY;
+
+    public static final int COMMA                       = 300;   // -
+    public static final int COLON                       = 310;   // :
+    public static final int SEMICOLON                   = 320;   // ;
+    public static final int QUESTION                    = 330;   // ?
+
+    // TODO refactor PIPE to be BITWISE_OR
+    public static final int PIPE                        = 340;   // |
+    public static final int DOUBLE_PIPE                 = LOGICAL_OR;   // ||
+    public static final int BITWISE_OR                  = PIPE;  // |
+    public static final int BITWISE_AND                 = 341;   // &
+    public static final int BITWISE_XOR                 = 342;   // ^
+
+    public static final int BITWISE_OR_EQUAL            = 350;   // |=
+    public static final int BITWISE_AND_EQUAL           = 351;   // &=
+    public static final int BITWISE_XOR_EQUAL           = 352;   // ^=
+    public static final int BITWISE_NEGATION            = REGEX_PATTERN;    // ~
+
+
+    //
+    // LITERALS
+
+    public static final int STRING                      = 400;   // any bare string data
+
+    public static final int IDENTIFIER                  = 440;   // anything text and not a keyword
+
+    public static final int INTEGER_NUMBER              = 450;   // integer
+    public static final int DECIMAL_NUMBER              = 451;   // decimal
+
+
+    //
+    // KEYWORDS: (PRIMARILY) CLASS/METHOD DECLARATION MODIFIERS
+
+    public static final int KEYWORD_PRIVATE             = 500;   // declaration visibility
+    public static final int KEYWORD_PROTECTED           = 501;   // declaration visibility
+    public static final int KEYWORD_PUBLIC              = 502;   // declaration visibility
+
+    public static final int KEYWORD_ABSTRACT            = 510;   // method body missing
+    public static final int KEYWORD_FINAL               = 511;   // declaration cannot be overridden
+    public static final int KEYWORD_NATIVE              = 512;   // a native code entry point
+    public static final int KEYWORD_TRANSIENT           = 513;   // property should not be persisted
+    public static final int KEYWORD_VOLATILE            = 514;   // compiler should never cache property
+
+    public static final int KEYWORD_SYNCHRONIZED        = 520;   // modifier and block type
+    public static final int KEYWORD_STATIC              = 521;   // modifier and block type
+
+
+    //
+    // KEYWORDS: TYPE SYSTEM
+
+    public static final int KEYWORD_DEF                 = 530;   // identifies a function declaration
+    public static final int KEYWORD_DEFMACRO            = 539;   // XXX br identifies a macro declaration
+    public static final int KEYWORD_CLASS               = 531;   // identifies a class declaration
+    public static final int KEYWORD_INTERFACE           = 532;   // identifies an interface declaration
+    public static final int KEYWORD_MIXIN               = 533;   // identifies a mixin declaration
+
+    public static final int KEYWORD_IMPLEMENTS          = 540;   // specifies the interfaces implemented by a class
+    public static final int KEYWORD_EXTENDS             = 541;   // specifies the base class/interface for a new one
+    public static final int KEYWORD_THIS                = 542;   // method variable points to the current instance
+    public static final int KEYWORD_SUPER               = 543;   // method variable points to the base instance
+    public static final int KEYWORD_INSTANCEOF          = 544;   // type comparator
+    public static final int KEYWORD_PROPERTY            = 545;   // deprecated; identifies a property
+    public static final int KEYWORD_NEW                 = 546;   // used to create a new instance of a class
+
+    public static final int KEYWORD_PACKAGE             = 550;   // declares the package scope
+    public static final int KEYWORD_IMPORT              = 551;   // declares an external class
+    public static final int KEYWORD_AS                  = 552;   // used in import statements to create an alias
+
+
+    //
+    // KEYWORDS: CONTROL STRUCTURES
+
+    public static final int KEYWORD_RETURN              = 560;   // returns from a closure or method
+    public static final int KEYWORD_IF                  = 561;   // if
+    public static final int KEYWORD_ELSE                = 562;   // else
+    public static final int KEYWORD_DO                  = 570;   // do loop
+    public static final int KEYWORD_WHILE               = 571;   // while loop
+    public static final int KEYWORD_FOR                 = 572;   // for loop
+    public static final int KEYWORD_IN                  = 573;   // for (each) loop separator
+    public static final int KEYWORD_BREAK               = 574;   // exits a loop or block
+    public static final int KEYWORD_CONTINUE            = 575;   // restarts a loop on the next iteration
+    public static final int KEYWORD_SWITCH              = 576;   // switch block
+    public static final int KEYWORD_CASE                = 577;   // item in a switch block
+    public static final int KEYWORD_DEFAULT             = 578;   // catch-all item in a switch block
+
+    public static final int KEYWORD_TRY                 = 580;   // block to monitor for exceptions
+    public static final int KEYWORD_CATCH               = 581;   // catch block for a particular exception
+    public static final int KEYWORD_FINALLY             = 582;   // block to always execute on exit of the try
+    public static final int KEYWORD_THROW               = 583;   // statement to throw an exception
+    public static final int KEYWORD_THROWS              = 584;   // method modifier to declare thrown transactions
+    public static final int KEYWORD_ASSERT              = 585;   // alternate throw for code invariants
+
+
+    //
+    // KEYWORDS: PRIMITIVE TYPES
+
+    public static final int KEYWORD_VOID                = 600;   // void
+    public static final int KEYWORD_BOOLEAN             = 601;   // boolean
+    public static final int KEYWORD_BYTE                = 602;   // 1 byte integer
+    public static final int KEYWORD_SHORT               = 603;   // 2 byte integer
+    public static final int KEYWORD_INT                 = 604;   // 4 byte integer
+    public static final int KEYWORD_LONG                = 605;   // 8 byte integer
+    public static final int KEYWORD_FLOAT               = 606;   // 32 bit floating point number
+    public static final int KEYWORD_DOUBLE              = 607;   // 64 bit floating point number
+    public static final int KEYWORD_CHAR                = 608;   // unicode character code
+
+
+    //
+    // KEYWORDS: SPECIAL VALUES
+
+    public static final int KEYWORD_TRUE                = 610;   // boolean truth
+    public static final int KEYWORD_FALSE               = 611;   // boolean false
+    public static final int KEYWORD_NULL                = 612;   // missing instance
+
+
+    //
+    // KEYWORDS: RESERVED
+
+    public static final int KEYWORD_CONST               = 700;   // reserved in java and groovy
+    public static final int KEYWORD_GOTO                = 701;   // reserved in java and groovy
+
+
+    //
+    // SPECIAL (CALCULATED) MEANINGS
+
+    public static final int SYNTH_COMPILATION_UNIT      = 800;   // reserved: a synthetic root for a CST
+
+    public static final int SYNTH_CLASS                 = 801;   // applied to class names
+    public static final int SYNTH_INTERFACE             = 802;   // applied to interface names
+    public static final int SYNTH_MIXIN                 = 803;   // applied to mixin names
+    public static final int SYNTH_METHOD                = 804;   // applied to method names
+    public static final int SYNTH_PROPERTY              = 805;   // applied to property names
+    public static final int SYNTH_PARAMETER_DECLARATION = 806;   // applied to method/closure parameter names
+
+    public static final int SYNTH_LIST                  = 810;   // applied to "[" that marks a list
+    public static final int SYNTH_MAP                   = 811;   // applied to "[" that marks a map
+    public static final int SYNTH_GSTRING               = 812;   // a complete GString
+
+    public static final int SYNTH_METHOD_CALL           = 814;   // applied to the optional "(" that marks a call to a method
+    public static final int SYNTH_CAST                  = 815;   // applied to "(" that marks a type cast
+    public static final int SYNTH_BLOCK                 = 816;   // applied to "{" that marks a block
+    public static final int SYNTH_CLOSURE               = 817;   // applied to "{" that marks a closure
+    public static final int SYNTH_LABEL                 = 818;   // applied to a statement label
+    public static final int SYNTH_TERNARY               = 819;   // applied to "?" that marks a ternary expression
+    public static final int SYNTH_TUPLE                 = 820;   // applied to "{" that marks an array initializer
+
+    public static final int SYNTH_VARIABLE_DECLARATION  = 830;   // applied to an identifier that specifies
+                                                                 // the type of a variable declaration
+
+    //
+    // GSTRING TOKENS
+
+    public static final int GSTRING_START               = 901;   // any marker tha begins a GString
+    public static final int GSTRING_END                 = 902;   // any matching marker that ends a GString
+    public static final int GSTRING_EXPRESSION_START    = 903;   // the ${ marker that starts a GString expression
+    public static final int GSTRING_EXPRESSION_END      = 904;   // the } marker that ends a GString expresssion
+
+
+    //
+    // TYPE CLASSES
+
+    public static final int ANY                         = 1000;  // anything
+    public static final int NOT_EOF                     = 1001;  // anything but EOF
+    public static final int GENERAL_END_OF_STATEMENT    = 1002;  // ";", "\n", EOF
+    public static final int ANY_END_OF_STATEMENT        = 1003;  // ";", "\n", EOF, "}"
+
+    public static final int ASSIGNMENT_OPERATOR         = 1100;  // =, +=, etc.
+    public static final int COMPARISON_OPERATOR         = 1101;  // ==, ===, >, <, etc.
+    public static final int MATH_OPERATOR               = 1102;  // +, -, / *, %, plus the LOGICAL_OPERATORS
+    public static final int LOGICAL_OPERATOR            = 1103;  // ||, &&, !
+    public static final int RANGE_OPERATOR              = 1104;  // .., ...
+    public static final int REGEX_COMPARISON_OPERATOR   = 1105;  // =~, etc.
+    public static final int DEREFERENCE_OPERATOR        = 1106;  // ., ->
+    public static final int BITWISE_OPERATOR            = 1107;  // |, &, <<, >>, >>>, ^, ~
+
+    public static final int PREFIX_OPERATOR             = 1200;  // ++, !, etc.
+    public static final int POSTFIX_OPERATOR            = 1210;  // ++, etc.
+    public static final int INFIX_OPERATOR              = 1220;  // +, -, =, etc.
+    public static final int PREFIX_OR_INFIX_OPERATOR    = 1230;  // +, -
+    public static final int PURE_PREFIX_OPERATOR        = 1235;  // prefix +, prefix -
+
+    public static final int KEYWORD                     = 1300;  // any keyword
+    public static final int SYMBOL                      = 1301;  // any symbol
+    public static final int LITERAL                     = 1310;  // strings, numbers, identifiers
+    public static final int NUMBER                      = 1320;  // integers and decimals
+    public static final int SIGN                        = 1325;  // "+", "-"
+    public static final int NAMED_VALUE                 = 1330;  // true, false, null
+    public static final int TRUTH_VALUE                 = 1331;  // true, false
+    public static final int PRIMITIVE_TYPE              = 1340;  // void, byte, short, int, etc.
+    public static final int CREATABLE_PRIMITIVE_TYPE    = 1341;  // any PRIMITIVE_TYPE except void
+    public static final int LOOP                        = 1350;  // do, while, etc.
+    public static final int RESERVED_KEYWORD            = 1360;  // const, goto, etc.
+    public static final int KEYWORD_IDENTIFIER          = 1361;  // keywords that can appear as identifiers
+    public static final int SYNTHETIC                   = 1370;  // any of the SYNTH types
+
+    public static final int TYPE_DECLARATION            = 1400;  // class, interface, mixin
+    public static final int DECLARATION_MODIFIER        = 1410;  // public, private, abstract, etc.
+
+    public static final int TYPE_NAME                   = 1420;  // identifiers, primitive types
+    public static final int CREATABLE_TYPE_NAME         = 1430;  // identifiers, primitive types except void
+
+    public static final int MATCHED_CONTAINER           = 1500;  // (, ), [, ], {, }
+    public static final int LEFT_OF_MATCHED_CONTAINER   = 1501;  // (, [, {
+    public static final int RIGHT_OF_MATCHED_CONTAINER  = 1502;  // ), ], }
+
+    public static final int EXPRESSION                  = 1900;  // all of the below 1900 series
+
+    public static final int OPERATOR_EXPRESSION         = 1901;  // "."-"<<"
+    public static final int SYNTH_EXPRESSION            = 1902;  // cast, ternary, and closure expression
+    public static final int KEYWORD_EXPRESSION          = 1903;  // new, this, super, instanceof, true, false, null
+    public static final int LITERAL_EXPRESSION          = 1904;  // LITERAL
+    public static final int ARRAY_EXPRESSION            = 1905;  // "["
+
+    public static final int SIMPLE_EXPRESSION           = 1910;  // LITERAL, this, true, false, null
+    public static final int COMPLEX_EXPRESSION          = 1911;  // SIMPLE_EXPRESSION, and various molecules
+
+
+
+    //
+    // TYPE GROUPS (OPERATIONS SUPPORT)
+
+    public static final int PARAMETER_TERMINATORS       = 2000;  // ")", ","
+    public static final int ARRAY_ITEM_TERMINATORS      = 2001;  // "]", ","
+    public static final int TYPE_LIST_TERMINATORS       = 2002;  // "implements", "throws", "{", ","
+    public static final int OPTIONAL_DATATYPE_FOLLOWERS = 2003;  // identifier, "[", "."
+
+    public static final int SWITCH_BLOCK_TERMINATORS    = 2004;  // "case", "default", "}"
+    public static final int SWITCH_ENTRIES              = 2005;  // "case", "default"
+
+    public static final int METHOD_CALL_STARTERS        = 2006;  // LITERAL, "(", "{"
+    public static final int UNSAFE_OVER_NEWLINES        = 2007;  // things the expression parser should cross lines for in it doesn't have to
+
+    public static final int PRECLUDES_CAST_OPERATOR     = 2008;  // anything that prevents (X) from being a cast
+
+
+
+
+
+  //---------------------------------------------------------------------------
+  // TYPE HIERARCHIES
+
+
+   /**
+    *  Given two types, returns true if the second describes the first.
+    */
+
+    public static boolean ofType( int specific, int general )
+    {
+
+        if( general == specific )
+        {
+            return true;
+        }
+
+        switch( general )
+        {
+            case ANY:
+                return true;
+
+            case NOT_EOF:
+                return specific >= UNKNOWN && specific <= SYNTH_VARIABLE_DECLARATION;
+
+            case GENERAL_END_OF_STATEMENT:
+                switch( specific )
+                {
+                    case EOF:
+                    case NEWLINE:
+                    case SEMICOLON:
+                        return true;
+                }
+                break;
+
+            case ANY_END_OF_STATEMENT:
+                switch( specific )
+                {
+                    case EOF:
+                    case NEWLINE:
+                    case SEMICOLON:
+                    case RIGHT_CURLY_BRACE:
+                        return true;
+                }
+                break;
+
+            case ASSIGNMENT_OPERATOR:
+                return specific == EQUAL || (specific >= PLUS_EQUAL && specific <= POWER_EQUAL) || (specific >= LOGICAL_OR_EQUAL && specific <= LOGICAL_AND_EQUAL)
+                                         || (specific >= LEFT_SHIFT_EQUAL && specific <= RIGHT_SHIFT_UNSIGNED_EQUAL)
+                                         || (specific >= BITWISE_OR_EQUAL && specific <= BITWISE_XOR_EQUAL);
+
+            case COMPARISON_OPERATOR:
+                return specific >= COMPARE_NOT_EQUAL && specific <= COMPARE_TO;
+
+            case MATH_OPERATOR:
+                return (specific >= PLUS && specific <= RIGHT_SHIFT_UNSIGNED) || (specific >= NOT && specific <= LOGICAL_AND)
+                                 || (specific >= BITWISE_OR && specific <= BITWISE_XOR);
+
+            case LOGICAL_OPERATOR:
+                return specific >= NOT && specific <= LOGICAL_AND;
+
+            case BITWISE_OPERATOR:
+                return (specific >= BITWISE_OR && specific <= BITWISE_XOR) || specific == BITWISE_NEGATION;
+
+            case RANGE_OPERATOR:
+                return specific == DOT_DOT || specific == DOT_DOT_DOT;
+
+            case REGEX_COMPARISON_OPERATOR:
+                return specific == FIND_REGEX || specific == MATCH_REGEX;
+
+            case DEREFERENCE_OPERATOR:
+                return specific == DOT || specific == NAVIGATE;
+
+            case PREFIX_OPERATOR:
+                switch( specific )
+                {
+                    case MINUS:
+                    case PLUS_PLUS:
+                    case MINUS_MINUS:
+                        return true;
+                }
+
+                /* FALL THROUGH */
+
+            case PURE_PREFIX_OPERATOR:
+                switch( specific )
+                {
+                    case REGEX_PATTERN:
+                    case NOT:
+                    case PREFIX_PLUS:
+                    case PREFIX_PLUS_PLUS:
+                    case PREFIX_MINUS:
+                    case PREFIX_MINUS_MINUS:
+                    case SYNTH_CAST:
+                        return true;
+                }
+                break;
+
+            case POSTFIX_OPERATOR:
+                switch( specific )
+                {
+                    case PLUS_PLUS:
+                    case POSTFIX_PLUS_PLUS:
+                    case MINUS_MINUS:
+                    case POSTFIX_MINUS_MINUS:
+                        return true;
+                }
+                break;
+
+            case INFIX_OPERATOR:
+                switch( specific )
+                {
+                    case DOT:
+                    case NAVIGATE:
+                    case LOGICAL_OR:
+                    case LOGICAL_AND:
+                    case BITWISE_OR:
+                    case BITWISE_AND:
+                    case BITWISE_XOR:
+                    case LEFT_SHIFT:
+                    case RIGHT_SHIFT:
+                    case RIGHT_SHIFT_UNSIGNED:
+                    case FIND_REGEX:
+                    case MATCH_REGEX:
+                    case DOT_DOT:
+                    case DOT_DOT_DOT:
+                    case KEYWORD_INSTANCEOF:
+                        return true;
+                }
+
+                return (specific >= COMPARE_NOT_EQUAL && specific <= COMPARE_TO) || (specific >= PLUS && specific <= MOD_EQUAL) || specific == EQUAL || (specific >= PLUS_EQUAL && specific <= POWER_EQUAL) || (specific >= LOGICAL_OR_EQUAL && specific <= LOGICAL_AND_EQUAL)
+                                 || (specific >= LEFT_SHIFT_EQUAL && specific <= RIGHT_SHIFT_UNSIGNED_EQUAL) || (specific >= BITWISE_OR_EQUAL && specific <= BITWISE_XOR_EQUAL);
+
+            case PREFIX_OR_INFIX_OPERATOR:
+                switch( specific )
+                {
+                    case POWER:
+                    case PLUS:
+                    case MINUS:
+                    case PREFIX_PLUS:
+                    case PREFIX_MINUS:
+                        return true;
+                }
+                break;
+
+
+            case KEYWORD:
+                return specific >= KEYWORD_PRIVATE && specific <= KEYWORD_GOTO;
+
+            case SYMBOL:
+                return specific >= NEWLINE && specific <= PIPE;
+
+            case LITERAL:
+                return specific >= STRING && specific <= DECIMAL_NUMBER;
+
+            case NUMBER:
+                return specific == INTEGER_NUMBER || specific == DECIMAL_NUMBER;
+
+            case SIGN:
+                switch( specific )
+                {
+                    case PLUS:
+                    case MINUS:
+                        return true;
+                }
+                break;
+
+            case NAMED_VALUE:
+                return specific >= KEYWORD_TRUE && specific <= KEYWORD_NULL;
+
+            case TRUTH_VALUE:
+                return specific == KEYWORD_TRUE || specific == KEYWORD_FALSE;
+
+            case TYPE_NAME:
+                if( specific == IDENTIFIER )
+                {
+                    return true;
+                }
+
+                /* FALL THROUGH */
+
+            case PRIMITIVE_TYPE:
+                return specific >= KEYWORD_VOID && specific <= KEYWORD_CHAR;
+
+            case CREATABLE_TYPE_NAME:
+                if( specific == IDENTIFIER )
+                {
+                    return true;
+                }
+
+                /* FALL THROUGH */
+
+            case CREATABLE_PRIMITIVE_TYPE:
+                return specific >= KEYWORD_BOOLEAN && specific <= KEYWORD_CHAR;
+
+            case LOOP:
+                switch( specific )
+                {
+                    case KEYWORD_DO:
+                    case KEYWORD_WHILE:
+                    case KEYWORD_FOR:
+                        return true;
+                }
+                break;
+
+            case RESERVED_KEYWORD:
+                return specific >= KEYWORD_CONST && specific <= KEYWORD_GOTO;
+
+            case KEYWORD_IDENTIFIER:
+                switch( specific )
+                {
+                    case KEYWORD_CLASS:
+                    case KEYWORD_INTERFACE:
+                    case KEYWORD_MIXIN:
+                    case KEYWORD_DEF:
+                    case KEYWORD_DEFMACRO:
+                    case KEYWORD_IN:
+                    case KEYWORD_PROPERTY:
+                        return true;
+                }
+                break;
+
+            case SYNTHETIC:
+                return specific >= SYNTH_COMPILATION_UNIT && specific <= SYNTH_VARIABLE_DECLARATION;
+
+            case TYPE_DECLARATION:
+                return specific >= KEYWORD_CLASS && specific <= KEYWORD_MIXIN;
+
+            case DECLARATION_MODIFIER:
+                return specific >= KEYWORD_PRIVATE && specific <= KEYWORD_STATIC;
+
+            case MATCHED_CONTAINER:
+                switch( specific )
+                {
+                    case LEFT_CURLY_BRACE:
+                    case RIGHT_CURLY_BRACE:
+                    case LEFT_SQUARE_BRACKET:
+                    case RIGHT_SQUARE_BRACKET:
+                    case LEFT_PARENTHESIS:
+                    case RIGHT_PARENTHESIS:
+                        return true;
+                }
+                break;
+
+            case LEFT_OF_MATCHED_CONTAINER:
+                switch( specific )
+                {
+                    case LEFT_CURLY_BRACE:
+                    case LEFT_SQUARE_BRACKET:
+                    case LEFT_PARENTHESIS:
+                        return true;
+                }
+                break;
+
+            case RIGHT_OF_MATCHED_CONTAINER:
+                switch( specific )
+                {
+                    case RIGHT_CURLY_BRACE:
+                    case RIGHT_SQUARE_BRACKET:
+                    case RIGHT_PARENTHESIS:
+                        return true;
+                }
+                break;
+
+
+            case PARAMETER_TERMINATORS:
+                return specific == RIGHT_PARENTHESIS || specific == COMMA;
+
+            case ARRAY_ITEM_TERMINATORS:
+                return specific == RIGHT_SQUARE_BRACKET || specific == COMMA;
+
+            case TYPE_LIST_TERMINATORS:
+                switch( specific )
+                {
+                    case KEYWORD_IMPLEMENTS:
+                    case KEYWORD_THROWS:
+                    case LEFT_CURLY_BRACE:
+                    case COMMA:
+                        return true;
+                }
+                break;
+
+            case OPTIONAL_DATATYPE_FOLLOWERS:
+                switch( specific )
+                {
+                    case IDENTIFIER:
+                    case LEFT_SQUARE_BRACKET:
+                    case DOT:
+                        return true;
+                }
+                break;
+
+            case SWITCH_BLOCK_TERMINATORS:
+                if( specific == RIGHT_CURLY_BRACE )
+                {
+                    return true;
+                }
+
+                /* FALL THROUGH */
+
+            case SWITCH_ENTRIES:
+                return specific == KEYWORD_CASE || specific == KEYWORD_DEFAULT;
+
+            case METHOD_CALL_STARTERS:
+                if( specific >= STRING && specific <= DECIMAL_NUMBER )
+                {
+                    return true;
+                }
+                switch( specific )
+				{
+                	case LEFT_PARENTHESIS:
+                    case GSTRING_START:
+                    case SYNTH_GSTRING:
+                    case KEYWORD_NEW:
+                    	return true;
+                }
+                break;
+
+            case UNSAFE_OVER_NEWLINES:
+                if( ofType(specific, SYMBOL) )
+                {
+                    switch( specific )
+                    {
+                        case LEFT_CURLY_BRACE:
+                        case LEFT_PARENTHESIS:
+                        case LEFT_SQUARE_BRACKET:
+                        case PLUS:
+                        case PLUS_PLUS:
+                        case MINUS:
+                        case MINUS_MINUS:
+                        case REGEX_PATTERN:
+                        case NOT:
+                            return true;
+                    }
+
+                    return false;
+                }
+
+                switch( specific )
+                {
+                    case KEYWORD_INSTANCEOF:
+                    case GSTRING_EXPRESSION_START:
+                    case GSTRING_EXPRESSION_END:
+                    case GSTRING_END:
+                        return false;
+                }
+
+                return true;
+
+            case PRECLUDES_CAST_OPERATOR:
+                switch( specific )
+                {
+                    case PLUS:
+                    case MINUS:
+                    case PREFIX_MINUS:
+                    case PREFIX_MINUS_MINUS:
+                    case PREFIX_PLUS:
+                    case PREFIX_PLUS_PLUS:
+                    case LEFT_PARENTHESIS:
+                        return false;
+                }
+
+                return !ofType( specific, COMPLEX_EXPRESSION );
+
+
+
+
+            case OPERATOR_EXPRESSION:
+                return specific >= DOT && specific <= RIGHT_SHIFT_UNSIGNED;
+
+            case SYNTH_EXPRESSION:
+                switch( specific )
+                {
+                    case SYNTH_CAST:
+                    case SYNTH_CLOSURE:
+                    case SYNTH_TERNARY:
+                        return true;
+                }
+                break;
+
+            case KEYWORD_EXPRESSION:
+                switch( specific )
+                {
+                    case KEYWORD_NEW:
+                    case KEYWORD_THIS:
+                    case KEYWORD_SUPER:
+                    case KEYWORD_INSTANCEOF:
+                    case KEYWORD_TRUE:
+                    case KEYWORD_FALSE:
+                    case KEYWORD_NULL:
+                        return true;
+                }
+                break;
+
+            case LITERAL_EXPRESSION:
+                return specific >= STRING && specific <= DECIMAL_NUMBER;
+
+            case ARRAY_EXPRESSION:
+                return specific == LEFT_SQUARE_BRACKET;
+
+            case EXPRESSION:
+                if( specific >= DOT && specific <= RIGHT_SHIFT_UNSIGNED )
+                {
+                    return true;
+                }
+
+                if( specific >= STRING && specific <= DECIMAL_NUMBER )
+                {
+                    return true;
+                }
+
+                switch( specific )
+                {
+                    case SYNTH_CAST:
+                    case SYNTH_CLOSURE:
+                    case SYNTH_TERNARY:
+                    case SYNTH_GSTRING:
+                    case KEYWORD_NEW:
+                    case KEYWORD_THIS:
+                    case KEYWORD_SUPER:
+                    case KEYWORD_INSTANCEOF:
+                    case KEYWORD_TRUE:
+                    case KEYWORD_FALSE:
+                    case KEYWORD_NULL:
+                    case LEFT_SQUARE_BRACKET:
+                        return true;
+                }
+                break;
+
+            case COMPLEX_EXPRESSION:
+                switch( specific )
+                {
+                    case KEYWORD_NEW:
+                    case SYNTH_METHOD_CALL:
+                    case SYNTH_GSTRING:
+                    case SYNTH_LIST:
+                    case SYNTH_MAP:
+                    case SYNTH_CLOSURE:
+                    case SYNTH_TERNARY:
+                    case SYNTH_VARIABLE_DECLARATION:
+                        return true;
+                }
+
+                /* FALL THROUGH */
+
+            case SIMPLE_EXPRESSION:
+                if( specific >= STRING && specific <= DECIMAL_NUMBER ) {
+                    return true;
+                }
+
+                switch( specific ) {
+                    case KEYWORD_SUPER:
+                    case KEYWORD_THIS:
+                    case KEYWORD_TRUE:
+                    case KEYWORD_FALSE:
+                    case KEYWORD_NULL:
+                        return true;
+                }
+
+                break;
+        }
+
+        return false;
+    }
+
+
+
+
+  //---------------------------------------------------------------------------
+  // TYPE COERSIONS
+
+
+   /**
+    *  Given two types, returns true if the first can be viewed as the second.
+    *  NOTE that <code>canMean()</code> is orthogonal to <code>ofType()</code>.
+    */
+
+    public static boolean canMean( int actual, int preferred ) {
+
+        if( actual == preferred ) {
+            return true;
+        }
+
+        switch( preferred ) {
+
+            case SYNTH_PARAMETER_DECLARATION:
+            case IDENTIFIER:
+                switch( actual ) {
+                    case IDENTIFIER:
+                    case KEYWORD_DEF:
+                    case KEYWORD_DEFMACRO:
+                    case KEYWORD_CLASS:
+                    case KEYWORD_INTERFACE:
+                    case KEYWORD_MIXIN:
+                        return true;
+                }
+                break;
+
+            case SYNTH_CLASS:
+            case SYNTH_INTERFACE:
+            case SYNTH_MIXIN:
+            case SYNTH_METHOD:
+            case SYNTH_PROPERTY:
+                return actual == IDENTIFIER;
+
+            case SYNTH_LIST:
+            case SYNTH_MAP:
+                return actual == LEFT_SQUARE_BRACKET;
+
+            case SYNTH_CAST:
+                return actual == LEFT_PARENTHESIS;
+
+            case SYNTH_BLOCK:
+            case SYNTH_CLOSURE:
+                return actual == LEFT_CURLY_BRACE;
+
+            case SYNTH_LABEL:
+                return actual == COLON;
+
+            case SYNTH_VARIABLE_DECLARATION:
+                return actual == IDENTIFIER;
+        }
+
+        return false;
+    }
+
+
+
+   /**
+    *  Converts a node from a generic type to a specific prefix type.
+    *  Throws a <code>GroovyBugError</code> if the type can't be converted
+    *  and requested.
+    */
+
+    public static void makePrefix( CSTNode node, boolean throwIfInvalid ) {
+
+        switch( node.getMeaning() ) {
+            case PLUS:
+                node.setMeaning( PREFIX_PLUS );
+                break;
+
+            case MINUS:
+                node.setMeaning( PREFIX_MINUS );
+                break;
+
+            case PLUS_PLUS:
+                node.setMeaning( PREFIX_PLUS_PLUS );
+                break;
+
+            case MINUS_MINUS:
+                node.setMeaning( PREFIX_MINUS_MINUS );
+                break;
+
+            default:
+                if( throwIfInvalid ) {
+                    throw new GroovyBugError( "cannot convert to prefix for type [" + node.getMeaning() + "]" );
+                }
+        }
+
+    }
+
+
+
+   /**
+    *  Converts a node from a generic type to a specific postfix type.
+    *  Throws a <code>GroovyBugError</code> if the type can't be converted.
+    */
+
+    public static void makePostfix( CSTNode node, boolean throwIfInvalid ) {
+
+        switch( node.getMeaning() ) {
+            case PLUS_PLUS:
+                node.setMeaning( POSTFIX_PLUS_PLUS );
+                break;
+
+            case MINUS_MINUS:
+                node.setMeaning( POSTFIX_MINUS_MINUS );
+                break;
+
+            default:
+                if( throwIfInvalid ) {
+                    throw new GroovyBugError( "cannot convert to postfix for type [" + node.getMeaning() + "]" );
+                }
+        }
+
+    }
+
+
+
+
+  //---------------------------------------------------------------------------
+  // OPERATOR PRECEDENCE
+
+
+   /**
+    *  Returns the precendence of the specified operator.  Non-operator's will
+    *  receive -1 or a GroovyBugError, depending on your preference.
+    */
+
+    public static int getPrecedence( int type, boolean throwIfInvalid ) {
+
+        switch( type ) {
+
+            case LEFT_PARENTHESIS:
+                return 0;
+
+            case EQUAL:
+            case PLUS_EQUAL:
+            case MINUS_EQUAL:
+            case MULTIPLY_EQUAL:
+            case DIVIDE_EQUAL:
+            case INTDIV_EQUAL:
+            case MOD_EQUAL:
+            case POWER_EQUAL:
+            case LOGICAL_OR_EQUAL:
+            case LOGICAL_AND_EQUAL:
+            case LEFT_SHIFT_EQUAL:
+            case RIGHT_SHIFT_EQUAL:
+            case RIGHT_SHIFT_UNSIGNED_EQUAL:
+            case BITWISE_OR_EQUAL:
+            case BITWISE_AND_EQUAL:
+            case BITWISE_XOR_EQUAL:
+                return 5;
+
+            case QUESTION:
+                return 10;
+
+            case LOGICAL_OR:
+                return 15;
+
+            case LOGICAL_AND:
+                return 20;
+
+            case BITWISE_OR:
+	    case BITWISE_AND:
+            case BITWISE_XOR:
+                return 22;
+
+            case COMPARE_IDENTICAL:
+            case COMPARE_NOT_IDENTICAL:
+                return 24;
+
+            case COMPARE_NOT_EQUAL:
+            case COMPARE_EQUAL:
+            case COMPARE_LESS_THAN:
+            case COMPARE_LESS_THAN_EQUAL:
+            case COMPARE_GREATER_THAN:
+            case COMPARE_GREATER_THAN_EQUAL:
+            case COMPARE_TO:
+            case FIND_REGEX:
+            case MATCH_REGEX:
+            case KEYWORD_INSTANCEOF:
+                return 25;
+
+            case DOT_DOT:
+            case DOT_DOT_DOT:
+                return 30;
+
+            case LEFT_SHIFT:
+            case RIGHT_SHIFT:
+            case RIGHT_SHIFT_UNSIGNED:
+                return 35;
+
+            case PLUS:
+            case MINUS:
+                return 40;
+
+            case MULTIPLY:
+            case DIVIDE:
+            case INTDIV:
+            case MOD:
+                return 45;
+
+            case NOT:
+            case REGEX_PATTERN:
+                return 50;
+
+            case SYNTH_CAST:
+                return 55;
+
+            case PLUS_PLUS:
+            case MINUS_MINUS:
+            case PREFIX_PLUS_PLUS:
+            case PREFIX_MINUS_MINUS:
+            case POSTFIX_PLUS_PLUS:
+            case POSTFIX_MINUS_MINUS:
+                return 65;
+
+            case PREFIX_PLUS:
+            case PREFIX_MINUS:
+                return 70;
+
+            case POWER:
+                return 72;
+
+            case SYNTH_METHOD:
+            case LEFT_SQUARE_BRACKET:
+                return 75;
+
+            case DOT:
+            case NAVIGATE:
+                return 80;
+
+            case KEYWORD_NEW:
+                return 85;
+        }
+
+        if( throwIfInvalid ) {
+            throw new GroovyBugError( "precedence requested for non-operator" );
+        }
+
+        return -1;
+    }
+
+
+
+
+  //---------------------------------------------------------------------------
+  // TEXTS
+
+    private static final Map TEXTS  = new HashMap();  // symbol/keyword type -> text
+    private static final Map LOOKUP = new HashMap();  // text -> symbol/keyword type
+
+
+   /**
+    *  Returns the type for the specified symbol/keyword text.  Returns UNKNOWN
+    *  if the text isn't found.  You can filter finds on a type.
+    */
+
+    public static int lookup( String text, int filter ) {
+        int type = UNKNOWN;
+
+        if( LOOKUP.containsKey(text) ) {
+            type = ((Integer)LOOKUP.get(text)).intValue();
+            if( filter != UNKNOWN && !ofType(type, filter) ) {
+                type = UNKNOWN;
+            }
+        }
+
+        return type;
+    }
+
+
+   /**
+    *  Returns the type for the specified keyword text.  Returns UNKNOWN
+    *  if the text isn't found.
+    */
+
+    public static int lookupKeyword( String text ) {
+        return lookup( text, KEYWORD );
+    }
+
+
+   /**
+    *  Returns the type for the specified symbol text.  Returns UNKNOWN
+    *  if the text isn't found.
+    */
+
+    public static int lookupSymbol( String text ) {
+        return lookup( text, SYMBOL );
+    }
+
+
+   /**
+    *  Returns the text for the specified type.  Returns "" if the
+    *  text isn't found.
+    */
+
+    public static String getText( int type ) {
+        Integer key = new Integer( type );
+        String text = "";
+
+        if( TEXTS.containsKey(key) ) {
+            text = (String)TEXTS.get( key );
+        }
+
+        return text;
+    }
+
+
+   /**
+    *  Adds a element to the TEXTS and LOOKUP.
+    */
+
+    private static void addTranslation( String text, int type ) {
+        Integer key = new Integer( type );
+
+        TEXTS.put( key, text );
+        LOOKUP.put( text, key );
+    }
+
+
+    static {
+
+        //
+        // SYMBOLS
+
+        addTranslation( "\n"          , NEWLINE                     );
+
+        addTranslation( "{"           , LEFT_CURLY_BRACE            );
+        addTranslation( "}"           , RIGHT_CURLY_BRACE           );
+        addTranslation( "["           , LEFT_SQUARE_BRACKET         );
+        addTranslation( "]"           , RIGHT_SQUARE_BRACKET        );
+        addTranslation( "("           , LEFT_PARENTHESIS            );
+        addTranslation( ")"           , RIGHT_PARENTHESIS           );
+
+        addTranslation( "."           , DOT                         );
+        addTranslation( ".."          , DOT_DOT                     );
+        addTranslation( "..."         , DOT_DOT_DOT                 );
+
+        addTranslation( "->"          , NAVIGATE                    );
+
+        addTranslation( "=~"          , FIND_REGEX                  );
+        addTranslation( "==~"         , MATCH_REGEX                 );
+        addTranslation( "~"           , REGEX_PATTERN               );
+
+        addTranslation( "="           , EQUAL                       );
+
+        addTranslation( "!="          , COMPARE_NOT_EQUAL           );
+        addTranslation( "==="         , COMPARE_IDENTICAL           );
+        addTranslation( "!=="         , COMPARE_NOT_IDENTICAL       );
+        addTranslation( "=="          , COMPARE_EQUAL               );
+        addTranslation( "<"           , COMPARE_LESS_THAN           );
+        addTranslation( "<="          , COMPARE_LESS_THAN_EQUAL     );
+        addTranslation( ">"           , COMPARE_GREATER_THAN        );
+        addTranslation( ">="          , COMPARE_GREATER_THAN_EQUAL  );
+        addTranslation( "<=>"         , COMPARE_TO                  );
+
+        addTranslation( "!"           , NOT                         );
+        addTranslation( "||"          , LOGICAL_OR                  );
+        addTranslation( "&&"          , LOGICAL_AND                 );
+
+        addTranslation( "||="         , LOGICAL_OR_EQUAL            );
+        addTranslation( "&&="         , LOGICAL_AND_EQUAL           );
+
+        addTranslation( "+"           , PLUS                        );
+        addTranslation( "-"           , MINUS                       );
+        addTranslation( "*"           , MULTIPLY                    );
+        addTranslation( "/"           , DIVIDE                      );
+        addTranslation( "\\"          , INTDIV                      );
+        addTranslation( "%"           , MOD                         );
+
+	addTranslation( "**"          , POWER                       );
+
+        addTranslation( "+="          , PLUS_EQUAL                  );
+        addTranslation( "-="          , MINUS_EQUAL                 );
+        addTranslation( "*="          , MULTIPLY_EQUAL              );
+        addTranslation( "/="          , DIVIDE_EQUAL                );
+        addTranslation( "\\="         , INTDIV_EQUAL                );
+        addTranslation( "%="          , MOD_EQUAL                   );
+        addTranslation( "**="         , POWER_EQUAL                 );
+
+        addTranslation( "++"          , PLUS_PLUS                   );
+        addTranslation( "--"          , MINUS_MINUS                 );
+
+        addTranslation( "<<"          , LEFT_SHIFT                  );
+        addTranslation( ">>"          , RIGHT_SHIFT                 );
+        addTranslation( ">>>"         , RIGHT_SHIFT_UNSIGNED        );
+
+        addTranslation( "<<="         , LEFT_SHIFT_EQUAL            );
+        addTranslation( ">>="         , RIGHT_SHIFT_EQUAL           );
+        addTranslation( ">>>="        , RIGHT_SHIFT_UNSIGNED_EQUAL  );
+
+        addTranslation( "&"           , BITWISE_AND                 );
+        addTranslation( "^"           , BITWISE_XOR                 );
+
+        addTranslation( "|="          , BITWISE_OR_EQUAL           );
+        addTranslation( "&="          , BITWISE_AND_EQUAL           );
+        addTranslation( "^="          , BITWISE_XOR_EQUAL           );
+
+        addTranslation( ","           , COMMA                       );
+        addTranslation( ":"           , COLON                       );
+        addTranslation( ";"           , SEMICOLON                   );
+        addTranslation( "?"           , QUESTION                    );
+        addTranslation( "|"           , PIPE                        );
+
+        addTranslation( "${}"         , GSTRING_EXPRESSION_START    );
+
+
+        //
+        // Keywords
+
+        addTranslation( "abstract"    , KEYWORD_ABSTRACT            );
+        addTranslation( "as"          , KEYWORD_AS                  );
+        addTranslation( "assert"      , KEYWORD_ASSERT              );
+        addTranslation( "break"       , KEYWORD_BREAK               );
+        addTranslation( "case"        , KEYWORD_CASE                );
+        addTranslation( "catch"       , KEYWORD_CATCH               );
+        addTranslation( "class"       , KEYWORD_CLASS               );
+        addTranslation( "const"       , KEYWORD_CONST               );
+        addTranslation( "continue"    , KEYWORD_CONTINUE            );
+        addTranslation( "def"         , KEYWORD_DEF                 );
+        addTranslation( "defmacro"    , KEYWORD_DEF                 ); // xxx br defmacro
+        addTranslation( "default"     , KEYWORD_DEFAULT             );
+        addTranslation( "do"          , KEYWORD_DO                  );
+        addTranslation( "else"        , KEYWORD_ELSE                );
+        addTranslation( "extends"     , KEYWORD_EXTENDS             );
+        addTranslation( "final"       , KEYWORD_FINAL               );
+        addTranslation( "finally"     , KEYWORD_FINALLY             );
+        addTranslation( "for"         , KEYWORD_FOR                 );
+        addTranslation( "goto"        , KEYWORD_GOTO                );
+        addTranslation( "if"          , KEYWORD_IF                  );
+        addTranslation( "in"          , KEYWORD_IN                  );
+        addTranslation( "implements"  , KEYWORD_IMPLEMENTS          );
+        addTranslation( "import"      , KEYWORD_IMPORT              );
+        addTranslation( "instanceof"  , KEYWORD_INSTANCEOF          );
+        addTranslation( "interface"   , KEYWORD_INTERFACE           );
+        addTranslation( "mixin"       , KEYWORD_MIXIN               );
+        addTranslation( "native"      , KEYWORD_NATIVE              );
+        addTranslation( "new"         , KEYWORD_NEW                 );
+        addTranslation( "package"     , KEYWORD_PACKAGE             );
+        addTranslation( "private"     , KEYWORD_PRIVATE             );
+        addTranslation( "property"    , KEYWORD_PROPERTY            );
+        addTranslation( "protected"   , KEYWORD_PROTECTED           );
+        addTranslation( "public"      , KEYWORD_PUBLIC              );
+        addTranslation( "return"      , KEYWORD_RETURN              );
+        addTranslation( "static"      , KEYWORD_STATIC              );
+        addTranslation( "super"       , KEYWORD_SUPER               );
+        addTranslation( "switch"      , KEYWORD_SWITCH              );
+        addTranslation( "synchronized", KEYWORD_SYNCHRONIZED        );
+        addTranslation( "this"        , KEYWORD_THIS                );
+        addTranslation( "throw"       , KEYWORD_THROW               );
+        addTranslation( "throws"      , KEYWORD_THROWS              );
+        addTranslation( "transient"   , KEYWORD_TRANSIENT           );
+        addTranslation( "try"         , KEYWORD_TRY                 );
+        addTranslation( "volatile"    , KEYWORD_VOLATILE            );
+        addTranslation( "while"       , KEYWORD_WHILE               );
+
+        addTranslation( "true"        , KEYWORD_TRUE                );
+        addTranslation( "false"       , KEYWORD_FALSE               );
+        addTranslation( "null"        , KEYWORD_NULL                );
+
+        addTranslation( "void"        , KEYWORD_VOID                );
+        addTranslation( "boolean"     , KEYWORD_BOOLEAN             );
+        addTranslation( "byte"        , KEYWORD_BYTE                );
+        addTranslation( "int"         , KEYWORD_INT                 );
+        addTranslation( "short"       , KEYWORD_SHORT               );
+        addTranslation( "long"        , KEYWORD_LONG                );
+        addTranslation( "float"       , KEYWORD_FLOAT               );
+        addTranslation( "double"      , KEYWORD_DOUBLE              );
+        addTranslation( "char"        , KEYWORD_CHAR                );
+    }
+
+
+
+
+  //---------------------------------------------------------------------------
+  // DESCRIPTIONS
+
+
+    private static final Map DESCRIPTIONS = new HashMap();
+
+
+   /**
+    *  Gets the description for the specified type.
+    */
+
+    public static String getDescription( int type ) {
+        Integer typeKey = new Integer(type);
+
+        if (DESCRIPTIONS.containsKey(typeKey)) {
+            return (String)DESCRIPTIONS.get(typeKey);
+        }
+
+        return "<>";
+    }
+
+
+   /**
+    *  Adds a description to the set.
+    */
+
+    private static void addDescription(int type, String description) {
+        addDescription(new Integer(type), description);
+    }
+
+
+   /**
+    *  Adds a description to the set.
+    */
+
+    private static void addDescription(Integer type, String description) {
+        if (description.startsWith("<") && description.endsWith(">")) {
+            DESCRIPTIONS.put(type, description);
+        }
+        else {
+            DESCRIPTIONS.put(type, '"' + description + '"');
+        }
+    }
+
+
+    static {
+
+        Iterator iterator = LOOKUP.keySet().iterator();
+        while( iterator.hasNext() )
+        {
+            String text = (String)iterator.next();
+            Integer key = (Integer)LOOKUP.get(text);
+
+            addDescription( key, text );
+        }
+
+        addDescription( NEWLINE                     , "<newline>"        );
+        addDescription( PREFIX_PLUS_PLUS            , "<prefix ++>"      );
+        addDescription( POSTFIX_PLUS_PLUS           , "<postfix ++>"     );
+        addDescription( PREFIX_MINUS_MINUS          , "<prefix -->"      );
+        addDescription( POSTFIX_MINUS_MINUS         , "<postfix -->"     );
+        addDescription( PREFIX_PLUS                 , "<positive>"       );
+        addDescription( PREFIX_MINUS                , "<negative>"       );
+
+        addDescription( STRING                      , "<string literal>" );
+        addDescription( IDENTIFIER                  , "<identifier>"     );
+        addDescription( INTEGER_NUMBER              , "<integer>"        );
+        addDescription( DECIMAL_NUMBER              , "<decimal>"        );
+
+        addDescription( SYNTH_COMPILATION_UNIT      , "<compilation unit>" );
+        addDescription( SYNTH_CLASS                 , "<class>"          );
+        addDescription( SYNTH_INTERFACE             , "<interface>"      );
+        addDescription( SYNTH_MIXIN                 , "<mixin>"          );
+        addDescription( SYNTH_METHOD                , "<method>"         );
+        addDescription( SYNTH_METHOD_CALL           , "<method call>"    );
+        addDescription( SYNTH_PROPERTY              , "<property>"       );
+        addDescription( SYNTH_PARAMETER_DECLARATION , "<parameter>"      );
+        addDescription( SYNTH_LIST                  , "<list>"           );
+        addDescription( SYNTH_MAP                   , "<map>"            );
+        addDescription( SYNTH_TUPLE                 , "<tuple>"          );
+        addDescription( SYNTH_GSTRING               , "<gstring>"        );
+        addDescription( SYNTH_CAST                  , "<cast>"           );
+        addDescription( SYNTH_BLOCK                 , "<block>"          );
+        addDescription( SYNTH_CLOSURE               , "<closure>"        );
+        addDescription( SYNTH_TERNARY               , "<ternary>"        );
+        addDescription( SYNTH_LABEL                 , "<label>"          );
+        addDescription( SYNTH_VARIABLE_DECLARATION  , "<variable declaration>"       );
+
+        addDescription( GSTRING_START               , "<start of gstring tokens>"    );
+        addDescription( GSTRING_END                 , "<end of gstring tokens>"      );
+        addDescription( GSTRING_EXPRESSION_START    , "<start of gstring expression>");
+        addDescription( GSTRING_EXPRESSION_END      , "<end of gstring expression>"  );
+
+        addDescription( ASSIGNMENT_OPERATOR         , "<assignment operator>"        );
+        addDescription( COMPARISON_OPERATOR         , "<comparison operator>"        );
+        addDescription( MATH_OPERATOR               , "<math operator>"              );
+        addDescription( LOGICAL_OPERATOR            , "<logical operator>"           );
+        addDescription( BITWISE_OPERATOR            , "<bitwise operator>"           );
+        addDescription( RANGE_OPERATOR              , "<range operator>"             );
+        addDescription( REGEX_COMPARISON_OPERATOR   , "<regex comparison operator>"  );
+        addDescription( DEREFERENCE_OPERATOR        , "<dereference operator>"       );
+        addDescription( PREFIX_OPERATOR             , "<prefix operator>"            );
+        addDescription( POSTFIX_OPERATOR            , "<postfix operator>"           );
+        addDescription( INFIX_OPERATOR              , "<infix operator>"             );
+        addDescription( KEYWORD                     , "<keyword>"                    );
+        addDescription( LITERAL                     , "<literal>"                    );
+        addDescription( NUMBER                      , "<number>"                     );
+        addDescription( NAMED_VALUE                 , "<named value>"                );
+        addDescription( TRUTH_VALUE                 , "<truth value>"                );
+        addDescription( PRIMITIVE_TYPE              , "<primitive type>"             );
+        addDescription( CREATABLE_PRIMITIVE_TYPE    , "<creatable primitive type>"   );
+        addDescription( LOOP                        , "<loop>"                       );
+        addDescription( RESERVED_KEYWORD            , "<reserved keyword>"           );
+        addDescription( SYNTHETIC                   , "<synthetic>"                  );
+        addDescription( TYPE_DECLARATION            , "<type declaration>"           );
+        addDescription( DECLARATION_MODIFIER        , "<declaration modifier>"       );
+        addDescription( TYPE_NAME                   , "<type name>"                  );
+        addDescription( CREATABLE_TYPE_NAME         , "<creatable type name>"        );
+        addDescription( MATCHED_CONTAINER           , "<matched container>"          );
+        addDescription( LEFT_OF_MATCHED_CONTAINER   , "<left of matched container>"  );
+        addDescription( RIGHT_OF_MATCHED_CONTAINER  , "<right of matched container>" );
+        addDescription( SWITCH_ENTRIES              , "<valid in a switch body>"     );
+    }
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/syntax/package.html b/groovy-core/src/main/org/codehaus/groovy/syntax/package.html
new file mode 100644
index 0000000..05b7042
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/syntax/package.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>package org.codehaus.groovy.syntax.*</title>
+  </head>
+  <body>
+    <p>Lexer, parser and trees.</p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/org/codehaus/groovy/tools/Compiler.java b/groovy-core/src/main/org/codehaus/groovy/tools/Compiler.java
new file mode 100644
index 0000000..c54aefd
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/tools/Compiler.java
@@ -0,0 +1,149 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.tools;
+
+import java.io.File;
+
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.SourceUnit;
+
+
+
+
+/**
+ *  A convenience front end for getting standard compilations done.
+ *  All compile() routines generate classes to the filesystem.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ *
+ *  @version $Id$
+ */
+
+public class Compiler
+{
+    public static Compiler DEFAULT = new Compiler();
+    
+    private CompilerConfiguration configuration = null;  // Optional configuration data
+    
+   /**
+    *  Initializes the Compiler with default configuration.
+    */
+    
+    public Compiler()
+    {
+        configuration = null;
+    }
+    
+    
+   /**
+    *  Initializes the Compiler with the specified configuration.
+    */
+    
+    public Compiler( CompilerConfiguration configuration )
+    {
+        this.configuration = configuration;
+    }
+
+    
+   
+   /**
+    *  Compiles a single File.
+    */
+   
+    public void compile( File file ) throws CompilationFailedException
+    {
+        CompilationUnit unit = new CompilationUnit( configuration );
+        unit.addSource( file );
+        unit.compile();
+    }
+    
+    
+    
+   /**
+    *  Compiles a series of Files.
+    */
+    
+    public void compile( File[] files ) throws CompilationFailedException
+    {
+        CompilationUnit unit = new CompilationUnit( configuration );
+        unit.addSources( files );
+        unit.compile();
+    }
+
+    
+    
+   /**
+    *  Compiles a series of Files from file names.
+    */
+    
+    public void compile( String[] files ) throws CompilationFailedException
+    {
+        CompilationUnit unit = new CompilationUnit( configuration );
+        unit.addSources( files );
+        unit.compile();
+    }
+
+    
+    
+   /**
+    *  Compiles a string of code.
+    */
+    
+    public void compile( String name, String code ) throws CompilationFailedException
+    {
+        CompilationUnit unit = new CompilationUnit( configuration );
+        unit.addSource( new SourceUnit(name, code, configuration, unit.getClassLoader(), unit.getErrorCollector()) );
+        unit.compile();
+    }
+
+}
+
+
+
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/tools/DocGenerator.groovy b/groovy-core/src/main/org/codehaus/groovy/tools/DocGenerator.groovy
new file mode 100644
index 0000000..b783baf
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/tools/DocGenerator.groovy
@@ -0,0 +1,327 @@
+package org.codehaus.groovy.tools
+
+import groovy.xml.StreamingMarkupBuilder
+
+import java.io.File
+
+import com.thoughtworks.qdox.JavaDocBuilder
+import com.thoughtworks.qdox.model.JavaSource
+import com.thoughtworks.qdox.model.JavaClass
+import com.thoughtworks.qdox.model.JavaMethod
+import com.thoughtworks.qdox.model.JavaParameter
+import com.thoughtworks.qdox.model.Type
+import java.util.*;
+
+
+/**
+ * Generate documentation about the methods provided by the Groovy Development Kit
+ * enhancing the standard JDK classes.
+ *
+ * @author Guillaume Laforge, John Wilson
+ */
+class DocGenerator
+{
+	File           file
+	File           outputFile
+	JavaDocBuilder builder
+
+	DocGenerator(File fileToParse, File outputFile)
+	{
+		this.file       = fileToParse
+		this.outputFile = outputFile
+	}
+
+	/**
+	 * Parse the DefaultGroovyMethods class to build a graph representing the structure of the class,
+	 * with its methods, javadoc comments and tags.
+	 */
+	private void parse()
+	{
+		def reader  = file.newReader()
+		builder = new JavaDocBuilder()
+
+		builder.addSource(reader)
+	}
+
+	/**
+	 * Builds an HTML page from the structure of DefaultGroovyMethods.
+	 */
+		
+		def generate() {
+			parse()
+			
+			def sources = builder.getSources()
+
+			def firstSource = sources[0]
+			def classes = firstSource.getClasses()
+			def groovyMeth = classes[0]
+	
+			// categorize all groovy methods per core JDK class to which it applies
+			def jdkEnhancedClasses = [:]
+			def methods = groovyMeth.getMethods()
+			
+            def start = System.currentTimeMillis();
+			for (method in methods) {
+				if (method.isPublic() && method.isStatic()) {
+					def parameters = method.getParameters()
+					def jdkClass = parameters[0].getType().toString()
+
+					if (jdkEnhancedClasses.containsKey(jdkClass)) {
+					    List l = jdkEnhancedClasses[jdkClass];
+						l.add(method)
+				    }
+					else
+						jdkEnhancedClasses[jdkClass] = [method]
+				}
+			}
+            //start = System.currentTimeMillis();
+	        println " added classes in ${System.currentTimeMillis() - start} ms"
+
+			def headElement = { head {
+								mkp.comment 'generated by Groovy using Streaming Markup'
+								title 'GDK : Groovy methods'
+								style(['type':'text/css'], '   @import url("./style/maven-base.css"); ')
+								style(['type':'text/css'], '   @import url("http://codehaus.org/codehaus-style.css"); ')
+							}
+						  }
+							
+			def sortedClasses = new TreeSet(jdkEnhancedClasses.keySet())
+							
+			def ind = 0
+			def cellsInRow = 4
+			// Split sortedClasses into list of 4-element lists
+			def rowList = sortedClasses.inject([]) { list, item ->
+				if (ind++ % cellsInRow == 0)
+					list << [item]
+				else
+					list[-1] << item
+				return list
+			}
+
+			def classLinks = { mkp.yield {
+					def classCounter = 0
+					table(width:'100%') {
+						tr {
+							th(colspan:"${cellsInRow}", "Groovy JDK classes")
+						}
+						for (row in rowList) {
+							if (row.size() < cellsInRow) {
+								(cellsInRow - row.size()).times { row << "" }
+							}
+							tr {
+								for (className in row) {
+									td(width:'25%') {
+										a(href:"#cls${classCounter}", "${className}")
+									}
+									classCounter++;            	    				
+								}
+							}
+						}
+					}
+				}
+			}
+
+			def summary = { mkp.yield {
+					            def counter = 0
+								def classCounter = 0
+					
+								// lets iterate in sorted class name order
+								for (String className in sortedClasses) {
+					
+									p { a(name:"cls${classCounter}") }
+									b className
+									classCounter++
+					
+									def listOfMethods = jdkEnhancedClasses[className]
+									listOfMethods.sort{ it.name }
+									
+									table(width:'100%') {
+										for (JavaMethod meth in listOfMethods) {
+						                    counter++
+						                    
+						                    tr {
+						                    	td(width:'30%') {
+						                    		mkp.yield getReturnType(meth)
+						                    	}
+						                    	td(width:'70%') {
+						                    		a(href:"#meth${counter}") { 
+						                    			mkp.yield meth.getName()
+						                    		}
+						                    		mkp.yield "(${getParametersDecl(meth)})"
+						                    	}
+						                    }
+										}
+									}
+								}
+							}
+						}
+								
+			def details = { mkp.yield {
+								def counter = 0
+								
+								for (className in sortedClasses) {
+					
+									h2 className
+					
+									def listOfMethods = jdkEnhancedClasses[className]
+									listOfMethods.sort{ it.name }
+									
+									for (JavaMethod meth in listOfMethods) {
+					                    counter++
+
+					                    a(name:"meth${counter}")
+					                    
+					                    p {
+					                    	b "${getReturnType(meth)} ${meth.getName()}(${getParametersDecl(meth)})"
+					                    }
+					                    
+				                    	ul {
+				                    		//
+				                    		// Java comments can contain markup - pass it through as is
+				                    		//
+				                   			mkp.yieldUnescaped "${getComment(meth)}  "
+				                   			
+					                    	ul {
+												def params = meth.getTags()
+												def count = 0
+												
+												for (param in params) {
+													if (count++ != 0 && param.getName() != "throws" && param.getName() != "return") {
+														li "${param.getName()} ${param.getValue()}"
+													}
+												 }
+
+												def returnType = getReturnType(meth)
+	
+												if (returnType != "") {
+												    if (returnType != "void") {
+													    li {
+													    	b "returns"
+															mkp.yield ": ${returnType}"
+															    	
+													        def returnTag = meth.getTagByName("return")
+													                
+													        if (returnTag != null) {
+													        	mkp.yield " - "
+													        	i returnTag.getValue()
+															}
+														}
+													}
+													
+													def exceptions = meth.getExceptions()
+													
+													for (ex in exceptions) {
+														if (ex != null) {
+															li {
+																b "throws"
+																mkp.yield ": ${ex}"
+	
+																def exMsg = meth.getTagByName("throws")
+																
+																if (exMsg != null) {
+																	mkp.yield " - "
+																	i exMsg.getValue()
+																}
+															}
+														}
+													}
+												}
+											}
+					                    }
+									}
+								}
+					  		}
+					  	}
+					  				
+			def bodyElement = { body {
+								h1 'Groovy JDK methods'
+								p 'New methods added to the JDK to make it more groovy.'
+								mkp.yield classLinks
+								mkp.yield summary
+								mkp.yield details
+							 }
+						   }
+					
+			 outputFile.getParentFile().mkdirs()
+			 outputFile.newPrintWriter() << new StreamingMarkupBuilder().bind{ html {
+																						mkp.yield headElement
+																						mkp.yield bodyElement
+																					 }
+																			  }
+		}
+
+		/**
+	 	* Retrieves a String representing the return type
+	 	*/
+		private getReturnType(method)
+		{
+		    def returnType = method.getReturns()
+		    
+		    if (returnType != null) {
+		    	    return returnType.toString()
+		    } else {
+		    	    return ""
+		    }
+		}
+
+		/**
+		 * Retrieve a String representing the declaration of the parameters of the method passed as parameter.
+		 *
+		 * @param method a method
+		 * @return the declaration of the method (long version)
+		 */
+		private getParametersDecl(method)
+		{
+			getParameters(method).collect{ "${it.getType()} ${it.getName()}" }.join(", ")
+		}
+
+		/**
+		 * Retrieve the parameters of the method.
+		 *
+		 * @param method a method
+		 * @return a list of parameters without the first one
+		 */
+		private getParameters(method)
+		{
+		    if (method.getParameters().size() > 1)
+			    return method.getParameters().toList()[1..-1]
+			else
+			    return []
+		}
+
+		/**
+		 * Retrieve the JavaDoc comment associated with the method passed as parameter.
+		 *
+		 * @param method a method
+		 * @return the JavaDoc comment associated with this method
+		 */
+		private getComment(method)
+		{
+			def ans = method.getComment()
+			if (ans == null) return ""
+			return ans
+		}
+
+    /**
+     * Main entry point.
+     */
+    static void main(args)
+    {
+        def defaultGroovyMethodSource =
+            //new File("D:/cvs-groovy/groovy/groovy-core/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java")
+            new File("src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java")
+        def outFileName =
+            //new File("D:/cvs-groovy/groovy/groovy-core/target/html/groovy-jdk.html")
+            new File("target/html/groovy-jdk.html")
+
+        def start = System.currentTimeMillis();
+
+        def docGen = new DocGenerator(defaultGroovyMethodSource, outFileName)
+        docGen.generate()
+
+        def end = System.currentTimeMillis();
+
+        println "Done. in ${end - start} millis"
+
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/tools/ErrorReporter.java b/groovy-core/src/main/org/codehaus/groovy/tools/ErrorReporter.java
new file mode 100644
index 0000000..a795d54
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/tools/ErrorReporter.java
@@ -0,0 +1,264 @@
+/*
+ $Id$
+
+ Copyright 2004 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+
+package org.codehaus.groovy.tools;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+import org.codehaus.groovy.GroovyExceptionInterface;
+import org.codehaus.groovy.control.CompilationFailedException;
+import groovy.lang.GroovyRuntimeException;
+
+
+/**
+ *  Provides services for reporting compilation errors to the
+ *  user.  Primary entry point is <code>write()</code>.
+ *
+ *  @author <a href="mailto:cpoirier%20AT%20tapestry_os%20DOT%20org">Chris Poirier</a>
+ *  @version $Revision$
+ */
+
+public class ErrorReporter
+{
+    private Throwable   base     = null;    // The exception on which to report
+    private boolean     debug    = false;   // If true, stack traces are always output
+
+    private Object      output   = null;    // The stream/writer to which to output
+
+
+   /**
+    *  Configures a new Reporter.  Default mode is not to report a stack trace unless
+    *  the error was not of one of the supported types.
+    *
+    *  @param e  the exception on which to report
+    */
+
+    public ErrorReporter( Throwable e )
+    {
+        this.base     = e;
+    }
+
+
+   /**
+    *  Configures a new Reporter.  
+    *
+    *  @param e      the exception on which to report
+    *  @param debug  if set, stack traces will be output for all reports
+    */
+
+    public ErrorReporter( Throwable e, boolean debug )
+    {
+        this.base  = e;
+        this.debug = debug;
+    }
+
+
+   /**
+    *  Writes the error to the specified <code>PrintStream</code>.
+    */
+
+    public void write( PrintStream stream )
+    {
+        this.output = stream;
+        dispatch( base, false );
+        stream.flush();
+    }
+
+
+   /**
+    *  Writes the error to the specified <code>PrintWriter</code>.
+    */
+
+    public void write( PrintWriter writer )
+    {
+        this.output = writer;
+        dispatch( base, false );
+        writer.flush();
+    }
+
+
+   /**
+    *  Runs the report once all initialization is complete.
+    */
+
+    protected void dispatch( Throwable object, boolean child )
+    {
+        if( object instanceof CompilationFailedException )
+        {
+            report( (CompilationFailedException)object, child );
+        }
+        else if( object instanceof GroovyExceptionInterface )
+        {
+            report( (GroovyExceptionInterface)object, child );
+        }
+        else if( object instanceof GroovyRuntimeException )
+        {
+            report( (GroovyRuntimeException)object, child );
+        }
+        else if( object instanceof Exception )
+        {
+            report( (Exception)object, child );
+        }
+        else
+        {
+            report( object, child );
+        }
+
+    }
+
+
+
+  //---------------------------------------------------------------------------
+  // REPORTING ROUTINES
+
+
+   /**
+    *  For CompilationFailedException.
+    */
+
+    protected void report( CompilationFailedException e, boolean child )
+    {
+        println( e.toString() );
+        stacktrace( e, false );
+    }
+
+
+
+   /**
+    *  For GroovyException.
+    */
+
+    protected void report( GroovyExceptionInterface e, boolean child )
+    {
+        println( ((Exception)e).getMessage() );
+        stacktrace( (Exception)e, false );
+    }
+
+
+
+   /**
+    *  For Exception.
+    */
+
+    protected void report( Exception e, boolean child )
+    {
+        println( e.getMessage() );
+        stacktrace( e, false );
+    }
+
+
+
+   /**
+    *  For everything else.
+    */
+
+    protected void report( Throwable e, boolean child )
+    {
+        println( ">>> a serious error occurred: " + e.getMessage() );
+        stacktrace( e, true );
+    }
+
+
+
+  //---------------------------------------------------------------------------
+  // GENERAL SUPPORT ROUTINES
+
+
+   /**
+    *  Prints a line to the underlying <code>PrintStream</code>
+    */
+
+    protected void println( String line )
+    {
+        if( output instanceof PrintStream )
+        {
+            ((PrintStream)output).println( line );
+        }
+        else
+        {
+            ((PrintWriter)output).println( line );
+        }
+    }
+
+    protected void println( StringBuffer line )
+    {
+        if( output instanceof PrintStream )
+        {
+            ((PrintStream)output).println( line );
+        }
+        else
+        {
+            ((PrintWriter)output).println( line );
+        }
+    }
+
+
+   /**
+    *  Displays an exception's stack trace, if <code>debug</code> or 
+    *  <code>always</code>.
+    */
+
+    protected void stacktrace( Throwable e, boolean always )
+    {
+        if( debug || always )
+        {
+            println( ">>> stacktrace:" );
+            if( output instanceof PrintStream )
+            {
+                e.printStackTrace( (PrintStream)output );
+            }
+            else
+            {
+                e.printStackTrace( (PrintWriter)output );
+            }
+        }
+    }
+
+
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/tools/FailsGenerator.groovy b/groovy-core/src/main/org/codehaus/groovy/tools/FailsGenerator.groovy
new file mode 100644
index 0000000..a72bcf8
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/tools/FailsGenerator.groovy
@@ -0,0 +1,201 @@
+package org.codehaus.groovy.tools;
+
+import java.io.*;
+import groovy.util.XmlSlurper;
+import groovy.xml.StreamingMarkupBuilder;
+
+class FailsGenerator {
+
+    def public conf;
+    def public map = new HashMap();
+    def public save=false
+    public boolean hasChanged=false
+    public int nr=0;
+    public boolean skipIgnores=true
+    
+    public FailsGenerator(){}    
+
+    static void main(args) {
+        if (args.length<2) {
+            println "usage: FailsGenerator [--save] [--skip-ignores] <conf-file> <reports-dir>"
+            println "         save           is optional argument and let the script store the results"
+            println "                        found in the xml files in the conf file"
+            println "         skip-ignores   don't print information about ignored files "
+            println "         conf-file      is the configuration file"
+            println "         reports-dir    is the directory containing the xml reports from JUnit"
+            System.exit(1)
+        }
+        def gen = new FailsGenerator();
+        int argIndex=0
+        while (args[argIndex].startsWith("--")) {
+          switch (args[argIndex]) {
+            case "--save":
+              gen.save=true
+              break;
+            case "--skip-ignores":
+              gen.skipIgnores=true
+              break;
+            default:
+              println "unknown option "+ args[argIndex]
+              System.exit(1);
+          }
+          argIndex++;
+        }
+        gen.conf = new File(args[argIndex])
+        gen.readConf()
+        gen.compareFiles(args[argIndex+1])
+        gen.saveConf()
+        println "DONE"
+    }
+    
+    
+    void compareFiles(dir) {
+    
+        def attReader = { name, attName, oldVal, newVal ->
+            if (attName!=null) oldVal=Integer.parseInt(oldVal)
+            boolean success = (oldVal!=0 && newVal==0)
+            if (success) {
+                println("${name}: well done, no more ${attName}");
+            } else if (oldVal==-1) {
+                // do nothing
+            } else if (newVal<oldVal) {
+                println("${name}: improved ${attName} from ${oldVal} to ${newVal}");
+            } else if (newVal>oldVal) {
+                println("${name}: more ${attName} (from ${oldVal} to ${newVal})");
+            }
+            hasChanged = hasChanged || newVal!=oldVal
+            return success
+        }
+
+
+        dir = new File(dir)
+        if (!dir.isDirectory()) throw new RuntimeException("${dir} has to be a directory containg the xml tests reports")
+        dir.eachFileRecurse {
+            file ->
+            if (!file.getName().endsWith(".xml")) return
+            if (file.getName().indexOf("\$")>-1) {
+              if (!skipIgnores) println("${file.name} is ignored because it's output for a subclass")
+              return
+            }
+            def node = new XmlSlurper().parse(file);
+            def name = node['@name']
+            def errorVal = Integer.parseInt(node['@errors'])
+            def failureVal = Integer.parseInt(node['@failures'])
+
+            def el = map.get(name)
+            if (el==null && !save) throw new RuntimeException("unknown test ${name}, please add it to conf file ${conf.name}")
+            if (el==null && save) {
+                el = new HashMap()
+                el.put("errors","-1");
+                el.put("failures","-1");
+                println "added configuration for test ${name}"
+                addToMap(name,el)
+                hasChanged=true
+            }
+
+            def err  = attReader(name,"errors",el.errors,errorVal)
+            def fail = attReader(name,"failures",el.failures,failureVal)
+            if (err && fail) {
+                println(">>> Congratulations ${name} has passed the test <<<");
+            }
+            el.errors = errorVal
+            el.failures = failureVal
+        }
+    }        
+    
+    void saveConf() {
+        if (!save) return
+        if (!hasChanged) {
+            println "no changes to configuration"
+            return
+        }
+        println "saving conf in ${conf}, old configuration is saved in ${conf}.old"
+        println "WARNING: comments are not in the new file"
+        def oldConf = new File(conf.absolutePath+".old")
+        def bytes = conf.readBytes()
+        def out = oldConf.newOutputStream()
+        out << bytes
+        out.close()
+        out = conf.newWriter()
+        try {
+            map.each {
+                 out.writeLine("[${it.key}]")
+                 it.value.each {
+                     out.writeLine("${it.key}=${it.value}")
+                 }
+            }
+        } finally {
+            out.close();
+        }
+    }
+
+    void readConf() {
+        def reader = new LineNumberReader(new FileReader(conf));
+        def line = null;
+
+        def readLine = {l ->
+            if (l!=null) return l
+            while (true) {
+                l = reader.readLine()
+                if (l==null) return null
+                if (""==l) continue
+                l=l.trim()
+                if (l[0] == "#") continue
+                return l
+            }
+        }
+
+        def lineloop = {l,lbreak,func ->
+            while(true) {
+                if (l!=null && lbreak) return l
+                if (l==null) l = readLine(l)
+                if (l==null) return
+                nr= reader.lineNumber;
+                l = func(l)
+            }
+            return l
+        }
+
+        def attRead = {el,l->
+            l = lineloop(l,true) {ll ->
+                if (ll[0]=="[" || ll[-1]=="]") return ll
+                int index = ll.indexOf('=');
+                if (index==-1) throw new RuntimeException(" ${conf.name}:${nr} = expected somewhere, but got ${ll}");
+                String name = ll.substring(0,index).trim();
+                String value = "";
+                if (ll.length()>=index) value = ll.substring(index+1).trim();
+                el.put(name,value);
+                return null
+            }
+            return l
+        }
+
+
+        def fileStart = {->
+            lineloop(null,false) {l ->
+                if (l[0]!="[" || l[-1]!="]") {
+                    throw new RuntimeException("${conf.name}:${nr} filename inside of [] expected, but got ${line}")
+                }
+                def el = new HashMap()
+                def file = line.substring(1,l.length()-1)
+                addToMap(file,el);
+                l = attRead(el,null)
+                return l
+            }
+        }
+        
+        try {
+            fileStart()
+        } finally {
+            reader.close();
+        }
+        if (map.size==0) throw new RuntimeException("${conf.name} was empty");
+    }
+    
+    def addToMap(name, el) {
+        map.put(name,el)
+    }
+
+    
+}
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/tools/FileSystemCompiler.java b/groovy-core/src/main/org/codehaus/groovy/tools/FileSystemCompiler.java
new file mode 100644
index 0000000..4c51fd4
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/tools/FileSystemCompiler.java
@@ -0,0 +1,229 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.tools;
+
+import java.io.File;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.PosixParser;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.ConfigurationException;
+
+public class FileSystemCompiler  
+{
+    private CompilationUnit unit;
+
+    
+    public FileSystemCompiler( CompilerConfiguration configuration ) throws ConfigurationException
+    {
+        this.unit = new CompilationUnit( configuration );
+    }
+
+    
+    public void compile( String[] paths ) throws Exception 
+    {
+        unit.addSources( paths );
+        unit.compile( );
+    }
+
+    
+    public void compile( File[] files ) throws Exception 
+    {
+        unit.addSources( files );
+        unit.compile( );
+    }
+
+
+    public static void displayHelp() // todo: use HelpFormatter to avoid duplication between help and OptionBuilder
+    {
+        System.err.println("Usage: groovyc <options> <source files>");
+        System.err.println("where possible options include: ");
+        System.err.println("  --classpath <path>        Specify where to find user class files");
+        System.err.println("  -d <directory>            Specify where to place generated class files");
+        System.err.println("  --encoding <encoding>     Specify the encoding of the user class files");
+//        System.err.println("  --strict                  Turn on strict type safety");
+        System.err.println("  --version                 Print the verion");
+        System.err.println("  --help                    Print a synopsis of standard options");
+        System.err.println("  --exception               Print stack trace on error");
+        System.err.println("");
+    }
+
+    public static void displayVersion() 
+    {
+        System.err.println("groovy compiler version 1.0-rc1");
+        System.err.println("Copyright 2003-2004 The Codehaus. http://groovy.codehaus.org/");
+        System.err.println("");
+    }
+
+    public static int checkFiles( String[] filenames ) 
+    {
+        int errors = 0;
+
+        for(int i = 0; i < filenames.length; ++i ) 
+        {
+            File file = new File( filenames[i] );
+
+            if( !file.exists() ) 
+            {
+                System.err.println( "error: file not found: " + file );
+                ++errors;
+            }
+            else if( !file.canRead() ) 
+            {
+                System.err.println( "error: file not readable: " + file );
+                ++errors;
+            } else {
+                String name = file.getName();
+                int p = name.lastIndexOf(".");
+                if ( p++ >= 0) {
+                    if (name.substring(p).equals("java")) {
+                        System.err.println( "error: cannot compile file with .java extension: " + file );
+                        ++errors;
+                    }
+                }
+            }
+        }
+
+        return errors;
+    }
+
+    
+    
+   /**
+    *  Primary entry point for compiling from the command line
+    *  (using the groovyc script).
+    */
+    
+    public static void main( String[] args )
+    {
+        boolean displayStackTraceOnError = false;
+        
+        try
+        {
+            //
+            // Parse the command line
+            
+            Options options = new Options();
+    
+            options.addOption(OptionBuilder.withLongOpt("classpath").hasArg().withArgName("classpath").create());
+            options.addOption(OptionBuilder.withLongOpt("sourcepath").hasArg().withArgName("sourcepath").create());
+            options.addOption(OptionBuilder.withLongOpt("encoding").hasArg().withArgName("encoding").create());
+            options.addOption(OptionBuilder.hasArg().create('d'));
+//            options.addOption(OptionBuilder.withLongOpt("strict").create('s'));
+            options.addOption(OptionBuilder.withLongOpt("help").create('h'));
+            options.addOption(OptionBuilder.withLongOpt("version").create('v'));
+            options.addOption(OptionBuilder.withLongOpt("exception").create('e'));
+    
+            PosixParser cliParser = new PosixParser();
+    
+            CommandLine cli = cliParser.parse(options, args);
+    
+            if( cli.hasOption('h') ) 
+            {
+                displayHelp();
+                return;
+            }
+    
+            if( cli.hasOption('v') ) 
+            {
+                displayVersion();
+            }
+    
+            
+            //
+            // Setup the configuration data
+            
+            CompilerConfiguration configuration = new CompilerConfiguration();
+    
+            if( cli.hasOption("classpath") ) 
+            {
+                configuration.setClasspath( cli.getOptionValue("classpath") );
+            }
+    
+            if( cli.hasOption('d') ) 
+            {
+                configuration.setTargetDirectory( cli.getOptionValue('d') );
+            }
+
+            if (cli.hasOption("encoding")) {
+                configuration.setSourceEncoding(cli.getOptionValue("encoding"));
+            }
+
+            displayStackTraceOnError = cli.hasOption('e');
+            
+            
+            //
+            // Load the file name list
+            
+            String[] filenames = cli.getArgs();
+            if( filenames.length == 0 ) 
+            {
+                displayHelp();
+                return;
+            }
+    
+            int errors = checkFiles( filenames );
+    
+            
+            //
+            // Create and start the compiler
+            
+            if( errors == 0 ) 
+            {
+                FileSystemCompiler compiler = new FileSystemCompiler( configuration );
+                compiler.compile( filenames );
+            }
+        }
+        catch( Throwable e ) 
+        {
+            new ErrorReporter( e, displayStackTraceOnError ).write( System.err );
+        }
+    }
+    
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/tools/Grok.java b/groovy-core/src/main/org/codehaus/groovy/tools/Grok.java
new file mode 100644
index 0000000..add7816
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/tools/Grok.java
@@ -0,0 +1,15 @@
+package org.codehaus.groovy.tools;
+
+/**
+ * This is a stub for the Groovy Doc tool
+ * 
+ * @author James Strachan
+ * @version $Revision$
+ */
+public class Grok
+{
+    public static void main(String[] args)
+    {
+        
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/tools/GroovyClass.java b/groovy-core/src/main/org/codehaus/groovy/tools/GroovyClass.java
new file mode 100644
index 0000000..5c8ae0b
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/tools/GroovyClass.java
@@ -0,0 +1,27 @@
+package org.codehaus.groovy.tools;
+
+public class GroovyClass
+{
+    public static final GroovyClass[] EMPTY_ARRAY = new GroovyClass[ 0 ];
+
+    private String name;
+    private byte[] bytes;
+
+    public GroovyClass(String name,
+                       byte[] bytes)
+    {
+        this.name  = name;
+        this.bytes = bytes;
+    }
+
+    public String getName()
+    {
+        return this.name;
+    }
+
+    public byte[] getBytes()
+    {
+        return this.bytes;
+    }
+}
+
diff --git a/groovy-core/src/main/org/codehaus/groovy/tools/GroovyStarter.java b/groovy-core/src/main/org/codehaus/groovy/tools/GroovyStarter.java
new file mode 100644
index 0000000..e8b4e07
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/tools/GroovyStarter.java
@@ -0,0 +1,222 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.tools;
+
+import java.lang.reflect .*;
+import java.io.FileInputStream;
+
+
+
+/**
+ * Helper class to help classworlds to load classes. 
+ */
+public class GroovyStarter {
+
+    static void printUsage() {
+        System.out.println("possible programs are 'groovyc','groovy','console','grok' and 'groovysh'");
+        System.exit(1);
+    }
+    
+    
+    public static void rootLoader(String args[]) {
+        String conf = System.getProperty("groovy.starter.conf",null);
+        LoaderConfiguration lc = new LoaderConfiguration();
+        
+        // evaluate parameters
+        boolean hadMain=false, hadConf=false, hadCP=false;
+        int argsOffset = 0;
+        while (args.length-argsOffset>0 && !(hadMain && hadConf && hadCP)) {
+            if (args[argsOffset].equals("--classpath")) {
+                if (hadCP) break;
+                if (args.length==argsOffset+1) {
+                    exit("classpath parameter needs argument");
+                }
+                lc.addClassPath(args[argsOffset+1]);
+                argsOffset+=2;
+            } else if (args[argsOffset].equals("--main")) {
+                if (hadMain) break;
+                if (args.length==argsOffset+1) {
+                    exit("main parameter needs argument");
+                }
+                lc.setMainClass(args[argsOffset+1]);
+                argsOffset+=2;
+            } else if (args[argsOffset].equals("--conf")) {
+                if (hadConf) break;
+                if (args.length==argsOffset+1) {
+                    exit("conf parameter needs argument");
+                }
+                conf=args[argsOffset+1];
+                argsOffset+=2;
+            } else {
+                break;
+            }            
+        }
+        
+        // we need to know the class we want to start
+        if (lc.getMainClass()==null && conf==null) {
+            exit("no configuration file or main class specified");
+        }
+        
+        // copy arguments for main class 
+        String[] newArgs = new String[args.length-argsOffset];
+        for (int i=0; i<newArgs.length; i++) {
+            newArgs[i] = args[i+argsOffset];
+        }        
+        // load configuration file
+        if (conf!=null) {
+            try {
+                lc.configure(new FileInputStream(conf));
+            } catch (Exception e) {
+                System.err.println("exception while configuring main class loader:");
+                exit(e);
+            }
+        }
+        // create loader and execute main class
+        ClassLoader loader = new RootLoader(lc);
+        Method m=null;
+        try {
+            Class c = loader.loadClass(lc.getMainClass());
+            m = c.getMethod("main", new Class[]{String[].class});
+        } catch (ClassNotFoundException e1) {
+            exit(e1);
+        } catch (SecurityException e2) {
+            exit(e2);
+        } catch (NoSuchMethodException e2) {
+            exit(e2);
+        }
+        try {
+            m.invoke(null, new Object[]{newArgs});
+        } catch (IllegalArgumentException e3) {
+            exit(e3);
+        } catch (IllegalAccessException e3) {
+            exit(e3);
+        } catch (InvocationTargetException e3) {
+            exit(e3);
+        } 
+    }
+    
+    private static void exit(Exception e) {
+        e.printStackTrace();
+        System.exit(1);
+    }
+    
+    private static void exit(String msg) {
+        System.err.println(msg);
+        System.exit(1);
+    }
+ 
+    // after migration from classworlds to the rootloader rename
+    // the rootLoader method to main and remove this method as 
+    // well as the classworlds method
+   /* public static void main(String args[],ClassWorld classWorld ) {
+        classworlds(args,classWorld);
+    }*/
+    
+    public static void main(String args[]) {
+        try {
+            rootLoader(args);
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+    }
+
+    /*public static void classworlds(String oldArgs[],ClassWorld classWorld ) {
+        try {
+            // Creates a realm with *just* the system classloader
+            ClassRealm system = classWorld.newRealm("system");
+     
+            // Get the groovy realm
+            ClassRealm groovy = classWorld.getRealm("groovy");
+           
+            // import everything from the system realm, because imports
+            // are searched *first* in Classworlds
+            groovy.importFrom("system", "");
+            
+            //add tools.jar to classpath
+            String tools = System.getProperty("tools.jar");
+            if (tools!=null) {
+            	URL ref = (new File(tools)).toURI().toURL();
+            	groovy.addConstituent(ref);
+            }
+        
+            if (oldArgs.length==0) {
+                printUsage();
+                System.exit(1);
+            }
+            
+            String program = oldArgs[0].toLowerCase();
+            String[] args = new String[oldArgs.length-1];
+            for (int i=0; i<args.length; i++) {
+                args[i] = oldArgs[i+1];
+            }
+            
+            if (program.equals("groovyc")) {
+                org.codehaus.groovy.tools.FileSystemCompiler.main(args);
+            } else if (program.equals("groovy")) {
+                GroovyMain.main(args);
+            } else if (program.equals("console")) {
+                // work around needed, because the console is compiled after this files
+                Class c = Class.forName("groovy.ui.Console");
+                Method m= c.getMethod("main", new Class[]{String[].class});
+                m.invoke(null, new Object[]{args});
+            } else if (program.equals("groovysh")) {
+                InteractiveShell.main(args);
+             } else if (program.equals("grok")) {
+                org.codehaus.groovy.tools.Grok.main(args);
+            } else {
+                System.out.println("unknown program "+program);
+                printUsage();
+                System.exit(1);
+            }
+        
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.exit(1);
+        }
+        
+    }*/
+    
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/tools/LoaderConfiguration.java b/groovy-core/src/main/org/codehaus/groovy/tools/LoaderConfiguration.java
new file mode 100644
index 0000000..d68e505
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/tools/LoaderConfiguration.java
@@ -0,0 +1,285 @@
+/*
+$Id$
+
+Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+package org.codehaus.groovy.tools;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+
+/**
+ * class used to configure a RootLoader from a stream or by using 
+ * it's methods.
+ * 
+ * The stream can be for example a FileInputStream from a file with
+ * the following format:
+ * 
+ * # comment
+ * main is classname
+ * load path
+ * load file
+ * load pathWith${property}
+ * load path/*.jar
+ *
+ *<ul>
+ * <li>All lines starting with "#" are ignored.</li> 
+ * <li>The "main is" part may only be once in the file. The String
+ * afterwards is the name of a class if a main method. </li>
+ * <li>The "load" command will add the given file or path to the 
+ * classpath in this configuration object.
+ * </li>
+ *</ul>
+ * 
+ * Defining the main class is optional if @see #setRequireMain(boolean) was 
+ * called with false, before reading the configuration. 
+ * You can use the wildcard "*" to filter the path, but only for files, not
+ * directories. The  ${propertyname} is replaced by the value of the system's
+ * propertyname. You can use user.home here for example. If the property does
+ * not exist, an empty string will be used. If the path or file after the load
+ * does not exist, the path will be ignored.
+ *
+ * @see RootLoader
+ * @author Jochen Theodorou
+ * @version $Revision$
+ */
+public class LoaderConfiguration {
+    
+    private final static String 
+        MAIN_PREFIX = "main is", LOAD_PREFIX="load";
+    private ArrayList classPath = new ArrayList();
+    private String main;
+    private boolean requireMain;
+    
+    /**
+     * creates a new loader configuration
+     */
+    public LoaderConfiguration() {
+        this.requireMain = true;
+    }
+    
+    /**
+     * configures this loader with a stream 
+     * 
+     * @param is           stream used to read the configuration
+     * @throws IOException if reading or parsing the contents of the stream fails
+     */
+    public void configure(InputStream is) throws IOException {
+        BufferedReader reader = new BufferedReader( new InputStreamReader(is));
+        int lineNumber=0;
+        
+        while(true) {
+            String line = reader.readLine();
+            if (line==null) break;
+            
+            line = line.trim();
+            lineNumber++;
+            
+            if (line.startsWith("#") || line.length()==0) continue;
+            
+            if (line.startsWith(LOAD_PREFIX)) {
+                String loadPath = line.substring(LOAD_PREFIX.length()).trim();
+                loadPath = assignProperties(loadPath);
+                loadFilteredPath(loadPath);
+            } else if (line.startsWith(MAIN_PREFIX)) {
+                if (main!=null) throw new IOException("duplicate definition of main in line "+lineNumber+" : "+line);
+                main = line.substring(MAIN_PREFIX.length()).trim();
+            } else {
+                throw new IOException("unexpected line in "+lineNumber+" : "+line);
+            }
+        }
+        
+        if (requireMain && main == null) throw new IOException("missing main class definition in config file");
+    }
+   
+    /**
+     * exapands the properties inside the given string to it's values
+     */
+    private String assignProperties(String str) {
+        int propertyIndexStart=0,propertyIndexEnd=0;
+        String result="";
+
+        while (propertyIndexStart<str.length()) {
+            propertyIndexStart=str.indexOf("${",propertyIndexStart);
+            if (propertyIndexStart==-1) break;
+            result += str.substring(propertyIndexEnd,propertyIndexStart);
+
+            propertyIndexEnd=str.indexOf("}",propertyIndexStart);
+            if (propertyIndexEnd==-1) break;
+            
+            String propertyKey = str.substring(propertyIndexStart+2,propertyIndexEnd);
+            String propertyValue = System.getProperty(propertyKey);
+            result+=propertyValue;
+            
+            propertyIndexEnd++;
+            propertyIndexStart=propertyIndexEnd;
+        }
+        
+        if (propertyIndexStart==-1 || propertyIndexStart>=str.length()) {
+            result+=str.substring(propertyIndexEnd);
+        } else if (propertyIndexEnd==-1) {
+            result+=str.substring(propertyIndexStart);
+        } 
+        
+        return result;
+    }
+    
+    
+    /**
+     * load a possible filtered path. Filters are defined
+     * by using the * wildcard like in any shell
+     */
+    private void loadFilteredPath(String filter) {
+        int starIndex = filter.indexOf('*');
+        if (starIndex==-1) {
+            addFile(new File(filter));
+            return;
+        } 
+        if (!parentPathDoesExist(filter)) return;        
+        String filterPart = getParentPath(filter);
+        int index = filterPart.indexOf('*');
+        final String prefix = filterPart.substring(0,index);
+        final String suffix = filterPart.substring(index+1);
+        File dir = new File(filter.substring(0,filter.length()-filterPart.length()));
+        FilenameFilter ff = new FilenameFilter() {
+            public boolean accept(File dir, String name) {
+                if (!name.startsWith(prefix)) return false;
+                if (!name.endsWith(suffix)) return false;
+                return true;
+            }
+        };
+        File[] matches = dir.listFiles(ff);
+        for (int i=0; i<matches.length; i++) addFile(matches[i]);
+    }
+    
+    /**
+     * return true if the parent of the path inside the given
+     * string does exist
+     */
+    private boolean parentPathDoesExist(String path) {
+        File dir = new File (path).getParentFile();
+        return dir.exists();
+    }
+    
+    /**
+     * seperates the given path at the last '/'
+     */
+    private String getParentPath(String filter) {
+        int index = filter.lastIndexOf('/');
+        if (index==-1) return "";
+        return filter.substring(index+1);
+    }
+    
+    /**
+     * adds a file to the classpath if it does exist
+     */
+    public void addFile(File f) {
+        if (f!=null && f.exists()) {
+            try {
+                classPath.add(f.toURI().toURL());
+            } catch (MalformedURLException e) {
+                throw new AssertionError("converting an existing file to an url should have never thrown an exception!");
+            }
+        }        
+    }
+    
+    /**
+     * adds a file to the classpath if it does exist
+     */
+    public void addFile(String s) {
+        if (s!=null) addFile(new File(s));
+    }
+    
+    /**
+     * adds a classpath to this configuration. It expects a string
+     * with multiple paths, seperated by the system dependent 
+     * @see java.io.File#pathSeparator
+     */
+    public void addClassPath(String path) {
+        String[] paths = path.split(File.pathSeparator);
+        for (int i=0; i<paths.length; i++) {
+            addFile(new File(paths[i]));
+        }
+    }
+    
+    /**
+     * gets a classpath as URL[] from this configuration. 
+     * This can be used to construct a @see java.net.URLClassLoader
+     */
+    public URL[] getClassPathUrls() {
+        return (URL[]) classPath.toArray(new URL[]{});
+    }
+    
+    /**
+     * returns the main class or null is no is defined
+     */
+    public String getMainClass() {
+        return main;
+    }
+    
+    /**
+     * sets the main class. If there is already a main class
+     * it is overwritten. Calling @see #configure(InputStream) 
+     * after calling this method does not require a main class
+     * definition inside the stream 
+     */
+    public void setMainClass(String clazz) {
+        main = clazz;
+        requireMain = false;
+    }
+    
+    /**
+     * if set to false no main class is required when calling
+     * @see #configure(InputStream)
+     */
+    public void setRequireMain(boolean requireMain) {
+        this.requireMain = requireMain;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/tools/RootLoader.java b/groovy-core/src/main/org/codehaus/groovy/tools/RootLoader.java
new file mode 100644
index 0000000..61fc5eb
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/tools/RootLoader.java
@@ -0,0 +1,167 @@
+/*
+$Id$
+
+Copyright 2003 (C) Jochen Theodorou. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+   statements and notices.  Redistributions must also contain a
+   copy of this document.
+
+2. Redistributions in binary form must reproduce the
+   above copyright notice, this list of conditions and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+   products derived from this Software without prior written
+   permission of The Codehaus.  For written permission,
+   please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+   nor may "groovy" appear in their names without prior written
+   permission of The Codehaus. "groovy" is a registered
+   trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+   http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+package org.codehaus.groovy.tools;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+/**
+ * This ClassLoader should be used as root of class loaders. Any
+ * RootLoader does have it's own classpath. When searching for a 
+ * class or resource this classpath will be used. Parent 
+ * Classloaders are ignored first. If a class or resource 
+ * can't be found in the classpath of the RootLoader, then parent is
+ * checked.
+ * 
+ * <b>Note:</b> this is very against the normal behavior of 
+ * classloaders. Normal is to frist check parent and then look in
+ * the ressources you gave this classloader.
+ * 
+ * It's possible to add urls to the classpath at runtime through
+ * @see #addURL(URL)
+ * 
+ * <b>Why using RootLoader?</b>
+ * If you have to load classes with multiple classloaders and a
+ * classloader does know a class which depends on a class only 
+ * a child of this loader does know, then you won't be able to 
+ * load the class. To load the class the child is not allowed 
+ * to redirect it's search for the class to the parent first.
+ * That way the child can load the class. If the child does not
+ * have all classes to do this, this fails of course.
+ *  
+ * For example:
+ *  
+ *  <pre>
+ *  parentLoader   (has classpath: a.jar;c.jar)
+ *      |
+ *      |
+ *  childLoader    (has classpath: a.jar;b.jar;c.jar)
+ *  </pre>
+ *  
+ *  class C (from c.jar) extends B (from b.jar)
+ *  
+ *  childLoader.find("C")
+ *  --> parentLoader does know C.class, try to load it
+ *  --> to load C.class it has to load B.class
+ *  --> parentLoader is unable to find B.class in a.jar or c.jar
+ *  --> NoClassDefFoundException!
+ *  
+ *  if childLoader had tried to load the class by itself, there
+ *  would be no problem. Changing childLoader to be a RootLoader 
+ *  instance will solve that problem.
+ *   
+ * @author Jochen Theodorou
+ */
+public class RootLoader extends URLClassLoader {
+
+    /**
+     * constructs a new RootLoader without classpath
+     * @param parent the parent Loader
+     */   
+    private RootLoader(ClassLoader parent) {
+        this(new URL[0],parent);
+    }
+    
+    /**
+     * constructs a new RootLoader with a parent loader and an
+     * array of URLs as classpath
+     */
+    public RootLoader(URL[] urls, ClassLoader parent) {
+        super(urls,parent);
+    }
+    
+    private static ClassLoader chooseParent(){
+      ClassLoader cl = RootLoader.class.getClassLoader();
+      if (cl!=null) return cl;
+      return ClassLoader.getSystemClassLoader();
+    }
+    
+    /**
+     * constructs a new RootLoader with a @see LoaderConfiguration
+     * object which holds the classpath
+     */
+    public RootLoader(LoaderConfiguration lc) {
+        this(chooseParent());
+        Thread.currentThread().setContextClassLoader(this);
+        URL[] urls = lc.getClassPathUrls();
+        for (int i=0; i<urls.length; i++) {
+            addURL(urls[i]);
+        }
+    }
+
+    /**
+     * loads a class using the name of the class
+     */
+    protected Class loadClass(final String name, boolean resolve) throws ClassNotFoundException {
+        Class c = this.findLoadedClass(name);
+        if (c!=null) return c;
+     
+        try {
+            c = findClass(name);
+        } catch (ClassNotFoundException cnfe) {}
+        if (c==null) c= super.loadClass(name,resolve);
+
+        if (resolve) resolveClass(c);
+        
+        return c;
+    }
+        
+    /**
+     * returns the URL of a resource, or null if it is not found
+     */
+    public URL getResource(String name) {
+        URL url = findResource(name);
+        if (url==null) url=super.getResource(name);
+        return url;
+    } 
+ 
+    /**
+     * adds an url to the classpath of this classloader
+     */
+    public void addURL(URL url) {
+        super.addURL(url);
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/tools/Utilities.java b/groovy-core/src/main/org/codehaus/groovy/tools/Utilities.java
new file mode 100644
index 0000000..aae0891
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/tools/Utilities.java
@@ -0,0 +1,36 @@
+package org.codehaus.groovy.tools;
+
+/**
+ *  Various utility functions for use in the compiler.
+ */
+
+public abstract class Utilities
+{
+   /**
+    *  Returns a string made up of repetitions of the specified string.
+    */
+
+    public static String repeatString( String pattern, int repeats )
+    {
+        StringBuffer buffer = new StringBuffer( pattern.length() * repeats );
+        for( int i = 0; i < repeats; i++ )
+        {
+            buffer.append( pattern );
+        }
+
+        return new String( buffer );
+    }
+
+
+   /**
+    *  Returns the end-of-line marker.
+    */
+
+    public static String eol()
+    {
+        return eol;
+    }
+    
+    private static String eol = System.getProperty( "line.separator", "\n" ); 
+
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/tools/package.html b/groovy-core/src/main/org/codehaus/groovy/tools/package.html
new file mode 100644
index 0000000..d388b5c
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/tools/package.html
@@ -0,0 +1,10 @@
+<html>
+  <head>
+    <title>package org.codehaus.groovy.tools.*</title>
+  </head>
+  <body>
+    <p>
+      Compiler entry points and miscellaneous development tools.
+    </p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/org/codehaus/groovy/tools/xml/DomToGroovy.java b/groovy-core/src/main/org/codehaus/groovy/tools/xml/DomToGroovy.java
new file mode 100644
index 0000000..78d757c
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/tools/xml/DomToGroovy.java
@@ -0,0 +1,336 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.tools.xml;
+
+import groovy.util.IndentPrinter;
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+
+/**
+ * A SAX handler for turning XML into Groovy scripts
+ * 
+ * @author James Strachan
+ * @author paulk
+ */
+public class DomToGroovy {
+
+    private IndentPrinter out;
+
+    public DomToGroovy(PrintWriter out) {
+        this(new IndentPrinter(out));
+    }
+
+    // TODO allow string quoting delimiter to be specified, e.g. ' vs "
+    public DomToGroovy(IndentPrinter out) {
+        this.out = out;
+    }
+
+    public void print(Document document) {
+        printChildren(document, new HashMap());
+    }
+
+    // Implementation methods
+    //-------------------------------------------------------------------------
+    protected void print(Node node, Map namespaces, boolean endWithComma) {
+        switch (node.getNodeType()) {
+            case Node.ELEMENT_NODE :
+                printElement((Element) node, namespaces, endWithComma);
+                break;
+            case Node.PROCESSING_INSTRUCTION_NODE :
+                printPI((ProcessingInstruction) node, endWithComma);
+                break;
+            case Node.TEXT_NODE :
+                printText((Text) node, endWithComma);
+                break;
+            case Node.COMMENT_NODE :
+                printComment((Comment) node, endWithComma);
+                break;
+        }
+    }
+
+    protected void printElement(Element element, Map namespaces, boolean endWithComma) {
+        namespaces = defineNamespaces(element, namespaces);
+
+        element.normalize();
+        printIndent();
+
+        String prefix = element.getPrefix();
+        if (prefix != null && prefix.length() > 0) {
+            print(prefix);
+            print(".");
+        }
+        print(getLocalName(element));
+
+        boolean hasAttributes = printAttributes(element);
+
+        NodeList list = element.getChildNodes();
+        int length = list.getLength();
+        if (length == 0) {
+            printEnd(hasAttributes ? ")" : "()", endWithComma);
+        } else {
+            Node node = list.item(0);
+            if (length == 1 && node instanceof Text) {
+                Text textNode = (Text) node;
+                String text = getTextNodeData(textNode);
+                if (hasAttributes) print(", '");
+                else print("('");
+                print(text);
+                printEnd("')", endWithComma);
+            } else if (mixedContent(list)) {
+                println(" [");
+                out.incrementIndent();
+                for (node = element.getFirstChild(); node != null; node = node.getNextSibling()) {
+                    boolean useComma = node.getNextSibling() != null;
+                    print(node, namespaces, useComma);
+                }
+                out.decrementIndent();
+                printIndent();
+                printEnd("]", endWithComma);
+            } else {
+                println(") {");
+                out.incrementIndent();
+                printChildren(element, namespaces);
+                out.decrementIndent();
+                printIndent();
+                printEnd("}", endWithComma);
+            }
+        }
+    }
+
+    protected void printPI(ProcessingInstruction instruction, boolean endWithComma) {
+        printIndent();
+        print("xml.pi('");
+        print(instruction.getTarget());
+        print("', '");
+        print(instruction.getData());
+        printEnd("');", endWithComma);
+    }
+
+    protected void printComment(Comment comment, boolean endWithComma) {
+        String text = comment.getData().trim();
+        if (text.length() >0) {
+            printIndent();
+            print("/* ");
+            print(text);
+            printEnd(" */", endWithComma);
+        }
+    }
+
+    protected void printText(Text node, boolean endWithComma) {
+        String text = getTextNodeData(node);
+        if (text.length() > 0) {
+            printIndent();
+            //            print("xml.append('");
+            //            print(text);
+            //            println("');");
+            print("'");
+            print(text);
+            printEnd("'", endWithComma);
+        }
+    }
+
+    protected Map defineNamespaces(Element element, Map namespaces) {
+        Map answer = null;
+        String prefix = element.getPrefix();
+        if (prefix != null && prefix.length() > 0 && !namespaces.containsKey(prefix)) {
+            answer = new HashMap(namespaces);
+            defineNamespace(answer, prefix, element.getNamespaceURI());
+        }
+        NamedNodeMap attributes = element.getAttributes();
+        int length = attributes.getLength();
+        for (int i = 0; i < length; i++) {
+            Attr attribute = (Attr) attributes.item(i);
+            prefix = attribute.getPrefix();
+            if (prefix != null && prefix.length() > 0 && !namespaces.containsKey(prefix)) {
+                if (answer == null) {
+                    answer = new HashMap(namespaces);
+                }
+                defineNamespace(answer, prefix, attribute.getNamespaceURI());
+            }
+        }
+        return (answer != null) ? answer : namespaces;
+    }
+
+    protected void defineNamespace(Map namespaces, String prefix, String uri) {
+        namespaces.put(prefix, uri);
+        if (!prefix.equals("xmlns") && !prefix.equals("xml")) {
+            printIndent();
+            print(prefix);
+            print(" = xmlns.namespace('");
+            print(uri);
+            println("')");
+        }
+    }
+
+    protected boolean printAttributes(Element element) {
+        boolean hasAttribute = false;
+        NamedNodeMap attributes = element.getAttributes();
+        int length = attributes.getLength();
+        if (length > 0) {
+            StringBuffer buffer = new StringBuffer();
+            for (int i = 0; i < length; i++) {
+                printAttributeWithPrefix((Attr) attributes.item(i), buffer);
+            }
+            print("(");
+            for (int i = 0; i < length; i++) {
+                hasAttribute = printAttributeWithoutPrefix((Attr) attributes.item(i), hasAttribute);
+            }
+            if (buffer.length() > 0) {
+                if (hasAttribute) {
+                    print(", ");
+                }
+                print("xmlns=[");
+                print(buffer.toString());
+                print("]");
+                hasAttribute = true;
+            }
+        }
+        return hasAttribute;
+    }
+
+    private void printAttributeWithPrefix(Attr attribute, StringBuffer buffer) {
+        String prefix = attribute.getPrefix();
+        if (prefix != null && prefix.length() > 0) {
+            if (buffer.length() > 0) {
+                buffer.append(", ");
+            }
+            buffer.append(prefix);
+            buffer.append(".");
+            buffer.append(getLocalName(attribute));
+            buffer.append(":'");
+            buffer.append(getAttributeValue(attribute));
+            buffer.append("'");
+        }
+    }
+
+    private String getAttributeValue(Attr attribute) {
+        return attribute.getValue();
+    }
+
+    private boolean printAttributeWithoutPrefix(Attr attribute, boolean hasAttribute) {
+        String prefix = attribute.getPrefix();
+        if (prefix == null || prefix.length() == 0) {
+            if (!hasAttribute) {
+                hasAttribute = true;
+            } else {
+                print(", ");
+            }
+            print(getLocalName(attribute));
+            print(":'");
+            print(getAttributeValue(attribute));
+            print("'");
+        }
+        return hasAttribute;
+    }
+
+    protected String getTextNodeData(Text node) {
+        return node.getData().trim();
+    }
+
+    protected boolean mixedContent(NodeList list) {
+        boolean hasText = false;
+        boolean hasElement = false;
+        for (int i = 0, size = list.getLength(); i < size; i++) {
+            Node node = list.item(i);
+            if (node instanceof Element) {
+                hasElement = true;
+            } else if (node instanceof Text) {
+                String text = getTextNodeData((Text) node);
+                if (text.length() > 0) {
+                    hasText = true;
+                }
+            }
+        }
+        return hasText && hasElement;
+    }
+
+    protected void printChildren(Node parent, Map namespaces) {
+        for (Node node = parent.getFirstChild(); node != null; node = node.getNextSibling()) {
+            print(node, namespaces, false);
+        }
+    }
+
+    protected String getLocalName(Node node) {
+        String answer = node.getLocalName();
+        if (answer == null) {
+            answer = node.getNodeName();
+        }
+        return answer.trim();
+    }
+
+    protected void printEnd(String text, boolean endWithComma) {
+        if (endWithComma) {
+            print(text);
+            println(",");
+        } else {
+            println(text);
+        }
+    }
+
+    protected void println(String text) {
+        out.println(text);
+    }
+
+    protected void print(String text) {
+        out.print(text);
+    }
+
+    protected void printIndent() {
+        out.printIndent();
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/tools/xml/package.html b/groovy-core/src/main/org/codehaus/groovy/tools/xml/package.html
new file mode 100644
index 0000000..324792b
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/tools/xml/package.html
@@ -0,0 +1,8 @@
+<html>
+  <head>
+    <title>package org.codehaus.groovy.tools.xml.*</title>
+  </head>
+  <body>
+    <p>XML utilities such as for converting XML into Groovy scripts.</p>
+  </body>
+</html>
diff --git a/groovy-core/src/main/org/codehaus/groovy/wiki/TestCaseRenderEngine.java b/groovy-core/src/main/org/codehaus/groovy/wiki/TestCaseRenderEngine.java
new file mode 100644
index 0000000..5b4769a
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/wiki/TestCaseRenderEngine.java
@@ -0,0 +1,156 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.wiki;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.regex.Pattern;
+
+import org.radeox.api.engine.RenderEngine;
+import org.radeox.api.engine.context.RenderContext;
+
+/**
+ * @author James Strachan
+ * @version $Revision$
+ */
+public class TestCaseRenderEngine implements RenderEngine {
+    Pattern groovyCodePattern = Pattern.compile("\\{code:groovy\\}");
+    Pattern groovyShellPattern = Pattern.compile("\\{code:groovysh\\}");
+    Pattern codePattern = Pattern.compile("\\{code\\}");
+
+    public TestCaseRenderEngine() {
+    }
+
+    public String getName() {
+        return "TestCase";
+    }
+
+    public String render(String content, RenderContext context) {
+        String name = (String) context.get("name");
+        if (name == null) {
+            name = "UknownName.wiki";
+        }
+        int idx = name.lastIndexOf('.');
+        if (idx > 0) {
+            name = name.substring(0, idx);
+        }
+        name = name + "Test";
+
+        // lets replace {code:groovy} with a unit test case method name
+        StringBuffer buf = new StringBuffer();
+
+        String[] parts = groovyCodePattern.split(content);
+
+        buf.append( "package wiki\nclass " + name + " extends GroovyTestCase {\n\n");
+        buf.append("/*\n");
+        buf.append(processShellScripts(parts[0]));
+
+        for (int count = 1; count < parts.length; count++ ) {
+            buf.append("*/ \n\n  void testCase" + count + "() {\n");
+
+            buf.append(processShellScripts(removeCloseCode(parts[count])));
+        }
+
+        buf.append("\n*/\n\n");
+        buf.append("void testDummy() {\n// this is a dummy test case\n}\n\n}\n");
+
+        return buf.toString();
+    }
+
+    /**
+     * Splits the comment block extracting any scripts that need to be tested
+     * @param text
+     */
+    protected String processShellScripts(String text) {
+        StringBuffer buf = new StringBuffer();
+
+        String[] parts = groovyShellPattern.split(text);
+
+        buf.append(parts[0]);
+
+        for (int count = 1; count < parts.length; count++ ) {
+            buf.append("*/ \n\n  void testScript" + count + "() {\n");
+            buf.append("    assertScript( <<<SCRIPT_EOF" + count + "\n");
+
+            String code = parts[count].replaceFirst("\\{code\\}", "\nSCRIPT_EOF" + count + " )\n}    \n\n /*");
+
+            // lets escape ${foo} expressions
+            StringBuffer temp = new StringBuffer(code);
+            for (int idx = 0; true; idx++) {
+                idx = temp.indexOf("$", idx);
+                if (idx >= 0) {
+                    String next = temp.substring(++idx, idx+1);
+                    if (next.equals("{")) {
+
+                        //
+                        // It's a hack, but we aren't escaping all \, so
+                        // we just let \${ stand...
+
+                        if( idx-2 >= 0 && !temp.substring(idx-2,idx-1).equals("\\") )
+                        {
+                            temp.insert(idx-1, "\\");
+                            idx++;
+                        }
+                    }
+                }
+                else {
+                    break;
+                }
+            }
+
+            buf.append(temp.toString());
+        }
+        return buf.toString();
+    }
+
+    protected String removeCloseCode(String text) {
+        return text.replaceFirst("\\{code\\}", "\n}\n\n /*");
+    }
+
+    public void render(Writer out, String content, RenderContext context) throws IOException {
+        out.write(render(content, context));
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/wiki/Wiki2Markup.java b/groovy-core/src/main/org/codehaus/groovy/wiki/Wiki2Markup.java
new file mode 100644
index 0000000..ab9a2c3
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/wiki/Wiki2Markup.java
@@ -0,0 +1,362 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.wiki;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.GlobPatternMapper;
+import org.apache.tools.ant.util.SourceFileScanner;
+import org.radeox.api.engine.RenderEngine;
+import org.radeox.api.engine.context.RenderContext;
+import org.radeox.engine.BaseRenderEngine;
+import org.radeox.engine.context.BaseRenderContext;
+
+/**
+ * Converts the Wiki markup into XML/HTML so that it can be styled
+ * by the Maven build
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$ 
+ */
+public class Wiki2Markup extends MatchingTask {
+
+    private Path src;
+    private File destDir;
+
+    protected boolean failOnError = true;
+    protected boolean listFiles = false;
+    protected File[] compileList = new File[0];
+    private GlobPatternMapper m = new GlobPatternMapper();
+
+    private RenderContext context;
+    private RenderEngine engine;
+
+    public static void main(String[] args) {
+        try {
+            Wiki2Markup engine = new Wiki2Markup();
+            engine.compileFiles(args);
+        }
+        catch (Exception e) {
+            System.out.println("Caught: " + e);
+            e.printStackTrace();
+        }
+    }
+
+    public Wiki2Markup() {
+        context = new BaseRenderContext();
+        engine = createRenderEngine();
+        m.setFrom("*.wiki");
+        m.setTo(getExtension());
+    }
+
+    /**
+     * Adds a path for source compilation.
+     *
+     * @return a nested src element.
+     */
+    public Path createSrc() {
+        if (src == null) {
+            src = new Path(getProject());
+        }
+        return src.createPath();
+    }
+
+    /**
+     * Recreate src.
+     *
+     * @return a nested src element.
+     */
+    protected Path recreateSrc() {
+        src = null;
+        return createSrc();
+    }
+
+    /**
+     * Set the source directories to find the source Java files.
+     * @param srcDir the source directories as a path
+     */
+    public void setSrcdir(Path srcDir) {
+        if (src == null) {
+            src = srcDir;
+        }
+        else {
+            src.append(srcDir);
+        }
+    }
+
+    /**
+     * Gets the source dirs to find the source java files.
+     * @return the source directorys as a path
+     */
+    public Path getSrcdir() {
+        return src;
+    }
+
+    /**
+     * Set the destination directory into which the Java source
+     * files should be compiled.
+     * @param destDir the destination director
+     */
+    public void setDestdir(File destDir) {
+        this.destDir = destDir;
+    }
+
+    /**
+     * Gets the destination directory into which the java source files
+     * should be compiled.
+     * @return the destination directory
+     */
+    public File getDestdir() {
+        return destDir;
+    }
+
+    /**
+     * If true, list the source files being handed off to the compiler.
+     * @param list if true list the source files
+     */
+    public void setListfiles(boolean list) {
+        listFiles = list;
+    }
+
+    /**
+     * Get the listfiles flag.
+     * @return the listfiles flag
+     */
+    public boolean getListfiles() {
+        return listFiles;
+    }
+
+    /**
+     * Indicates whether the build will continue
+     * even if there are compilation errors; defaults to true.
+     * @param fail if true halt the build on failure
+     */
+    public void setFailonerror(boolean fail) {
+        failOnError = fail;
+    }
+
+    /**
+     * @ant.attribute ignore="true"
+     * @param proceed inverse of failoferror
+     */
+    public void setProceed(boolean proceed) {
+        failOnError = !proceed;
+    }
+
+    /**
+     * Gets the failonerror flag.
+     * @return the failonerror flag
+     */
+    public boolean getFailonerror() {
+        return failOnError;
+    }
+
+    /**
+     * Executes the task.
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+        checkParameters();
+        resetFileLists();
+
+        // scan source directories and dest directory to build up
+        // compile lists
+        String[] list = src.list();
+        for (int i = 0; i < list.length; i++) {
+            File srcDir = getProject().resolveFile(list[i]);
+            if (!srcDir.exists()) {
+                throw new BuildException("srcdir \"" + srcDir.getPath() + "\" does not exist!", getLocation());
+            }
+
+            DirectoryScanner ds = this.getDirectoryScanner(srcDir);
+            String[] files = ds.getIncludedFiles();
+
+            scanDir(srcDir, destDir != null ? destDir : srcDir, files);
+        }
+
+        compile();
+    }
+
+    /**
+     * Clear the list of files to be compiled and copied..
+     */
+    protected void resetFileLists() {
+        compileList = new File[0];
+    }
+
+    /**
+     * Scans the directory looking for source files to be compiled.
+     * The results are returned in the class variable compileList
+     *
+     * @param srcDir   The source directory
+     * @param destDir  The destination directory
+     * @param files    An array of filenames
+     */
+    protected void scanDir(File srcDir, File destDir, String[] files) {
+        SourceFileScanner sfs = new SourceFileScanner(this);
+        File[] newFiles = sfs.restrictAsFiles(files, srcDir, destDir, m);
+
+        if (newFiles.length > 0) {
+            File[] newCompileList = new File[compileList.length + newFiles.length];
+            System.arraycopy(compileList, 0, newCompileList, 0, compileList.length);
+            System.arraycopy(newFiles, 0, newCompileList, compileList.length, newFiles.length);
+            compileList = newCompileList;
+        }
+    }
+
+    /**
+     * Gets the list of files to be compiled.
+     * @return the list of files as an array
+     */
+    public File[] getFileList() {
+        return compileList;
+    }
+
+    protected void checkParameters() throws BuildException {
+        if (src == null) {
+            throw new BuildException("srcdir attribute must be set!", getLocation());
+        }
+        if (src.size() == 0) {
+            throw new BuildException("srcdir attribute must be set!", getLocation());
+        }
+
+        if (destDir != null && !destDir.isDirectory()) {
+            throw new BuildException(
+                "destination directory \"" + destDir + "\" does not exist " + "or is not a directory",
+                getLocation());
+        }
+    }
+
+    public void compileFiles(String[] args) throws IOException {
+        for (int i = 0; i < args.length; i++) {
+            File file = new File(args[i]);
+            compile(file, args[i]);
+        }
+    }
+
+    protected void compile() {
+        if (compileList.length > 0) {
+            log(
+                "Compiling "
+                    + compileList.length
+                    + " source file"
+                    + (compileList.length == 1 ? "" : "s")
+                    + (destDir != null ? " to " + destDir : ""));
+
+            try {
+                for (int i = 0; i < compileList.length; i++) {
+                    String filename = compileList[i].getAbsolutePath();
+                    if (listFiles) {
+                        log(filename);
+                    }
+                    compile(compileList[i], compileList[i].getName());
+                }
+            }
+            catch (Exception e) {
+                String message = "Compile failed: " + e;
+                if (failOnError) {
+                    throw new BuildException(message, e, getLocation());
+                }
+                else {
+                    log(message, Project.MSG_ERR);
+                }
+            }
+        }
+    }
+
+    protected void compile(File file, String name) throws IOException {
+        String[] names = m.mapFileName(name);
+        String outputName = names[0];
+
+        context.set("name", name);
+        
+        String text = readFile(file);
+        String result = engine.render(text, context);
+
+        File outputFile = new File(getDestdir(), outputName);
+        System.out.println("Creating file: " + outputFile);
+
+        FileWriter writer = new FileWriter(outputFile);
+        result = filter(result);
+        writer.write(result);
+        writer.close();
+    }
+
+    protected String filter(String result) {
+        return "<html><body>\n" + result + "\n<body><html>\n";
+    }
+
+    protected String readFile(File file) throws IOException {
+        StringBuffer buffer = new StringBuffer();
+        BufferedReader reader = new BufferedReader(new FileReader(file));
+        while (true) {
+            String line = reader.readLine();
+            if (line == null) {
+                break;
+            }
+            buffer.append(line);
+            buffer.append("\n");
+        }
+        return buffer.toString();
+    }
+
+    protected RenderEngine createRenderEngine() {
+        return new BaseRenderEngine();
+    }
+
+    protected String getExtension() {
+        return "*.html";
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/wiki/Wiki2TestCase.java b/groovy-core/src/main/org/codehaus/groovy/wiki/Wiki2TestCase.java
new file mode 100644
index 0000000..f639699
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/wiki/Wiki2TestCase.java
@@ -0,0 +1,80 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.wiki;
+
+import org.radeox.api.engine.RenderEngine;
+
+/**
+ * A wiki renderer that creates JUnit test cases
+ * 
+ * @author James Strachan
+ * @version $Revision$
+ */
+public class Wiki2TestCase extends Wiki2Markup {
+
+    public static void main(String[] args) {
+        try {
+            Wiki2TestCase engine = new Wiki2TestCase();
+            engine.compileFiles(args);
+        }
+        catch (Exception e) {
+            System.out.println("Caught: " + e);
+            e.printStackTrace();
+        }
+    }
+
+    protected RenderEngine createRenderEngine() {
+        return new TestCaseRenderEngine();
+    }
+
+    protected String getExtension() {
+        return "*Test.groovy";
+    }
+
+    protected String filter(String result) {
+        return result;
+    }
+}
diff --git a/groovy-core/src/main/org/codehaus/groovy/wiki/package.html b/groovy-core/src/main/org/codehaus/groovy/wiki/package.html
new file mode 100644
index 0000000..bfb6bab
--- /dev/null
+++ b/groovy-core/src/main/org/codehaus/groovy/wiki/package.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <title>package org.codehaus.groovy.wiki.*</title>
+  </head>
+  <body>
+    <p>
+      Wiki related code and Ant tasts for styling wiki docs to HTML and extracting unit test cases 
+      from documentation
+    </p>
+  </body>
+</html>
diff --git a/groovy-core/src/native/base.c b/groovy-core/src/native/base.c
new file mode 100644
index 0000000..2200421
--- /dev/null
+++ b/groovy-core/src/native/base.c
@@ -0,0 +1,85 @@
+#ifdef __APPLE__
+#ifdef __MACH__
+#define MACOSX
+#define UNIX
+#endif
+#endif
+
+#ifdef __linux__
+#define UNIX
+#define LINUX
+#endif
+
+#ifdef UNIX
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#endif
+
+#ifdef LINUX
+#include <unistd.h>
+#include <linux/limits.h>
+#include <malloc.h>
+#endif
+
+#ifdef MACOSX
+#include <mach-o/dyld.h>
+#include <sys/param.h>
+#endif
+
+int main(int argc, char* argv[]) {
+
+  // Get the location of the executable -- platform specific
+#ifdef UNIX
+  char *jarexe = malloc((MAXPATHLEN+2)*sizeof(char));
+#endif
+
+#ifdef MACOSX
+  uint32_t length = MAXPATHLEN + 2;
+  while (_NSGetExecutablePath((char*)jarexe, &length) == -1) {
+    free(jarexe);
+    jarexe = malloc((length)*sizeof(char));
+  }
+#endif
+
+#ifdef LINUX
+  char temp[PATH_MAX];
+  sprintf(temp, "/proc/%d/exe", getpid());
+  realpath(temp, jarexe);
+#endif
+
+  // Setup the command line.
+  // TODO: Add -J support for passing Java options
+  char* argv2[argc+2];
+  argv2[0] = "java";
+  argv2[1] = JAVA_CLASS_NAME;
+
+  // Setup the CLASSPATH environment
+  char *CLASSPATH = (char*) getenv("CLASSPATH");
+  if (!CLASSPATH) CLASSPATH="";
+  char *NEWCLASSPATH = (char*) calloc(strlen(CLASSPATH)+1+strlen(jarexe)+1, sizeof(char)); // +1 for :, +1 for null terminator
+  sprintf(NEWCLASSPATH, "%s:%s", jarexe, CLASSPATH);
+  setenv("CLASSPATH", NEWCLASSPATH, 1);
+
+  // Setup the rest of the command line that was passed in.
+  // TODO: This will also be affected by -J options
+  int i;
+  for (i = 1; i < argc; i++) {
+    argv2[i+1] = argv[i];
+  }
+  argv2[argc+1] = 0;
+
+  // Execute java
+#ifdef UNIX
+  free(jarexe);
+  execvp("java", argv2);
+#endif
+
+  // Report if the exec fails
+  printf("Cannot execute '");
+  for (i = 0; i < argc+1; i ++) { printf("%s ", argv2[i]); }
+#ifdef UNIX
+  printf("', caused by error: %d\n.  In order to run %s you must have the Java VM you want to use in your PATH", errno, argv[0]);
+#endif
+}
diff --git a/groovy-core/src/script/helloWorld b/groovy-core/src/script/helloWorld
new file mode 100644
index 0000000..ada1655
--- /dev/null
+++ b/groovy-core/src/script/helloWorld
@@ -0,0 +1,7 @@
+#!/usr/bin/env groovy
+
+println("Hello world")
+
+for (a in args) {
+	println("Argument: " + a)
+}	
\ No newline at end of file
diff --git a/groovy-core/src/tck/.cvsignore b/groovy-core/src/tck/.cvsignore
new file mode 100644
index 0000000..f84e6d3
--- /dev/null
+++ b/groovy-core/src/tck/.cvsignore
@@ -0,0 +1,3 @@
+build
+dist
+gentest
diff --git a/groovy-core/src/tck/build.xml b/groovy-core/src/tck/build.xml
new file mode 100644
index 0000000..b2d8316
--- /dev/null
+++ b/groovy-core/src/tck/build.xml
@@ -0,0 +1,202 @@
+<?xml version="1.0"?>
+<project name="tck" default="default">
+
+  <!-- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -->
+  <!--                   compile settings                -->
+  <!-- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -->
+  <property name="build.debug" value="on"/>
+  
+  <!-- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -->
+  <!--                   directories                     -->
+  <!-- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -->
+  <property name="src.dir" value="src"/>
+  <property name="build.dir" value="build"/>
+  <property name="build.classes.dir" value="${build.dir}/classes"/>
+  <property name="dist.dir" value="dist"/>
+
+  <!-- javadoc properties -->
+  <property name="javadoc.dir" value="doc"/>
+  <property name="javadoc.packages" value="org.codehaus.groovy.*"/>
+
+  <!-- junit properties -->
+  <property name="junit.style.dir" value="styles"/>
+  <property name="testcase.src.dir" value="test"/>
+  <property name="generated.test.src.dir" value="gentest"/>
+  
+  <property name="test.classes.dir" value="${build.dir}/test/classes"/>
+
+  <!-- TODO: here you specify where the classes to test reside -->
+  <property name="items.under.test.dir" value="../../target/install/lib"/>
+  
+  <property name="test.reports.dir" value="reports"/>
+  
+  <!-- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -->
+  <!--                  targets                          -->
+  <!-- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -->
+  <target name="default" 
+          depends="clean,test-compile" 
+          description="default: run the groovy test suite"
+  />
+  
+  <target name="all" 
+          depends="test,dist" 
+          description="build and test everything"
+  />
+
+  <target name="clean" description="remove all built files">
+    <delete dir="${javadoc.dir}" />
+    <delete dir="${build.dir}" />
+    <delete dir="${dist.dir}" />
+    <delete dir="${generated.test.src.dir}" />
+  </target>
+
+  <target name="dist" 
+          depends="compile" 
+          description="create distributables (jars etc)">
+    <mkdir dir="${dist.dir}" />
+    <jar jarfile="${dist.dir}/tck.jar" 
+         manifest="${src.dir}/manifest.txt">
+      <fileset dir="${build.classes.dir}"/>
+    </jar>
+  </target>
+
+  <target name="docs" depends="init" description="generate documentation">
+    <mkdir dir="${javadoc.dir}" />
+    <javadoc sourcepath="${src.dir}" 
+             destdir="${javadoc.dir}" 
+             packagenames="${javadoc.packages}"
+             use="true"
+             windowtitle="tck"
+             private="true"/>
+  </target>
+
+  <target name="run" depends="compile" description="compile and run">
+    <java classname="org.codehaus.groovy.tck.GenerateTestCases" 
+          fork="yes" 
+          classpathref="project.classpath"/>
+  </target>
+
+  <target name="plain-test"
+          depends="test-compile" 
+          description="run all test cases">
+    <junit haltonfailure="true" fork="no">
+      <classpath refid="project.classpath"/>
+      <formatter type="plain" usefile="false"/>
+      <formatter type="xml" usefile="true"/>
+      <batchtest todir="${test.reports.dir}">
+        <fileset dir="${test.classes.dir}">
+          <include name="**/*Test.class" />
+        </fileset>
+      </batchtest>
+    </junit>
+  </target>
+        
+  <target name="test" 
+          depends="test-compile" 
+          description="HTML output of test cases">
+    <mkdir dir="${test.reports.dir}"/>
+    <junit haltonfailure="false" fork="no">
+      <classpath refid="project.classpath"/>
+      <formatter type="xml" usefile="true"/>
+
+      <batchtest todir="${test.reports.dir}">
+        <fileset dir="${test.classes.dir}">
+            <include name="**/*Test.class" /> 
+        </fileset>
+      </batchtest>
+
+    </junit>
+
+    <junitreport todir="${test.reports.dir}">
+      <fileset dir="${test.reports.dir}">
+        <include name="TEST-*.xml"/>
+      </fileset>
+      <report format="frames" styledir="${junit.style.dir}" todir="${test.reports.dir}"/>
+    </junitreport>
+    <echo>
++-------------------------+
+| open reports/index.html |
++-------------------------+
+</echo>
+  </target>
+
+
+
+  <target name="compile" depends="init" description="compile java and groovy sources">
+    <mkdir dir="${build.classes.dir}" />
+
+    <groovyc destdir="${build.classes.dir}"
+             srcdir="${src.dir}"
+             listfiles="true">
+        <classpath refid="project.classpath"/>
+    </groovyc>
+
+    <javac srcdir="${src.dir}"
+           destdir="${build.classes.dir}"
+           classpathref="project.classpath"
+           debug="${build.debug}"
+           deprecation="on"/>
+  </target>
+
+    <target name="generate" depends="dist" description="generate test cases">
+      <mkdir dir="${generated.test.src.dir}" />
+      <taskdef name="gentests" classname="org.codehaus.groovy.tck.GenerateTestCases" classpathref="project.classpath"/>
+
+      <gentests destdir="${generated.test.src.dir}"
+                srcdir="${testcase.src.dir}"
+                listfiles="true"/>
+    </target>
+
+  <target name="test-compile" depends="generate" description="compile tests">
+    <mkdir dir="${test.classes.dir}" />
+    <javac srcdir="${generated.test.src.dir}"
+           destdir="${test.classes.dir}" 
+           classpathref="project.classpath" 
+           debug="${build.debug}" 
+           deprecation="on">
+    </javac>
+  </target>
+
+  <target name="independent-test-compile" depends="generate" description="compile tests">
+    <mkdir dir="${test.classes.dir}" />
+    <javac srcdir="${generated.test.src.dir}"
+           destdir="${test.classes.dir}" 
+           classpathref="project.classpath" 
+           debug="${build.debug}" 
+           deprecation="on">
+    </javac>
+  </target>
+
+  <target name="init" depends="init.sub.build,init.independent.build">
+    <tstamp/>
+  </target>
+
+  <!-- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -->
+  <!--                     Datatypes                     -->
+  <!-- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- -->
+
+  <!-- this target is performed we are within a maven build -->
+  <target name="init.sub.build" if="maven.compile.source">
+
+    <path id="project.classpath">
+      <pathelement location="${test.classes.dir}"/>
+      <path refid="passed.classpath"/>
+      <pathelement location="${build.classes.dir}"/>
+    </path>
+  
+  </target>
+
+  <!-- this target is performed when ant is called from command line -->
+  <target name="init.independent.build" unless="maven.compile.source">
+
+    <path id="project.classpath">
+      <pathelement location="${test.classes.dir}"/>
+      <pathelement location="${build.classes.dir}"/>
+      <fileset dir="${items.under.test.dir}">
+        <include name="**/*.jar" />
+      </fileset>
+    </path>
+
+  </target>
+       
+</project>
diff --git a/groovy-core/src/tck/src/manifest.txt b/groovy-core/src/tck/src/manifest.txt
new file mode 100644
index 0000000..2dd0636
--- /dev/null
+++ b/groovy-core/src/tck/src/manifest.txt
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Main-Class: org.codehaus.groovy.tck.GenerateTestCases
diff --git a/groovy-core/src/tck/src/org/codehaus/groovy/tck/BatchGenerate.groovy b/groovy-core/src/tck/src/org/codehaus/groovy/tck/BatchGenerate.groovy
new file mode 100644
index 0000000..af43c2c
--- /dev/null
+++ b/groovy-core/src/tck/src/org/codehaus/groovy/tck/BatchGenerate.groovy
@@ -0,0 +1,86 @@
+/**
+ * @author Jeremy Rayner
+ */
+package org.codehaus.groovy.tck
+
+import java.io.File;
+
+class BatchGenerate {
+    def generator;
+    def srcDirPath;
+    def targetDir;
+    def srcEncoding;
+    def srcs;
+    def spew
+
+    public BatchGenerate() {
+        generator = new TestGenerator();
+        // verbose = false;
+        spew = true;
+        srcDirPath = "./";
+    }
+
+    public void setSrcdirPath(String pathName) {
+        if (spew) {println("srcDir:${pathName}") }
+        srcDirPath = pathName;
+    }
+
+    public void setTargetDirectory(File destDir) {
+        if (spew) { println("destDir:${destDir}") }
+        targetDir = destDir;
+    }
+
+    public void setSourceEncoding(String encoding) {
+        if (spew) { println("encoding:${encoding}") }
+        srcEncoding = encoding;
+    }
+
+    public void addSources( File[] compileList ) {
+        if (spew) { println("compileList:${compileList}") }
+        srcs = compileList
+    }
+
+    public void setVerbose(boolean verbose) {
+        spew = verbose
+    }
+
+    public void compile() {
+        if (spew) { println("compile()") }
+
+
+        for (src in srcs) {
+            println( src )
+            // mung the ${test.src.dir}/gls/ch14/s4 path into ${dest.dir}/gls/ch14/s4
+            // first determine the relative path e.g. gls/ch14/s4
+            def relativeSrcFilePathAndName = src.getAbsolutePath().substring(srcDirPath.length() + 1)
+            def relativeSrcFileNameStartIndex = relativeSrcFilePathAndName.lastIndexOf(File.separator);
+            def relativeOutputPath = ""
+            if (relativeSrcFileNameStartIndex >= 0) {
+                relativeOutputPath = relativeSrcFilePathAndName.substring(0,relativeSrcFileNameStartIndex);
+            }
+
+            // then determine the absolute output path
+            def ghostOutputFile = new File(targetDir, relativeSrcFilePathAndName)
+            def ghostOutputFilePath = ghostOutputFile.getAbsolutePath()
+            def fileNameStartIndex = ghostOutputFilePath.lastIndexOf(File.separator);
+            def realOutputPath = ghostOutputFilePath.substring(0,fileNameStartIndex);
+
+            // mkdir if does not exist
+            File directory = new File(realOutputPath)
+            if (directory != null && !directory.exists()) {
+                directory.mkdirs();
+            }
+
+            // generate a suitable java file to put there
+            def fileStem = src.name.tokenize(".")[0]
+            def targetFileName = "${fileStem}Test.java"
+            def anOutputFile = new File(realOutputPath, targetFileName)
+
+            System.out.println("generating " + targetFileName)
+            def someOutputText = generator.generate(relativeOutputPath, targetDir, src.name,src.text);
+            if (someOutputText != null && someOutputText != "") {
+                anOutputFile.write(someOutputText);
+            }
+        }
+    }
+}
diff --git a/groovy-core/src/tck/src/org/codehaus/groovy/tck/ClassicGroovyTestGeneratorHelper.java b/groovy-core/src/tck/src/org/codehaus/groovy/tck/ClassicGroovyTestGeneratorHelper.java
new file mode 100644
index 0000000..3c6be2b
--- /dev/null
+++ b/groovy-core/src/tck/src/org/codehaus/groovy/tck/ClassicGroovyTestGeneratorHelper.java
@@ -0,0 +1,93 @@
+package org.codehaus.groovy.tck;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import junit.framework.TestResult;
+// Jsr parser
+// @todo - refactor pulling generic parser interface up
+import org.codehaus.groovy.antlr.parser.GroovyLexer;
+import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
+
+// codehaus reference implementation usage
+// @todo - remove classic references from the TCK
+import org.codehaus.groovy.control.CompilerConfiguration;
+import groovy.lang.GroovyShell;
+import antlr.RecognitionException;
+
+/** Helper methods for generated TCK test case using new JSR parser and classic groovy AST and evaluation */
+public class ClassicGroovyTestGeneratorHelper implements TestGeneratorHelper {
+
+    /** evaluate the source text against the classic AST with the JSR parser implementation*/
+    public Object evaluate(String theSrcText, String testName) throws Exception {
+        parse(theSrcText, testName); // fail early with a direct message if possible')
+        GroovyShell groovy = new GroovyShell(new CompilerConfiguration());
+        return groovy.run(theSrcText, "main", new ArrayList());
+    }
+
+    /** run the JSR parser implementation over the supplied source text*/
+    public void parse(String theSrcText, String testName) throws Exception {
+        System.out.println("-------------------------------");
+        System.out.println("  " + testName);
+        System.out.println("-------------------------------");
+        try {
+            Reader reader = new BufferedReader(new StringReader(theSrcText));
+            GroovyRecognizer recognizer = GroovyRecognizer.make(reader);
+            recognizer.compilationUnit();
+            System.out.println(decorateWithLineNumbers(theSrcText));
+
+        } catch (RecognitionException parseException) {
+            System.out.println(decorateWithLineNumbersAndErrorMessage(theSrcText,parseException));
+            throw parseException;
+        }
+        System.out.println("-------------------------------");
+
+    }
+
+    private String decorateWithLineNumbersAndErrorMessage(String theSrcText, RecognitionException parseException) {
+        try {
+            BufferedReader reader = new BufferedReader(new StringReader(theSrcText));
+            String line = null;
+            StringBuffer numberedSrcTextBuffer = new StringBuffer();
+            int lineNum = 1;
+            while ((line = reader.readLine() ) != null) {
+                numberedSrcTextBuffer.append(lineNum);
+                numberedSrcTextBuffer.append("\t");
+                numberedSrcTextBuffer.append(line);
+                numberedSrcTextBuffer.append(lineSep);
+
+                if (parseException != null) {
+                    if (lineNum == parseException.getLine()) {
+                        StringBuffer padding = new StringBuffer("\t");
+                        for (int col=1; col<parseException.getColumn();col++) {
+                            padding.append(" ");
+                        }
+                        numberedSrcTextBuffer.append(padding);
+                        numberedSrcTextBuffer.append("^");
+                        numberedSrcTextBuffer.append(lineSep);
+                        numberedSrcTextBuffer.append("ERROR:");
+                        numberedSrcTextBuffer.append(lineSep);
+                        numberedSrcTextBuffer.append(parseException.getMessage());
+                        numberedSrcTextBuffer.append(lineSep);
+                        numberedSrcTextBuffer.append(lineSep);
+                    }
+                }
+
+                lineNum++;
+
+            }
+            theSrcText = numberedSrcTextBuffer.toString();
+        } catch (IOException e) {
+            //ignore
+        }
+        return theSrcText;
+    }
+
+    private String decorateWithLineNumbers(String theSrcText) {
+        return decorateWithLineNumbersAndErrorMessage(theSrcText,null);
+    }
+
+    protected String lineSep = System.getProperty("line.separator");
+}
diff --git a/groovy-core/src/tck/src/org/codehaus/groovy/tck/GenerateTestCases.java b/groovy-core/src/tck/src/org/codehaus/groovy/tck/GenerateTestCases.java
new file mode 100644
index 0000000..9456fbf
--- /dev/null
+++ b/groovy-core/src/tck/src/org/codehaus/groovy/tck/GenerateTestCases.java
@@ -0,0 +1,387 @@
+/**
+ * @author Jeremy Rayner
+ */
+package org.codehaus.groovy.tck;
+
+import java.io.*;
+import java.nio.charset.Charset;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.*;
+import org.apache.tools.ant.util.*;
+
+/**
+ * Generates test files. This task can take the following
+ * arguments:
+ * <ul>
+ * <li>sourcedir
+ * <li>destdir
+ * </ul>
+ * Both are required.
+ * <p>
+ * When this task executes, it will recursively scan the sourcedir
+ * looking for source files to expand into testcases. This task makes its
+ * generation decision based on timestamp.
+ *
+ * Based heavily on the Javac implementation in Ant
+ *
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+public class GenerateTestCases extends MatchingTask {
+
+    private BatchGenerate batchGenerate = new BatchGenerate();
+    private Path src;
+    private File destDir;
+    private Path compileClasspath;
+    private Path compileSourcepath;
+    private String encoding;
+
+    protected boolean failOnError = true;
+    protected boolean listFiles = false;
+    protected File[] compileList = new File[0];
+
+    public GenerateTestCases() {
+    }
+
+    /**
+     * Adds a path for source compilation.
+     *
+     * @return a nested src element.
+     */
+    public Path createSrc() {
+        if (src == null) {
+            src = new Path(getProject());
+        }
+        return src.createPath();
+    }
+
+    /**
+     * Recreate src.
+     *
+     * @return a nested src element.
+     */
+    protected Path recreateSrc() {
+        src = null;
+        return createSrc();
+    }
+
+    /**
+     * Set the source directories to find the source Java files.
+     * @param srcDir the source directories as a path
+     */
+    public void setSrcdir(Path srcDir) {
+        if (src == null) {
+            src = srcDir;
+        }
+        else {
+            src.append(srcDir);
+        }
+        batchGenerate.setSrcdirPath(src.toString());
+    }
+
+    /**
+     * Gets the source dirs to find the source java files.
+     * @return the source directorys as a path
+     */
+    public Path getSrcdir() {
+        return src;
+    }
+
+    /**
+     * Set the destination directory into which the Java source
+     * files should be compiled.
+     * @param destDir the destination director
+     */
+    public void setDestdir(File destDir) {
+        this.destDir = destDir;
+    }
+
+    /**
+     * Enable verbose compiling which will display which files
+     * are being compiled
+     * @param verbose
+     */
+    public void setVerbose(boolean verbose) {
+        batchGenerate.setVerbose( verbose );
+    }
+
+    /**
+     * Gets the destination directory into which the java source files
+     * should be compiled.
+     * @return the destination directory
+     */
+    public File getDestdir() {
+        return destDir;
+    }
+
+    /**
+     * Set the sourcepath to be used for this compilation.
+     * @param sourcepath the source path
+     */
+    public void setSourcepath(Path sourcepath) {
+        if (compileSourcepath == null) {
+            compileSourcepath = sourcepath;
+        }
+        else {
+            compileSourcepath.append(sourcepath);
+        }
+    }
+
+    /**
+     * Gets the sourcepath to be used for this compilation.
+     * @return the source path
+     */
+    public Path getSourcepath() {
+        return compileSourcepath;
+    }
+
+    /**
+     * Adds a path to sourcepath.
+     * @return a sourcepath to be configured
+     */
+    public Path createSourcepath() {
+        if (compileSourcepath == null) {
+            compileSourcepath = new Path(getProject());
+        }
+        return compileSourcepath.createPath();
+    }
+
+    /**
+     * Adds a reference to a source path defined elsewhere.
+     * @param r a reference to a source path
+     */
+    public void setSourcepathRef(Reference r) {
+        createSourcepath().setRefid(r);
+    }
+
+    /**
+     * Set the classpath to be used for this compilation.
+     *
+     * @param classpath an Ant Path object containing the compilation classpath.
+     */
+    public void setClasspath(Path classpath) {
+        if (compileClasspath == null) {
+            compileClasspath = classpath;
+        }
+        else {
+            compileClasspath.append(classpath);
+        }
+    }
+
+    /**
+     * Gets the classpath to be used for this compilation.
+     * @return the class path
+     */
+    public Path getClasspath() {
+        return compileClasspath;
+    }
+
+    /**
+     * Adds a path to the classpath.
+     * @return a class path to be configured
+     */
+    public Path createClasspath() {
+        if (compileClasspath == null) {
+            compileClasspath = new Path(getProject());
+        }
+        return compileClasspath.createPath();
+    }
+
+    /**
+     * Adds a reference to a classpath defined elsewhere.
+     * @param r a reference to a classpath
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    public String createEncoding() {
+        if (encoding == null) {
+            encoding = System.getProperty("file.encoding");
+        }
+        return encoding;
+    }
+
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * If true, list the source files being handed off to the compiler.
+     * @param list if true list the source files
+     */
+    public void setListfiles(boolean list) {
+        listFiles = list;
+    }
+
+    /**
+     * Get the listfiles flag.
+     * @return the listfiles flag
+     */
+    public boolean getListfiles() {
+        return listFiles;
+    }
+
+    /**
+     * Indicates whether the build will continue
+     * even if there are compilation errors; defaults to true.
+     * @param fail if true halt the build on failure
+     */
+    public void setFailonerror(boolean fail) {
+        failOnError = fail;
+    }
+
+    /**
+     * @param proceed inverse of failoferror
+     */
+    public void setProceed(boolean proceed) {
+        failOnError = !proceed;
+    }
+
+    /**
+     * Gets the failonerror flag.
+     * @return the failonerror flag
+     */
+    public boolean getFailonerror() {
+        return failOnError;
+    }
+
+    /**
+     * Executes the task.
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+        checkParameters();
+        resetFileLists();
+
+        // scan source directories and dest directory to build up
+        // compile lists
+        String[] list = src.list();
+        for (int i = 0; i < list.length; i++) {
+            File srcDir = getProject().resolveFile(list[i]);
+            if (!srcDir.exists()) {
+                throw new BuildException("srcdir \"" + srcDir.getPath() + "\" does not exist!", getLocation());
+            }
+
+            DirectoryScanner ds = this.getDirectoryScanner(srcDir);
+            String[] files = ds.getIncludedFiles();
+
+            scanDir(srcDir, destDir != null ? destDir : srcDir, files);
+        }
+
+        compile();
+    }
+
+    /**
+     * Clear the list of files to be compiled and copied..
+     */
+    protected void resetFileLists() {
+        compileList = new File[0];
+    }
+
+    /**
+     * Scans the directory looking for source files to be compiled.
+     * The results are returned in the class variable compileList
+     *
+     * @param srcDir   The source directory
+     * @param destDir  The destination directory
+     * @param files    An array of filenames
+     */
+    protected void scanDir(File srcDir, File destDir, String[] files) {
+        GlobPatternMapper m = new GlobPatternMapper();
+        m.setFrom("*");
+        m.setTo("*.html");
+        SourceFileScanner sfs = new SourceFileScanner(this);
+        File[] newFiles = sfs.restrictAsFiles(files, srcDir, destDir, m);
+
+        if (newFiles.length > 0) {
+            File[] newCompileList = new File[compileList.length + newFiles.length];
+            System.arraycopy(compileList, 0, newCompileList, 0, compileList.length);
+            System.arraycopy(newFiles, 0, newCompileList, compileList.length, newFiles.length);
+            compileList = newCompileList;
+        }
+    }
+
+    /**
+     * Gets the list of files to be compiled.
+     * @return the list of files as an array
+     */
+    public File[] getFileList() {
+        return compileList;
+    }
+
+    protected void checkParameters() throws BuildException {
+        if (src == null) {
+            throw new BuildException("srcdir attribute must be set!", getLocation());
+        }
+        if (src.size() == 0) {
+            throw new BuildException("srcdir attribute must be set!", getLocation());
+        }
+
+        if (destDir != null && !destDir.isDirectory()) {
+            throw new BuildException(
+                "destination directory \"" + destDir + "\" does not exist " + "or is not a directory",
+                getLocation());
+        }
+
+        if (encoding != null && !Charset.isSupported(encoding)) {
+            throw new BuildException("encoding \"\" not supported");
+        }
+    }
+
+    protected void compile() {
+        if (compileList.length > 0) {
+            log(
+                "Generating Tests "
+                    + compileList.length
+                    + " source file"
+                    + (compileList.length == 1 ? "" : "s")
+                    + (destDir != null ? " to " + destDir : ""));
+
+            if (listFiles) {
+                for (int i = 0; i < compileList.length; i++) {
+                    String filename = compileList[i].getAbsolutePath();
+                    log(filename);
+                }
+            }
+
+            try {
+                Path classpath = getClasspath();
+                if (classpath != null) {
+                    //@todo - is this useful?
+                    //batchOfBiscuits.setClasspath(classpath.toString());
+                }
+                batchGenerate.setTargetDirectory(destDir);
+
+                if (encoding != null) {
+                    batchGenerate.setSourceEncoding(encoding);
+                }
+
+                batchGenerate.addSources( compileList );
+                batchGenerate.compile( );
+            }
+            catch (Exception e) {
+
+                StringWriter writer = new StringWriter();
+                //@todo --
+                e.printStackTrace();
+                //new ErrorReporter( e, false ).write( new PrintWriter(writer) );
+                String message = writer.toString();
+
+                if (failOnError) {
+                    throw new BuildException(message, e, getLocation());
+                }
+                else {
+                    log(message, Project.MSG_ERR);
+                }
+
+            }
+        }
+    }
+}
diff --git a/groovy-core/src/tck/src/org/codehaus/groovy/tck/TestGenerator.groovy b/groovy-core/src/tck/src/org/codehaus/groovy/tck/TestGenerator.groovy
new file mode 100644
index 0000000..0f808f5
--- /dev/null
+++ b/groovy-core/src/tck/src/org/codehaus/groovy/tck/TestGenerator.groovy
@@ -0,0 +1,209 @@
+/**
+ * This will take a groovy test file and turn it into a Java TestCase
+ * @author Jeremy Rayner
+ */
+package org.codehaus.groovy.tck
+import java.io.*;
+class TestGenerator{
+    public String generate(realOutputPath, targetDir, srcName,srcText) {
+//        System.out.println('single \\\\')
+//        System.out.println("double \\\\")
+        srcText = srcText.replaceAll('\\\\','\\\\\\\\') // need to escape a slash with slash slash
+
+        def resultWriter = new StringWriter()
+        def result = new PrintWriter(resultWriter)
+
+        def fileName = srcName
+        def fileStem = fileName.tokenize(".")[0]
+
+        def comments = scrape(srcText," * ",".") // Take the first javadoc sentence, if it exists, for use as method name
+        if (comments == null || comments[0] == null) {comments = [""]}
+        def behaviourDescription = comments[0].trim()
+
+        if ("" != realOutputPath) {
+            def realOutputPackage = ''
+            if (File.separator != '\\')
+                realOutputPackage = realOutputPath.replaceAll(File.separator,'.')
+            else
+                realOutputPackage = realOutputPath.replaceAll('\\\\','.')
+            result.println("package ${realOutputPackage};")
+        }
+        result.println("import junit.framework.*;")
+        result.println("import org.codehaus.groovy.tck.*;")
+
+        result.println("public class ${fileStem}Test extends TestCase {")
+
+        //methodName = turnSentenceIntoJavaName(behaviourDescription)
+        def methodName = ""
+        methodName = "test${methodName}"
+
+        // test for the source 'as is'
+        printCommonTestMethodStart(result, "${methodName}Pass",srcText)
+        result.println('        Object result = helper.evaluate(srcBuffer.toString(),"' + "${methodName}Pass" + '");')
+        result.println('        if (result instanceof TestResult) {')
+        result.println('            TestResult testResult = (TestResult)result;')
+        result.println('            if (testResult.errorCount() > 0) {')
+        result.println('                TestFailure firstTestFailure = (TestFailure)testResult.errors().nextElement();')
+        result.println('                throw firstTestFailure.thrownException();')
+        result.println('            }')
+        result.println('            if (testResult.failureCount() > 0) {')
+        result.println('                AssertionFailedError firstFailure = (AssertionFailedError)(testResult.failures().nextElement());')
+        result.println('                throw firstFailure;')
+        result.println('            }')
+        result.println('        }')
+        result.println("    }")
+
+        // test for each of the '@pass' alternatives
+        def passAlternatives = generateAlternatives(srcText,"@pass")
+
+        passAlternatives.eachWithIndex{anAlternative,i ->
+            printCommonTestMethodStart(result, "${methodName}Pass${i+1}",anAlternative[0]);
+            result.println('        Object result = helper.evaluate(srcBuffer.toString(),"' + "${methodName}Pass${i+1}" + '");')
+            result.println('        if (result instanceof TestResult) {')
+            result.println('            TestResult testResult = (TestResult)result;')
+            result.println('            if (testResult.errorCount() > 0) {')
+            result.println('                TestFailure firstTestFailure = (TestFailure)testResult.errors().nextElement();')
+            result.println('                throw firstTestFailure.thrownException();')
+            result.println('            }')
+            result.println('            if (testResult.failureCount() > 0) {')
+            result.println('                AssertionFailedError firstFailure = (AssertionFailedError)(testResult.failures().nextElement());')
+            result.println('                throw firstFailure;')
+            result.println('            }')
+            result.println('        }')
+
+            result.println("    }")
+        }
+
+        // test for each of the '@fail:parse' alternatives
+        def failureToParseAlternatives = generateAlternatives(srcText,"@fail:parse")
+        failureToParseAlternatives.eachWithIndex{anAlternative,i ->
+            printCommonTestMethodStart(result, "${methodName}FailParse${i+1}",anAlternative[0]);
+            result.println("        try {")
+            result.println('            helper.parse(srcBuffer.toString(),"' + "${methodName}FailParse${i+1}" + '");')
+
+
+            result.println('            fail("This line did not fail to parse: ' + anAlternative[1] + '");')
+            result.println("        } catch (Exception e) {")
+            result.println("            // ignore an exception as that is what we're hoping for in this case.")
+            result.println("        }")
+            result.println("    }")
+        }
+
+        // test for each of the '@fail' alternatives, i.e. without being followed by a colon
+        def failureAlternatives = generateAlternatives(srcText,"@fail(?!:)")
+        failureAlternatives.eachWithIndex{anAlternative,i ->
+            printCommonTestMethodStart(result, "${methodName}Fail${i+1}",anAlternative[0]);
+            result.println("        try {")
+            result.println('            helper.evaluate(srcBuffer.toString(),"' + "${methodName}Fail${i+1}" + '");')
+            result.println('            fail("This line did not fail to evaluate: ' + anAlternative[1] + '");')
+            result.println("        } catch (Exception e) {")
+            result.println("            // ignore an exception as that is what we're hoping for in this case.")
+            result.println("        }")
+            result.println("    }")
+        }
+        result.println('    protected String lineSep = System.getProperty("line.separator");')
+        result.println('    protected TestGeneratorHelper helper = new ClassicGroovyTestGeneratorHelper();')
+        result.println("}")
+
+        return resultWriter.toString()
+    }
+
+
+    // -- useful stuff
+
+    /**
+     * Creates alternative versions of the given source, one for each end of line comment tag e.g. //@fail
+     * will remove the double slash from the start of each of the matching line.
+     * e.g. src text of...
+     * <pre>
+     *     // a = 1 // @fail
+     *     // b = 2 // @fail
+     * </pre>
+     * will return
+     * <pre>
+     * [ "a = 1 // @fail NLS // b = 2 // @fail",
+     *   "// a = 1 // @fail NLS b = 2 // @fail" ]
+     * </pre>
+     *
+     */
+    List generateAlternatives(String srcText, String tag) {
+        def alternatives = []
+        def m = java.util.regex.Pattern.compile("//(.*?//\\s*" + tag + "\\S*)\\s").matcher(srcText)
+        while (m.find()) {
+            def foundText = m.group(1)
+            def uncommentedSrcText = (srcText.substring(0,m.start()) + "  " + srcText.substring(m.start() + 2))
+            alternatives << [uncommentedSrcText, foundText.replaceAll('"', '\\\\"')]
+        }
+        return alternatives
+    }
+
+
+    /**
+     * Common setup code for each test method
+     */
+    void printCommonTestMethodStart(result, fullMethodName,someSrcText) {
+        def buffer = new java.io.StringReader(someSrcText)
+
+        result.println("    public void ${fullMethodName}() throws Throwable {")
+        result.println("        StringBuffer srcBuffer = new StringBuffer();")
+
+        // append each line to the buffer
+        buffer.eachLine {line ->
+            // escape double quotes
+            line = line.replaceAll('"','\\\\"')
+            result.println ('        srcBuffer.append("' + line + '").append(lineSep);')
+        }
+    }
+
+    /**
+     * Converts the given sentence into a Java style name like TheQuickBrownFox
+     */
+    String turnSentenceIntoJavaName(String sentence) {
+        //uppercase each word and remove spaces to give camel case
+        def tokens = sentence.tokenize(" ,;");
+        def methodName = ""
+        for (t in tokens) {
+            if (t.size() > 1) {
+                methodName += ( t[0].toUpperCase() + t[1..<t.size()].toLowerCase() )
+            } else if (t.size() == 1) {
+                methodName += t[0].toUpperCase()
+            }
+        }
+
+        //remove nonalphanumeric characters
+        methodName = methodName.replaceAll("[^A-Za-z0-9]","")
+
+        return methodName
+    }
+
+    /**
+     * Fetches a list of all the occurances of text between a string delimiter.
+     */
+    List scrape(String txt, String tag) {
+        return scrape(txt,tag,tag)
+    }
+
+    /**
+     * Fetches a list of all the occurances of text between two string delimiters (tags).
+     */
+    List scrape(String txt, String openTag, String closeTag) {
+        def i = 0; def j = 0; def k = 0;
+        def contents = []
+        if (txt != null) {
+            while (i> -1 && k > -1) {
+              i = txt.indexOf(openTag,k)
+                if (i > -1) {
+                  j = i + openTag.length()
+                    if (j > -1) {
+                      k = txt.indexOf(closeTag,j)
+                        if (k > -1) {
+                          contents << txt.substring(j,k)
+                        }
+                    }
+                }
+            }
+        }
+        return contents
+    }
+
+}
diff --git a/groovy-core/src/tck/src/org/codehaus/groovy/tck/TestGeneratorHelper.java b/groovy-core/src/tck/src/org/codehaus/groovy/tck/TestGeneratorHelper.java
new file mode 100644
index 0000000..7059f62
--- /dev/null
+++ b/groovy-core/src/tck/src/org/codehaus/groovy/tck/TestGeneratorHelper.java
@@ -0,0 +1,8 @@
+package org.codehaus.groovy.tck;
+
+/** Helper methods used by generated TCK test cases */
+
+public interface TestGeneratorHelper {
+    Object evaluate(String theSrcText, String testName) throws Exception;
+    void parse(String theSrcText, String testName) throws Exception;
+}
diff --git a/groovy-core/src/tck/styles/junit-frames.xsl b/groovy-core/src/tck/styles/junit-frames.xsl
new file mode 100644
index 0000000..c208c5a
--- /dev/null
+++ b/groovy-core/src/tck/styles/junit-frames.xsl
@@ -0,0 +1,723 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+    xmlns:lxslt="http://xml.apache.org/xslt"
+    xmlns:redirect="http://xml.apache.org/xalan/redirect"
+    xmlns:stringutils="xalan://org.apache.tools.ant.util.StringUtils"
+    extension-element-prefixes="redirect">
+<xsl:output method="html" indent="yes" encoding="US-ASCII"/>
+<xsl:decimal-format decimal-separator="." grouping-separator=","/>
+<!--
+   Copyright 2001-2004 The Apache Software Foundation
+
+   Licensed 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.
+ -->
+
+<!--
+
+ Sample stylesheet to be used with Ant JUnitReport output.
+
+ It creates a set of HTML files a la javadoc where you can browse easily
+ through all packages and classes.
+
+ @author Stephane Bailliez <a href="mailto:sbailliez@apache.org"/>
+ @author Erik Hatcher <a href="mailto:ehatcher@apache.org"/>
+ @author Martijn Kruithof <a href="mailto:martijn@kruithof.xs4all.nl"/>
+
+-->
+<xsl:param name="output.dir" select="'.'"/>
+
+
+<xsl:template match="testsuites">
+    <!-- create the index.html -->
+    <redirect:write file="{$output.dir}/index.html">
+        <xsl:call-template name="index.html"/>
+    </redirect:write>
+
+    <!-- create the stylesheet.css -->
+    <redirect:write file="{$output.dir}/stylesheet.css">
+        <xsl:call-template name="stylesheet.css"/>
+    </redirect:write>
+
+    <!-- create the overview-packages.html at the root -->
+    <redirect:write file="{$output.dir}/overview-summary.html">
+        <xsl:apply-templates select="." mode="overview.packages"/>
+    </redirect:write>
+
+    <!-- create the all-packages.html at the root -->
+    <redirect:write file="{$output.dir}/overview-frame.html">
+        <xsl:apply-templates select="." mode="all.packages"/>
+    </redirect:write>
+
+    <!-- create the all-classes.html at the root -->
+    <redirect:write file="{$output.dir}/allclasses-frame.html">
+        <xsl:apply-templates select="." mode="all.classes"/>
+    </redirect:write>
+
+    <!-- process all packages -->
+    <xsl:for-each select="./testsuite[not(./@package = preceding-sibling::testsuite/@package)]">
+        <xsl:call-template name="package">
+            <xsl:with-param name="name" select="@package"/>
+        </xsl:call-template>
+    </xsl:for-each>
+</xsl:template>
+
+
+<xsl:template name="package">
+    <xsl:param name="name"/>
+    <xsl:variable name="package.dir">
+        <xsl:if test="not($name = '')"><xsl:value-of select="translate($name,'.','/')"/></xsl:if>
+        <xsl:if test="$name = ''">.</xsl:if>
+    </xsl:variable>
+    <!--Processing package <xsl:value-of select="@name"/> in <xsl:value-of select="$output.dir"/> -->
+    <!-- create a classes-list.html in the package directory -->
+    <redirect:write file="{$output.dir}/{$package.dir}/package-frame.html">
+        <xsl:call-template name="classes.list">
+            <xsl:with-param name="name" select="$name"/>
+        </xsl:call-template>
+    </redirect:write>
+
+    <!-- create a package-summary.html in the package directory -->
+    <redirect:write file="{$output.dir}/{$package.dir}/package-summary.html">
+        <xsl:call-template name="package.summary">
+            <xsl:with-param name="name" select="$name"/>
+        </xsl:call-template>
+    </redirect:write>
+
+    <!-- for each class, creates a @name.html -->
+    <!-- @bug there will be a problem with inner classes having the same name, it will be overwritten -->
+    <xsl:for-each select="/testsuites/testsuite[@package = $name]">
+        <redirect:write file="{$output.dir}/{$package.dir}/{@name}.html">
+            <xsl:apply-templates select="." mode="class.details"/>
+        </redirect:write>
+        <xsl:if test="string-length(./system-out)!=0">
+            <redirect:write file="{$output.dir}/{$package.dir}/{@name}-out.txt">
+                <xsl:value-of select="./system-out" />
+            </redirect:write>
+        </xsl:if>
+        <xsl:if test="string-length(./system-err)!=0">
+            <redirect:write file="{$output.dir}/{$package.dir}/{@name}-err.txt">
+                <xsl:value-of select="./system-err" />
+            </redirect:write>
+        </xsl:if>
+    </xsl:for-each>
+</xsl:template>
+
+<xsl:template name="index.html">
+<html>
+    <head>
+        <title>Groovy TCK Results.</title>
+    </head>
+    <frameset cols="20%,80%">
+        <frameset rows="30%,70%">
+            <frame src="overview-frame.html" name="packageListFrame"/>
+            <frame src="allclasses-frame.html" name="classListFrame"/>
+        </frameset>
+        <frame src="overview-summary.html" name="classFrame"/>
+        <noframes>
+            <h2>Frame Alert</h2>
+            <p>
+                This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
+            </p>
+        </noframes>
+    </frameset>
+</html>
+</xsl:template>
+
+<!-- this is the stylesheet css to use for nearly everything -->
+<xsl:template name="stylesheet.css">
+body {
+    font:normal 68% verdana,arial,helvetica;
+    color:#000000;
+}
+table tr td, table tr th {
+    font-size: 68%;
+}
+table.details tr th{
+    font-weight: bold;
+    text-align:left;
+    background:#a6caf0;
+}
+table.details tr td{
+    background:#eeeee0;
+}
+
+p {
+    line-height:1.5em;
+    margin-top:0.5em; margin-bottom:1.0em;
+}
+h1 {
+    margin: 0px 0px 5px; font: 165% verdana,arial,helvetica
+}
+h2 {
+    margin-top: 1em; margin-bottom: 0.5em; font: bold 125% verdana,arial,helvetica
+}
+h3 {
+    margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica
+}
+h4 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+}
+h5 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+}
+h6 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+}
+.Error {
+    font-weight:bold; color:red;
+}
+.Failure {
+    font-weight:bold; color:purple;
+}
+.Properties {
+  text-align:right;
+}
+</xsl:template>
+
+
+<!-- ======================================================================
+    This page is created for every testsuite class.
+    It prints a summary of the testsuite and detailed information about
+    testcase methods.
+     ====================================================================== -->
+<xsl:template match="testsuite" mode="class.details">
+    <xsl:variable name="package.name" select="@package"/>
+    <xsl:variable name="class.name"><xsl:if test="not($package.name = '')"><xsl:value-of select="$package.name"/>.</xsl:if><xsl:value-of select="@name"/></xsl:variable>
+    <html>
+        <head>
+          <title>Groovy TCK Results: <xsl:value-of select="$class.name"/></title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$package.name"/>
+            </xsl:call-template>
+       <script type="text/javascript" language="JavaScript">
+        var TestCases = new Array();
+        var cur;
+        <xsl:apply-templates select="properties"/>
+       </script>
+       <script type="text/javascript" language="JavaScript"><![CDATA[
+        function displayProperties (name) {
+          var win = window.open('','JUnitSystemProperties','scrollbars=1,resizable=1');
+          var doc = win.document.open();
+          doc.write("<html><head><title>Properties of " + name + "</title>");
+          doc.write("<style type=\"text/css\">");
+          doc.write("body {font:normal 68% verdana,arial,helvetica; color:#000000; }");
+          doc.write("table tr td, table tr th { font-size: 68%; }");
+          doc.write("table.properties { border-collapse:collapse; border-left:solid 1 #cccccc; border-top:solid 1 #cccccc; padding:5px; }");
+          doc.write("table.properties th { text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#eeeeee; }");
+          doc.write("table.properties td { font:normal; text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#fffffff; }");
+          doc.write("h3 { margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica }");
+          doc.write("</style>");
+          doc.write("</head><body>");
+          doc.write("<h3>Properties of " + name + "</h3>");
+          doc.write("<div align=\"right\"><a href=\"javascript:window.close();\">Close</a></div>");
+          doc.write("<table class='properties'>");
+          doc.write("<tr><th>Name</th><th>Value</th></tr>");
+          for (prop in TestCases[name]) {
+            doc.write("<tr><th>" + prop + "</th><td>" + TestCases[name][prop] + "</td></tr>");
+          }
+          doc.write("</table>");
+          doc.write("</body></html>");
+          doc.close();
+          win.focus();
+        }
+      ]]>
+      </script>
+        </head>
+        <body>
+            <xsl:call-template name="pageHeader"/>
+            <h3>Class <xsl:value-of select="$class.name"/></h3>
+
+
+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+                <xsl:call-template name="testsuite.test.header"/>
+                <xsl:apply-templates select="." mode="print.test"/>
+            </table>
+            <h2>Tests</h2>
+            <xsl:if test="string-length(./system-out)!=0">
+                    <a>
+                        <xsl:attribute name="href">./<xsl:value-of select="@name"/>-out.txt</xsl:attribute>
+                        sources &#187;
+                    </a>
+            </xsl:if>
+            <p/>
+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+        <xsl:call-template name="testcase.test.header"/>
+              <!--
+              test can even not be started at all (failure to load the class)
+              so report the error directly
+              -->
+                <xsl:if test="./error">
+                    <tr class="Error">
+                        <td colspan="4"><xsl:apply-templates select="./error"/></td>
+                    </tr>
+                </xsl:if>
+                <xsl:apply-templates select="./testcase" mode="print.test"/>
+            </table>
+            <div class="Properties">
+                <a>
+                    <xsl:attribute name="href">javascript:displayProperties('<xsl:value-of select="@package"/>.<xsl:value-of select="@name"/>');</xsl:attribute>
+                    Properties &#187;
+                </a>
+            </div>
+            <xsl:if test="string-length(./system-out)!=0">
+                <div class="Properties">
+                    <a>
+                        <xsl:attribute name="href">./<xsl:value-of select="@name"/>-out.txt</xsl:attribute>
+                        System.out &#187;
+                    </a>
+                </div>
+            </xsl:if>
+            <xsl:if test="string-length(./system-err)!=0">
+                <div class="Properties">
+                    <a>
+                        <xsl:attribute name="href">./<xsl:value-of select="@name"/>-err.txt</xsl:attribute>
+                        System.err &#187;
+                    </a>
+                </div>
+            </xsl:if>
+        </body>
+    </html>
+</xsl:template>
+
+  <!--
+   Write properties into a JavaScript data structure.
+   This is based on the original idea by Erik Hatcher (ehatcher@apache.org)
+   -->
+  <xsl:template match="properties">
+    cur = TestCases['<xsl:value-of select="../@package"/>.<xsl:value-of select="../@name"/>'] = new Array();
+    <xsl:for-each select="property">
+    <xsl:sort select="@name"/>
+        cur['<xsl:value-of select="@name"/>'] = '<xsl:call-template name="JS-escape"><xsl:with-param name="string" select="@value"/></xsl:call-template>';
+    </xsl:for-each>
+  </xsl:template>
+
+
+<!-- ======================================================================
+    This page is created for every package.
+    It prints the name of all classes that belongs to this package.
+    @param name the package name to print classes.
+     ====================================================================== -->
+<!-- list of classes in a package -->
+<xsl:template name="classes.list">
+    <xsl:param name="name"/>
+    <html>
+        <head>
+            <title>Groovy TCK Classes: <xsl:value-of select="$name"/></title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <table width="100%">
+                <tr>
+                    <td nowrap="nowrap">
+                        <h2><a href="package-summary.html" target="classFrame">
+                            <xsl:value-of select="$name"/>
+                            <xsl:if test="$name = ''">&lt;none&gt;</xsl:if>
+                        </a></h2>
+                    </td>
+                </tr>
+            </table>
+
+            <h2>Classes</h2>
+            <table width="100%">
+                <xsl:for-each select="/testsuites/testsuite[./@package = $name]">
+                    <xsl:sort select="@name"/>
+                    <tr>
+                        <td nowrap="nowrap">
+                            <a href="{@name}.html" target="classFrame"><xsl:value-of select="@name"/></a>
+                        </td>
+                    </tr>
+                </xsl:for-each>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+
+<!--
+    Creates an all-classes.html file that contains a link to all package-summary.html
+    on each class.
+-->
+<xsl:template match="testsuites" mode="all.classes">
+    <html>
+        <head>
+            <title>All Groovy TCK Classes</title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <h2>Classes</h2>
+            <table width="100%">
+                <xsl:apply-templates select="testsuite" mode="all.classes">
+                    <xsl:sort select="@name"/>
+                </xsl:apply-templates>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+<xsl:template match="testsuite" mode="all.classes">
+    <xsl:variable name="package.name" select="@package"/>
+    <tr>
+        <td nowrap="nowrap">
+            <a target="classFrame">
+                <xsl:attribute name="href">
+                    <xsl:if test="not($package.name='')">
+                        <xsl:value-of select="translate($package.name,'.','/')"/><xsl:text>/</xsl:text>
+                    </xsl:if><xsl:value-of select="@name"/><xsl:text>.html</xsl:text>
+                </xsl:attribute>
+                <xsl:value-of select="@name"/>
+            </a>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<!--
+    Creates an html file that contains a link to all package-summary.html files on
+    each package existing on testsuites.
+    @bug there will be a problem here, I don't know yet how to handle unnamed package :(
+-->
+<xsl:template match="testsuites" mode="all.packages">
+    <html>
+        <head>
+            <title>All Groovy TCK Packages</title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <h2><a href="overview-summary.html" target="classFrame">Home</a></h2>
+            <h2>Packages</h2>
+            <table width="100%">
+                <xsl:apply-templates select="testsuite[not(./@package = preceding-sibling::testsuite/@package)]" mode="all.packages">
+                    <xsl:sort select="@package"/>
+                </xsl:apply-templates>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+<xsl:template match="testsuite" mode="all.packages">
+    <tr>
+        <td nowrap="nowrap">
+            <a href="./{translate(@package,'.','/')}/package-summary.html" target="classFrame">
+                <xsl:value-of select="@package"/>
+                <xsl:if test="@package = ''">&lt;none&gt;</xsl:if>
+            </a>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<xsl:template match="testsuites" mode="overview.packages">
+    <html>
+        <head>
+            <title>Groovy TCK Results: Summary</title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+        <xsl:attribute name="onload">open('allclasses-frame.html','classListFrame')</xsl:attribute>
+        <xsl:call-template name="pageHeader"/>
+        <h2>Summary</h2>
+        <xsl:variable name="testCount" select="sum(testsuite/@tests)"/>
+        <xsl:variable name="errorCount" select="sum(testsuite/@errors)"/>
+        <xsl:variable name="failureCount" select="sum(testsuite/@failures)"/>
+        <xsl:variable name="timeCount" select="sum(testsuite/@time)"/>
+        <xsl:variable name="successRate" select="($testCount - $failureCount - $errorCount) div $testCount"/>
+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+        <tr valign="top">
+            <th>Tests</th>
+            <th>Failures</th>
+            <th>Errors</th>
+            <th>Success rate</th>
+            <th>Time</th>
+        </tr>
+        <tr valign="top">
+            <xsl:attribute name="class">
+                <xsl:choose>
+                    <xsl:when test="$errorCount &gt; 0">Error</xsl:when>
+                    <xsl:when test="$failureCount &gt; 0">Failure</xsl:when>
+                    <xsl:otherwise>Pass</xsl:otherwise>
+                </xsl:choose>
+            </xsl:attribute>
+            <td><xsl:value-of select="$testCount"/></td>
+            <td><xsl:value-of select="$failureCount"/></td>
+            <td><xsl:value-of select="$errorCount"/></td>
+            <td>
+                <xsl:call-template name="display-percent">
+                    <xsl:with-param name="value" select="$successRate"/>
+                </xsl:call-template>
+            </td>
+            <td>
+                <xsl:call-template name="display-time">
+                    <xsl:with-param name="value" select="$timeCount"/>
+                </xsl:call-template>
+            </td>
+
+        </tr>
+        </table>
+        <table border="0" width="95%">
+        <tr>
+        <td style="text-align: justify;">
+        Note: <em>failures</em> are anticipated and checked for with assertions while <em>errors</em> are unanticipated.
+        </td>
+        </tr>
+        </table>
+
+        <h2>Packages</h2>
+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+            <xsl:call-template name="testsuite.test.header"/>
+            <xsl:for-each select="testsuite[not(./@package = preceding-sibling::testsuite/@package)]">
+                <xsl:sort select="@package" order="ascending"/>
+                <!-- get the node set containing all testsuites that have the same package -->
+                <xsl:variable name="insamepackage" select="/testsuites/testsuite[./@package = current()/@package]"/>
+                <tr valign="top">
+                    <!-- display a failure if there is any failure/error in the package -->
+                    <xsl:attribute name="class">
+                        <xsl:choose>
+                            <xsl:when test="sum($insamepackage/@errors) &gt; 0">Error</xsl:when>
+                            <xsl:when test="sum($insamepackage/@failures) &gt; 0">Failure</xsl:when>
+                            <xsl:otherwise>Pass</xsl:otherwise>
+                        </xsl:choose>
+                    </xsl:attribute>
+                    <td><a href="./{translate(@package,'.','/')}/package-summary.html">
+                        <xsl:value-of select="@package"/>
+                        <xsl:if test="@package = ''">&lt;none&gt;</xsl:if>
+                    </a></td>
+                    <td><xsl:value-of select="sum($insamepackage/@tests)"/></td>
+                    <td><xsl:value-of select="sum($insamepackage/@errors)"/></td>
+                    <td><xsl:value-of select="sum($insamepackage/@failures)"/></td>
+                    <td>
+                    <xsl:call-template name="display-time">
+                        <xsl:with-param name="value" select="sum($insamepackage/@time)"/>
+                    </xsl:call-template>
+                    </td>
+                </tr>
+            </xsl:for-each>
+        </table>
+        </body>
+        </html>
+</xsl:template>
+
+
+<xsl:template name="package.summary">
+    <xsl:param name="name"/>
+    <html>
+        <head>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <xsl:attribute name="onload">open('package-frame.html','classListFrame')</xsl:attribute>
+            <xsl:call-template name="pageHeader"/>
+            <h3>Package <xsl:value-of select="$name"/></h3>
+
+            <!--table border="0" cellpadding="5" cellspacing="2" width="95%">
+                <xsl:call-template name="class.metrics.header"/>
+                <xsl:apply-templates select="." mode="print.metrics"/>
+            </table-->
+
+            <xsl:variable name="insamepackage" select="/testsuites/testsuite[./@package = $name]"/>
+            <xsl:if test="count($insamepackage) &gt; 0">
+                <h2>Classes</h2>
+                <p>
+                <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+                    <xsl:call-template name="testsuite.test.header"/>
+                    <xsl:apply-templates select="$insamepackage" mode="print.test">
+                        <xsl:sort select="@name"/>
+                    </xsl:apply-templates>
+                </table>
+                </p>
+            </xsl:if>
+        </body>
+    </html>
+</xsl:template>
+
+
+<!--
+    transform string like a.b.c to ../../../
+    @param path the path to transform into a descending directory path
+-->
+<xsl:template name="path">
+    <xsl:param name="path"/>
+    <xsl:if test="contains($path,'.')">
+        <xsl:text>../</xsl:text>
+        <xsl:call-template name="path">
+            <xsl:with-param name="path"><xsl:value-of select="substring-after($path,'.')"/></xsl:with-param>
+        </xsl:call-template>
+    </xsl:if>
+    <xsl:if test="not(contains($path,'.')) and not($path = '')">
+        <xsl:text>../</xsl:text>
+    </xsl:if>
+</xsl:template>
+
+
+<!-- create the link to the stylesheet based on the package name -->
+<xsl:template name="create.stylesheet.link">
+    <xsl:param name="package.name"/>
+    <link rel="stylesheet" type="text/css" title="Style"><xsl:attribute name="href"><xsl:if test="not($package.name = 'unnamed package')"><xsl:call-template name="path"><xsl:with-param name="path" select="$package.name"/></xsl:call-template></xsl:if>stylesheet.css</xsl:attribute></link>
+</xsl:template>
+
+
+<!-- Page HEADER -->
+<xsl:template name="pageHeader">
+    <img src="http://groovy.codehaus.org/images/groovy-logo.png" alt="Groovy"/>
+    <h1>TCK Results</h1>
+    <table width="100%">
+    <tr>
+        <td align="left"></td>
+        <td align="right"><a href="http://groovy.codehaus.org/jsr/spec">Specification</a>.</td>
+    </tr>
+    </table>
+    <hr size="1"/>
+</xsl:template>
+
+<!-- class header -->
+<xsl:template name="testsuite.test.header">
+    <tr valign="top">
+        <th width="80%">Name</th>
+        <th>Tests</th>
+        <th>Errors</th>
+        <th>Failures</th>
+        <th nowrap="nowrap">Time(s)</th>
+    </tr>
+</xsl:template>
+
+<!-- method header -->
+<xsl:template name="testcase.test.header">
+    <tr valign="top">
+        <th>Name</th>
+        <th>Status</th>
+        <th width="80%">Type</th>
+        <th nowrap="nowrap">Time(s)</th>
+    </tr>
+</xsl:template>
+
+
+<!-- class information -->
+<xsl:template match="testsuite" mode="print.test">
+    <tr valign="top">
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="@errors[.&gt; 0]">Error</xsl:when>
+                <xsl:when test="@failures[.&gt; 0]">Failure</xsl:when>
+                <xsl:otherwise>Pass</xsl:otherwise>
+            </xsl:choose>
+        </xsl:attribute>
+        <td><a href="{@name}.html"><xsl:value-of select="@name"/></a></td>
+        <td><xsl:apply-templates select="@tests"/></td>
+        <td><xsl:apply-templates select="@errors"/></td>
+        <td><xsl:apply-templates select="@failures"/></td>
+        <td><xsl:call-template name="display-time">
+                <xsl:with-param name="value" select="@time"/>
+            </xsl:call-template>
+        </td>
+    </tr>
+</xsl:template>
+
+<xsl:template match="testcase" mode="print.test">
+    <tr valign="top">
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="error">Error</xsl:when>
+                <xsl:when test="failure">Failure</xsl:when>
+                <xsl:otherwise>TableRowColor</xsl:otherwise>
+            </xsl:choose>
+        </xsl:attribute>
+        <td><xsl:value-of select="@name"/></td>
+        <xsl:choose>
+            <xsl:when test="failure">
+                <td>Failure</td>
+                <td><xsl:apply-templates select="failure"/></td>
+            </xsl:when>
+            <xsl:when test="error">
+                <td>Error</td>
+                <td><xsl:apply-templates select="error"/></td>
+            </xsl:when>
+            <xsl:otherwise>
+                <td>Success</td>
+                <td></td>
+            </xsl:otherwise>
+        </xsl:choose>
+        <td>
+            <xsl:call-template name="display-time">
+                <xsl:with-param name="value" select="@time"/>
+            </xsl:call-template>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<!-- Note : the below template error and failure are the same style
+            so just call the same style store in the toolkit template -->
+<xsl:template match="failure">
+    <xsl:call-template name="display-failures"/>
+</xsl:template>
+
+<xsl:template match="error">
+    <xsl:call-template name="display-failures"/>
+</xsl:template>
+
+<!-- Style for the error and failure in the testcase template -->
+<xsl:template name="display-failures">
+    <xsl:choose>
+        <xsl:when test="not(@message)">N/A</xsl:when>
+        <xsl:otherwise>
+            <xsl:value-of select="@message"/>
+        </xsl:otherwise>
+    </xsl:choose>
+    <!-- display the stacktrace -->
+    <br/><br/>
+    <code>
+        <xsl:call-template name="br-replace">
+            <xsl:with-param name="word" select="."/>
+        </xsl:call-template>
+    </code>
+    <!-- the latter is better but might be problematic for non-21" monitors... -->
+    <!--pre><xsl:value-of select="."/></pre-->
+</xsl:template>
+
+<xsl:template name="JS-escape">
+    <xsl:param name="string"/>
+    <xsl:param name="tmp1" select="stringutils:replace(string($string),'\','\\')"/>
+    <xsl:param name="tmp2" select="stringutils:replace(string($tmp1),&quot;'&quot;,&quot;\&apos;&quot;)"/>
+    <xsl:value-of select="$tmp2"/>
+</xsl:template>
+
+
+<!--
+    template that will convert a carriage return into a br tag
+    @param word the text from which to convert CR to BR tag
+-->
+<xsl:template name="br-replace">
+    <xsl:param name="word"/>
+    <xsl:param name="br"><br/></xsl:param>
+    <xsl:value-of select='stringutils:replace(string($word),"&#xA;",$br)'/>
+</xsl:template>
+
+<xsl:template name="display-time">
+    <xsl:param name="value"/>
+    <xsl:value-of select="format-number($value,'0.000')"/>
+</xsl:template>
+
+<xsl:template name="display-percent">
+    <xsl:param name="value"/>
+    <xsl:value-of select="format-number($value,'0.00%')"/>
+</xsl:template>
+</xsl:stylesheet>
+
diff --git a/groovy-core/src/tck/test/gls/ch03/s01/Unicode1.groovy b/groovy-core/src/tck/test/gls/ch03/s01/Unicode1.groovy
new file mode 100644
index 0000000..e72d400
--- /dev/null
+++ b/groovy-core/src/tck/test/gls/ch03/s01/Unicode1.groovy
@@ -0,0 +1,43 @@
+package gls.ch03.s01;
+/**
+ * Except for comments, identifiers and the contents of ... string 
+ * literals, all input elements are formed from ASCII characters.
+ *
+ * TODO: Find a better way to test these things
+ * Note that this is a little hard to test since the input file is ASCII.
+ *
+ * @author Alan Green
+ * @author Jeremy Rayner
+ */
+
+class Unicode1 extends GroovyTestCase {
+    //TODO: find some way to assert that Unicode3.0 + is available
+
+    /**
+      * This doc comment checks that Unicode is allowed in javadoc.
+      * e.g. \u05D0\u2136\u05d3\u05d7
+      */
+    public void testComments() {
+        // Unicode is allowed in comments
+        // This is a comment \u0410\u0406\u0414\u0419
+        /* Another comment \u05D0\u2136\u05d3\u05d7 */
+
+        /**/ // Tiny comment
+        /***/ // Also valid
+    }
+
+    public void testStringLiterals() {
+        assert 1 == "\u0040".length()
+        assert "A" == "\u0041"
+    }
+
+    public void testCharNotAvailableAsLiteral() {
+        char a = 'x'
+        char b = "x"
+        def c = "x".charAt(0)
+        assert a == b
+        assert a == c 
+    }
+
+}
+
diff --git a/groovy-core/src/tck/test/gls/ch03/s01/Unicode2.groovy b/groovy-core/src/tck/test/gls/ch03/s01/Unicode2.groovy
new file mode 100644
index 0000000..b10add8
--- /dev/null
+++ b/groovy-core/src/tck/test/gls/ch03/s01/Unicode2.groovy
@@ -0,0 +1,24 @@
+package gls.ch03.s01;
+/**
+ * Except for comments, identifiers and the contents of ... string 
+ * literals, all input elements are formed from ASCII characters.
+ *
+ * TODO: Find a better way to test these things
+ * Note that this is a little hard to test since the input file is ASCII.
+ *
+ * @author Jeremy Rayner
+ */
+
+class Unicode2 extends GroovyTestCase {
+
+//todo - this doesn't seem to work in raw Java5.0 either
+//    public void testUTF16SupplementaryCharacters() {
+//        assert 1 == "\uD840\uDC00".length()
+//    }
+
+    public void testIdentifiers() {
+        def foo\u0044 = 12
+        assert 20 == foo\u0044 + 8
+    }
+}
+
diff --git a/groovy-core/src/tck/test/gls/ch03/s02/LexicalTranslation1.groovy b/groovy-core/src/tck/test/gls/ch03/s02/LexicalTranslation1.groovy
new file mode 100644
index 0000000..fcf424f
--- /dev/null
+++ b/groovy-core/src/tck/test/gls/ch03/s02/LexicalTranslation1.groovy
@@ -0,0 +1,12 @@
+package gls.ch03.s02
+
+/** Checks Lexical Translation steps as defined in $3.2 of GLS
+ * @author Jeremy Rayner
+ */
+class LexicalTranslation1 extends GroovyTestCase {
+    void testTranslationOfUnicodeEscapes() {
+        assert "A" == "\u0041"
+    }
+    //todo: test that we have a stream of tokens (RI is antlr specific...)
+}
+
diff --git a/groovy-core/src/tck/test/gls/ch03/s02/Longest1.groovy b/groovy-core/src/tck/test/gls/ch03/s02/Longest1.groovy
new file mode 100644
index 0000000..e673ed8
--- /dev/null
+++ b/groovy-core/src/tck/test/gls/ch03/s02/Longest1.groovy
@@ -0,0 +1,28 @@
+package gls.ch03.s02
+
+/**
+ * GLS 3.2: The longest possible translation is used at each step, even if the 
+ * result does not ultimately make a correct program while another lexical 
+ * translation would.
+ * 
+ * This is fundamental to the way the lexer works. If there is a problem with
+ * it, other tests (e.g. to test functionality of operators or identifier
+ * names) would expose it quickly. Nevertheless, we test some combinations
+ * here for consistency.
+ *
+ * @author Alan Green
+ */
+class Longest1 extends GroovyTestCase {
+
+    // Increment and decrement operators
+    void testPrefixIncDec() {
+        def a = 20
+        def b = 10
+        def c = a - b
+        //c = a -- b // @fail:parse 
+        //c = a ++ b // @fail:parse
+        //c = a +- b // @pass
+        //c = a -+ b // @pass
+    }
+}
+
diff --git a/groovy-core/src/tck/test/gls/ch03/s03/UnicodeEscapes1.groovy b/groovy-core/src/tck/test/gls/ch03/s03/UnicodeEscapes1.groovy
new file mode 100644
index 0000000..653f595
--- /dev/null
+++ b/groovy-core/src/tck/test/gls/ch03/s03/UnicodeEscapes1.groovy
@@ -0,0 +1,49 @@
+package gls.ch03.s03
+/**
+ * GLS 3.3:
+ * Implementations first recognize Unicode escapes in their input, translating 
+ * the ASCII characters backslash and 'u' followed by four hexadecimal digits
+ * to the Unicode character with the indicated hexadecimal value, and passing
+ * all other characters unchanged.  
+ *
+ * @author Alan Green
+ * @author Jeremy Rayner
+ */
+
+class UnicodeEscapes1 extends GroovyTestCase {
+
+    void testAllHexDigits() {
+        // All hex digits work (char def0 is a special codepoint)
+        def s = "\u1234\u5678\u9abc\u0fed\u9ABC\u0FEC"
+        assert s.charAt(0) == 0x1234
+        assert s.charAt(1) == 0x5678
+        assert s.charAt(2) == 0x9abc
+        assert s.charAt(3) == 0x0fed
+        assert s.charAt(4) == 0x9abc
+        assert s.charAt(5) == 0x0fec
+    }
+
+    // There can be 1 or more u's after the backslash
+    void testMultipleUs() {
+        assert "\uu0061" == "a"
+        assert "\uuu0061" == "a"
+        assert "\uuuuu0061" == "a"
+    }
+
+    void testOtherVariations() {
+        // Capital 'U' not allowed
+        // assert "\U0061" == "a" // @fail:parse 
+    }
+
+    // todo: Implementations should use the \ uxxxx notation as an output format to
+    // display Unicode characters when a suitable font is not available.
+    // (to be tested as part of the standard library)
+
+    // todo: Representing supplementary characters requires two consecutive Unicode
+    // escapes. 
+    // (not sure how to test)
+    // see: gls.ch03.s01.Unicode2.testUTF16SupplementaryCharacters()
+
+    // todo: test unicode escapes last in file
+    // and invalid escapes at end of file
+}
diff --git a/groovy-core/src/tck/test/gls/ch03/s03/UnicodeEscapes2.groovy b/groovy-core/src/tck/test/gls/ch03/s03/UnicodeEscapes2.groovy
new file mode 100644
index 0000000..83f2bfa
--- /dev/null
+++ b/groovy-core/src/tck/test/gls/ch03/s03/UnicodeEscapes2.groovy
@@ -0,0 +1,51 @@
+package gls.ch03.s03
+/**
+ * GLS 3.3:
+ * Implementations first recognize Unicode escapes in their input, translating 
+ * the ASCII characters backslash and 'u' followed by four hexadecimal digits
+ * to the Unicode character with the indicated hexadecimal value, and passing
+ * all other characters unchanged.  
+ *
+ * @author Alan Green
+ */
+
+class UnicodeEscapes2 extends GroovyTestCase {
+
+    // GLS: If an even number of backslashes precede the 'u', it is not 
+    // an escape
+    void testCountBackslash() {
+        def a = 1
+        assert \u0061 == 1 // char 61 is 'a'
+        
+        // Not intepreted as an escape
+        // \\u0061 == 1 // @fail:parse
+
+        assert "\u0061".length() == 1
+        // Double backslash interpreted as a single backslash in string
+        assert "\\u0061".length() == 6
+        assert "\\\u0061".length() == 2
+        
+    }
+
+    // GLS: If an eligible \ is followed by u, or more than one u, and the last u
+    // is not followed by four hexadecimal digits, then a compile-time error
+    // occurs.
+    void testFourHexDigits() {
+        // these next lines won't work. The backslash has been replace by a 
+        // forwards slash so that the file parses. (Comments don't comment out
+        // unicode escapes.)
+        // assert "/u7" == "\07" //@fail:parse 
+        // def /u61 = 2 //@fail:parse 
+        // def /u061 = 2 //@fail:parse 
+
+        // If five digits, only the first four count
+        def \u00610 = 2 
+        assert a0 == 2
+    }
+    void testInvalidHexDigits() {
+        // invalid hex digits
+        // assert "\ufffg" == "a" // @fail:parse
+        // assert "\uu006g" == "a" // @fail:parse
+        // assert "\uab cd" == "acd" // @fail:parse
+    }
+}
diff --git a/groovy-core/src/test/AllCodehausJavaTestsSuite.java b/groovy-core/src/test/AllCodehausJavaTestsSuite.java
new file mode 100644
index 0000000..b5edd25
--- /dev/null
+++ b/groovy-core/src/test/AllCodehausJavaTestsSuite.java
@@ -0,0 +1,70 @@
+import org.codehaus.groovy.syntax.TokenTest;
+import org.codehaus.groovy.runtime.*;
+//import org.codehaus.groovy.wiki.RunWikiTest;
+//import org.codehaus.groovy.wiki.TestCaseRenderEngineTest;
+import org.codehaus.groovy.tools.FileSystemCompilerTest;
+import org.codehaus.groovy.tools.CompilerTest;
+import org.codehaus.groovy.control.CompilationUnitTest;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessageTest;
+import org.codehaus.groovy.antlr.*;
+import org.codehaus.groovy.antlr.treewalker.*;
+import org.codehaus.groovy.bsf.*;
+import org.codehaus.groovy.ast.*;
+import org.codehaus.groovy.classgen.*;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * All Java Unit tests in the 'org.codehaus.groovy' dir
+ */
+
+public class AllCodehausJavaTestsSuite {
+
+    public static Test suite() {
+        TestSuite suite = new TestSuite();
+        suite.addTestSuite(BSFTest.class);
+        suite.addTestSuite(BytecodeHelperTest.class);
+        suite.addTestSuite(CacheBSFTest.class);
+        suite.addTestSuite(CapitalizeTest.class);
+        suite.addTestSuite(ClassCompletionVerifierTest.class);
+        suite.addTestSuite(ClassNodeTest.class);
+        suite.addTestSuite(CompilationUnitTest.class);
+        suite.addTestSuite(CompilerTest.class);
+        suite.addTestSuite(ConstructorTest.class);
+        suite.addTestSuite(DefaultGroovyMethodsTest.class);
+        suite.addTestSuite(FileSystemCompilerTest.class);
+        suite.addTestSuite(ForTest.class);
+        suite.addTestSuite(GetPropertyTest.class);
+        suite.addTestSuite(GroovyClassLoaderTest.class);
+        suite.addTestSuite(GroovySourceASTTest.class);
+        suite.addTestSuite(GStringTest.class);
+        suite.addTestSuite(IfElseTest.class);
+        suite.addTestSuite(InvokerTest.class);
+        suite.addTestSuite(InvokeMethodTest.class);
+        suite.addTestSuite(InvokeGroovyMethodTest.class);
+        suite.addTestSuite(InvokeConstructorTest.class);
+        suite.addTestSuite(InheritedInterfaceMethodTest.class);
+        suite.addTestSuite(MainTest.class);
+        suite.addTestSuite(MethodFailureTest.class);
+        suite.addTestSuite(MethodKeyTest.class);
+        suite.addTestSuite(MethodTest.class);
+        suite.addTestSuite(ModuleNodeTest.class);
+        suite.addTestSuite(NewStaticMetaMethodTest.class);
+        suite.addTestSuite(org.codehaus.groovy.classgen.PropertyTest.class);
+        suite.addTestSuite(org.codehaus.groovy.runtime.PropertyTest.class);
+        suite.addTestSuite(ReflectorGeneratorTest.class);
+        suite.addTestSuite(RunBugsTest.class);
+        suite.addTestSuite(RunClosureTest.class);
+        suite.addTestSuite(RunGroovyTest.class);
+//        suite.addTestSuite(RunWikiTest.class);
+        suite.addTestSuite(SourceBufferTest.class);
+        suite.addTestSuite(SourcePrinterTest.class);
+        suite.addTestSuite(SyntaxErrorMessageTest.class);
+//        suite.addTestSuite(TestCaseRenderEngineTest.class);
+        suite.addTestSuite(TokenTest.class);
+        suite.addTestSuite(org.codehaus.groovy.classgen.TupleListTest.class);
+        suite.addTestSuite(org.codehaus.groovy.runtime.TupleListTest.class);
+        suite.addTestSuite(VerifierCodeVisitorTest.class);
+        return suite;
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/AllGlsJavaTestsSuite.java b/groovy-core/src/test/AllGlsJavaTestsSuite.java
new file mode 100644
index 0000000..57ebcbb
--- /dev/null
+++ b/groovy-core/src/test/AllGlsJavaTestsSuite.java
@@ -0,0 +1,16 @@
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import gls.ch06.s05.JName1Test;
+
+/**
+ * All Java Unit tests in the 'gls' dir
+ */
+
+public class AllGlsJavaTestsSuite {
+
+    public static Test suite() {
+        TestSuite suite = new TestSuite();
+        suite.addTestSuite(JName1Test.class);
+        return suite;
+    }
+}
diff --git a/groovy-core/src/test/AllGroovyJavaTestsSuite.java b/groovy-core/src/test/AllGroovyJavaTestsSuite.java
new file mode 100644
index 0000000..2017fd5
--- /dev/null
+++ b/groovy-core/src/test/AllGroovyJavaTestsSuite.java
@@ -0,0 +1,48 @@
+import groovy.inspect.InspectorTest;
+import groovy.lang.*;
+import groovy.security.SecurityTest;
+import groovy.security.SignedJarTest;
+import groovy.servlet.GroovyServletTest;
+import groovy.text.TemplateTest;
+import groovy.text.XmlTemplateEngineTest;
+import groovy.tree.NodePrinterTest;
+import groovy.util.EvalTest;
+import groovy.util.MBeanTest;
+import groovy.xml.XmlTest;
+import groovy.xml.FactorySupportTest;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * All Java Unit tests in the 'groovy' dir
+ */
+
+public class AllGroovyJavaTestsSuite {
+
+    public static Test suite() {
+        TestSuite suite = new TestSuite();
+        suite.addTestSuite(InspectorTest.class);
+        suite.addTestSuite(GroovyShellTest.class);
+        suite.addTestSuite(GStringTest.class);
+        suite.addTestSuite(IntRangeTest.class);
+        suite.addTestSuite(MetaClassTest.class);
+        suite.addTestSuite(RangeTest.class);
+        suite.addTestSuite(ScriptIntegerDivideTest.class);
+        suite.addTestSuite(ScriptPrintTest.class);
+        suite.addTestSuite(ScriptTest.class);
+        suite.addTestSuite(SequenceTest.class);
+        suite.addTestSuite(TupleTest.class);
+        suite.addTestSuite(SecurityTest.class);
+        suite.addTestSuite(SignedJarTest.class);
+        suite.addTestSuite(GroovyServletTest.class);
+        suite.addTestSuite(TemplateTest.class);
+        suite.addTestSuite(XmlTemplateEngineTest.class);
+        suite.addTestSuite(NodePrinterTest.class);
+        suite.addTestSuite(EvalTest.class);
+        suite.addTestSuite(MBeanTest.class);
+        suite.addTestSuite(XmlTest.class);
+        suite.addTestSuite(FactorySupportTest.class);
+
+        return suite;
+    }
+}
diff --git a/groovy-core/src/test/UberTestCase.java b/groovy-core/src/test/UberTestCase.java
new file mode 100644
index 0000000..eb89324
--- /dev/null
+++ b/groovy-core/src/test/UberTestCase.java
@@ -0,0 +1,70 @@
+/**
+ * Collects all TestCases in the Groovy test root that are written in Groovy.
+ *
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @author Dierk Koenig (refactored to use AllTestSuite)
+ * @version $Revision$
+ */
+import junit.framework.*;
+import groovy.util.AllTestSuite;
+
+public class UberTestCase extends TestCase {
+    public static Test suite() {
+        TestSuite suite = (TestSuite) AllTestSuite.suite("src/test/groovy", "*Test.groovy");
+
+        String osName = System.getProperty ( "os.name" ) ;
+        if ( osName.equals ( "Linux" ) || osName.equals ( "SunOS" ) ) {
+          suite.addTestSuite ( ExecuteTest_LinuxSolaris.class ) ;
+        }
+        else {
+          System.err.println ( "XXXXXX  No execute testsfor this OS.  XXXXXX" ) ;
+        }
+
+        return suite;
+    }
+
+//  The following classes appear in target/test-classes but do not extend junit.framework.TestCase
+//
+//        AnotherMockInputStream.class
+//        Bean.class
+//        Bean249.class
+//        BooleanBean.class
+//        CallAnotherScript.class
+//        ClassWithScript.class
+//        ComparableFoo.class
+//        CreateData.class
+//        Entry.class
+//        EvalInScript.class
+//        Feed.class
+//        Foo.class
+//        HelloWorld.class
+//        HelloWorld2.class
+//        Html2Wiki.class
+//        IntegerCategory.class
+//        Loop.class
+//        Loop2.class
+//        MapFromList.class
+//        MarkupTestScript.class
+//        MethodTestScript.class
+//        MockInputStream.class
+//        MockProcess.class
+//        MockSocket.class
+//        OverloadA.class
+//        OverloadB.class
+//        NavToWiki.class
+//        Person.class
+//        SampleMain.class
+//        ScriptWithFunctions.class
+//        ShowArgs.class
+//        StringCategory.class
+//        SuperBase.class
+//        SuperDerived.class
+//        TestBase.class
+//        TestCaseBug.class
+//        TestDerived.class
+//        TinyAgent.class
+//        UnitTestAsScript.class
+//        UseClosureInScript.class
+//        X.class
+//        createLoop.class
+}
diff --git a/groovy-core/src/test/UberTestCase2.java b/groovy-core/src/test/UberTestCase2.java
new file mode 100644
index 0000000..ab7fd87
--- /dev/null
+++ b/groovy-core/src/test/UberTestCase2.java
@@ -0,0 +1,57 @@
+/**
+ * Collects all Bug-related tests.
+ *
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+import junit.framework.*;
+import groovy.util.AllTestSuite;
+
+public class UberTestCase2 extends TestCase {
+    public static Test suite() {
+        return AllTestSuite.suite("./src/test/groovy","**/*Bug.groovy");
+    }
+
+// no tests inside (should we have an AbstractGroovyTestCase???)
+//        groovy.bugs.TestSupport.class
+//        groovy.sql.TestHelper.class
+//        groovy.swing.Demo.class
+
+//  The following classes appear in target/test-classes but do not extend junit.framework.TestCase
+//
+//        cheese.Cheddar.class
+//        cheese.Provolone.class
+//        groovy.bugs.Cheese.class
+//        groovy.bugs.MyRange.class
+//        groovy.bugs.Scholastic.class
+//        groovy.bugs.SimpleModel.class
+//        groovy.DummyInterface.class
+//        groovy.DummyMethods.class
+//        groovy.gravy.Build.class
+//        groovy.j2ee.J2eeConsole.class
+//        groovy.lang.DerivedScript.class
+//        groovy.lang.DummyGString.class
+//        groovy.lang.MockWriter.class
+//        groovy.mock.example.CheeseSlicer.class
+//        groovy.mock.example.SandwichMaker.class
+//        groovy.model.MvcDemo.class
+//        groovy.OuterUser.class
+//        groovy.script.AtomTestScript.class
+//        groovy.script.Entry.class
+//        groovy.script.Feed.class
+//        groovy.script.PackageScript.class
+//        groovy.script.Person.class
+//        groovy.sql.Person.class
+//        groovy.swing.MyTableModel.class
+//        groovy.swing.SwingDemo.class
+//        groovy.swing.TableDemo.class
+//        groovy.swing.TableLayoutDemo.class
+//        groovy.txn.TransactionBean.class
+//        groovy.txn.TransactionBuilder.class
+//        groovy.util.Dummy.class
+//        groovy.util.DummyMBean.class
+//        groovy.util.SpoofTask.class
+//        groovy.util.SpoofTaskContainer.class
+//        groovy.xml.TestXmlSupport.class);
+
+}
diff --git a/groovy-core/src/test/UberTestCase3.java b/groovy-core/src/test/UberTestCase3.java
new file mode 100644
index 0000000..cd336b5
--- /dev/null
+++ b/groovy-core/src/test/UberTestCase3.java
@@ -0,0 +1,40 @@
+/**
+ * Collecting all Groovy unit tests that are written in Groovy, not in root, and not Bug-related.
+ *
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @author Dierk Koenig
+ * @version $Revision$
+ */
+import junit.framework.Test;
+import junit.framework.TestCase;
+import groovy.util.AllTestSuite;
+
+public class UberTestCase3 extends TestCase {
+    public static Test suite() {
+        return AllTestSuite.suite("src/test/groovy", "*/**/*Test.groovy");
+    }
+
+// no tests inside (should we have an AbstractGroovyTestCase???)
+//
+//        suite.addTestSuite(org.codehaus.groovy.classgen.DummyTestDerivation.class);
+//        suite.addTestSuite(org.codehaus.groovy.classgen.TestSupport.class);
+
+//  The following classes appear in target/test-classes but do not extend junit.framework.TestCase
+//
+//        suite.addTestSuite(org.codehaus.groovy.classgen.DerivedBean.class);
+//        suite.addTestSuite(org.codehaus.groovy.classgen.DummyReflector.class);
+//        suite.addTestSuite(org.codehaus.groovy.classgen.DumpClass.class);
+//        suite.addTestSuite(org.codehaus.groovy.classgen.DumpClass2.class);
+//        suite.addTestSuite(org.codehaus.groovy.classgen.DumpClass3.class);
+//        suite.addTestSuite(org.codehaus.groovy.classgen.DumpClass4.class);
+//        suite.addTestSuite(org.codehaus.groovy.classgen.DumpingClassLoader.class);
+//        suite.addTestSuite(org.codehaus.groovy.classgen.Main.class);
+//        suite.addTestSuite(org.codehaus.groovy.classgen.MyBean.class);
+//        suite.addTestSuite(org.codehaus.groovy.classgen.SimpleBean.class);
+//        suite.addTestSuite(org.codehaus.groovy.dummy.FooHandler.class);
+//        suite.addTestSuite(org.codehaus.groovy.runtime.DummyBean.class);
+//        suite.addTestSuite(org.codehaus.groovy.runtime.MockGroovyObject.class);
+//        suite.addTestSuite(org.codehaus.groovy.syntax.parser.TestParserSupport.class);
+//        suite.addTestSuite(org.codehaus.groovy.tools.DocGeneratorMain.class);
+
+}
diff --git a/groovy-core/src/test/UberTestCase4.java b/groovy-core/src/test/UberTestCase4.java
new file mode 100644
index 0000000..5b3cd55
--- /dev/null
+++ b/groovy-core/src/test/UberTestCase4.java
@@ -0,0 +1,16 @@
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+/**
+ * Collecting all Groovy Unit Tests, written in Java.
+ * @author Christian Stein
+ * @author Dierk Koenig
+ */
+public class UberTestCase4 extends TestCase {
+
+    public static Test suite() {
+        return AllGroovyJavaTestsSuite.suite();
+    }
+
+
+}
diff --git a/groovy-core/src/test/UberTestCaseLongRunningTests.java b/groovy-core/src/test/UberTestCaseLongRunningTests.java
new file mode 100644
index 0000000..7cc4587
--- /dev/null
+++ b/groovy-core/src/test/UberTestCaseLongRunningTests.java
@@ -0,0 +1,17 @@
+/**
+ * The tests collected here all take a 'significant' length of time to execute,
+ * i.e. greater than 2 seconds elapsed on my machine.
+ *
+ * to prevent a JVM startup-shutdown time per test, it should be more efficient to
+ * collect the tests together into a suite.
+ *
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+import junit.framework.*;
+public class UberTestCaseLongRunningTests extends TestCase {
+    public static Test suite() {
+        return AllCodehausJavaTestsSuite.suite();
+    }
+
+}
diff --git a/groovy-core/src/test/UberTestCaseTCK.java b/groovy-core/src/test/UberTestCaseTCK.java
new file mode 100644
index 0000000..a9e231f
--- /dev/null
+++ b/groovy-core/src/test/UberTestCaseTCK.java
@@ -0,0 +1,20 @@
+/**
+ * All TCK testcases written in Groovy or Java.
+ *
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @author Dierk Koenig
+ * @version $Revision$
+ */
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import groovy.util.AllTestSuite;
+
+public class UberTestCaseTCK extends TestCase {
+    public static Test suite() {
+        TestSuite suite = (TestSuite) AllTestSuite.suite("src/test/gls","**/*Test.groovy");
+        suite.addTest(AllGlsJavaTestsSuite.suite());
+        return suite;
+    }
+}
+
diff --git a/groovy-core/src/test/gls/CompilableTestSupport.groovy b/groovy-core/src/test/gls/CompilableTestSupport.groovy
new file mode 100644
index 0000000..13a1c7a
--- /dev/null
+++ b/groovy-core/src/test/gls/CompilableTestSupport.groovy
@@ -0,0 +1,23 @@
+package gls

+

+import org.codehaus.groovy.control.CompilationFailedException;

+import groovy.util.GroovyTestCase;

+

+public class CompilableTestSupport extends GroovyTestCase {

+	protected void shouldNotCompile(String script) {

+	  try {

+        GroovyShell shell = new GroovyShell()

+        shell.parse(script, getTestClassName())

+      } catch (CompilationFailedException cfe) {

+        assert true

+        return

+      }

+      fail("the compilation succeeded but should have failed")

+	}

+	

+	protected void shouldCompile(String script) {

+      GroovyShell shell = new GroovyShell()

+      shell.parse(script, getTestClassName())

+      assert true

+	}

+}
\ No newline at end of file
diff --git a/groovy-core/src/test/gls/ch06/s05/GName1Test.groovy b/groovy-core/src/test/gls/ch06/s05/GName1Test.groovy
new file mode 100644
index 0000000..a3236f1
--- /dev/null
+++ b/groovy-core/src/test/gls/ch06/s05/GName1Test.groovy
@@ -0,0 +1,145 @@
+package gls.ch06.s05;
+
+import gls.ch06.s05.testClasses.Tt1cgi;
+import gls.ch06.s05.testClasses.Tt1cgo;
+import gls.ch06.s05.testClasses.Tt1gi;
+import gls.ch06.s05.testClasses.Tt1go;
+import gls.ch06.s05.testClasses.Tt1;
+import gls.ch06.s05.testClasses.Tt1c;
+
+class GName1Test extends GroovyTestCase {
+  void testObjectSupportNameHandling() {
+    Tt1  obj = new Tt1()  // Test POJO
+    def newX = "new x"
+    def newX1 = "new x1"
+    def newX2 = "new x2"
+    
+    assert obj.x == "property"
+    assert obj.@x == "field"
+    assert obj.x() == "method"
+    
+    obj.x = newX
+    obj.@x = newX1
+    
+    assert obj.x == newX
+    assert obj.@x == newX1
+    
+    obj.setX newX2
+    
+    assert obj.x == newX2
+    assert obj.@x == newX1
+  }
+  
+  void testObjectSupportNameHandling1() {
+    Tt1go  obj = new Tt1go()  // Test class subclassing GroovyObjectSupport
+    def newX = "new x"
+    def newX1 = "new x1"
+    def newX2 = "new x2"
+    
+    assert obj.x == "property"
+    assert obj.@x == "field"
+    assert obj.x() == "method"
+    
+    obj.x = newX
+    obj.@x = newX1
+    
+    assert obj.x == newX
+    assert obj.@x == newX1
+    
+    obj.setX newX2
+    
+    assert obj.x == newX2
+    assert obj.@x == newX1
+  }
+  
+  void testObjectSupportNameHandling2() {
+    Tt1  obj = new Tt1gi()  // Test POJO implementing GroovyObject
+    def newX = "new x"
+    def newX1 = "new x1"
+    def newX2 = "new x2"
+    
+    assert obj.x == "dynamic property"
+    assert obj.@x == "field"
+    assert obj.x() == "dynamic method"
+    
+    obj.x = newX
+    obj.@x = newX1
+    
+    assert obj.x == "dynamic property"
+    assert obj.@x == newX1
+    
+    obj.setX newX2
+    
+    assert obj.x == "dynamic property"
+    assert obj.@x == newX1
+  }
+  
+  void testObjectSupportNameHandlingWitnClosureValues() {
+    Tt1c obj = new Tt1c()  // Test POJO
+    def newX = {"new x"}
+    def newX1 = {"new x1"}
+    def newX2 = {"new x2"}
+    
+    assert (obj.x)() == "property"
+    assert obj.@x() == "field"
+    assert obj.x() == "method"
+    
+      
+    obj.x = newX
+    obj.@x = newX1
+    
+    assert (obj.x)() == newX()
+    assert obj.@x() == newX1()
+    
+    obj.setX newX2
+    
+    assert (obj.x)() == newX2()
+    assert obj.@x() == newX1()
+  }
+  
+  void testObjectSupportNameHandlingWitnClosureValues1() {
+    Tt1cgo obj = new Tt1cgo()  // class subclassing GroovyObjectSupport
+    def newX = {"new x"}
+    def newX1 = {"new x1"}
+    def newX2 = {"new x2"}
+    
+    assert (obj.x)() == "property"
+    assert obj.@x() == "field"
+    assert obj.x() == "method"
+    
+      
+    obj.x = newX
+    obj.@x = newX1
+    
+    assert (obj.x)() == newX()
+    assert (obj.@x)() == newX1()
+    
+    obj.setX newX2
+    
+    assert (obj.x)() == newX2()
+    assert (obj.@x)() == newX1()
+  }
+  
+  void testObjectSupportNameHandlingWitnClosureValues2() {
+    Tt1c obj = new Tt1cgi()  // Test POJO implementing GroovyObject
+    def newX = {"new x"}
+    def newX1 = {"new x1"}
+    def newX2 = {"new x2"}
+    
+    assert (obj.x)() == "property"
+    assert (obj.@x)() == "field"  // can't write obj.@x() - syntax error
+    assert obj.x() == "method"
+    
+      
+    obj.x = newX
+    obj.@x = newX1
+    
+    assert (obj.x)() == newX()
+    assert (obj.@x)() == newX1()
+    
+    obj.setX newX2
+    
+    assert (obj.x)() == newX2()
+    assert (obj.@x)() == newX1()
+  }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/gls/ch06/s05/JName1Test.java b/groovy-core/src/test/gls/ch06/s05/JName1Test.java
new file mode 100644
index 0000000..0358602
--- /dev/null
+++ b/groovy-core/src/test/gls/ch06/s05/JName1Test.java
@@ -0,0 +1,289 @@
+package gls.ch06.s05;
+
+
+import groovy.lang.Closure;
+import junit.framework.TestCase;
+
+import gls.ch06.s05.testClasses.Tt1cgi;
+import gls.ch06.s05.testClasses.Tt1cgo;
+import gls.ch06.s05.testClasses.Tt1gi;
+import gls.ch06.s05.testClasses.Tt1go;
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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.
+ *
+ */
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class JName1Test extends TestCase {
+  public void testObjectSupportNameHandling() {
+    final Tt1go obj = new Tt1go();  // Test subclass of GroovyObjectSupport
+    final String newX = "new x";
+    final String newX1 = "new x1";
+    final String newX2 = "new x2";
+    final String newX3 = "new x3";
+    
+    assertTrue(obj.getProperty("x") == obj.getX());
+    assertTrue(obj.getMetaClass().getAttribute(obj, "x") == obj.x);
+    assertTrue(obj.invokeMethod("x", new Object[]{}) == obj.x());
+    
+    obj.setProperty("x", newX);
+    obj.getMetaClass().setAttribute(obj, "x", newX1);
+    
+    assertTrue(obj.getProperty("x") == newX);
+    assertTrue(obj.getMetaClass().getAttribute(obj, "x") == newX1);
+    
+    obj.setX(newX2);
+    obj.x = newX3;
+    
+    assertTrue(obj.getProperty("x") == newX2);
+    assertTrue(obj.getMetaClass().getAttribute(obj, "x") == newX3);
+  }
+
+  public void testObjectSupportNameHandling1() {
+    final Tt1go obj = new Tt1go() {}; // repeat test with subclass
+    final String newX = "new x";
+    final String newX1 = "new x1";
+    final String newX2 = "new x2";
+    final String newX3 = "new x3";
+    
+    assertTrue(obj.getProperty("x") == obj.getX());
+    assertTrue(obj.getMetaClass().getAttribute(obj, "x") == obj.x);
+    assertTrue(obj.invokeMethod("x", new Object[]{}) == obj.x());
+    
+    obj.setProperty("x", newX);
+    obj.getMetaClass().setAttribute(obj, "x", newX1);
+    
+    assertTrue(obj.getProperty("x") == newX);
+    assertTrue(obj.getMetaClass().getAttribute(obj, "x") == newX1);
+    
+    obj.setX(newX2);
+    obj.x = newX3;
+    
+    assertTrue(obj.getProperty("x") == newX2);
+    assertTrue(obj.getMetaClass().getAttribute(obj, "x") == newX3);
+  }
+  
+  public void testObjectSupportNameHandlingWitnClosureValues() {
+    final Tt1cgo obj = new Tt1cgo();  // Test subclass of GroovyObjectSupport
+    final Closure newX = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x";
+      }
+    };
+    final Closure newX1 = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x1";
+      }
+    };
+    final Closure newX2 = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x2";
+      }
+    };
+    final Closure newX3 = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x3";
+      }
+    };
+    
+    assertTrue(((Closure)obj.getProperty("x")).call() == obj.getX().call());
+    assertTrue(((Closure)obj.getMetaClass().getAttribute(obj, "x")).call() == obj.x.call());
+    assertTrue(obj.invokeMethod("x", new Object[]{}) == obj.x());
+    
+    obj.setProperty("x", newX);
+    obj.getMetaClass().setAttribute(obj, "x", newX1);
+    
+    assertTrue(((Closure)obj.getProperty("x")).call() == newX.call());
+    assertTrue(((Closure)obj.getMetaClass().getAttribute(obj, "x")).call() == newX1.call());
+    
+    obj.setX(newX2);
+    obj.x = newX3;
+    
+    assertTrue(((Closure)obj.getProperty("x")).call() == newX2.call());
+    assertTrue(((Closure)obj.getMetaClass().getAttribute(obj, "x")).call() == newX3.call());
+  }
+  
+  public void testObjectSupportNameHandlingWitnClosureValuesi() {
+    final Tt1cgo obj = new Tt1cgo() {};  // repeat test with subclass
+    final Closure newX = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x";
+      }
+    };
+    final Closure newX1 = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x1";
+      }
+    };
+    final Closure newX2 = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x2";
+      }
+    };
+    final Closure newX3 = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x3";
+      }
+    };
+    
+    assertTrue(((Closure)obj.getProperty("x")).call() == obj.getX().call());
+    assertTrue(((Closure)obj.getMetaClass().getAttribute(obj, "x")).call() == obj.x.call());
+    assertTrue(obj.invokeMethod("x", new Object[]{}) == obj.x());
+    
+    obj.setProperty("x", newX);
+    obj.getMetaClass().setAttribute(obj, "x", newX1);
+    
+    assertTrue(((Closure)obj.getProperty("x")).call() == newX.call());
+    assertTrue(((Closure)obj.getMetaClass().getAttribute(obj, "x")).call() == newX1.call());
+    
+    obj.setX(newX2);
+    obj.x = newX3;
+    
+    assertTrue(((Closure)obj.getProperty("x")).call() == newX2.call());
+    assertTrue(((Closure)obj.getMetaClass().getAttribute(obj, "x")).call() == newX3.call());
+  }
+
+  public void testMetaClassNameHandling() {
+    final Tt1gi obj = new Tt1gi();  // Test class implementing GroovyObject
+    final String newX = "new x";
+    final String newX1 = "new x1";
+    final String newX2 = "new x2";
+    final String newX3 = "new x3";
+    
+    assertTrue("dynamic property".equals(obj.getProperty("x")));
+    assertTrue(obj.getMetaClass().getAttribute(obj, "x") == obj.x);
+    assertTrue("dynamic method".equals(obj.invokeMethod("x", new Object[]{})));
+    
+    obj.setProperty("x", newX);
+    obj.getMetaClass().setAttribute(obj, "x", newX1);
+    
+    assertTrue("dynamic property".equals(obj.getProperty("x")));
+    assertTrue(obj.getMetaClass().getAttribute(obj, "x") == newX1);
+    
+    obj.setX(newX2);
+    obj.x = newX3;
+    
+    assertTrue("dynamic property".equals(obj.getProperty("x")));
+    assertTrue(obj.getMetaClass().getAttribute(obj, "x") == newX3);
+  }
+
+  public void testMetaClassNameHandling1() {
+    final Tt1gi obj = new Tt1gi() {}; // repeat test with subclass
+    final String newX = "new x";
+    final String newX1 = "new x1";
+    final String newX2 = "new x2";
+    final String newX3 = "new x3";
+    
+    assertTrue("dynamic property".equals(obj.getProperty("x")));
+    assertTrue(obj.getMetaClass().getAttribute(obj, "x") == obj.x);
+    assertTrue("dynamic method".equals(obj.invokeMethod("x", new Object[]{})));
+    
+    obj.setProperty("x", newX);
+    obj.getMetaClass().setAttribute(obj, "x", newX1);
+    
+    assertTrue("dynamic property".equals(obj.getProperty("x")));
+    assertTrue(obj.getMetaClass().getAttribute(obj, "x") == newX1);
+    
+    obj.setX(newX2);
+    obj.x = newX3;
+    
+    assertTrue("dynamic property".equals(obj.getProperty("x")));
+    assertTrue(obj.getMetaClass().getAttribute(obj, "x") == newX3);
+  }
+
+  public void testMetaClassNameHandlingWithClosures() {
+    final Tt1cgi obj = new Tt1cgi();  // Test class implementing GroovyObject
+    final Closure newX = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x";
+      }
+    };
+    final Closure newX1 = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x1";
+      }
+    };
+    final Closure newX2 = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x2";
+      }
+    };
+    final Closure newX3 = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x3";
+      }
+    };
+    
+    assertTrue(((Closure)obj.getProperty("x")).call() == obj.getX().call());
+    assertTrue(((Closure)obj.getMetaClass().getAttribute(obj, "x")).call() == obj.x.call());
+    assertTrue(obj.invokeMethod("x", new Object[]{}) == obj.x());
+    
+    obj.setProperty("x", newX);
+    obj.getMetaClass().setAttribute(obj, "x", newX1);
+    
+    assertTrue(((Closure)obj.getProperty("x")).call() == newX.call());
+    assertTrue(((Closure)obj.getMetaClass().getAttribute(obj, "x")).call() == newX1.call());
+    
+    obj.setX(newX2);
+    obj.x = newX3;
+    
+    assertTrue(((Closure)obj.getProperty("x")).call() == newX2.call());
+    assertTrue(((Closure)obj.getMetaClass().getAttribute(obj, "x")).call() == newX3.call());
+  }
+
+  public void testMetaClassNameHandlingWithClosures1() {
+    final Tt1cgi obj = new Tt1cgi() {};  // repeat test with subclass
+    final Closure newX = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x";
+      }
+    };
+    final Closure newX1 = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x1";
+      }
+    };
+    final Closure newX2 = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x2";
+      }
+    };
+    final Closure newX3 = new Closure(null) {
+      public Object doCall(final Object params) {
+        return "new x3";
+      }
+    };
+    
+    assertTrue(((Closure)obj.getProperty("x")).call() == obj.getX().call());
+    assertTrue(((Closure)obj.getMetaClass().getAttribute(obj, "x")).call() == obj.x.call());
+    assertTrue(obj.invokeMethod("x", new Object[]{}) == obj.x());
+    
+    obj.setProperty("x", newX);
+    obj.getMetaClass().setAttribute(obj, "x", newX1);
+    
+    assertTrue(((Closure)obj.getProperty("x")).call() == newX.call());
+    assertTrue(((Closure)obj.getMetaClass().getAttribute(obj, "x")).call() == newX1.call());
+    
+    obj.setX(newX2);
+    obj.x = newX3;
+    
+    assertTrue(((Closure)obj.getProperty("x")).call() == newX2.call());
+    assertTrue(((Closure)obj.getMetaClass().getAttribute(obj, "x")).call() == newX3.call());
+  }
+}
diff --git a/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1.java b/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1.java
new file mode 100644
index 0000000..0ba7695
--- /dev/null
+++ b/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1.java
@@ -0,0 +1,43 @@
+/*
+* Copyright 2005 John G. Wilson
+*
+* Licensed 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 gls.ch06.s05.testClasses;
+
+
+
+/**
+* @author John Wilson
+*
+*/
+
+public class Tt1 {
+  public String x ="field";
+  
+  public String getX() {
+    return this.p1;
+  }
+  
+  public void setX(final String x) {
+    this.p1 = x;
+  }
+  
+  public String x() {
+    return "method";
+  }
+  private String p1 = "property";
+}
+
diff --git a/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1c.java b/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1c.java
new file mode 100644
index 0000000..f85e08b
--- /dev/null
+++ b/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1c.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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 gls.ch06.s05.testClasses;
+
+import groovy.lang.Closure;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class Tt1c {
+  public Closure x = new Closure(null) {
+                          public Object doCall(final Object params) {
+                            return "field";
+                          }
+                        };
+  
+  public Closure getX() {
+    return this.p1;
+  }
+  
+  public void setX(final Closure y) {
+    this.p1 = y;
+  }
+  
+  public String x() {
+    return "method";
+  }
+
+  private Closure p1 = new Closure(null) {
+    public Object doCall(final Object params) {
+      return "property";
+    }
+  };
+}
diff --git a/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1cgi.java b/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1cgi.java
new file mode 100644
index 0000000..de241ce
--- /dev/null
+++ b/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1cgi.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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 gls.ch06.s05.testClasses;
+
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import groovy.lang.GroovyObject;
+import groovy.lang.MetaClass;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class Tt1cgi extends Tt1c implements GroovyObject {
+
+  private MetaClass metaClass = InvokerHelper.getMetaClass(this);
+  
+  public MetaClass getMetaClass() {
+    return this.metaClass;
+  }
+
+  public Object getProperty(final String property) {
+    return this.metaClass.getProperty(this, property);
+  }
+
+  public Object invokeMethod(final String name, final Object args) {
+    return this.metaClass.invokeMethod(this, name, args);
+  }
+
+  public void setMetaClass(final MetaClass metaClass) {
+    this.metaClass = metaClass;
+  }
+
+  public void setProperty(final String property, final Object newValue) {
+    this.metaClass.setProperty(this, property, newValue);
+  }
+}
diff --git a/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1cgo.java b/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1cgo.java
new file mode 100644
index 0000000..e40b53d
--- /dev/null
+++ b/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1cgo.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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 gls.ch06.s05.testClasses;
+
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyObjectSupport;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class Tt1cgo extends GroovyObjectSupport {
+  public Closure x = new Closure(null) {
+    public Object doCall(final Object params) {
+      return "field";
+    }
+  };
+
+  public Closure getX() {
+    return this.p1;
+  }
+
+  public void setX(final Closure x) {
+    this.p1 = x;
+  }
+  
+  public String x() {
+    return "method";
+  }
+  
+  private Closure p1 = new Closure(null) {
+    public Object doCall(final Object params) {
+      return "property";
+    }
+  };
+}
diff --git a/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1gi.java b/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1gi.java
new file mode 100644
index 0000000..4ad9fb8
--- /dev/null
+++ b/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1gi.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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 gls.ch06.s05.testClasses;
+
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import groovy.lang.GroovyInterceptable;
+import groovy.lang.GroovyObject;
+import groovy.lang.MetaClass;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class Tt1gi extends Tt1 implements GroovyObject, GroovyInterceptable {
+
+  private MetaClass metaClass = InvokerHelper.getMetaClass(this);
+  
+  public MetaClass getMetaClass() {
+    return this.metaClass;
+  }
+
+  public Object getProperty(final String property) {
+    if ("x".equals(property)) {
+      return "dynamic property";
+    } else {
+      return this.metaClass.getProperty(this, property);
+    }
+  }
+
+  public Object invokeMethod(final String name, final Object args) {
+    if ("x".equals(name)) {
+      return "dynamic method";
+    } else {
+      return this.metaClass.invokeMethod(this, name, args);
+    }
+  }
+
+  public void setMetaClass(final MetaClass metaClass) {
+    this.metaClass = metaClass;
+  }
+
+  public void setProperty(final String property, final Object newValue) {
+    this.metaClass.setProperty(this, property, newValue);
+  }
+}
diff --git a/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1go.java b/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1go.java
new file mode 100644
index 0000000..99488ce
--- /dev/null
+++ b/groovy-core/src/test/gls/ch06/s05/testClasses/Tt1go.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2005 John G. Wilson
+ *
+ * Licensed 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 gls.ch06.s05.testClasses;
+
+
+import groovy.lang.GroovyObjectSupport;
+
+/**
+ * @author John Wilson
+ *
+ */
+
+public class Tt1go extends GroovyObjectSupport {
+  public String x ="field";
+  
+  public String getX() {
+    return this.p1;
+  }
+  
+  public void setX(final String x) {
+    this.p1 = x;
+  }
+  
+  public String x() {
+    return "method";
+  }
+  
+  public String p1 = "property";
+}
diff --git a/groovy-core/src/test/gls/ch08/s04/FormalParameterTest.groovy b/groovy-core/src/test/gls/ch08/s04/FormalParameterTest.groovy
new file mode 100644
index 0000000..b6f7448
--- /dev/null
+++ b/groovy-core/src/test/gls/ch08/s04/FormalParameterTest.groovy
@@ -0,0 +1,29 @@
+package gls.ch08.s04
+
+import gls.scope.CompilableTestSupport
+
+/**
+* a formal parameter is a parameter to a method, this parameter must work
+* as any local variable. But we generally do boxing on local variables, which
+* is not possible for formal parameters. The type is givven through the
+* method signature.
+*/
+class FormalParameterTest extends CompilableTestSupport{
+    
+  void testPrimitiveParameterAssignment(){
+    // test int and long as they have different lengths on in the bytecode
+    assert intMethod(1i,2i) == 2i
+    assert longMethod(1l,2l) == 2l
+    
+  }
+  
+  int intMethod(int i, int j) {
+    i=j
+    return i
+  }
+  
+  long longMethod(long i, long j) {
+    i=j
+    return i
+  }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/gls/ch08/s04/RepetitiveMethodTest.groovy b/groovy-core/src/test/gls/ch08/s04/RepetitiveMethodTest.groovy
new file mode 100644
index 0000000..22c3f86
--- /dev/null
+++ b/groovy-core/src/test/gls/ch08/s04/RepetitiveMethodTest.groovy
@@ -0,0 +1,16 @@
+package gls.ch08.s04
+
+import gls.scope.CompilableTestSupport
+
+class RepetitiveMethodTest extends CompilableTestSupport{
+
+  void testRepetitiveMethod() {
+    def text ="""
+		class A  {
+			void foo() {}
+			void foo() {}
+		}
+	"""
+	shouldNotCompile(text)
+  }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/gls/scope/BlockScopeVisibilityTest.groovy b/groovy-core/src/test/gls/scope/BlockScopeVisibilityTest.groovy
new file mode 100644
index 0000000..632923d
--- /dev/null
+++ b/groovy-core/src/test/gls/scope/BlockScopeVisibilityTest.groovy
@@ -0,0 +1,14 @@
+package gls.scope
+
+class BlockScopeVisibilityTest extends CompilableTestSupport {
+
+  public void testForLoopVariableNotVisibleOutside() {
+ 	
+  	assertScript("""
+  	  i=1
+  	  for (i in [1,2]) {}
+  	  assert i==1
+  	""")
+  }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/gls/scope/ClassVariableHidingTest.groovy b/groovy-core/src/test/gls/scope/ClassVariableHidingTest.groovy
new file mode 100644
index 0000000..02c5401
--- /dev/null
+++ b/groovy-core/src/test/gls/scope/ClassVariableHidingTest.groovy
@@ -0,0 +1,19 @@
+package gls.scope;
+
+public class ClassVariableHidingTest extends CompilableTestSupport {
+
+   def foo=1;
+   def bar=2;
+   
+   public void testFooHiding() {
+     assert foo==1
+     def foo = 5
+     assert foo == 5
+   }
+   
+   public void testBarHiding() {
+     assert bar==2
+     def bar = 5
+     assert bar == 5
+   }
+ }
\ No newline at end of file
diff --git a/groovy-core/src/test/gls/scope/CompilableTestSupport.groovy b/groovy-core/src/test/gls/scope/CompilableTestSupport.groovy
new file mode 100644
index 0000000..e4c3e47
--- /dev/null
+++ b/groovy-core/src/test/gls/scope/CompilableTestSupport.groovy
@@ -0,0 +1,23 @@
+package gls.scope
+
+import org.codehaus.groovy.control.CompilationFailedException;
+import groovy.util.GroovyTestCase;
+
+public class CompilableTestSupport extends GroovyTestCase {
+	protected void shouldNotCompile(String script) {
+	  try {
+        GroovyShell shell = new GroovyShell()
+        shell.parse(script, getTestClassName())
+      } catch (CompilationFailedException cfe) {
+        assert true
+        return
+      }
+      fail("the compilation succeeded but should have failed")
+	}
+	
+	protected void shouldCompile(String script) {
+      GroovyShell shell = new GroovyShell()
+      shell.parse(script, getTestClassName())
+      assert true
+	}
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/gls/scope/MultipleDefinitionOfSameVariableTest.groovy b/groovy-core/src/test/gls/scope/MultipleDefinitionOfSameVariableTest.groovy
new file mode 100644
index 0000000..93c2030
--- /dev/null
+++ b/groovy-core/src/test/gls/scope/MultipleDefinitionOfSameVariableTest.groovy
@@ -0,0 +1,103 @@
+package gls.scope
+
+import gls.scope.CompilableTestSupport
+
+public class MultipleDefinitionOfSameVariableTest extends CompilableTestSupport {
+
+   public void testInSameBlock() {
+     shouldNotCompile("""
+       def foo = 1
+       def foo = 2
+     """)
+      
+     shouldNotCompile("""
+       class Foo {
+         def foo() {
+           def bar=1
+           def bar=2
+         }
+       }
+     """)
+   }
+   
+   public void testInSubblocks() {
+     shouldNotCompile("""
+       def foo = 1
+       5.times { def foo=2 }
+     """)
+     
+     shouldNotCompile("""
+       def foo = 1
+       label1: { def foo=2 }
+     """)
+     
+     shouldNotCompile("""
+       def foo = 1
+       for (i in []) { def foo=2 }
+     """)
+     
+     shouldNotCompile("""
+       def foo = 1
+       while (true) { def foo=2 }
+     """)     
+   } 
+   
+   public void testInNestedClosure() {
+     shouldNotCompile("""
+       def foo = 1
+       5.times { 6.times {def foo=2 }
+     """)
+     
+     assertScript ("""
+       def foo = 1
+       5.times { 6.times {foo=2 } }
+       assert foo == 2
+     """)
+   }
+   
+   public void testBindingHiding() {
+     assertScript("""
+       foo = 1
+       def foo = 3
+       assert foo==3
+       assert this.foo == 1
+       assert binding.foo == 1
+     """)
+   }
+   
+   public void testBindingAccessInMethod() {
+	   assertScript("""
+	     def methodUsingBinding() {
+	       try {
+	         s = "  bbb  ";
+	       } finally {
+	         s = s.trim();
+	       }
+	       assert s == "bbb"
+	     } 
+	     methodUsingBinding()
+	     assert s == "bbb"
+	   """)
+   }
+   
+   public void testMultipleOfSameName() {
+   		shouldNotCompile("""
+   		  class DoubleField {
+			def zero = 0
+			public zero = 0
+		  }
+		  
+   		""")
+   
+   		shouldNotCompile("""
+   		  class DoubleField {
+			def zero = 0
+			def zero = 0
+		  }
+		  
+   		""")
+
+   }
+   
+   
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/gls/scope/NameResolvingTest.groovy b/groovy-core/src/test/gls/scope/NameResolvingTest.groovy
new file mode 100644
index 0000000..0e7afeb
--- /dev/null
+++ b/groovy-core/src/test/gls/scope/NameResolvingTest.groovy
@@ -0,0 +1,24 @@
+package gls.scope
+
+class NameResolvingTest extends GroovyTestCase {
+  public void testVariableNameEqualsToAClassName() {
+	Object String = ""
+	assert String == ""
+	assert String.class == java.lang.String
+  }
+  
+  public void testVariableNameEqualsCurrentClassName() {
+	Object NameResolvingTest = ""
+	assert NameResolvingTest == ""
+	assert NameResolvingTest.class == java.lang.String.class
+  }  
+  
+  public void testClassNoVariableInStaticMethod(){
+    assertScript """
+      static def foo() {
+   	     Class.forName('java.lang.Integer')
+      }
+      assert foo() == Integer
+    """
+  }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/gls/scope/StaticScopeTest.groovy b/groovy-core/src/test/gls/scope/StaticScopeTest.groovy
new file mode 100644
index 0000000..5328bf0
--- /dev/null
+++ b/groovy-core/src/test/gls/scope/StaticScopeTest.groovy
@@ -0,0 +1,44 @@
+package gls.scope
+
+import gls.scope.CompilableTestSupport
+
+public class StaticScopeTest extends CompilableTestSupport {
+
+   public void testNormalStaticScope() {
+     shouldNotCompile("""
+       static foo() {
+         foo = 1
+       }
+     """)
+      
+     shouldCompile("""
+       static foo() {
+         def foo=1
+       }
+     """)
+     
+     assertScript("""
+       class A {
+         static i
+         static foo() {
+           i=1
+         }
+       }
+       A.foo()
+       assert A.i == 1  
+     """)
+   }
+   
+   public void testClosureInStaticScope() {
+     shouldCompile("""
+       5.times { foo=2 }
+     """)
+     
+     shouldCompile("""
+       5.times { foo=it }
+     """)
+     
+   }
+   
+   
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/gls/syntax/AssertTest.groovy b/groovy-core/src/test/gls/syntax/AssertTest.groovy
new file mode 100644
index 0000000..6e08438
--- /dev/null
+++ b/groovy-core/src/test/gls/syntax/AssertTest.groovy
@@ -0,0 +1,12 @@
+package gls.syntax

+

+public class AssertTest extends gls.CompilableTestSupport {

+  

+  void testAssignment() {

+    // don't allow "=" here, it most certainly must be a "=="

+    shouldNotCompile """

+       def a = 1

+       assert a = 2

+    """

+  }

+}
\ No newline at end of file
diff --git a/groovy-core/src/test/gls/syntax/OldClosureSyntaxRemovalTest.groovy b/groovy-core/src/test/gls/syntax/OldClosureSyntaxRemovalTest.groovy
new file mode 100644
index 0000000..427c218
--- /dev/null
+++ b/groovy-core/src/test/gls/syntax/OldClosureSyntaxRemovalTest.groovy
@@ -0,0 +1,25 @@
+package gls.syntax

+

+public class OldClosureSyntaxRemovalTest extends gls.CompilableTestSupport {

+  def a = 2

+  def b = 3

+  

+  void testOneParameter(){

+    def newClosure = {a -> a}

+    def oldClosure = {a|b}

+    assert newClosure(1)==1

+    assert oldClosure.getMaximumNumberOfParameters() == 1

+    // the old closure would have cimply returned b

+    // after removal this is the logic or

+    assert oldClosure(1)==(a|b)

+  }

+  

+  void testMultipleParameters() {

+    shouldNotCompile """

+       c = {a,b|a+b}

+    """

+    shouldCompile   """

+       c = { a,b -> a+b }

+    """

+  }

+}
\ No newline at end of file
diff --git a/groovy-core/src/test/gls/syntax/OldPropertySyntaxRemovalTest.groovy b/groovy-core/src/test/gls/syntax/OldPropertySyntaxRemovalTest.groovy
new file mode 100644
index 0000000..0bc084e
--- /dev/null
+++ b/groovy-core/src/test/gls/syntax/OldPropertySyntaxRemovalTest.groovy
@@ -0,0 +1,12 @@
+package gls.syntax

+

+public class OldPropertySyntaxRemovalTest extends gls.CompilableTestSupport {

+  

+  void testMultipleParameters() {

+    shouldNotCompile """

+       class C {

+         @Property foo

+       }

+    """

+  }

+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/.cvsignore b/groovy-core/src/test/groovy/.cvsignore
new file mode 100644
index 0000000..e43b0f9
--- /dev/null
+++ b/groovy-core/src/test/groovy/.cvsignore
@@ -0,0 +1 @@
+.DS_Store
diff --git a/groovy-core/src/test/groovy/AbstractClassAndInterfaceTest.groovy b/groovy-core/src/test/groovy/AbstractClassAndInterfaceTest.groovy
new file mode 100644
index 0000000..878cba8
--- /dev/null
+++ b/groovy-core/src/test/groovy/AbstractClassAndInterfaceTest.groovy
@@ -0,0 +1,206 @@
+import org.codehaus.groovy.control.CompilationFailedException
+
+class AbstractClassAndInterfaceTest extends GroovyTestCase {
+
+	def shouldNotCompile(String script) {
+	  try {
+        GroovyShell shell = new GroovyShell()
+        shell.parse(script, getTestClassName())
+      } catch (CompilationFailedException cfe) {
+        assert true
+        return
+      }
+      fail("the compilation succeeded but should have failed")
+	}
+
+	void testInterface() {
+    	def shell = new GroovyShell()
+        def text = """
+        	interface A {
+				void methodOne(Object o)
+				Object methodTwo()
+			}
+			
+			class B implements A {
+				void methodOne(Object o){assert true}
+				Object methodTwo(){
+					assert true
+					methodOne(null)
+					return new Object()
+				}
+			}
+			
+			def b = new B();
+			return b.methodTwo()
+			"""
+		def retVal = shell.evaluate(text)
+		assert retVal.class == Object
+	}
+	
+	void testClassImplementingAnInterfaceButMissesMethod() {
+        shouldNotCompile """
+        	interface A {
+				void methodOne(Object o)
+				Object methodTwo()
+			}
+			
+			class B implements A {
+				void methodOne(Object o){assert true}
+			}
+			
+			def b = new B();
+			return b.methodTwo()
+			"""
+		
+		shouldNotCompile """
+			interface A {
+				Object methodTwo()
+		    }
+        	interface B extends A{
+				void methodOne(Object o)
+			}
+			
+			class C implements A {
+				void methodOne(Object o){assert true}
+			}
+			
+			def b = new C();
+			return b.methodTwo()
+			"""
+	}
+	
+	void testAbstractClass() {
+    	def shell = new GroovyShell()
+        def text = """
+        	abstract class A {
+				abstract void methodOne(Object o)
+				Object methodTwo(){
+					assert true
+					methodOne(null)
+					return new Object()
+				}
+			}
+			
+			class B extends A {
+				void methodOne(Object o){assert true}
+			}
+			
+			def b = new B();
+			return b.methodTwo()
+			"""
+		def retVal = shell.evaluate(text)
+		assert retVal.class == Object
+	}	
+	
+	void testClassExtendingAnAbstractClassButMissesMethod() {
+        shouldNotCompile """
+        	abstract class A {
+				abstract void methodOne(Object o)
+				Object methodTwo(){
+					assert true
+					methodOne(null)
+					return new Object()
+				}
+				abstract void MethodThree()
+			}
+			
+			abstract class B extends A {
+				void methodOne(Object o){assert true}
+			}
+			
+			class C extends B{}
+			
+			def b = new C();
+			return b.methodTwo()
+			"""	
+		
+       shouldNotCompile """
+        	abstract class A {
+				abstract void methodOne(Object o)
+				Object methodTwo(){
+					assert true
+					methodOne(null)
+					return new Object()
+				}
+				abstract void MethodThree()
+			}
+			
+			class B extends A {
+				void methodOne(Object o){assert true}
+			}
+			
+			def b = new B();
+			return b.methodTwo()
+			"""
+	}
+	
+	void testInterfaceAbstractClassCombination() {
+    	def shell = new GroovyShell()
+        def text = """
+			interface A {
+				void methodOne()
+			}
+			
+			abstract class B implements A{
+				abstract void methodTwo()
+			}
+			
+			class C extends B {
+				void methodOne(){assert true}
+				void methodTwo(){
+				  methodOne()
+				}
+			}
+			def c = new C()
+			c.methodTwo()
+			"""
+		shell.evaluate(text)
+		
+		shouldNotCompile """
+			interface A {
+				void methodOne()
+			}
+			
+			abstract class B implements A{
+				abstract void methodTwo()
+			}
+			
+			class C extends B {}
+			def c = new c()
+			c.methodTwo()
+			"""
+	}
+	
+	void testDefaultModifiersForInterfaces() {
+    	def shell = new GroovyShell()
+        def text = """
+            import java.lang.reflect.Modifier
+            
+			interface A {
+				def foo
+			}
+			
+			def fields = A.class.declaredFields
+            assert fields.length==1
+            assert fields[0].name == "foo"
+            assert Modifier.isPublic (fields[0].modifiers)
+            assert Modifier.isStatic (fields[0].modifiers)
+            assert Modifier.isFinal  (fields[0].modifiers)
+			"""
+		shell.evaluate(text)
+	}
+	
+	void testAccessToInterfaceField() {
+    	def shell = new GroovyShell()
+        def text = """
+			interface A {
+				def foo=1
+			}
+            class B implements A {
+              def foo(){foo}
+            }
+            assert new B().foo()==1
+	   """
+	   shell.evaluate(text)
+	}
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/AmbiguousInvocationTest.groovy b/groovy-core/src/test/groovy/AmbiguousInvocationTest.groovy
new file mode 100644
index 0000000..7ce173f
--- /dev/null
+++ b/groovy-core/src/test/groovy/AmbiguousInvocationTest.groovy
@@ -0,0 +1,27 @@
+/**
+ * to prove GROOVY-467 is no longer an issue    
+ * 
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+import groovy.DummyMethods
+
+class AmbiguousInvocationTest extends GroovyTestCase { 
+    def dummy
+    
+    void setUp() {
+    	dummy = new DummyMethods()
+    }
+    
+    void testAmbiguousInvocationWithFloats() {
+   	assert "float args" == dummy.foo("bar",1.0f,2.0f)
+   	assert "float args" == dummy.foo("bar",(float)1,(float)2)
+   	assert "float args" == dummy.foo("bar",(Float)1,(Float)2)
+    }
+    void testAmbiguousInvocationWithInts() {
+   	assert "int args" == dummy.foo("bar",1,2)
+   	assert "int args" == dummy.foo("bar",(int)1,(int)2)
+   	assert "int args" == dummy.foo("bar",(Integer)1,(Integer)2)
+    }
+} 
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/ArrayAutoboxingTest.groovy b/groovy-core/src/test/groovy/ArrayAutoboxingTest.groovy
new file mode 100644
index 0000000..1b95735
--- /dev/null
+++ b/groovy-core/src/test/groovy/ArrayAutoboxingTest.groovy
@@ -0,0 +1,25 @@
+class ArrayAutoboxingTest extends GroovyTestCase {
+    
+    void testUnwantedAutoboxingWhenInvokingMethods() {
+      def cl
+      cl = blah2(new int[2*2])
+      assert cl == "[I"
+      cl = blah2(new long[2*2])
+      assert cl == "[J"
+      cl = blah2(new short[2*2])
+      assert cl == "[S"
+      cl = blah2(new boolean[2*2])
+      assert cl == "[Z"
+      cl = blah2(new char[2*2])
+      assert cl == "[C"
+      cl = blah2(new double[2*2])
+      assert cl == "[D"
+      cl = blah2(new float[2*2])
+      assert cl == "[F"
+    }
+    
+    def blah2(Object o) {
+       return o.class.name
+    }
+        
+} 
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/ArrayCoerceTest.groovy b/groovy-core/src/test/groovy/ArrayCoerceTest.groovy
new file mode 100644
index 0000000..1df6aa6
--- /dev/null
+++ b/groovy-core/src/test/groovy/ArrayCoerceTest.groovy
@@ -0,0 +1,209 @@
+class ArrayCoerceTest extends GroovyTestCase {
+
+    Object[] field
+    Long[] numberField
+    int[] primitiveField
+
+    void testStaticallyTypedPrimitiveTypeArrays() {
+        int[] a = [1, 2, 3]
+        assert a instanceof int[]
+        assert a.length == 3
+        dump(a)
+    }
+
+    void testStaticallyTypedPrimitiveFieldArrays() {
+        primitiveField = [1, 2, 3]
+        dump(primitiveField)
+
+        assert primitiveField instanceof int[]
+        assert primitiveField.length == 3
+    }
+
+
+    void testFoo2() {
+        def x = [1, 2, 3] as Object[]
+        dump(x)
+        assert x instanceof Object[]
+        def c = x.getClass()
+        def et = c.componentType
+        assert et == Object.class
+    }
+
+    void testStaticallyTypedObjectArrays() {
+        Object[] b = [1, 2, 3]
+        dump(b)
+
+        assert b instanceof Object[]
+        assert b.length == 3
+        def c = b.getClass()
+        def et = c.componentType
+        assert et == Object.class
+
+    }
+
+    void testStaticallyTypedArrays() {
+        Integer[] b = [1, 2, 3]
+        dump(b)
+
+        assert b instanceof Integer[]
+        assert b.length == 3
+        def c = b.getClass()
+        def et = c.componentType
+        assert et == Integer.class
+
+    }
+
+    void testStaticallyTypedObjectFieldArrays() {
+        field = [1, 2, 3]
+        dump(field)
+
+        assert field instanceof Object[]
+        assert field.length == 3
+    }
+
+    void testStaticallyTypedFieldArrays() {
+        numberField = [1, 2, 3]
+        dump(numberField)
+
+        assert numberField instanceof Long[]
+        assert numberField.length == 3
+    }
+
+    void testMakePrimitiveArrayTypes() {
+        def x = null
+
+        x = [1, 0, 1] as boolean[]
+        assert x instanceof boolean[]
+        assert x.length == 3
+        dump(x)
+
+        x = [1, 2, 3] as byte[]
+        assert x.length == 3
+        assert x instanceof byte[]
+        dump(x)
+
+        x = [1, 2, 3] as char[]
+        assert x.length == 3
+        assert x instanceof char[]
+        dump(x)
+
+        x = [1, 2, 3] as short[]
+        assert x.length == 3
+        assert x instanceof short[]
+        dump(x)
+
+        x = [1, 2, 3] as int[]
+        assert x.length == 3
+        assert x instanceof int[]
+        dump(x)
+
+        x = [1, 2, 3] as long[]
+        assert x.length == 3
+        assert x instanceof long[]
+        dump(x)
+
+        x = [1, 2, 3] as float[]
+        assert x.length == 3
+        assert x instanceof float[]
+        dump(x)
+
+        x = [1, 2, 3] as double[]
+        assert x.length == 3
+        assert x instanceof double[]
+        dump(x)
+    }
+
+
+
+    void testAsObjectArray() {
+        def x = [1, 2, 3] as Object[]
+        def c = x.getClass()
+        def et = c.componentType
+        assert et == Object.class
+        dump(x)
+
+        Integer[] y = [1, 2, 3]
+        c = y.getClass()
+        et = c.componentType
+        assert et == Integer.class
+        dump(y)
+    }
+
+    void testMakeArrayThenCoerceToAnotherType() {
+        def x = [1, 2, 3] as int[]
+        assert x.size() == 3
+        assert x instanceof int[]
+        dump(x)
+
+        // lets try coerce it into an array of longs
+        def y = x as long[]
+        assert y instanceof long[]
+        dump(y)
+
+        def z = y as Object[]
+        assert z instanceof Object[]
+        def c = z.getClass()
+        def et = c.componentType
+        assert et == Object.class
+        dump(z)
+
+        x = y as int[]
+        assert x.size() == 3
+        assert x instanceof int[]
+        dump(x)
+    }
+
+
+    void testMakeArrayTypes() {
+        def x = null
+
+        x = [1, 0, 1] as Boolean[]
+        assert x instanceof Boolean[]
+        assert x.length == 3
+        dump(x)
+
+        x = [1, 2, 3] as Byte[]
+        assert x.length == 3
+        assert x instanceof Byte[]
+        dump(x)
+
+        x = [1, 2, 3] as Character[]
+        assert x.length == 3
+        assert x instanceof Character[]
+        dump(x)
+
+        x = [1, 2, 3] as Short[]
+        assert x.length == 3
+        assert x instanceof Short[]
+        dump(x)
+
+        x = [1, 2, 3] as Integer[]
+        assert x.length == 3
+        assert x instanceof Integer[]
+        dump(x)
+
+        x = [1, 2, 3] as Long[]
+        assert x.length == 3
+        assert x instanceof Long[]
+        dump(x)
+
+        x = [1, 2, 3] as Float[]
+        assert x.length == 3
+        assert x instanceof Float[]
+        dump(x)
+
+        x = [1, 2, 3] as Double[]
+        assert x.length == 3
+        assert x instanceof Double[]
+        dump(x)
+    }
+
+    void dump(array) {
+        println "Array is of type ${array.class} which has element type ${array.class.componentType}"
+        for (i in array) {
+            println "Contains entry $i of type ${i.class}"
+        }
+        println()
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/ArrayParamMethodTest.groovy b/groovy-core/src/test/groovy/ArrayParamMethodTest.groovy
new file mode 100644
index 0000000..6b6d92b
--- /dev/null
+++ b/groovy-core/src/test/groovy/ArrayParamMethodTest.groovy
@@ -0,0 +1,25 @@
+import groovy.DummyInterface
+
+class ArrayParamMethodTest extends GroovyTestCase implements DummyInterface {
+
+    void testMethodCall() {
+        def array = "a b c".split(' ')
+        
+        assert array.size() == 3
+        
+        methodWithArrayParam(array)
+    }
+    
+    void methodWithArrayParam(String[] args) {
+        println("first item: ${args[0]}")
+        
+        // lets turn it into a list
+        def list = args.toList()
+        assert list instanceof java.util.List
+        list[4] = "e"
+        
+        assert list == ["a", "b", "c", null, "e"]
+        
+        println("Created list ${list}")
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/ArrayTest.groovy b/groovy-core/src/test/groovy/ArrayTest.groovy
new file mode 100644
index 0000000..896aed1
--- /dev/null
+++ b/groovy-core/src/test/groovy/ArrayTest.groovy
@@ -0,0 +1,127 @@
+class ArrayTest extends GroovyTestCase {
+
+    void testFixedSize() {
+        def array = new String[10]
+        
+        assert array.size() == 10
+        
+        array[0] = "Hello"
+        
+        assert array[0] == "Hello"
+        
+        println "Created array ${array.inspect()} with type ${array.class}"
+    }
+    
+    void testArrayWithInitializer() {
+        String[] array = [ "nice", "cheese", "gromit" ]
+        
+        println "Created array ${array.inspect()} with type ${array.class}"
+        
+        assert array.size() == 3
+        assert array[0] == "nice" , array.inspect()
+        assert array[1] == "cheese"
+        assert array[2] == "gromit"
+    }
+
+    void testCharArrayCreate() {
+           def array  = new char[3]
+           assert array.size() == 3
+    }
+
+    void testCharArrayWithInitializer() {
+        char[] array = [ 'a', 'b', 'c' ]
+        
+        println "Created array ${array.inspect()} with type ${array.class}"
+        
+        assert array.size() == 3
+        assert array[0] == 'a' , array.inspect()
+        assert array[1] == 'b'
+        assert array[2] == 'c'
+    }
+    
+    void testByteArrayCreate() {
+        def array = new byte[100]
+        assert array.size() == 100;
+    }
+
+    void testByteArrayWithInitializer() {
+        byte[] array = [0, 1, 2, 3]
+        
+        println "Created array ${array.inspect()} with type ${array.class}"
+        
+        assert array.size() == 4
+        assert array[0] == 0 , array.inspect()
+        assert array[1] == 1
+        assert array[2] == 2
+        assert array[3] == 3
+    }
+
+    void testByteArrayWithInitializerAndAssignmentOfNumber() {
+        byte[] array = [ 2, 4]
+        println "Created array ${array.inspect()} with type ${array.class}"
+        assert array.size() == 2
+        assert array[0] == 2
+        assert array[1] == 4
+
+        array[0] = 76
+        array[1] = 32
+        assert array[0] == 76
+        assert array[1] == 32
+
+        array.putAt(0, 45)
+        array.putAt(1, 67)
+        assert array[0] == 45
+        assert array[1] == 67
+    }
+
+    void testDoubleArrayCreate() {
+         def array  = new double[3]
+         assert array.size() == 3
+    }
+
+    void testDoubleArrayWithInitializer() {
+        double[] array = [ 1.3, 3.14, 2.7]
+        
+        println "Created array ${array.inspect()} with type ${array.class}"
+        
+        assert array.size() == 3
+        assert array[0] == 1.3 , array.inspect()
+        assert array[1] == 3.14
+        assert array[2] == 2.7
+    }
+
+
+    void testIntArrayCreate() {
+        def array = new int[5]
+        
+        assert array.size() == 5
+    }
+
+    void testIntArrayWithInitializer() {
+        int[] array = [42, -5, 360]
+        
+        println "Created array ${array.inspect()} with type ${array.class}"
+        
+        assert array.size() == 3
+        assert array[0] == 42 , array.inspect()
+        assert array[1] == -5
+        assert array[2] == 360
+    }
+
+
+
+    void testArrayDeclaration() {
+        String[] array = [ "a", "b", "c" ]
+
+        array.each { element -> println( element ) }
+
+        assert array.size() == 3
+
+    }
+
+    static void main( String[] args ) {
+        def o = new ArrayTest();
+
+        o.testArrayDeclaration();
+    }
+}
diff --git a/groovy-core/src/test/groovy/ArrayTypeTest.groovy b/groovy-core/src/test/groovy/ArrayTypeTest.groovy
new file mode 100644
index 0000000..adcc966
--- /dev/null
+++ b/groovy-core/src/test/groovy/ArrayTypeTest.groovy
@@ -0,0 +1,20 @@
+class ArrayTypeTest extends GroovyTestCase {
+
+    void testClosureWithTypedParam() {
+        def c = {String[] foo->println("called with $foo") }
+        c(null)
+    }
+
+    void testVariableType() {
+        Object[] foo = methodThatReturnsArray()
+        println "foo is $foo"
+
+    }
+
+
+
+    Object[] methodThatReturnsArray() {
+        println "Invoked the method"
+        return null
+    }
+}
diff --git a/groovy-core/src/test/groovy/AssertNumberTest.groovy b/groovy-core/src/test/groovy/AssertNumberTest.groovy
new file mode 100644
index 0000000..7c5bcf7
--- /dev/null
+++ b/groovy-core/src/test/groovy/AssertNumberTest.groovy
@@ -0,0 +1,40 @@
+class AssertNumberTest extends GroovyTestCase {
+
+    void testCompare() {
+        def x = null
+
+        assert x == null
+        assert x != 432
+        assert x != 423.2342
+   		     
+        x = 123
+
+        assert x != null
+        assert x != 432
+        assert x != 423.2342
+        assert x == 123
+		
+        x = 42.2342
+
+        assert x != null
+        assert x != 432
+        assert x != 423.2342
+        assert x == 42.2342
+    }
+	
+    void testLessThan() {
+        def x = 123
+
+        assert x < 200
+        assert x <= 200
+        assert x <= 123
+    }
+
+    void testGreaterThan() {
+        def x = 123
+	    
+        assert x > 10
+        assert x >= 10
+        assert x >= 123
+    }
+}
diff --git a/groovy-core/src/test/groovy/AssertTest.groovy b/groovy-core/src/test/groovy/AssertTest.groovy
new file mode 100644
index 0000000..a8b3705
--- /dev/null
+++ b/groovy-core/src/test/groovy/AssertTest.groovy
@@ -0,0 +1,43 @@
+class AssertTest extends GroovyTestCase {
+
+    void testAssert() {
+        def x = null
+        
+        assert x == null
+        assert x != "abc"
+        assert x != "foo"
+	    
+        x = "abc"
+
+        assert x != "foo"
+        assert x !=  null
+        assert x != "def"
+        assert x == "abc"
+        
+        assert x.equals("abc")
+        
+        assert !x.equals("def")
+        assert !false
+        assert !(1==2)
+        assert !(1>3)
+        assert !(1!=1)
+    }
+	
+    void testAssertFail() {
+        def x = 1234
+
+        def runCode = false
+        try {
+            runCode = true
+            assert x == 5
+
+            fail("Should have thrown an exception")
+        }
+        catch (AssertionError e) {
+            //msg = "Expression: (x == 5). Values: x = 1234"
+            //assert e.getMessage() == msg
+            //assert e.message == msg
+        }
+        assert runCode, "has not ran the try / catch block code"
+    }
+}
diff --git a/groovy-core/src/test/groovy/Bar.groovy b/groovy-core/src/test/groovy/Bar.groovy
new file mode 100644
index 0000000..6741017
--- /dev/null
+++ b/groovy-core/src/test/groovy/Bar.groovy
@@ -0,0 +1,30 @@
+package cheese;
+
+import java.util.HashMap as Goober;
+
+class Cheddar extends Goober implements Runnable
+{
+    Goober theMap;
+    protected def cheesier;
+    public static def cheesiest;
+
+    static void main(args) {
+        def f = new Cheddar()
+        println f
+    }
+
+    def cheeseIt() {  }
+
+    String getStringCheese() { }
+    String getOtherCheese(foo,bar) { }
+
+    void run() { cheeseIt() }
+
+    static Goober mutateGoober(Goober theGoober) { }
+   
+}
+
+class Provolone
+{
+
+}
diff --git a/groovy-core/src/test/groovy/Base64Test.groovy b/groovy-core/src/test/groovy/Base64Test.groovy
new file mode 100644
index 0000000..48871ab
--- /dev/null
+++ b/groovy-core/src/test/groovy/Base64Test.groovy
@@ -0,0 +1,24 @@
+class Base64Test extends GroovyTestCase {
+
+    void testCodec() {
+        def testString ="§1234567890-=±!@£\$%^&*()_+qwertyuiop[]QWERTYUIOP{}asdfghjkl;'\\ASDFGHJKL:\"|`zxcvbnm,./~ZXCVBNM<>?\u0003\u00ff\u00f0\u000f"
+
+        // get a byte array using the least significant eigth bits of each caharacter
+           def testBytes = testString.getBytes("ISO-8859-1")
+
+           // turn the bytes back into a string for later comparison
+            testString = new String(testBytes, "ISO-8859-1")
+
+            // encode the bytes as base64. This produces a Writable object convert it to a String
+            def encodedBytes = testBytes.encodeBase64().toString()
+
+            // decode the base64 back to a byte array
+            def decodedBytes = encodedBytes.decodeBase64()
+
+            // turn the byte array back to a String for caomparison
+            def decodedString = new String(decodedBytes, "ISO-8859-1")
+
+            assert decodedString.equals(testString)
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/BigDecimalOperationTest.groovy b/groovy-core/src/test/groovy/BigDecimalOperationTest.groovy
new file mode 100644
index 0000000..f448516
--- /dev/null
+++ b/groovy-core/src/test/groovy/BigDecimalOperationTest.groovy
@@ -0,0 +1,127 @@
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+class BigDecimalOperationTest extends GroovyTestCase {
+
+    def x, y
+
+    void testPlus() {
+
+        x = 0.1 + 1.1
+        assert x instanceof BigDecimal;
+        assert x == 1.2
+
+        x = 3 + 2.2
+        assert x == 5.2
+        assert x instanceof BigDecimal;
+
+        x = 2.2 + 4
+        assert x instanceof BigDecimal;
+        assert x == 6.2
+
+        y = x + 1
+        assert y instanceof BigDecimal;
+        assert y == 7.2
+
+        def z = y + x + 1 + 2
+        assert z instanceof BigDecimal;
+        assert z == 16.4
+    }
+
+    void testMinus() {
+        x = 1.1-0.01
+        assert x == 1.09
+
+        x = 6 - 2.2
+        assert x == 3.8
+
+        x = 5.8 - 2
+        assert x == 3.8
+
+        y = x - 1
+        assert y == 2.8
+    }
+
+    void testMultiply() {
+        x = 3 * 2.0
+        assert x == 6.0
+
+        x = 3.0 * 2
+        assert x == 6.0
+
+        x = 3.0 * 2.0
+        assert x == 6.0
+
+        y = x * 2
+        assert y == 12.0
+
+        y = 11 * 3.333
+        assert y == 36.663 , "y = " + y
+
+        y = 3.333 * 11
+        assert y == 36.663 , "y = " + y
+    }
+
+    void testDivide() {
+        x = 80.0 / 4
+        assert x == 20.0 , "x = " + x
+
+        x = 80 / 4.0
+        assert x == 20.0 , "x = " + x
+
+        y = x / 2
+        assert y == 10.0 , "y = " + y
+        assert y == 10 , "y = " + y
+
+        y = 34 / 3.000
+        assert y == 11.3333333333 , "y = " + y
+
+        y = 34.00000000000 / 3
+        assert y == 11.33333333333 , "y = " + y
+    }
+    
+    BigDecimal echoX ( BigDecimal x, BigDecimal y) {x}
+    
+    // test for Groovy-1250
+    void testBigDecimalCoerce() {
+        assert echoX(9.95, 1.0) == echoX(9.95, 1)
+    }
+    
+    void testAssign() {
+        BigDecimal foo
+        foo = (byte) 20
+        assert foo.class == BigDecimal.class
+        assert foo == 20
+
+        foo = (short) 20
+        assert foo.class == BigDecimal.class
+        assert foo == 20
+
+        foo = (int) 20
+        assert foo.class == BigDecimal.class
+        assert foo == 20
+
+        foo = (long) 20
+        assert foo.class == BigDecimal.class
+        assert foo == 20
+
+        foo = (float) 0.5f
+        assert foo.class == BigDecimal.class
+        assert foo == 0.5
+
+        foo = (double) 0.5d
+        assert foo.class == BigDecimal.class
+        assert foo == 0.5
+        
+        foo = 10G
+        assert foo.class == BigDecimal.class
+        assert foo == 10
+        
+        double d = 1000
+        d *= d
+        d *= d
+        d *= d
+        assert (long)d != d
+		assert (BigDecimal) d == d
+    }
+}
diff --git a/groovy-core/src/test/groovy/BigIntegerOperationTest.groovy b/groovy-core/src/test/groovy/BigIntegerOperationTest.groovy
new file mode 100644
index 0000000..0205213
--- /dev/null
+++ b/groovy-core/src/test/groovy/BigIntegerOperationTest.groovy
@@ -0,0 +1,39 @@
+class BigIntegerOperationTest extends GroovyTestCase {

+    void testAssign() {

+        BigInteger foo

+        foo = (byte) 20

+        assert foo.class == BigInteger

+        assert foo == 20

+

+        foo = (short) 20

+        assert foo.class == BigInteger

+        assert foo == 20

+

+        foo = (int) 20

+        assert foo.class == BigInteger

+        assert foo == 20

+

+        foo = (long) 20

+        assert foo.class == BigInteger

+        assert foo == 20

+

+        foo = (float) 0.5f

+        assert foo.class == BigInteger

+        assert foo == 0

+

+        foo = (double) 0.5d

+        assert foo.class == BigInteger

+        assert foo == 0

+        

+        foo = 10.5G

+        assert foo.class == BigInteger

+        assert foo == 10

+        

+        double d = 1000

+        d *= d

+        d *= d

+        d *= d

+        assert (long)d != d

+		assert (BigInteger) d == d

+    }

+}

diff --git a/groovy-core/src/test/groovy/BindingTest.groovy b/groovy-core/src/test/groovy/BindingTest.groovy
new file mode 100644
index 0000000..8037135
--- /dev/null
+++ b/groovy-core/src/test/groovy/BindingTest.groovy
@@ -0,0 +1,19 @@
+class BindingTest extends GroovyTestCase {
+
+    void testProperties() {
+    	def b = new Binding()
+    	b.setVariable("foo", 123)
+    	
+    	assert b.foo == 123
+    	
+    	b.bar = 456
+    	
+    	assert b.getVariable("bar") == 456
+    	assert b["bar"] == 456
+    	
+    	b["a.b.c"] = 'abc'
+    	
+    	assert b.getVariable("a.b.c") == 'abc'
+    	assert b["a.b.c"] == 'abc'
+    }
+}
diff --git a/groovy-core/src/test/groovy/BitwiseOperationsTest.groovy b/groovy-core/src/test/groovy/BitwiseOperationsTest.groovy
new file mode 100644
index 0000000..f5cbb27
--- /dev/null
+++ b/groovy-core/src/test/groovy/BitwiseOperationsTest.groovy
@@ -0,0 +1,281 @@
+/** 
+ * Test Bitwise Operations in Classic/New Groovy
+ * 
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+class BitwiseOperationsTest extends GroovyTestCase {
+
+    void testBitwiseShift() {
+        def a = 4
+        def b = -4
+        assert a << 1 == 8
+        assert a << 2 == 16
+        assert a >> 1 == 2
+        assert a >> 2 == 1
+        assert a >>> 1 == 2
+        assert a >>> 2 == 1
+        assert b << 1 == -8
+        assert b << 2 == -16
+        assert b >> 1 == -2
+        assert b >> 2 == -1
+        assert b >>> 1 == 0x7FFFFFFE
+        assert b >>> 2 == 0x3FFFFFFF
+    }
+
+    void testBitwiseShiftEQUAL() {
+        def a = 4
+        a <<= 1
+        assert a == 8
+        a <<= 2
+        assert a == 32
+        a >>= 1
+        assert a == 16
+        a >>= 2
+        assert a == 4
+
+        def b = -4
+        b <<= 1
+        assert b == -8
+        b <<= 2
+        assert b == -32
+        b >>= 1
+        assert b == -16
+        b >>= 2
+        assert b == -4
+
+        b = -4
+        b >>>= 1
+        assert b == 0x7FFFFFFE
+        b = -8
+        b >>>= 2
+        assert b == 0x3FFFFFFE
+    }
+
+    void testBitwiseAnd() {
+
+        def a = 13
+        assert (a & 3) == 1    // 0x0000000D & 0x00000003
+        assert (a & 7) == 5    // 0x0000000D & 0x00000007
+        def b = -13
+        assert (b & 3) == 3    // 0xFFFFFFF3 & 0x00000003
+        assert (b & 7) == 3    // 0xFFFFFFF3 & 0x00000007
+    }
+
+    void testBitwiseAndOperatorPrecedence_FAILS() { if (notYetImplemented()) return
+        // Oprator Precedence Problem
+        // ^, &, | should be prior to ==, <, >, <=, >=
+        def a = 13
+        assert a & 3 == 1    // 0x0000000D & 0x00000003
+        assert a & 7 == 5    // 0x0000000D & 0x00000007
+        def b = -13
+        assert b & 3 == 3    // 0xFFFFFFF3 & 0x00000003
+        assert b & 7 == 3    // 0xFFFFFFF3 & 0x00000007
+    }
+
+    void testBitwiseAndEqual() {
+        def a = 13
+        a &= 3
+        assert a == 1    // 0x0000000D & 0x00000003
+        a &= 4
+        assert a == 0    // 0x00000001 & 0x00000004
+        def b = -13
+        b &= 3
+        assert b == 3    // 0xFFFFFFF3 & 0x00000003
+        b &= 7
+        assert b == 3    // 0x00000003 & 0x00000007
+    }
+
+    void testBitwiseOr() {
+        def a = 13
+        assert (a | 8) == 13      // 0x0000000D | 0x00000008
+        assert (a | 16) == 29     // 0x0000000D | 0x00000010
+        def b = -13
+        assert (b | 8) == -5      // 0xFFFFFFF3 | 0x00000008
+        assert (b | 16) == -13    // 0xFFFFFFF3 | 0x00000010
+    }
+
+    void testBitwiseOrOperatorPrecedence_FAILS() { if (notYetImplemented()) return
+        // Oprator Precedence Problem
+        // ^, &, | should be prior to ==, <, >, <=, >=
+        def a = 13
+        assert a | 8 == 13      // 0x0000000D | 0x00000008
+        assert a | 16 == 29     // 0x0000000D | 0x00000010
+        def b = -13
+        assert b | 8 == -5      // 0xFFFFFFF3 | 0x00000008
+        assert b | 16 == -13    // 0xFFFFFFF3 | 0x00000010
+    }
+
+    void testBitwiseOrEqual() {
+        def a = 13
+        a |= 2
+        assert a == 15     // 0x0000000D | 0x00000002
+        a |= 16
+        assert a == 31     // 0x0000000F | 0x0000001F
+        def b = -13
+        b |= 8
+        assert b == -5     // 0xFFFFFFF3 | 0x00000008
+        b |= 1
+        assert b == -5     // 0xFFFFFFFB | 0x00000001
+    }
+
+    void testBitwiseXor() {
+        def a = 13
+        assert (a ^ 10) == 7     // 0x0000000D ^ 0x0000000A = 0x000000007
+        assert (a ^ 15) == 2     // 0x0000000D ^ 0x0000000F = 0x000000002
+        def b = -13
+        assert (b ^ 10) == -7    // 0xFFFFFFF3 ^ 0x0000000A = 0xFFFFFFF9
+        assert (b ^ 15) == -4    // 0xFFFFFFF3 ^ 0x0000000F = 0xFFFFFFFC
+    }
+    void testBitwiseXorOperatorPrecedence_FAILS() { if (notYetImplemented()) return
+        // Oprator Precedence Problem
+        // ^, &, | should be prior to ==, <, >, <=, >=
+        def a = 13
+        assert a ^ 10 == 7     // 0x0000000D ^ 0x0000000A = 0x000000007
+        assert a ^ 15 == 2     // 0x0000000D ^ 0x0000000F = 0x000000002
+        def b = -13
+        assert b ^ 10 == -7    // 0xFFFFFFF3 ^ 0x0000000A = 0xFFFFFFF9
+        assert b ^ 15 == -4    // 0xFFFFFFF3 ^ 0x0000000F = 0xFFFFFFFC
+    }
+
+    void testBitwiseXorEqual() {
+        def a = 13
+        a ^= 8
+        assert a == 5      // 0x0000000D ^ 0x00000008 = 0x000000005
+        a ^= 16
+        assert a == 21     // 0x00000005 ^ 0x00000010 = 0x000000015
+        def b = -13
+        b ^= 8
+        assert b == -5     // 0xFFFFFFF3 ^ 0x00000008 = 0xFFFFFFFB
+        b ^= 16
+        assert b == -21    // 0xFFFFFFFB ^ 0x00000010 = 0xFFFFFFEB
+    }
+
+    void testBitwiseOrInClosure() {
+        def c1 = { x, y -> return x | y }
+        assert c1(14, 5) == 15          // 0x0000000E | 0x00000005 = 0x0000000F
+        assert c1(0x0D, 0xFE) == 255    // 0x0000000D | 0x000000FE = 0x000000FF
+
+        def c2 = { x, y -> return x | y }
+        assert c2(14, 5) == 15          // 0x0000000E | 0x00000005 = 0x0000000F
+        assert c2(0x0D, 0xFE) == 255    // 0x0000000D | 0x000000FE = 0x000000FF
+    }
+
+    void testAmbiguityOfBitwiseOr() {
+        def c1 = { x, y -> return x | y }
+        assert c1(14, 5) == 15          // 0x0000000E | 0x00000005 = 0x0000000F
+        assert c1(0x0D, 0xFE) == 255    // 0x0000000D | 0x000000FE = 0x000000FF
+
+        def c2 = { x, y -> return x | y }
+        assert c2(14, 5) == 15          // 0x0000000E | 0x00000005 = 0x0000000F
+        assert c2(0x0D, 0xFE) == 255    // 0x0000000D | 0x000000FE = 0x000000FF
+
+        def x = 3
+        def y = 5
+        c1 = { xx -> return y }         // -> is a closure delimiter
+        c2 = { return x & y }        // & is a bitAnd
+        def c3 = { return x ^ y }      // & is a bitXor
+        def c11 = {
+             xx -> return y             // -> is a closure delimiter
+        }
+        def c12 = {
+             return (x | y)            // | is a bitOr
+        }
+        def c13 = { xx -> return y      // -> is a closure delimiter
+        }
+        def c14 = {-> return x | y     // last | is a bitOr
+        }
+
+        assert c1(null) == 5
+        assert c2() == 1
+        assert c3() == 6
+        assert c11(null) == 5
+        assert c12() == 7
+        assert c13(null) == 5
+        assert c14() == 7
+
+        x = 0x03
+
+        def d1 = { xx -> return xx }      // -> is a closure delimiter
+        def d2 = { return x & x }       // & is a bitAnd
+        def d3 = { return x ^ x }       // & is a bitXor
+        def d11 = {
+             xx -> return xx              // -> is a closure delimiter
+        }
+        def d12 = {
+             return (x | x)            // | is a bitOr
+        }
+        def d13 = {xx -> return xx       // -> is a closure delimiter
+        }
+        def d14 = {-> return x | x     // last | is a bitOr
+        }
+        assert d1(0xF0) == 0xF0
+        assert d2(0xF0) == 0x03
+        assert d3(0xF0) == 0
+        assert d11(0xF0) == 0xF0
+        assert d12(0xF0) == 0x03
+        assert d13(0xF0) == 0xF0
+        assert d14() == 0x03
+    }
+
+    void testBitwiseNegation() {
+        assert ~1 == -2     // ~0x00000001 = 0xFFFFFFFE
+        assert ~-1 == 0     // ~0xFFFFFFFF = 0x00000000
+        assert ~~5 == 5     // ~~0x00000005 = ~0xFFFFFFFA = 0xFFFFFFF5
+        def a = 13
+        assert ~a  == -14     // ~0x0000000D = 0xFFFFFFF2
+        assert ~~a  == 13     // ~~0x0000000D = ~0xFFFFFFF2 = 0x0000000D
+        assert -~a  == 14     // -~0x0000000D = -0xFFFFFFF2 = 0x0000000E
+    }
+
+    void testBitwiseNegationType() {
+        def x = ~7
+        assert x.class == java.lang.Integer
+
+        def y = ~"foo"
+        assert y.class == java.util.regex.Pattern
+
+        def z = ~"${x}"
+        assert z.class == java.util.regex.Pattern
+    }
+
+    void testBitwiseNegationTypeCallFunction() {
+        // integer test
+        assert neg(2).class == java.lang.Integer
+        assert neg(2) instanceof java.lang.Integer
+        assert neg(2) == ~2
+
+        // long test
+        assert neg(2L).class == java.lang.Long
+        assert neg(2L) instanceof java.lang.Long
+        assert neg(2L) == ~2
+
+        // BigInteger test
+        assert neg(new java.math.BigInteger("2")).class == java.math.BigInteger
+        assert neg(new java.math.BigInteger("2")) instanceof java.math.BigInteger
+        assert neg(new java.math.BigInteger("2")) == ~2
+
+        // BigInteger test
+        assert neg(2G).class == java.math.BigInteger
+        assert neg(2G) instanceof java.math.BigInteger
+        assert neg(2G) == ~2
+
+        assert neg("foo").class == java.util.regex.Pattern
+        assert neg("foo") instanceof java.util.regex.Pattern
+    }
+
+    Object neg(n) {
+        if (n instanceof java.lang.Integer) {
+            return ~n
+        }
+        else if (n instanceof java.lang.Long) {
+            return ~n
+        }
+        else if (n instanceof java.math.BigInteger) {
+            return ~n
+        }
+        else {
+             return ~n.toString()
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/BooleanOperationTest.groovy b/groovy-core/src/test/groovy/BooleanOperationTest.groovy
new file mode 100644
index 0000000..6ea8ad9
--- /dev/null
+++ b/groovy-core/src/test/groovy/BooleanOperationTest.groovy
@@ -0,0 +1,127 @@
+class BooleanOperationTest extends GroovyTestCase {
+
+    void testComparisons() {
+        assert true
+        assert true != false
+        
+        def x = true
+        
+        assert x
+        assert x == true
+        assert x != false
+        
+        x = false
+        
+        assert x == false
+        assert x != true
+        
+        assert !x
+        
+        def y = false        
+        assert x == y
+        
+        y = true
+        assert x != y
+    }
+    
+    
+    void testIfBranch() {
+        def x = false
+        def r = false
+        
+        if ( x ) {
+            // ignore
+        }
+        else {
+            r = true
+        }
+
+        assert r
+        
+        x = true
+        r = false
+        
+        if ( x ) {
+            r = true
+        }
+        else {
+            // ignore
+        }
+        assert r
+        
+        if ( !x ) {
+            r = false
+        }
+        else {
+            r = true
+        }
+        
+        assert r
+    }
+
+
+	void testBooleanExpression() {
+	    def x = 5
+	    def value = x > 2
+	    assert value
+	    
+	    value = x < 2
+	    assert value == false
+	}
+	
+	
+	void testBooleanOps() {
+	    boolean x = true
+	    boolean y = false
+	    assert (x & x) == true
+	    assert (x & y) == false
+	    assert (y & x) == false
+	    assert (y & y) == false
+
+	    assert (x | x) == true
+	    assert (x | y) == true
+	    assert (y | x) == true
+	    assert (y | y) == false
+
+	    assert (x ^ x) == false
+	    assert (x ^ y) == true
+	    assert (y ^ x) == true
+	    assert (y ^ y) == false
+
+	    assert (!x) == false
+	    assert (!y) == true
+	}
+
+
+	void testBooleanAssignOps() {
+	    boolean z = true
+	    z &= true
+	    assert z == true
+	    z &= false
+	    assert z == false
+
+	    z = true
+	    z |= true
+	    assert z == true
+	    z |= false
+	    assert z == true
+	    z = false
+	    z |= false
+	    assert z == false
+	    z |= true
+	    assert z == true
+
+        z = true
+        z ^= true
+        assert z == false
+        z ^= true
+        assert z == true
+        z ^= false
+        assert z == true
+        z ^= true
+        assert z == false
+        z ^= false
+        assert z == false
+	}
+
+}
diff --git a/groovy-core/src/test/groovy/BreakContinueLabelTest.groovy b/groovy-core/src/test/groovy/BreakContinueLabelTest.groovy
new file mode 100644
index 0000000..0aa576a
--- /dev/null
+++ b/groovy-core/src/test/groovy/BreakContinueLabelTest.groovy
@@ -0,0 +1,104 @@
+/**
+ * todo: add BreakContinueLabelWithClosureTest (when break is used to return from a Closure)
+
+ * @author Dierk Koenig
+ */
+class BreakContinueLabelTest extends GroovyTestCase {
+
+    void testDeclareSimpleLabel() {
+        label_1: assert true
+        label_2:
+        assert true
+    }
+    void testBreakLabelInSimpleForLoop() {
+        label_1: for (i in [1]) {
+            break label_1
+            assert false
+        }
+    }
+
+    void testBreakLabelInNestedForLoop() {
+        label: for (i in [1]) {
+            for (j in [1]){
+                break label
+                assert false, 'did not break inner loop'
+            }
+            assert false, 'did not break outer loop'
+        }
+    }
+
+    void testUnlabelledBreakInNestedForLoop() {
+        def reached = false
+        for (i in [1]) {
+            for (j in [1]){
+                break
+                assert false, 'did not break inner loop'
+            }
+            reached = true
+        }
+        assert reached, 'must not break outer loop'
+    }
+
+    void testBreakLabelInSimpleWhileLoop() {
+        label_1: while (true) {
+            break label_1
+            assert false
+        }
+    }
+
+    void testBreakLabelInNestedWhileLoop() {
+        def count = 0
+        label: while (count < 1) {
+            count++
+            while (true){
+                break label
+                assert false, 'did not break inner loop'
+            }
+            assert false, 'did not break outer loop'
+        }
+    }
+
+    void testBreakLabelInNestedMixedForAndWhileLoop() {
+        def count = 0
+        label_1: while (count < 1) {
+            count++
+            for (i in [1]){
+                break label_1
+                assert false, 'did not break inner loop'
+            }
+            assert false, 'did not break outer loop'
+        }
+        label_2: for (i in [1]) {
+            while (true){
+                break label_2
+                assert false, 'did not break inner loop'
+            }
+            assert false, 'did not break outer loop'
+        }
+    }
+
+    void testUnlabelledContinueInNestedForLoop() {
+        def log = ''
+        for (i in [1,2]) {
+            log += i
+            for (j in [3,4]){
+                if (j==3) continue
+                log += j
+            }
+        }
+        assertEquals '1424',log
+    }
+
+    void testContinueLabelInNestedForLoop() {
+        def log = ''
+        label: for (i in [1,2]) {
+            log += i
+            for (j in [3,4]){
+                if (j==4) continue label
+                log += j
+            }
+            log += 'never reached'
+        }
+        assertEquals '1323',log
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/CallInnerClassCtorTest.groovy b/groovy-core/src/test/groovy/CallInnerClassCtorTest.groovy
new file mode 100644
index 0000000..70fcd41
--- /dev/null
+++ b/groovy-core/src/test/groovy/CallInnerClassCtorTest.groovy
@@ -0,0 +1,36 @@
+import groovy.OuterUser
+
+/**
+ * Checks that it's possible to call inner classes constructor from groovy
+ * @author Guillaume Laforge
+ */
+class CallInnerClassCtorTest extends GroovyTestCase {
+
+    void testCallCtor() {
+        def user = new groovy.OuterUser()
+        user.name = "Guillaume"
+        user.age = 27
+
+        assert user.name == "Guillaume"
+        assert user.age == 27
+    }
+
+    void testCallInnerCtor() {
+        def address = new groovy.OuterUser.InnerAddress()
+        address.city = "Meudon"
+        address.zipcode = 92360
+
+        assert address.city == "Meudon"
+        assert address.zipcode == 92360
+    }
+
+    void testCallInnerInnerCtor() {
+        def address = new groovy.OuterUser.InnerAddress.Street()
+        address.name = "rue de la paix"
+        address.number = 17
+
+        assert address.name == "rue de la paix"
+        assert address.number == 17
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/CastTest.groovy b/groovy-core/src/test/groovy/CastTest.groovy
new file mode 100644
index 0000000..c4fa350
--- /dev/null
+++ b/groovy-core/src/test/groovy/CastTest.groovy
@@ -0,0 +1,104 @@
+class CastTest extends GroovyTestCase {
+
+    Short b = 1
+    
+    void testCast() {
+        def x = (Short) 5
+
+        println("Cast Integer to ${x} with type ${x.class}")
+        
+        assert x.class == Short
+        
+        methodWithShort(x)
+    }
+    
+    void testImplicitCast() {
+        Short x = 6
+        
+        println("Created ${x} with type ${x.class}")
+        
+        assert x.class == Short , "Type is ${x.class}"
+        
+		methodWithShort(x)
+        
+        x = 7
+        
+        println("Updated ${x} with type ${x.class}")
+        
+        assert x.class == Short , "Type is ${x.class}"
+    }
+
+    void testImplicitCastOfField() {
+
+        println("Field is ${b} with type ${b.class}")
+        
+        assert b.class == Short , "Type is ${b.class}"
+        
+        b = 5
+        
+        println("Updated field ${b} with type ${b.class}")
+ 
+        assert b.class == Short , "Type is ${b.class}"
+    }
+    
+    void testIntCast() {
+        def i = (Integer) 'x'
+        
+        assert i instanceof Integer
+    }
+    
+    void testCharCompare() {
+        def i = (Integer) 'x'
+        def c = 'x'
+        
+        assert i == c
+        assert i =='x'
+        assert c == 'x'
+		assert i == i
+		assert c == c
+
+        assert 'x' == 'x'
+        assert 'x' == c
+        assert 'x' == i
+    }
+    
+    void testCharCast() {
+        def c = (Character) 'x'
+        
+        assert c instanceof Character
+        
+        c = (Character)10
+        
+        assert c instanceof Character
+    }
+    
+    void methodWithShort(Short s) {
+        println("Called with ${s} with type ${s.class}")
+        assert s.class == Short
+    }
+    
+    void methodWithChar(Character x) {
+        println("Called with ${x} with type ${s.class}")
+        
+        def text = "text"
+        def idx = text.indexOf(x)
+        
+        assert idx == 2
+    }
+    // br
+    void testPrimitiveCasting() {
+        def d = 1.23
+        def i1 = (int)d
+        def i2 = (Integer)d
+        assert i1.class.name == 'java.lang.Integer'
+        assert i2.class.name == 'java.lang.Integer'
+
+        def ch = (char) i1
+        assert ch.class.name == 'java.lang.Character'
+
+        def dd = (double)d
+        assert dd.class.name == 'java.lang.Double'
+
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/CategoryTest.groovy b/groovy-core/src/test/groovy/CategoryTest.groovy
new file mode 100644
index 0000000..3c10e12
--- /dev/null
+++ b/groovy-core/src/test/groovy/CategoryTest.groovy
@@ -0,0 +1,50 @@
+class CategoryTest extends GroovyTestCase {
+
+  void testCategories() {
+    use (StringCategory.class) {
+      assert "Sam".lower() == "sam";
+      use (IntegerCategory.class) {
+        assert "Sam".lower() == "sam";
+        assert 1.inc() == 2;
+      }
+        shouldFail(MissingMethodException, { 1.inc() });
+    }
+    shouldFail(MissingMethodException, { "Sam".lower() });
+  }
+  
+  void testCategoryDefinedProperties() {
+  
+    use(CategoryTestPropertyCategory) { 
+      assert getSomething() == "hello"
+      assert something == "hello"
+      something = "nihao"
+      assert something == "nihao"
+    }
+    
+    // test the new value again in a new block
+    use(CategoryTestPropertyCategory) { 
+      assert something == "nihao"
+    }
+
+  }
+}
+
+class StringCategory {
+  static String lower(String string) {
+    return string.toLowerCase();
+  }
+}
+
+class IntegerCategory {
+  static Integer inc(Integer i) {
+    return i + 1;
+  }
+}
+
+
+class CategoryTestPropertyCategory {
+     private static aVal = "hello"
+     static getSomething(Object self) { return aVal }
+     static void setSomething(Object self, newValue) { aVal = newValue }
+}
+
diff --git a/groovy-core/src/test/groovy/ChainedAssignmentTest.groovy b/groovy-core/src/test/groovy/ChainedAssignmentTest.groovy
new file mode 100644
index 0000000..4aeb492
--- /dev/null
+++ b/groovy-core/src/test/groovy/ChainedAssignmentTest.groovy
@@ -0,0 +1,20 @@
+class ChainedAssignmentTest extends GroovyTestCase {
+
+    def dummy(v) {
+        print v
+    }
+
+    void testCompare() {
+        def i = 123
+        def s = "hello"
+
+        def i2
+        def i1 = i2 = i;
+        assert i1 == 123
+        assert i2 == 123
+
+        def s1
+        dummy(s1 = s)
+        assert s1 == "hello"
+    }
+}
diff --git a/groovy-core/src/test/groovy/ClassExpressionTest.groovy b/groovy-core/src/test/groovy/ClassExpressionTest.groovy
new file mode 100644
index 0000000..df8cef5
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClassExpressionTest.groovy
@@ -0,0 +1,62 @@
+/** 
+ * Tests the use of classes as variable expressions
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class ClassExpressionTest extends GroovyTestCase {
+
+    void testUseOfClass() {
+        def x = String
+        
+        System.out.println("x: " + x)
+        
+        assert x != null
+
+        assert x.getName().endsWith('String')
+        assert x.name.endsWith('String')
+
+        x = Integer
+        
+        assert x != null
+        assert x.name.endsWith('Integer')
+        
+        x = GroovyTestCase
+        
+        assert x != null
+        assert x.name.endsWith('GroovyTestCase')
+        
+        x = ClassExpressionTest
+        
+        assert x != null
+
+        System.out.println("x: " + x)
+    }
+
+    void testClassPsuedoProperty() {
+
+        def x = "cheese";
+
+        assert x.class != null
+
+        assert x.class == x.getClass();
+
+        System.err.println( "x.class: " + x.class );
+    }
+    
+    void testPrimitiveClasses() {
+        assert void == Void.TYPE
+        assert int == Integer.TYPE
+        assert byte == Byte.TYPE
+        assert char == Character.TYPE
+        assert double == Double.TYPE
+        assert float == Float.TYPE
+        assert long == Long.TYPE
+        assert short == Short.TYPE
+    }
+    
+    void testArrayClassReference() {
+       def foo = int[]
+       assert foo.name == "[I"
+    }
+}
diff --git a/groovy-core/src/test/groovy/ClassLoaderBug.groovy b/groovy-core/src/test/groovy/ClassLoaderBug.groovy
new file mode 100644
index 0000000..a0178b6
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClassLoaderBug.groovy
@@ -0,0 +1,11 @@
+class ClassLoaderBug extends GroovyTestCase {
+    
+    static void main(args) {
+        def gst = new ClassLoaderBug();
+        gst.testWithOneVariable();
+    }
+
+    void testWithOneVariable() {
+        println("Called method")
+    }
+}
diff --git a/groovy-core/src/test/groovy/ClassTest.groovy b/groovy-core/src/test/groovy/ClassTest.groovy
new file mode 100644
index 0000000..b2fc3ae
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClassTest.groovy
@@ -0,0 +1,20 @@
+class ClassTest extends GroovyTestCase {
+
+    void testClassExpression() {
+    	def c = String.class
+    	println c
+    	assert c instanceof Class
+    	assert c.name == "java.lang.String" , c.name
+    	
+    	c = GroovyTestCase.class
+    	println c
+    	assert c instanceof Class
+    	assert c.name.endsWith("GroovyTestCase") , c.name
+    	
+    	c = ClassTest.class
+    	println c
+    	assert c instanceof Class
+    	assert c.name.endsWith("ClassTest") , c.name
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/ClosureAsParamTest.groovy b/groovy-core/src/test/groovy/ClosureAsParamTest.groovy
new file mode 100644
index 0000000..f480ec7
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureAsParamTest.groovy
@@ -0,0 +1,17 @@
+/** 
+ * Tests Closures in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class ClosureAsParamTest extends GroovyTestCase {
+
+    void testSimpleBlockCall() {
+        assertClosure({owner-> println(owner) })
+    }
+  
+    def assertClosure(Closure block) {
+        assert block != null
+        block.call("hello!")
+    }
+}
diff --git a/groovy-core/src/test/groovy/ClosureCloneTest.groovy b/groovy-core/src/test/groovy/ClosureCloneTest.groovy
new file mode 100644
index 0000000..0dffb1c
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureCloneTest.groovy
@@ -0,0 +1,21 @@
+/** 
+ * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
+ * @version $Revision$
+ */
+class ClosureCloneTest extends GroovyTestCase {
+
+    void testCloneOfClosure() {
+        def factor = 2
+        def closure = { it * factor }
+
+        def value = closure(5)
+        assert value == 10
+
+        // now lets clone the closure
+        def c2 = closure.clone()
+        assert c2 != null
+
+        value = c2(6)
+        assert value == 12
+    }  
+}
diff --git a/groovy-core/src/test/groovy/ClosureComparatorTest.groovy b/groovy-core/src/test/groovy/ClosureComparatorTest.groovy
new file mode 100644
index 0000000..aa9ea7f
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureComparatorTest.groovy
@@ -0,0 +1,95 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+/**
+ * Tests for ClosureComparator
+ *
+ * @author Alexey Verkhovsky
+ * @version $Revision$
+ */
+ class ClosureComparatorTest extends GroovyTestCase {
+
+
+  public void testClosureComparatorForGroovyObjects() {
+
+    def comparator = new ClosureComparator() { one, another ->
+      one.greaterThan(another)
+    }
+
+    def one = new ComparableFoo(5)
+    def another = new ComparableFoo(-5)
+
+    assertEquals(10, comparator.compare(one, another))
+    assertEquals(0, comparator.compare(one, one))
+    assertEquals(-10, comparator.compare(another, one))
+
+  }
+
+  public void testClosureComparatorForNumericTypes() {
+
+    def comparator = new ClosureComparator() { one, another ->
+      one - another
+    }
+
+    assertEquals(1, comparator.compare(Integer.MAX_VALUE, Integer.MAX_VALUE-1))
+    assertEquals(0, comparator.compare(Double.MIN_VALUE, Double.MIN_VALUE))
+    assertEquals(-1, comparator.compare(Long.MIN_VALUE, Long.MIN_VALUE+1))
+  }
+
+}
+
+class ComparableFoo {
+  long value
+
+  public ComparableFoo(long theValue) {
+    this.value = theValue
+  }
+
+  def greaterThan(anotherFoo) {
+    return (this.value - anotherFoo.value)
+  }
+}
+
diff --git a/groovy-core/src/test/groovy/ClosureCurryTest.groovy b/groovy-core/src/test/groovy/ClosureCurryTest.groovy
new file mode 100644
index 0000000..01280c4
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureCurryTest.groovy
@@ -0,0 +1,83 @@
+/** 
+ * @author Hallvard Tr¾tteberg
+ * @version $Revision$
+ */
+class ClosureCurryTest extends GroovyTestCase {
+
+    void testCurry() {
+		def clos1 = {s1, s2 -> s1 + s2}
+		def clos2 = clos1.curry("hi")
+		def value = clos2("there")
+		assert value == "hithere"
+
+		def clos3 = {s1, s2, s3 -> s1 + s2 + s3}
+		def clos4 = clos3.curry('a')
+		def clos5 = clos4.curry('b')
+		def clos6 = clos4.curry('x')
+		def clos7 = clos4.curry('f', 'g')
+		value = clos5('c')
+		assert value == "abc"
+		value = clos6('c')
+		assert value == "axc"
+		value = clos4('y', 'z')
+		assert value == "ayz"
+		value = clos7()
+		assert value == "afg"
+
+		clos3 = {s1, s2, s3 -> s1 + s2 + s3}.asWritable()
+		clos4 = clos3.curry('a')
+		clos5 = clos4.curry('b')
+		clos6 = clos4.curry('x')
+		clos7 = clos4.curry('f', 'g')
+		value = clos5('c')
+		assert value == "abc"
+		value = clos6('c')
+		assert value == "axc"
+		value = clos4('y', 'z')
+		assert value == "ayz"
+		value = clos7()
+		assert value == "afg"
+
+		clos3 = {s1, s2, s3 -> s1 + s2 + s3}
+		clos4 = clos3.curry('a').asWritable()
+		clos5 = clos4.curry('b').asWritable()
+		clos6 = clos4.curry('x').asWritable()
+		clos7 = clos4.curry('f', 'g').asWritable()
+		value = clos5('c')
+		assert value == "abc"
+		value = clos6('c')
+		assert value == "axc"
+		value = clos4('y', 'z')
+		assert value == "ayz"
+		value = clos7()
+		assert value == "afg"
+
+		clos3 = {s1, s2, s3 -> s1 + s2 + s3}
+		clos4 = clos3.curry('a').clone()
+		clos5 = clos4.curry('b').clone()
+		clos6 = clos4.curry('x').clone()
+		clos7 = clos4.curry('f', 'g').clone()
+		value = clos5('c')
+		assert value == "abc"
+		value = clos6('c')
+		assert value == "axc"
+		value = clos4('y', 'z')
+		assert value == "ayz"
+		value = clos7()
+		assert value == "afg"
+
+		clos3 = {s1, s2, s3 -> s1 + s2 + s3}
+		clos4 = clos3.curry('a').asWritable().clone()
+		clos5 = clos4.curry('b').asWritable().clone()
+		clos6 = clos4.curry('x').asWritable().clone()
+		clos7 = clos4.curry('f', 'g').asWritable().clone()
+		value = clos5('c')
+		assert value == "abc"
+		value = clos6('c')
+		assert value == "axc"
+		value = clos4('y', 'z')
+		assert value == "ayz"
+		value = clos7()
+		assert value == "afg"
+    }  
+}
diff --git a/groovy-core/src/test/groovy/ClosureDefaultParameterTest.groovy b/groovy-core/src/test/groovy/ClosureDefaultParameterTest.groovy
new file mode 100644
index 0000000..c634bdb
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureDefaultParameterTest.groovy
@@ -0,0 +1,21 @@
+/** 
+ * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
+ * @version $Revision$
+ */
+class ClosureDefaultParameterTest extends GroovyTestCase {
+
+    void testClosureWithDefaultParams() {
+
+        def block = {a = 123, b = 456 -> println "value of a = $a and b = $b" }
+
+        block = { Integer a = 123, String b = "abc" ->
+                  println "value of a = $a and b = $b"; return "$a $b".toString() }
+
+        assert block.call(456, "def") == "456 def"
+        assert block.call() == "123 abc"
+        assert block(456) == "456 abc"
+        assert block(456, "def") == "456 def"
+    }
+
+}
+
diff --git a/groovy-core/src/test/groovy/ClosureInClosureTest.groovy b/groovy-core/src/test/groovy/ClosureInClosureTest.groovy
new file mode 100644
index 0000000..2006673
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureInClosureTest.groovy
@@ -0,0 +1,29 @@
+/**
+ * Bug illustrating the nested closures variable scope visibility issue.
+ * l.each is ClosureInClosureBug$1 and it.each is ClosureInClosureBug$2
+ * The variable text is not visible from ClosureInClosureBug$2.
+ * Indeed, a closure can only see the variable defined outside this closure (one level up)
+ * but cannot see what's in the second level.
+ *
+ * In order to make the test work, do not forget to uncomment the line "println(text)"
+ *
+ * @authour Guillaume Laforge
+ */
+class ClosureInClosureTest extends GroovyTestCase {
+	void testInvisibleVariable() {
+		def text = "test "
+
+		def l = [1..11, 2..12, 3..13, 4..14]
+
+		l.each{
+			it.each{
+			    println(text)
+			}
+		}
+	}
+
+	static void main(args) {
+		def bug = new ClosureInClosureTest()
+		bug.testInvisibleVariable()
+	}
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/ClosureInStaticMethodTest.groovy b/groovy-core/src/test/groovy/ClosureInStaticMethodTest.groovy
new file mode 100644
index 0000000..a17d8b4
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureInStaticMethodTest.groovy
@@ -0,0 +1,45 @@
+/** 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class ClosureInStaticMethodTest extends GroovyTestCase {
+
+    void testClosureInStaticMethod() {
+        def closure = closureInStaticMethod()
+        assertClosure(closure)    
+    }
+
+    void testMethodClosureInStaticMethod() {
+        def closure = methodClosureInStaticMethod()
+        assertClosure(closure)    
+    }
+    
+    static def closureInStaticMethod() {
+        return { println(it) }
+    }
+
+    static def methodClosureInStaticMethod() {
+        System.out.&println
+    }
+    
+    static def assertClosure(Closure block) {
+        assert block != null
+        block.call("hello!")
+    }
+    
+    void testClosureInStaticMethodCallingStaticMethod() {
+       assert doThing(1) == 10
+       assert this.doThing(1) == 10
+       assert ClosureInStaticMethodTest.doThing(1) == 10
+    }
+    
+    
+    static doThing(count) {
+      def ret = count
+      if (count > 2) return ret
+      count.times {
+        ret += doThing(count+it+1)
+      }
+      return ret
+    }
+}
diff --git a/groovy-core/src/test/groovy/ClosureListenerTest.groovy b/groovy-core/src/test/groovy/ClosureListenerTest.groovy
new file mode 100644
index 0000000..5be2525
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureListenerTest.groovy
@@ -0,0 +1,44 @@
+import javax.swing.JButton
+import java.util.Arrays
+
+/**
+ * @version $Revision$
+ */
+class ClosureListenerTest extends GroovyTestCase {
+     
+    void testAddingAndRemovingAClosureListener() {
+        def value = System.getProperty('java.awt.headless')
+        println("Value of java.awt.headless = ${value}")
+        
+        def b = new JButton("foo")
+        b.actionPerformed = { println("Found ${it}") }
+
+        def size = b.actionListeners.size()
+        assert size == 1
+        
+        def l = b.actionListeners[0]
+		def code = l.hashCode()
+        
+        println("listener: ${l} with hashCode code ${code}")
+        
+        assert l.toString() != "null"
+        
+        assert l.equals(b) == false
+        assert l.equals(l)
+        
+        assert l.hashCode() != 0
+        
+        b.removeActionListener(l)
+        
+        println(b.actionListeners)
+        
+        size = b.actionListeners.size()
+        assert size == 0
+    }
+    
+    void testGettingAListenerProperty() {
+    	def b = new JButton("foo")
+    	def foo = b.actionPerformed
+    	assert foo == null
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/ClosureMethodCallTest.groovy b/groovy-core/src/test/groovy/ClosureMethodCallTest.groovy
new file mode 100644
index 0000000..e5a87d4
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureMethodCallTest.groovy
@@ -0,0 +1,25 @@
+/** 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class ClosureMethodCallTest extends GroovyTestCase {
+
+    void testCallingClosureWithMultipleArguments() {
+        def foo
+        def closure = { a, b -> foo = "hello ${a} and ${b}".toString() }
+        
+        closure("james", "bob")
+
+        assert foo == "hello james and bob"
+
+        closure.call("sam", "james")
+
+        assert foo == "hello sam and james"
+    }
+    
+    
+    void testSystemOutPrintlnAsAClosure() {
+        def closure = System.out.&println
+        closure("Hello world")
+    }
+}
diff --git a/groovy-core/src/test/groovy/ClosureMethodTest.groovy b/groovy-core/src/test/groovy/ClosureMethodTest.groovy
new file mode 100644
index 0000000..d031ce6
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureMethodTest.groovy
@@ -0,0 +1,236 @@
+import java.io.File
+
+/** 
+ * Tests the various Closure methods in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class ClosureMethodTest extends GroovyTestCase {
+
+    void testListCollect() {
+        def list = [1, 2, 3, 4]
+        def answer = list.collect( {item -> return item * 2 } )
+
+        assert answer.size() == 4
+
+        def expected = [2, 4, 6, 8]
+        assert answer == expected
+    }
+
+    void testMapCollect() {
+        def map = [1:2, 2:4, 3:6, 4:8]
+        def answer = map.collect( {e-> return e.key + e.value } )
+
+        // lest sort the results since maps are in hash code order
+        answer = answer.sort()
+
+        assert answer.size() == 4
+        assert answer == [3, 6, 9, 12]
+        assert answer.get(0) == 3
+        assert answer.get(1) == 6
+        assert answer.get(2) == 9
+        assert answer.get(3) == 12
+    }
+
+    void testListFind() {
+        def list = ["a", "b", "c"]
+        def answer = list.find( {item-> return item == "b" })
+        assert answer == "b"
+
+        answer = list.find{item-> return item == "z" }
+        assert answer == null
+    }
+
+    void testMapFind() {
+        def map = [1:2, 2:4, 3:6, 4:8]
+        def answer = map.find( {entry-> return entry.value == 6 })
+        assert answer != null
+        assert answer.key == 3
+        assert answer.value == 6
+
+        answer = map.find{entry-> return entry.value == 0 }
+        assert answer == null
+    }
+
+    void testListFindAll() {
+        def list = [20, 5, 40, 2]
+        def answer = list.findAll( {item-> return item < 10 } )
+
+        assert answer.size() == 2
+        assert answer == [5, 2]
+    }
+
+    void testMapFindAll() {
+        def map = [1:2, 2:4, 3:6, 4:8]
+        def answer = map.findAll( {entry-> return entry.value > 5 })
+
+        assert answer.size() == 2
+
+        def keys = answer.collect( {entry-> return entry.key })
+        def values = answer.collect {entry-> return entry.value }
+
+        println("keys " + keys + " values " + values)
+
+        // maps are in hash order so lets sort the results
+        keys.sort()
+        values.sort()
+
+        assert keys == [3, 4]
+        assert values == [6, 8]
+    }
+
+    void testListEach() {
+        def count = 0
+
+        def list = [1, 2, 3, 4]
+        list.each({item-> count = count + item })
+
+        assert count == 10
+
+        list.each{item-> count = count + item }
+
+        assert count == 20
+    }
+
+    void testMapEach() {
+        def count = 0
+
+        def map = [1:2, 2:4, 3:6, 4:8]
+        map.each({e-> count = count + e.value })
+
+        assert count == 20
+
+        map.each({e-> count = count + e.value + e.key })
+
+        assert count == 50
+    }
+
+    void testMapEachWith2Params() {
+        def count = 0
+
+        def map = [1:2, 2:4, 3:6, 4:8]
+        map.each {key, value -> count = count + value }
+
+        assert count == 20
+
+        map.each {key, value -> count = count + value + key }
+
+        assert count == 50
+    }
+
+    void testListEvery() {
+        assert [1, 2, 3, 4].every {i-> return i < 5 }
+        assert [1, 2, 7, 4].every {i-> return i < 5 } == false
+    }
+
+    void testListAny() {
+        assert [1, 2, 3, 4].any {i-> return i < 5 }
+        assert [1, 2, 3, 4].any {i-> return i > 3 }
+        assert [1, 2, 3, 4].any {i-> return i > 5 } == false
+    }
+
+    void testJoin() {
+        def value = [1, 2, 3].join('-')
+        assert value == "1-2-3"
+    }
+
+    void testListReverse() {
+        def value = [1, 2, 3, 4].reverse()
+        assert value == [4, 3, 2, 1]
+    }
+
+    void testListInject() {
+        def value = [1, 2, 3].inject('counting: ') { str, item -> str + item }
+        assert value == "counting: 123"
+
+        value = [1, 2, 3].inject(0) { c, item -> c + item }
+        assert value == 6
+
+        value = ([1, 2, 3, 4] as Object[]).inject(0) { c, item -> c + item }
+        assert value == 10
+    }
+
+    void testDump() {
+        def text = dump()
+        println("Dumping object ${text}")
+        assert text != null && text.startsWith("<")
+    }
+
+    void testInspect() {
+        def text = [1, 2, 'three'].inspect()
+        println("Inspecting ${text}")
+        assert text == '[1, 2, "three"]'
+    }
+
+    void testEachLine() {
+        def file = new File("src/test/groovy/Bar.groovy")
+        if(file.exists() == false) {
+            file = new File("Bar.groovy")
+        }
+
+        println("Contents of file: " + file)
+
+        file.eachLine { line -> println(line) }
+
+        println("")
+    }
+
+    void testForEachLine() {
+        def file = new File("src/test/groovy/Bar.groovy")
+        if(file.exists() == false) {
+            file = new File("Bar.groovy")
+        }
+
+        println("For loop to display contents of file: " + file)
+
+        for (line in file) { println(line) }
+
+        println("")
+    }
+
+    void testReadLines() {
+        def file = new File("src/test/groovy/Bar.groovy")
+        if(file.exists() == false) {
+            file = new File("Bar.groovy")
+        }
+
+        def lines = file.readLines()
+
+        assert lines != null
+        assert lines.size() > 0
+
+        println("File has: " + lines.size() + " line(s)")
+    }
+
+    void testEachFile() {
+        def file = new File("src/test/groovy")
+        if(!file.exists()) {
+            file = new File(".")
+        }
+
+        println("Closure loop to display contents of dir: " + file)
+
+        file.eachFile { f -> println(f.getName()) }
+        
+        println("")
+    }
+    
+    void testTokenize() {
+        def text = "hello-there-how-are-you"
+        
+        def answer = []
+        for (i in text.tokenize('-')) {
+            answer.add(i)
+        }
+        assert answer == ['hello', 'there', 'how', 'are', 'you']
+    }
+    
+    void testUpto() {
+        def answer = []
+        
+        1.upto(5) { answer.add(it) }
+        
+        assert answer == [1, 2, 3, 4, 5]
+    }
+}
diff --git a/groovy-core/src/test/groovy/ClosureReturnTest.groovy b/groovy-core/src/test/groovy/ClosureReturnTest.groovy
new file mode 100644
index 0000000..802e71f
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureReturnTest.groovy
@@ -0,0 +1,32 @@
+/** 
+ * Tests Closures in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class ClosureReturnTest extends GroovyTestCase {
+
+    void testReturnValues() {
+        def block = {x-> return x > 5}
+
+        def value = block.call(10)
+        assert value
+
+        value = block.call(3)
+        assert value == false
+    }
+
+    void testReturnValueUsingFunction() {
+        def block = {x-> return someFunction(x) }
+        
+        def value = block.call(10)
+        assert value
+
+        value = block.call(3)
+        assert value == false
+    }
+    
+    def someFunction(x) {
+        return x > 5
+    }
+}
diff --git a/groovy-core/src/test/groovy/ClosureReturnWithoutReturnStatementTest.groovy b/groovy-core/src/test/groovy/ClosureReturnWithoutReturnStatementTest.groovy
new file mode 100644
index 0000000..8843e7d
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureReturnWithoutReturnStatementTest.groovy
@@ -0,0 +1,26 @@
+class ClosureReturnWithoutReturnStatementTest extends GroovyTestCase {
+
+    void testReturnValues() {
+        def block = {x-> x > 5}
+
+        def value = block.call(10)
+        assert value
+
+        value = block.call(3)
+        assert value == false
+    }
+
+    void testReturnValueUsingFunction() {
+        def block = {x-> someFunction(x) }
+        
+        def value = block.call(10)
+        assert value
+
+        value = block.call(3)
+        assert value == false
+    }
+    
+    def someFunction(x) {
+        x > 5
+    }
+}
diff --git a/groovy-core/src/test/groovy/ClosureSugarTest.groovy b/groovy-core/src/test/groovy/ClosureSugarTest.groovy
new file mode 100644
index 0000000..4379120
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureSugarTest.groovy
@@ -0,0 +1,33 @@
+class ClosureSugarTest extends GroovyTestCase {
+
+    def count;
+
+    void testClosureSugar() {
+        count = 11;
+
+        sugar {
+             count = 20;
+        }
+
+        assert count == 20;
+    }
+
+    void testMixedClosureSugar() {
+        def count = 11;
+
+        mixedSugar (5){a->
+             count = count + a;
+        }
+
+        assert count == 16;
+
+    }
+
+    def mixedSugar(incrBy, Closure closure) {
+        closure.call( incrBy ); 
+    }
+
+    def sugar(Closure closure) {
+        closure.call();
+    }
+}
diff --git a/groovy-core/src/test/groovy/ClosureTest.groovy b/groovy-core/src/test/groovy/ClosureTest.groovy
new file mode 100644
index 0000000..5cb3acc
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureTest.groovy
@@ -0,0 +1,126 @@
+/** 
+ * Tests Closures in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class ClosureTest extends GroovyTestCase {
+
+    def count
+
+    void testSimpleBlockCall() {
+        count = 0
+
+        def block = {owner-> owner.incrementCallCount() }
+
+        assertClosure(block)
+        assert count == 1
+
+        assertClosure({owner-> owner.incrementCallCount() })
+        assert count == 2
+    }
+
+    void testVariableLengthParameterList() {
+
+        def c1 = {Object[] args -> args.each{count += it}}
+
+        count = 0
+        c1(1, 2, 3)
+        assert count == 6
+
+        count = 0
+        c1(1)
+        assert count == 1
+
+        count = 0
+        c1([1, 2, 3] as Object[])
+        assert count == 6
+
+        def c2 = {a, Object[] args -> count += a; args.each{count += it}}
+
+        count = 0
+        c2(1, 2, 3)
+        assert count == 6
+
+        count = 0
+        c2(1)
+        assert count == 1
+
+        count = 0
+        c2(1, [2, 3] as Object[])
+        assert count == 6
+    }
+
+    void testBlockAsParameter() {
+        count = 0
+
+        callBlock(5, {owner-> owner.incrementCallCount() })
+        assert count == 6
+
+        callBlock2(5, {owner-> owner.incrementCallCount() })
+        assert count == 12
+    }
+  
+    void testMethodClosure() {
+        def block = this.&incrementCallCount
+
+        count = 0
+
+        block.call()
+
+        assert count == 1
+
+        block = System.out.&println
+
+        block.call("I just invoked a closure!")
+    }
+  
+    def incrementCallCount() {
+        //System.out.println("invoked increment method!")
+        count = count + 1
+    }
+
+    def assertClosure(Closure block) {
+        assert block != null
+        block.call(this)
+    }
+
+    protected void callBlock(Integer num, Closure block) {
+        for ( i in 0..num ) {
+            block.call(this)
+        }
+    }
+
+    protected void callBlock2(num, block) {
+        for ( i in 0..num ) {
+            block.call(this)
+        }
+    }
+
+
+    int numAgents = 4
+    boolean testDone = false
+
+    void testIntFieldAccess() {
+        def agents = new ArrayList();
+        numAgents.times {
+            TinyAgent btn = new TinyAgent()
+            testDone = true
+            btn.x = numAgents
+            agents.add(btn)
+        }
+        assert agents.size() == numAgents
+    }
+
+    void testWithIndex() {
+        def str = ''
+        def sum = 0
+        ['a','b','c','d'].eachWithIndex { item, index -> str += item; sum += index }
+        assert str == 'abcd' && sum == 6
+    }
+}
+
+public class TinyAgent {
+    int x
+}
+
diff --git a/groovy-core/src/test/groovy/ClosureUsingOuterVariablesTest.groovy b/groovy-core/src/test/groovy/ClosureUsingOuterVariablesTest.groovy
new file mode 100644
index 0000000..01f9bef
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureUsingOuterVariablesTest.groovy
@@ -0,0 +1,69 @@
+/** 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class ClosureUsingOuterVariablesTest extends GroovyTestCase {
+    
+    void testUseOfOuterVariable() {
+        
+        def x = 123
+        def y = "hello"
+        
+        def closure = { i ->
+            println("x ${x}")
+            println("y ${y}")
+            println("i ${i}")
+                
+            assert x == 123
+            assert y == 'hello'
+        }
+        closure.call(321)
+	}
+
+     /*
+     TODO: is this a valid test case?
+     void testInnerVariablesVisibleInOuterScope() {
+                
+        closure = { z = 456 } 
+        closure.call(321)
+        
+        assert z == 456
+    }
+    */
+    
+    void testModifyingOuterVariable() {
+        
+        def m = 123
+        
+        def closure = { m = 456 } 
+        closure.call(321)
+        
+        assert m == 456
+    }
+    
+    void testCounting() {
+        def sum = 0
+
+        [1, 2, 3, 4].each { sum = sum + it }
+
+        assert sum == 10
+    }
+    
+    void testExampleUseOfClosureScopes() {
+        def a = 123
+        def b
+        def c = { b = a + it }
+        c(5)
+        
+        println(b)
+        assert b == a + 5
+    }    
+
+    void testExampleUseOfClosureScopesUsingEach() {
+        def a = 123
+        def b
+        [5].each { b = a + it }
+
+        assert b == a + 5
+    }
+}
diff --git a/groovy-core/src/test/groovy/ClosureWithDefaultParamTest.groovy b/groovy-core/src/test/groovy/ClosureWithDefaultParamTest.groovy
new file mode 100644
index 0000000..17bee11
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureWithDefaultParamTest.groovy
@@ -0,0 +1,160 @@
+import java.io.File
+
+/** 
+ * Demonstrates the use of the default named parameter in a closure
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class ClosureWithDefaultParamTest extends GroovyTestCase {
+
+    void methodWithDefaultParam(example='default'){
+        assert 'default' == example
+    }
+
+    void testListCollect() {
+        def list = [1, 2, 3, 4]
+        def answer = list.collect { it * 2 }
+
+        assert answer.size() == 4
+        
+        def expected = [2, 4, 6, 8]
+        assert answer == expected
+    }
+
+    void testMapCollect() {
+        def map = [1:2, 2:4, 3:6, 4:8]
+        def answer = map.collect { it.key + it.value }
+		
+		// lest sort the results since maps are in hash code order
+		answer = answer.sort()
+		
+        assert answer.size() == 4
+        assert answer == [3, 6, 9, 12]
+        assert answer.get(0) == 3
+        assert answer.get(1) == 6
+        assert answer.get(2) == 9
+        assert answer.get(3) == 12
+    }
+
+    void testListFind() {
+        def list = ["a", "b", "c"]
+        def answer = list.find {it == "b" }
+        assert answer == "b"
+        
+        answer = list.find {it == "z" }
+        assert answer == null
+    }
+    
+    void testMapFind() {
+        def map = [1:2, 2:4, 3:6, 4:8]
+        def answer = map.find {it.value == 6 }
+        assert answer != null
+        assert answer.key == 3
+        assert answer.value == 6
+        
+        answer = map.find {it.value == 0 }
+        assert answer == null
+    }
+
+    void testListFindAll() {
+        def list = [20, 5, 40, 2]
+        def answer = list.findAll {it < 10 }
+
+        assert answer.size() == 2
+        assert answer == [5, 2]
+    }
+    
+    void testMapFindAll() {
+        def map = [1:2, 2:4, 3:6, 4:8]
+        def answer = map.findAll {it.value > 5 }
+
+        assert answer.size() == 2
+        
+        def keys = answer.collect {it.key }
+        def values = answer.collect {it.value }
+
+        System.out.println("keys " + keys + " values " + values)
+		
+        // maps are in hash order so lets sort the results       
+        keys.sort() 
+        values.sort() 
+        
+        assert keys == [3, 4]
+        assert values == [6, 8]
+    }
+
+    void testListEach() {
+        def count = 0
+
+        def list = [1, 2, 3, 4]
+        list.each { count = count + it }
+		
+        assert count == 10
+
+        list.each { count = count + it }
+		
+        assert count == 20
+    }
+
+    void testMapEach() {
+        def count = 0
+
+        def map = [1:2, 2:4, 3:6, 4:8]
+        map.each { count = count + it.value }
+
+        assert count == 20
+    }
+    
+    void testListEvery() {
+        assert [1, 2, 3, 4].every { it < 5 }
+        assert [1, 2, 7, 4].every { it < 5 } == false
+    }
+
+    void testListAny() {
+        assert [1, 2, 3, 4].any { it < 5 }
+        assert [1, 2, 3, 4].any { it > 3 }
+        assert [1, 2, 3, 4].any { it > 5 } == false
+    }
+    
+    void testJoin() {
+        def value = [1, 2, 3].join('-')
+        assert value == "1-2-3"
+    }
+    
+    void testListReverse() {
+        def value = [1, 2, 3, 4].reverse()
+        assert value == [4, 3, 2, 1]
+    }
+    
+    void testEachLine() {
+        def file = new File("src/test/groovy/Bar.groovy")
+        
+        System.out.println("Contents of file: " + file)
+        
+        file.eachLine { println(it) }
+        
+        println("")
+    }
+    
+    void testReadLines() {
+        def file = new File("src/test/groovy/Bar.groovy")
+
+		def lines = file.readLines()
+		
+		assert lines != null
+		assert lines.size() > 0
+
+        System.out.println("File has number of lines: " + lines.size())
+    }
+    
+    void testEachFile() {
+        def file = new File("src/test/groovy")
+        
+        System.out.println("Contents of dir: " + file)
+        
+        file.eachFile { println(it.getName()) }
+        
+        println("")
+    }
+}
diff --git a/groovy-core/src/test/groovy/ClosureWithEmptyParametersTest.groovy b/groovy-core/src/test/groovy/ClosureWithEmptyParametersTest.groovy
new file mode 100644
index 0000000..7272a3f
--- /dev/null
+++ b/groovy-core/src/test/groovy/ClosureWithEmptyParametersTest.groovy
@@ -0,0 +1,19 @@
+/** 
+ * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
+ * @version $Revision$
+ */
+class ClosureWithEmptyParametersTest extends GroovyTestCase {
+
+    void testNoParams() {
+
+        def block = {-> println "hey I'm a closure!" }
+
+        println "About to call closure"
+
+        block.call()
+
+        println "Done"
+    }
+
+}
+
diff --git a/groovy-core/src/test/groovy/CollectionTest.groovy b/groovy-core/src/test/groovy/CollectionTest.groovy
new file mode 100644
index 0000000..bd6480a
--- /dev/null
+++ b/groovy-core/src/test/groovy/CollectionTest.groovy
@@ -0,0 +1,59 @@
+package groovy
+
+class CollectionTest extends GroovyTestCase {
+
+    void testUniqueOnListNoDupls() {
+    	assert [].unique() == []
+    	assert [1].unique() == [1]
+    	assert [1,2].unique() == [1,2]
+    	def a = [1,2]
+    	assert a.is(a.unique())
+    }
+
+    void testUniqueOnListOneDupl() {
+    	assert [1,1].unique() == [1]
+    	def a = [1,1]
+    	assert a.is(a.unique())
+    	assert [1,2,1].unique() == [1,2]
+    	assert [1,2,1,1].unique() == [1,2]
+    	assert [1,1,2].unique() == [1,2]
+    	assert [1,1,2,1].unique() == [1,2]
+    	assert [1,1,2,1,1].unique() == [1,2]
+    }
+
+    void testUniqueOnListTwoDupls() {
+    	assert [1,1,2,2].unique() == [1,2]
+    	def a = [1,1,2,2]
+    	assert a.is(a.unique())
+    	assert [1,2,1,2].unique() == [1,2]
+    	assert [1,2,1,1,2].unique() == [1,2]
+    	assert [1,1,2,2].unique() == [1,2]
+    	assert [1,1,2,1,2].unique() == [1,2]
+    	assert [1,1,2,2,1,1,2,2].unique() == [1,2]
+    }
+
+    void testUniqueOnOtherCollections() {
+    	def a = new HashSet([1,1])
+    	assert a.is(a.unique())
+    	assert 1 == a.size()
+    	a = new TreeSet([1,1])
+    	assert a.is(a.unique())
+    	assert 1 == a.size()
+    	a = new Vector([1,1])
+    	assert a.is(a.unique())
+    	assert 1 == a.size()
+    	a = new LinkedList([1,1])
+    	assert a.is(a.unique())
+    	assert 1 == a.size()
+    }
+
+    // todo: GROOVY-1006
+    void testUniqueOnDifferentTypes() {
+    	def a = [1, 2, (short)1, 2L, 2.0]
+    	def b = a.unique()
+    	assert (b == a && a == [1, 2])
+    	a = [Math.PI, "foo", 1.0, 2L, (short)2, 2.0F]
+    	b = a.unique()
+    	assert (b == a && a == [Math.PI, "foo", 1.0, 2L])
+    }
+}
diff --git a/groovy-core/src/test/groovy/CompareToTest.groovy b/groovy-core/src/test/groovy/CompareToTest.groovy
new file mode 100644
index 0000000..372cabc
--- /dev/null
+++ b/groovy-core/src/test/groovy/CompareToTest.groovy
@@ -0,0 +1,37 @@
+class CompareToTest extends GroovyTestCase {
+
+    void testCompareTo() {
+
+        def a = 12
+        def b = 20
+        def c = 30
+        
+        def result = a <=> b
+        assert result < 0
+
+        result = a <=> 12
+        assert result == 0
+
+        result = c <=> b
+        assert result > 0
+        
+        assert (a <=> b) < 0
+        assert a <=> 12 == 0
+        assert (c <=> b) > 0
+    }
+
+    void testNullCompares() {
+    
+    	def a = 123
+    	def b = null
+    	
+    	def result = a <=> b
+    	assert result > 0
+    	
+    	result = b <=> a
+    	assert result < 0
+    	
+    	result = b <=> null
+    	assert result == 0
+    }
+}
diff --git a/groovy-core/src/test/groovy/CompareTypesTest.groovy b/groovy-core/src/test/groovy/CompareTypesTest.groovy
new file mode 100644
index 0000000..8218b8e
--- /dev/null
+++ b/groovy-core/src/test/groovy/CompareTypesTest.groovy
@@ -0,0 +1,56 @@
+/**
+ * @version $Revision$
+ */
+class NumberTest extends GroovyTestCase { 
+    void testCompareByteToInt() { 
+        Byte a = 12
+        Integer b = 10
+        
+        assert a instanceof Byte
+        assert b instanceof Integer
+        
+        assert a > b
+    } 
+    
+    void testCompareByteToDouble() { 
+        Byte a = 12
+        Double b = 10
+        
+        assert a instanceof Byte
+        assert b instanceof Double
+        
+        assert a > b
+    } 
+     
+    void testCompareLongToDouble() { 
+        Long a = 12
+        Double b = 10
+        
+        assert a instanceof Long
+        assert b instanceof Double
+        
+        assert a > b
+    } 
+     
+    void testCompareLongToByte() { 
+        Long a = 12
+        Byte b = 10
+        
+        assert a instanceof Long
+        assert b instanceof Byte
+        
+        assert a > b
+    } 
+     
+    void testCompareIntegerToByte() { 
+        Integer a = 12
+        Byte b = 10
+        
+        assert a instanceof Integer
+        assert b instanceof Byte
+        
+        assert a > b
+    } 
+} 
+
+
diff --git a/groovy-core/src/test/groovy/CompilerErrorTest.groovy b/groovy-core/src/test/groovy/CompilerErrorTest.groovy
new file mode 100644
index 0000000..132a86c
--- /dev/null
+++ b/groovy-core/src/test/groovy/CompilerErrorTest.groovy
@@ -0,0 +1,37 @@
+class CompilerErrorTest extends GroovyTestCase {
+
+    void testBadMethodName() {
+
+        shouldFail {
+            println "About to call shell script"
+            println "Really am about to call shell script"
+
+            def shell = new GroovyShell()
+            def text = 'badMethod(); println "Called method"'
+            println "About to test script ${text}"
+            shell.evaluate(text)
+        }
+    }
+
+    void testBadPropertyName() {
+
+        shouldFail {
+            def shell = new GroovyShell()
+            shell.evaluate """
+                def x = [:]
+                x.\$foo = 123
+            """
+        }
+    }
+
+    void testBadVariableName() {
+
+        shouldFail {
+            def shell = new GroovyShell()
+            shell.evaluate """
+                def \$x = 123
+            """
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/Constructor2Test.groovy b/groovy-core/src/test/groovy/Constructor2Test.groovy
new file mode 100644
index 0000000..a455769
--- /dev/null
+++ b/groovy-core/src/test/groovy/Constructor2Test.groovy
@@ -0,0 +1,13 @@
+class Constructor2Test extends GroovyTestCase {
+
+    Constructor2Test() {
+        println "Hey"
+    }
+
+    void testConstructor() {
+        def foo = new Constructor2Test()
+        assert foo != null
+        println foo
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/ConstructorTest.groovy b/groovy-core/src/test/groovy/ConstructorTest.groovy
new file mode 100644
index 0000000..09faa84
--- /dev/null
+++ b/groovy-core/src/test/groovy/ConstructorTest.groovy
@@ -0,0 +1,13 @@
+class ConstructorTest extends GroovyTestCase {
+
+    public ConstructorTest() {
+        println "Hey"
+    }
+
+    public void testConstructor() {
+        def foo = new ConstructorTest()
+        assert foo != null
+        println foo
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/CurlyBracketLayoutTest.groovy b/groovy-core/src/test/groovy/CurlyBracketLayoutTest.groovy
new file mode 100644
index 0000000..aabc5f0
--- /dev/null
+++ b/groovy-core/src/test/groovy/CurlyBracketLayoutTest.groovy
@@ -0,0 +1,22 @@
+class CurlyBracketLayoutTest extends GroovyTestCase
+{
+    void testBracketPlacement()
+    {
+        def foo = "abc"
+
+        if (foo.contains("b"))
+        {
+            println "Worked a treat. foo = $foo"
+        }
+        else
+        {
+            fail("Should have found 'b' inside $foo")
+        }
+
+        def list = [1, 2, 3]
+        list.each
+        {
+            println it
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/DateTest.groovy b/groovy-core/src/test/groovy/DateTest.groovy
new file mode 100644
index 0000000..e7cb532
--- /dev/null
+++ b/groovy-core/src/test/groovy/DateTest.groovy
@@ -0,0 +1,33 @@
+import java.util.Date
+
+class DateTest extends GroovyTestCase {
+  
+    void testNextPrevious() {
+        def x = new Date()
+        def y = x + 2
+        
+        assert x < y
+        ++x
+        --y
+        
+        assert x == y
+        x += 2
+        assert x > y
+        
+        println "have dates ${x} and ${y}"
+    }
+    
+    void testDateRange() {
+        
+        def today = new Date()
+        def later = today + 3
+        
+        def expected = [today, today + 1, today + 2, today + 3]
+        
+        def list = []
+        for (d in today..later) {
+            list << d
+        }
+        assert list == expected
+    }
+}
diff --git a/groovy-core/src/test/groovy/DefaultParamClosureTest.groovy b/groovy-core/src/test/groovy/DefaultParamClosureTest.groovy
new file mode 100644
index 0000000..d4e71da
--- /dev/null
+++ b/groovy-core/src/test/groovy/DefaultParamClosureTest.groovy
@@ -0,0 +1,42 @@
+class DefaultParamClosureTest extends GroovyTestCase {
+
+    void testDefaultParameters() {
+        // Default parameters working for closures 
+	def doSomething = { a, b = 'defB', c = 'defC' ->
+			println "Called with a: ${a}, b ${b}, c ${c}"
+			return a + "-" + b + "-" + c
+		}
+
+    	def value = doSomething("X", "Y", "Z")
+    	assert value == "X-Y-Z"
+
+    	value = doSomething("X", "Y")
+    	assert value == "X-Y-defC"
+
+    	value = doSomething("X")
+    	assert value == "X-defB-defC"
+
+    	shouldFail { doSomething() }
+    }
+
+    void testDefaultTypedParameters() {
+	// Handle typed parameters
+	def doTypedSomething = { String a = 'defA', String b = 'defB', String c = 'defC' ->
+			println "Called typed method with a: ${a}, b ${b}, c ${c}"
+			return a + "-" + b + "-" + c
+		}
+	
+    	def value = doTypedSomething("X", "Y", "Z")
+    	assert value == "X-Y-Z"
+    	
+    	value = doTypedSomething("X", "Y")
+    	assert value == "X-Y-defC"
+    	
+    	value = doTypedSomething("X")
+    	assert value == "X-defB-defC"
+    	
+    	value = doTypedSomething()
+    	assert value == "defA-defB-defC"
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/DefaultParamTest.groovy b/groovy-core/src/test/groovy/DefaultParamTest.groovy
new file mode 100644
index 0000000..d3e2fe7
--- /dev/null
+++ b/groovy-core/src/test/groovy/DefaultParamTest.groovy
@@ -0,0 +1,75 @@
+class DefaultParamTest extends GroovyTestCase {
+
+    void testDefaultParameters() {
+    
+    	def value = doSomething("X", "Y", "Z")
+    	assert value == "X-Y-Z"
+    	
+    	value = doSomething("X", "Y")
+    	assert value == "X-Y-defC"
+    	
+    	value = doSomething("X")
+    	assert value == "X-defB-defC"
+    	
+    	shouldFail { doSomething() }
+    }
+
+    void testDefaultTypedParameters() {
+    	def value = doTypedSomething("X", "Y", "Z")
+    	assert value == "X-Y-Z"
+    	
+    	value = doTypedSomething("X", "Y")
+    	assert value == "X-Y-defC"
+    	
+    	value = doTypedSomething("X")
+    	assert value == "X-defB-defC"
+    	
+    	value = doTypedSomething()
+    	assert value == "defA-defB-defC"
+    }
+
+    void testDefaultTypedParametersAnother() {
+    	def value = doTypedSomethingAnother("X", "Y", "Z")
+    	assert value == "X-Y-Z"
+    	
+    	value = doTypedSomethingAnother("X", "Z")
+    	assert value == "X-defB-Z"
+    	
+    	value = doTypedSomethingAnother("Z")
+    	assert value == "defA-defB-Z"
+    	
+    	shouldFail{ value = doTypedSomethingAnother() }
+    }
+
+
+    def doSomething(a, b = 'defB', c = 'defC') {
+        println "Called with a: ${a}, b ${b}, c ${c}"
+
+        return a + "-" + b + "-" + c
+    }
+
+    String doTypedSomething(String a = 'defA', String b = 'defB', String c = 'defC') {
+        println "Called typed method with a: ${a}, b ${b}, c ${c}"
+
+        return a + "-" + b + "-" + c
+    }
+
+    String doTypedSomethingAnother(String a = 'defA', String b = 'defB', String c) {
+        println "Called typed method with a: ${a}, b ${b}, c ${c}"
+
+        return a + "-" + b + "-" + c
+    }
+    
+    void testConstructor() {
+        assert DefaultParamTestTestClass.declaredConstructors.size() == 2
+        def foo = new DefaultParamTestTestClass()
+        assert foo.j == 1
+        foo = new DefaultParamTestTestClass(2)
+        assert foo.j == 2
+    }
+}
+
+class DefaultParamTestTestClass {
+  def j
+  DefaultParamTestTestClass(int i = 1){j=i}
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/DoWhileLoopTest.groovy b/groovy-core/src/test/groovy/DoWhileLoopTest.groovy
new file mode 100644
index 0000000..30efb93
--- /dev/null
+++ b/groovy-core/src/test/groovy/DoWhileLoopTest.groovy
@@ -0,0 +1,22 @@
+class DoWhileLoopTest extends GroovyTestCase {
+
+    void testDoWhileWhile() {
+
+    /**
+
+      We currently do not support do ... while in the JSR syntax
+
+        def x = 0
+        def y = 5
+
+        do {
+            x = x + 1
+            y = y - 1
+        }
+        while ( y > 0 )
+
+        assert x == 5
+    */
+            
+    }
+}
diff --git a/groovy-core/src/test/groovy/DollarEscapingTest.groovy b/groovy-core/src/test/groovy/DollarEscapingTest.groovy
new file mode 100644
index 0000000..076fe82
--- /dev/null
+++ b/groovy-core/src/test/groovy/DollarEscapingTest.groovy
@@ -0,0 +1,12 @@
+class DollarEscapingTest extends GroovyTestCase {
+
+    void testEscaping() {
+        def foo = "hello \${foo}"
+        
+        assert foo instanceof String
+        
+        def c = foo.count('$')
+        
+        assert c == 1 , foo
+    }
+}
diff --git a/groovy-core/src/test/groovy/DoubleOperationTest.groovy b/groovy-core/src/test/groovy/DoubleOperationTest.groovy
new file mode 100644
index 0000000..5b84585
--- /dev/null
+++ b/groovy-core/src/test/groovy/DoubleOperationTest.groovy
@@ -0,0 +1,80 @@
+class DoubleOperationTest extends GroovyTestCase {
+
+    def x
+    def y
+    
+    void testPlus() {
+        x = 2.1 + 2.1
+        assert x == 4.2
+        
+        x = 3 + 2.2
+        assert x == 5.2
+        
+        x = 2.2 + 4
+        assert x == 6.2
+        
+        y = x + 1
+        assert y == 7.2       
+        	
+        def z = y + x + 1 + 2
+        assert z == 16.4
+    }
+    
+    void testMinus() {
+        x = 6 - 2.2
+        assert x == 3.8
+        
+        x = 5.8 - 2
+        assert x == 3.8
+        
+        y = x - 1
+		assert y == 2.8        
+    }
+    
+    void testMultiply() {
+        x = 3 * 2.0
+        assert x == 6.0
+        
+        x = 3.0 * 2
+        assert x == 6.0
+        
+        x = 3.0 * 2.0
+        assert x == 6.0
+        y = x * 2
+        assert y == 12.0        
+    }
+    
+    void testDivide() {
+        x = 80.0 / 4
+        assert x == 20.0 , "x = " + x
+        
+        x = 80 / 4.0
+        assert x == 20.0 , "x = " + x
+        
+        y = x / 2
+        assert y == 10.0 , "y = " + y     
+    }
+
+    void testMethodNotFound() {
+    	try {
+    		println( Math.sin("foo", 7) );
+	    	fail("Should catch a MissingMethodException");
+    	} catch (MissingMethodException mme) {
+    	}
+    }
+        
+    void testCoerce() {
+    	def xyz = Math.sin(1.1);
+    	assert xyz instanceof Double;
+    	assert xyz == Math.sin(1.1D);
+    	
+        //Note that (7.3F).doubleValue() != 7.3D
+    	x = Math.sin(7.3F);
+    	assert x instanceof Double;
+    	assert x == Math.sin((7.3F).doubleValue());
+
+    	x = Math.sin(7);
+    	assert x instanceof Double;
+    	assert x == Math.sin(7.0D);
+    }
+}
diff --git a/groovy-core/src/test/groovy/DownUpStepTest.groovy b/groovy-core/src/test/groovy/DownUpStepTest.groovy
new file mode 100644
index 0000000..e1c7fe8
--- /dev/null
+++ b/groovy-core/src/test/groovy/DownUpStepTest.groovy
@@ -0,0 +1,33 @@
+public class DownUpStepTest extends GroovyTestCase {
+
+    void testDownto() {
+        def z = []
+        (10.5).downto(5.9) { z << it }
+        assertEquals( [10.5, 9.5, 8.5, 7.5, 6.5], z)
+    }
+
+    void testBigIntegerDowntoBigDecimal() {
+        def z = []
+        10G.downto(5.9G) { z << it }
+        assertEquals( [10G, 9G, 8G, 7G, 6G], z)
+    }
+
+    void testUpto() {
+        def z = 0.0
+        (3.1).upto(7.2) { z += it }
+        assert z == 3.1 + 4.1 + 5.1 + 6.1 + 7.1
+        assert z == 25.5
+    }
+
+    void testStep() {
+        def z = 0.0
+        (1.2).step(3.9, 0.1) { z += it }
+        assert z == 67.5
+    }
+
+    void testDownStep() {
+        def z = 0.0
+        (3.8).step(1.1, -0.1) { z += it }
+        assert z == 67.5
+    }
+}
diff --git a/groovy-core/src/test/groovy/DummyInterface.java b/groovy-core/src/test/groovy/DummyInterface.java
new file mode 100644
index 0000000..969ddc8
--- /dev/null
+++ b/groovy-core/src/test/groovy/DummyInterface.java
@@ -0,0 +1,6 @@
+package groovy;
+
+public interface DummyInterface {
+
+    public void methodWithArrayParam(String[] args);
+}
diff --git a/groovy-core/src/test/groovy/DummyMethods.groovy b/groovy-core/src/test/groovy/DummyMethods.groovy
new file mode 100644
index 0000000..839f2a2
--- /dev/null
+++ b/groovy-core/src/test/groovy/DummyMethods.groovy
@@ -0,0 +1,25 @@
+/**
+ * methods with specific parameters (e.g. primitives)
+ * for use with groovy tests
+ *
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+ 
+package groovy;
+
+public class DummyMethods {
+    public static void main(String[] args) {
+        DummyMethods tmp = new DummyMethods();
+        String answer = tmp.foo("Hey", 1, 2);
+        System.out.println("Answer: " + answer);
+    }
+
+    public String foo(String a, float b, float c) {
+    	return "float args";
+    }
+
+    public String foo(String a, int b, int c) {
+    	return "int args";
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/DummyMethods.java b/groovy-core/src/test/groovy/DummyMethods.java
new file mode 100644
index 0000000..8c49769
--- /dev/null
+++ b/groovy-core/src/test/groovy/DummyMethods.java
@@ -0,0 +1,17 @@
+/**
+ * methods with specific parameters (e.g. primitives)
+ * for use with groovy tests
+ * 
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+package groovy;
+
+public class DummyMethods {
+    public String foo(String a, float b, float c) {
+    	return "float args";
+    }
+    public String foo(String a, int b, int c) {
+    	return "int args";
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/DynamicMemberTest.groovy b/groovy-core/src/test/groovy/DynamicMemberTest.groovy
new file mode 100644
index 0000000..873cd24
--- /dev/null
+++ b/groovy-core/src/test/groovy/DynamicMemberTest.groovy
@@ -0,0 +1,40 @@
+
+class DynamicMemberTest extends GroovyTestCase {
+  def aTestMethod(o){o}
+  def aProperty
+  
+  public void testGStringMethodCall(){
+    def name = "aTestMethod"
+    assert this."$name"(1) == 1
+    assert this."${name}"(2) == 2
+    assert "$name"(3) == 3
+    assert "${name}"(4) == 4
+    name = "TestMethod"
+    assert this.("a"+"TestMethod")(5) == 5
+    assert this.("a"+name)(6) == 6
+  }
+  
+  public void testGStringPropertyAccess(){
+    def name = "aProperty"
+    this.aProperty = "foo"
+    assert this."$name" == "foo"
+    assert this."${name}" == "foo"
+    assert "$name" == "aProperty"
+    assert "${name}" == "aProperty"
+  }
+  
+  public void testStringMethodCallAndAttributeAccess() {
+    this.aProperty = "String"
+    assert this."aProperty" == "String"
+    assert this."aTestMethod"("String") == "String"
+    assert "aTestMethod"("String") == "String"
+  }
+  
+  public void testDynamicAttributeAccess() {
+    this.aProperty = "tada"
+    def name = "aProperty"
+    assert this.@"$name" == "tada"
+    assert this.@"${name}" == "tada"
+  }
+  
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/EscapedUnicodeTest.groovy b/groovy-core/src/test/groovy/EscapedUnicodeTest.groovy
new file mode 100644
index 0000000..5b0c8a4
--- /dev/null
+++ b/groovy-core/src/test/groovy/EscapedUnicodeTest.groovy
@@ -0,0 +1,26 @@
+\u0063\u006c\u0061\u0073\u0073\u0020\u0045\u0073\u0063\u0061\u0070\u0065\u0064\u0055\u006e\u0069\u0063\u006f\u0064\u0065\u0054\u0065\u0073\u0074\u0020\u0065\u0078\u0074\u0065\u006e\u0064\u0073\u0020\u0047\u0072\u006f\u006f\u0076\u0079\u0054\u0065\u0073\u0074\u0043\u0061\u0073\u0065\u0020\u007b
+
+\u0020\u0020\u0020\u0020\u0076\u006f\u0069\u0064\u0020\u0074\u0065\u0073\u0074\u0041\u0073\u0073\u0065\u0072\u0074\u0028\u0029\u0020\u007b
+\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0064\u0065\u0066\u0020\u0078\u0020\u003d\u0020\u0022\u0061\u0062\u0063\u0022
+
+\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0061\u0073\u0073\u0065\u0072\u0074\u0020\u0078\u0020\u0021\u003d\u0020\u0022\u0066\u006f\u006f\u0022
+\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0061\u0073\u0073\u0065\u0072\u0074\u0020\u0078\u0020\u0021\u003d\u0020\u0020\u006e\u0075\u006c\u006c
+\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0061\u0073\u0073\u0065\u0072\u0074\u0020\u0078\u0020\u0021\u003d\u0020\u0022\u0064\u0065\u0066\u0022
+\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0061\u0073\u0073\u0065\u0072\u0074\u0020\u0078\u0020\u003d\u003d\u0020\u0022\u0061\u0062\u0063\u0022
+\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020
+\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0061\u0073\u0073\u0065\u0072\u0074\u0020\u0078\u002e\u0065\u0071\u0075\u0061\u006c\u0073\u0028\u0022\u0061\u0062\u0063\u0022\u0029
+\u0009\u007d
+\u0020\u0020\u0020\u0020
+\u0020\u0020\u0020\u0020\u0076\u006f\u0069\u0064\u0020\u0074\u0065\u0073\u0074\u0055\u006e\u006b\u006e\u006f\u0077\u006e\u0056\u0061\u0072\u0069\u0061\u0062\u006c\u0065\u0028\u0029\u0020\u007b
+\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0074\u0072\u0079\u0020\u007b
+\u0009\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0064\u0065\u0066\u0020\u0079\u0020\u003d\u0020\u0074\u0068\u0069\u0073\u002e\u0078
+\u0009\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0066\u0061\u0069\u006c\u0028\u0022\u0078\u0020\u0069\u0073\u0020\u0075\u006e\u0064\u0065\u0066\u0069\u006e\u0065\u0064\u002c\u0020\u0073\u0068\u006f\u0075\u006c\u0064\u0020\u0074\u0068\u0072\u006f\u0077\u0020\u0061\u006e\u0020\u0065\u0078\u0063\u0065\u0070\u0074\u0069\u006f\u006e\u0022\u0029
+\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u007d
+\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0063\u0061\u0074\u0063\u0068\u0020\u0028\u004d\u0069\u0073\u0073\u0069\u006e\u0067\u0050\u0072\u006f\u0070\u0065\u0072\u0074\u0079\u0045\u0078\u0063\u0065\u0070\u0074\u0069\u006f\u006e\u0020\u0065\u0029\u0020\u007b
+\u0009\u0009\u0009\u0061\u0073\u0073\u0065\u0072\u0074\u0020\u0065\u002e\u0067\u0065\u0074\u0050\u0072\u006f\u0070\u0065\u0072\u0074\u0079\u0028\u0029\u0020\u003d\u003d\u0020\u0022\u0078\u0022\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020
+\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0064\u0065\u0066\u0020\u0074\u0065\u0078\u0074\u0020\u003d\u0020\u0065\u002e\u006d\u0065\u0073\u0073\u0061\u0067\u0065
+\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0061\u0073\u0073\u0065\u0072\u0074\u0020\u0074\u0065\u0078\u0074\u0020\u003d\u003d\u0020\u0022\u004e\u006f\u0020\u0073\u0075\u0063\u0068\u0020\u0070\u0072\u006f\u0070\u0065\u0072\u0074\u0079\u003a\u0020\u0078\u0020\u0066\u006f\u0072\u0020\u0063\u006c\u0061\u0073\u0073\u003a\u0020\u0045\u0073\u0063\u0061\u0070\u0065\u0064\u0055\u006e\u0069\u0063\u006f\u0064\u0065\u0054\u0065\u0073\u0074\u0022
+\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\u007d
+\u0020\u0020\u0020\u0020\u007d
+\u0009\u0020\u0020\u0020\u0020
+\u007d
diff --git a/groovy-core/src/test/groovy/ExceptionInClosureTest.groovy b/groovy-core/src/test/groovy/ExceptionInClosureTest.groovy
new file mode 100644
index 0000000..136b629
--- /dev/null
+++ b/groovy-core/src/test/groovy/ExceptionInClosureTest.groovy
@@ -0,0 +1,24 @@
+/** 
+ * Tests exception handling inside of a closure
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class ExceptionInClosureTest extends GroovyTestCase {
+
+    void testCallingOfFailedClosure() {
+        def closure = { it -> it.foo() }
+        
+        try {
+	        closure.call("cheese")
+	        
+	        fail("Should have thrown an exception by now")
+        }
+        catch (MissingMethodException e) {
+   			System.out.println("Caught: " + e)    
+   			
+   			assert e.method == "foo"
+			assert e.type == String   			
+        }
+    }
+}
diff --git a/groovy-core/src/test/groovy/ExecuteTest_LinuxSolaris.groovy b/groovy-core/src/test/groovy/ExecuteTest_LinuxSolaris.groovy
new file mode 100644
index 0000000..20c6207
--- /dev/null
+++ b/groovy-core/src/test/groovy/ExecuteTest_LinuxSolaris.groovy
@@ -0,0 +1,57 @@
+#! /usr/bin/env groovy 
+
+import java.io.IOException
+
+/**
+ *  Test to ensure that the execute mechanism works fine on Linux and Solaris.  For these OSs we
+ *  can effectively guarantee the existance of some programs that we can run.  Assume the search
+ *  path is partway reasonable so we can access sh and echo.
+ *
+ *  <p>These test are a bit trivial but at least they are here :-)</p>
+ *
+ *  @author Russel Winder
+ *  @version $Revision$
+ */
+class ExecuteTest_LinuxSolaris extends GroovyTestCase {
+  void testShellEchoOneArray ( ) {
+    def process = ( [ "sh" , "-c" , "echo 1" ] as String[] ).execute ( )
+    process.waitFor ( )
+    assert process.in.getText ( ).trim ( ) == "1"
+  }
+  void testShellEchoOneList ( ) {
+    def process = [ "sh" , "-c" , "echo 1" ].execute ( )
+    process.waitFor ( )
+    assert process.in.getText ( ).trim ( ) == "1"
+  }
+  void testEchoOneArray ( ) {
+    try {
+      def process = ( [ "echo 1" ] as String[] ).execute ( )
+      process.waitFor ( )
+       fail ( "Should have thrown java.io.IOException: echo 1: not found" )
+    }
+    catch ( IOException ioe ) { }
+  }
+  void testEchoOneList ( ) {
+    try {
+      def process = [ "echo 1" ].execute ( )
+      process.waitFor ( )
+       fail ( "Should have thrown java.io.IOException: echo 1: not found" )
+    }
+    catch ( IOException ioe ) { }
+  }
+  void testEchoOneScalar ( ) {
+    def process = "echo 1".execute ( )
+    process.waitFor ( )
+    assert process.in.getText ( ).trim ( ) == "1"
+  }
+  void testEchoArray ( ) {
+    def process = ( [ "echo" , "1" ] as String[] ).execute ( )
+    process.waitFor ( )
+    assert process.in.getText ( ).trim ( ) == "1"
+   }
+  void testEchoList ( ) {
+    def process = [ "echo" , "1" ].execute ( )
+    process.waitFor ( )
+    assert process.in.getText ( ).trim ( ) == "1"
+   }
+}
diff --git a/groovy-core/src/test/groovy/ExpandoPropertyTest.groovy b/groovy-core/src/test/groovy/ExpandoPropertyTest.groovy
new file mode 100644
index 0000000..aa87890
--- /dev/null
+++ b/groovy-core/src/test/groovy/ExpandoPropertyTest.groovy
@@ -0,0 +1,98 @@
+class ExpandoPropertyTest extends GroovyTestCase {
+
+    void testExpandoProperty() {
+        def foo = new Expando()
+        
+        foo.cheese = "Cheddar"
+        foo.name = "Gromit"
+        
+        assert foo.cheese == "Cheddar"
+        assert foo.name == "Gromit"
+        
+        assert foo.properties.size() == 2
+    }
+    
+    void testExpandoMethods() {
+        def foo = new Expando()
+
+        foo.cheese = "Cheddar"
+        foo.fullName = "Gromit"
+        foo.nameLength = { return fullName.length() }
+        foo.multiParam = { a, b, c -> println("Called with ${a}, ${b}, ${c}"); return a + b + c }
+
+        assert foo.cheese == "Cheddar"
+        assert foo.fullName == "Gromit"
+        assert foo.nameLength() == 6 , foo.nameLength()
+        assert foo.multiParam(1, 2, 3) == 6
+        
+        // lets test using wrong number of parameters
+        shouldFail { foo.multiParam(1) }
+        shouldFail { foo.nameLength(1, 2) }
+    }
+    
+    void testExpandoConstructorAndToString() {
+        def foo = new Expando(type:"sometype", value:42)
+        println foo
+        assert foo.toString() == "{type=sometype, value=42}"
+        assert "${foo}" == "{type=sometype, value=42}"
+    }
+
+    void testExpandoMethodOverrides() {
+        def equals = { Object obj -> return obj.value == value }
+        def foo = new Expando(type:"myfoo", value:42, equals:equals)
+        def bar = new Expando(type:"mybar", value:43, equals:equals)
+        def zap = new Expando(type:"myzap", value:42, equals:equals)
+        println(foo)
+	
+        assert foo.equals(bar) == false
+        assert foo.equals(zap) == true
+	
+        def list = []
+        list << foo
+        list << bar
+        println list
+	
+        assert list.contains(foo) == true
+        assert list.contains(bar) == true
+        assert list.contains(zap) == true
+        assert list.indexOf(bar) == 1
+        assert list.indexOf(foo) == 0
+	
+        println "hashCode: " + foo.hashCode()
+	
+        foo.hashCode = { return value }
+        println("hashCode: " + foo.hashCode())
+	
+        assert foo.hashCode() == foo.value
+        println("toString: " + foo.toString())
+	
+        foo.toString = { return "Type: ${type}, Value: ${value}" }
+        println("toString: " + foo.toString())
+        assert foo.toString() == "Type: myfoo, Value: 42"
+    }
+    
+    void testArrayAccessOnThis() {
+        def a = new FancyExpando([a:1,b:2])
+        a.update([b:5,a:2])
+        
+        assert a.a == 2
+        assert a.b == 5
+    }
+    
+    void testExpandoClassProperty() {
+        def e = new Expando()
+        e.class = "hello world"
+        
+        assert e.class == "hello world"
+    }
+}
+
+class FancyExpando extends Expando {
+ FancyExpando(args) { super(args) }
+ 
+ def update(args) {
+   for (e in args) this[e.key] = e.value // using 'this'
+ }
+ 
+ String toString() { dump() }
+}
diff --git a/groovy-core/src/test/groovy/FilterLineTest.groovy b/groovy-core/src/test/groovy/FilterLineTest.groovy
new file mode 100644
index 0000000..877d8d2
--- /dev/null
+++ b/groovy-core/src/test/groovy/FilterLineTest.groovy
@@ -0,0 +1,44 @@
+/**
+ * check that the new filterLine() method on InputStream is ok
+ * (and indirectly test newReader() method on InputStream)
+ * as specified in GROOVY-624 and GROOVY-625
+ *
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+import java.io.*
+
+class FilterLineTest extends GroovyTestCase {
+	def myFile
+	def myInput
+	def myOutput
+
+	void setUp() {
+	    myFile = new File("src/test/groovy/FilterLineTest.groovy")
+		myInput = new FileInputStream(myFile)
+		myOutput = new CharArrayWriter()
+	}
+
+	void testFilterLineOnFileReturningAWritable() {
+		def writable = myFile.filterLine() {it.contains("testFilterLineOnFileReturningAWritable")}
+		writable.writeTo(myOutput)
+		assert 3 == myOutput.toString().count("testFilterLineOnFileReturningAWritable")
+	}
+
+	void testFilterLineOnFileUsingAnOutputStream() {
+		myFile.filterLine(myOutput) {it.contains("testFilterLineOnFileUsingAnOutputStream")}
+		assert 3 == myOutput.toString().count("testFilterLineOnFileUsingAnOutputStream")
+	}
+
+	void testFilterLineOnInputStreamReturningAWritable() {
+		def writable = myInput.filterLine() {it.contains("testFilterLineOnInputStreamReturningAWritable")}
+		writable.writeTo(myOutput)
+		assert 3 == myOutput.toString().count("testFilterLineOnInputStreamReturningAWritable")
+	}
+
+	void testFilterLineOnInputStreamUsingAnOutputStream() {
+		myInput.filterLine(myOutput) {it.contains("testFilterLineOnInputStreamUsingAnOutputStream")}
+		assert 3 == myOutput.toString().count("testFilterLineOnInputStreamUsingAnOutputStream")
+	}
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/FinallyTest.groovy b/groovy-core/src/test/groovy/FinallyTest.groovy
new file mode 100644
index 0000000..7eca2a3
--- /dev/null
+++ b/groovy-core/src/test/groovy/FinallyTest.groovy
@@ -0,0 +1,117 @@
+class FinallyTest extends GroovyTestCase{

+ 

+  void testBreakInTry() {

+    def called = false

+    while (true){

+      try {

+        break

+      } finally {

+        called = true

+      }

+    }

+    assert called, "finally block was not called"

+  }

+  

+  void testBreakInFinally() {

+    def called = false

+    while (true){

+      try {

+        throw new Exception("foo")

+      } catch (e) {

+        assert e.message == "foo"

+      } finally {

+        called = true

+        break

+      }

+    }

+    assert called, "finally block was not called"

+  }

+  

+  void testContinueInTry() {

+    def called = false

+    boolean b = true

+    while (b){

+      try {

+        b=false

+        continue

+      } finally {

+        called = true

+      }

+    }

+    assert called, "finally block was not called"

+  }

+  

+  void testContinueInFinally() {

+    def called = false

+    boolean b = true

+    while (b){

+      try {

+        throw new Exception("foo")

+      } catch (e) {

+        assert e.message == "foo"

+      } finally {

+        b=false

+        called = true

+        continue

+      }

+    }

+    assert called, "finally block was not called"

+  }

+  

+  void testReturn() {

+    def map = methodWithReturnInTry()

+    assert map.called, "finally block was not called"

+    def called = methodWithReturnInFinally()

+    assert called, "finally block was not called"

+  }

+  

+  def methodWithReturnInTry(){

+    def map = [:]

+    try {

+      return map

+    } finally {

+	  map.called = true

+    }

+  }

+  

+  def methodWithReturnInFinally(){

+    try {

+      return false

+    } finally {

+	  return true

+    }

+  }

+  

+  void testStackeFinally(){

+    def calls = methodWithStackedFinally()

+    if (calls==12) {

+      assert false,"wrong order of finally blocks"

+    }

+    assert calls==102 

+  }

+

+  def methodWithStackedFinally(){

+    def calls = 0

+    def first = true;

+    try {

+      try {

+        calls = 0

+      } finally {

+        calls++

+        if (first) {

+          first = false

+        } else {

+          calls += 10

+        }

+      }

+    } finally {

+      calls++

+      if (first) {

+        first = false

+      } else {

+        calls += 100

+      }

+    }

+    return calls

+  }

+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/Foo.groovy b/groovy-core/src/test/groovy/Foo.groovy
new file mode 100644
index 0000000..9373556
--- /dev/null
+++ b/groovy-core/src/test/groovy/Foo.groovy
@@ -0,0 +1,54 @@
+import java.io.Serializable
+
+/** 
+ * A dummy bean for testing the use of properties in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class Foo implements Serializable {
+
+    // public properties
+    def name = "James"
+    def count
+    String location = "London"
+    
+    // declare private variables
+    private blah = 9
+    private invisible = "invisible"
+
+    // declare a protected variable
+    protected prot = "hide me!"
+
+    // declare a bean with explicit typing
+    private String body
+
+    static void main(args) {
+        def f = new Foo()
+        println f
+    }
+    
+    // provide a getter method
+    def getCount() {
+         if (count == null) {
+             count = 1
+         }
+         return count
+    }
+     
+    def getBlah() {
+         return blah
+    }
+
+    public String getBody() {
+        return this.body
+    }
+
+    public void setBody(String body) {
+        this.body = body
+    }
+
+    String toString() {
+        return super.toString() + " name: ${name} location: ${location}"
+    }
+}
diff --git a/groovy-core/src/test/groovy/ForLoopTest.groovy b/groovy-core/src/test/groovy/ForLoopTest.groovy
new file mode 100644
index 0000000..56b38e7
--- /dev/null
+++ b/groovy-core/src/test/groovy/ForLoopTest.groovy
@@ -0,0 +1,113 @@
+import groovy.bugs.TestSupport
+
+import java.util.Vector
+
+class ForLoopTest extends GroovyTestCase {
+
+    def x
+	
+    void testRange() {
+        x = 0
+
+        for ( i in 0..9 ) {
+            x = x + i
+        }
+
+        assert x == 45
+    }
+
+    void testRangeWithType() {
+        x = 0
+
+        for ( Integer i in 0..9 ) {
+            assert i.getClass() == Integer
+            x = x + i
+        }
+
+        assert x == 45
+    }
+
+    /** TODO - no longer applicable?
+
+    void testRangeWithJdk15Style() {
+        x = 0
+
+        for ( i : 0..9 ) {
+            x = x + i
+        }
+
+        assert x == 45
+	}
+	
+	void testRangeWithJdk15StyleAndType() {
+        x = 0
+
+        for ( Integer i : 0..9 ) {
+            assert i.getClass() == Integer
+            x = x + i
+        }
+
+        assert x == 45
+    }
+    */
+	
+    void testList() {
+        x = 0
+		
+        for ( i in [0, 1, 2, 3, 4] ) {
+            x = x + i
+        }
+
+        assert x == 10
+    }
+
+    void testArray() {
+        def array = (0..4).toArray()
+        
+        println "Class: ${array.getClass()} for array ${array}"
+        
+        x = 0
+        
+        for ( i in array ) {
+            x = x + i
+        }
+
+        assert x == 10
+    }
+    
+    void testIntArray() {
+        def array = TestSupport.getIntArray()
+        
+        println "Class: ${array.getClass()} for array ${array}"
+        
+        x = 0
+        
+        for ( i in array ) {
+            x = x + i
+        }
+
+        assert x == 15
+    }
+    
+    void testString() {
+        def text = "abc"
+        
+        def list = []
+        for (c in text) {
+            list.add(c)
+        }
+        
+        assert list == ["a", "b", "c"]
+    }
+    
+    void testVector() {
+        def vector = new Vector()
+        vector.addAll( [1, 2, 3] )
+        
+        def answer = []
+        for (i in vector.elements()) {
+            answer << i
+        }
+        assert answer == [1, 2, 3]
+    }
+}
diff --git a/groovy-core/src/test/groovy/ForLoopWithLocalVariablesTest.groovy b/groovy-core/src/test/groovy/ForLoopWithLocalVariablesTest.groovy
new file mode 100644
index 0000000..680fa79
--- /dev/null
+++ b/groovy-core/src/test/groovy/ForLoopWithLocalVariablesTest.groovy
@@ -0,0 +1,15 @@
+/**
+ * Tests iterating with local variables
+ */
+class ForLoopWithLocalVariablesTest extends GroovyTestCase {
+
+    void testForLoop() {
+        def x = null
+
+        for ( i in 0..9 ) {
+            x = i
+        }
+
+        assert x == 9
+	}
+}
diff --git a/groovy-core/src/test/groovy/GStringTest.groovy b/groovy-core/src/test/groovy/GStringTest.groovy
new file mode 100644
index 0000000..84e252b
--- /dev/null
+++ b/groovy-core/src/test/groovy/GStringTest.groovy
@@ -0,0 +1,186 @@
+class GStringTest extends GroovyTestCase {
+
+    void check(template, teststr) {
+        assert template instanceof GString
+
+        def count = template.getValueCount()
+        assert count == 1
+        assert template.getValue(0) == "Bob"
+
+        def string = template.toString()
+        assert string == teststr
+    }
+
+    void testWithOneVariable() {
+        def name = "Bob"
+        def teststr = "hello Bob how are you?"
+
+
+    check("hello $name how are you?", teststr)
+    check("hello ${name} how are you?", teststr)
+    check("hello ${println "feep"; name} how are you?", teststr)
+    check(/hello $name how are you?/, teststr)
+    check(/hello ${name} how are you?/, teststr)
+    check(/hello ${println "feep"; name} how are you?/, teststr)
+    }
+
+    void testWithVariableAtEnd() {
+        def name = "Bob"
+        def teststr = "hello Bob"
+
+        check("hello $name", teststr)
+        check("hello ${name}", teststr)
+        check(/hello $name/, teststr)
+        check(/hello ${name}/, teststr)
+    }
+    
+    void testWithVariableAtBeginning() {
+        def name = "Bob"
+        def teststr = "Bob hey"
+        check("$name hey", teststr)
+        check("${name} hey", teststr)
+        name = ""
+        check("${name += "Bob"; name} hey", teststr)
+        assert name == "Bob"
+        check(/$name hey/, teststr)
+        check(/${name} hey/, teststr)
+        name = ""
+        check(/${name += "Bob"; name} hey/, teststr)
+    }
+
+    void testWithJustVariable() {
+        def teststr
+        def name = teststr = "Bob"
+        check("$name", teststr)
+        check("${name}", teststr)
+        check("${assert name=="Bob"; name}", teststr)
+        // Put punctuation after the variable name:
+        check("$name.", "Bob.")
+        check("$name...", "Bob...")
+        check("$name?", "Bob?")
+
+        check(/$name/, teststr)
+        check(/${name}/, teststr)
+        check(/${assert name=="Bob"; name}/, teststr)
+        // Put punctuation after the variable name:
+        check(/$name./, "Bob.")
+        check(/$name.../, "Bob...")
+        check(/$name?/, "Bob?")
+        check(/$name\?/, "Bob\\?")
+        check(/$name$/, "Bob\$")
+
+        def guy = [name: name]
+        check("${guy.name}", "Bob")
+        check("$guy.name", "Bob")
+        check("$guy.name.", "Bob.")
+        check("$guy.name...", "Bob...")
+        check("$guy.name?", "Bob?")
+        check(/$guy.name/, "Bob")
+        check(/$guy.name./, "Bob.")
+        check(/$guy.name.../, "Bob...")
+        check(/$guy.name?/, "Bob?")
+        check(/$guy.name\?/, "Bob\\?")
+        check(/$guy.name$/, "Bob\$")
+    }
+    
+    void testWithTwoVariables() {
+        def name = "Bob"
+        def template = "${name}${name}"
+        def string = template.toString()
+        
+        assert string == "BobBob"
+    }
+    
+    void testWithTwoVariablesWithSpace() {
+        def name = "Bob"
+        def template = "${name} ${name}"
+        def string = template.toString()
+        
+        assert string == "Bob Bob"
+    }
+    
+    void testAppendString() {
+        def a = "dog" 
+        def b = "a ${a}"
+        
+        def c = b + " cat"
+
+        println("Created ${c}")
+        
+        assert c.toString() == "a dog cat" , c
+        
+        b += " cat"
+        
+        assert b.toString() == "a dog cat" , b
+    }
+    
+    void testAppendGString() {
+        def a = "dog" 
+        def b = "a ${a}" 
+        b += " cat${a}"
+        
+        assert b.toString() == "a dog catdog" , b
+        
+        println("Created ${b}")
+    }
+    
+    void testReturnString() {
+        def value = dummyMethod()
+        assert value == "Hello Gromit!"
+    }
+    
+    String dummyMethod() {
+        def name = "Gromit"
+        return "Hello ${name}!"
+    }
+    
+    void testCoerce() {
+        def enc = "US-ASCII"
+        def value = "test".getBytes("${enc}")
+        
+        println "Created ${value}"
+        assert value != null
+    }
+    
+    void testGroovy441() {
+        def arg = "test"
+        def content = "${arg} ="
+
+        if (arg != "something") {
+            content += "?"
+        }
+
+        content += "= ${arg}."
+
+        assert content == "test =?= test."
+    }
+
+    void testTwoStringsInMiddle() {
+        def a = "---"
+        def b = "${a} :"
+        b += "<<"
+        b += ">>"
+        b += ": ${a}"
+        assert b == "--- :<<>>: ---"
+    }
+
+    void testAlternatingGStrings() {
+        def a = "---"
+        def b = "${a} :"
+        b += "<<"
+        b += " [[${a}]] "
+        b += ">>"
+        b += ": ${a}"
+        assert b == "--- :<< [[---]] >>: ---"
+    }
+
+    // Test case for bug GROOVY-599
+    void testGStringInStaticMethod() {
+        int value = 2
+        String str = "1${value}3"
+        int result = Integer.parseInt(str)
+        assert result == 123
+        result = Integer.parseInt("1${value}3")
+        assert result == 123
+    }
+ }
diff --git a/groovy-core/src/test/groovy/GeneratorTest.groovy b/groovy-core/src/test/groovy/GeneratorTest.groovy
new file mode 100644
index 0000000..35bf30a
--- /dev/null
+++ b/groovy-core/src/test/groovy/GeneratorTest.groovy
@@ -0,0 +1,49 @@
+
+class GeneratorTest extends GroovyTestCase {
+
+    void testGenerator() {
+        def x = this.&sampleGenerator
+        //System.out.println("x: " + x)
+		
+        def result = ''
+        for (i in x) {
+            result = result + i
+        }
+	    
+        assert result == "ABC"
+    }
+
+    void testFindAll() {
+        def x = this.&sampleGenerator
+ 	    
+        def value = x.findAll { item -> return item == "C" }
+        assert value == ["C"]
+
+        value = x.findAll { item -> return item != "B" }
+        assert value == ["A", "C"]
+    }
+    
+	
+    void testEach() {
+        def x = this.&sampleGenerator
+ 	    
+        def value = x.each { println(it) }
+    }
+    
+	
+    void testMissingThisBug() {
+        def result = ''
+        for (i in this.&sampleGenerator) {
+            result = result + i
+        }
+	    
+        assert result == "ABC"
+    }
+	
+    void sampleGenerator(closure) {
+        // kinda like yield statements
+        closure.call("A")
+        closure.call("B")
+        closure.call("C")
+    }
+}
diff --git a/groovy-core/src/test/groovy/GlobalPrintlnTest.groovy b/groovy-core/src/test/groovy/GlobalPrintlnTest.groovy
new file mode 100644
index 0000000..17d08ef
--- /dev/null
+++ b/groovy-core/src/test/groovy/GlobalPrintlnTest.groovy
@@ -0,0 +1,11 @@
+class GlobalPrintlnTest extends GroovyTestCase {
+
+    void testGlobalPrintln() {
+        println("Hello World!")
+	}
+
+    void testGlobalPrint() {
+        print("Hello ")
+        println("World!")
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/GroovyClosureMethodsTest.groovy b/groovy-core/src/test/groovy/GroovyClosureMethodsTest.groovy
new file mode 100644
index 0000000..3a1db92
--- /dev/null
+++ b/groovy-core/src/test/groovy/GroovyClosureMethodsTest.groovy
@@ -0,0 +1,171 @@
+
+/**
+ * Test case for the eachObject method on a file containing
+ * zero, one or more objects (object stream).  Also test cases
+ * for eachDir, eachFileMatch and runAfter methods.
+ *
+ * @author Hein Meling
+ */
+class GroovyClosureMethodsTest extends GroovyTestCase {
+
+    private String dirname_target = "target"
+    private String dirname_source = "src/test/groovy"
+
+    private String filename = "${dirname_target}/GroovyClosureMethodsTest.each.object"
+
+    void testEachObjectMany() {
+        def file = new File(filename)
+        def oos = new ObjectOutputStream(new FileOutputStream(file))
+        def list = [1, 2, 3, "foo", 9, "bar", 191, file, 9129]
+        list.each {
+            oos.writeObject(it)
+        }
+
+        println("Contents of file with multiple objects: " + file)
+        int c = 0
+        file.eachObject {
+            print "${it} "
+            c++
+        }
+        assert list.size() == c
+        println ""
+        //ensure to remove the created file
+        file.delete()
+    }
+
+    void testEachObjectOne() {
+        def file = new File(filename)
+        def oos = new ObjectOutputStream(new FileOutputStream(file))
+        oos.writeObject(file)
+
+        println("Contents of file with one object: " + file)
+        int c = 0
+        file.eachObject {
+            print "${it} "
+            c++
+        }
+        assert c == 1
+        println ""
+        //ensure to remove the created file
+        file.delete()
+    }
+
+    void testEachObjectEmptyFile() {
+        def file = new File(filename)
+        def oos = new ObjectOutputStream(new FileOutputStream(file))
+
+        println("Contents of empty file: " + file)
+        int c = 0
+        file.eachObject {
+            print "${it} "
+            c++
+        }
+        assert c == 0
+        println ""
+        //ensure to remove the created file
+        file.delete()
+    }
+
+    void testEachObjectNullFile() {
+        def file = new File(filename)
+        def oos = new ObjectOutputStream(new FileOutputStream(file))
+        oos.writeObject(null)
+        oos.writeObject("foo")
+        oos.writeObject(null)
+
+        println("Contents of null file: " + file)
+        int c = 0
+        file.eachObject {
+            print "${it} "
+            c++
+        }
+        assert c == 3
+        println ""
+        //ensure to remove the created file
+        file.delete()
+    }
+
+    void testEachDir() {
+        def dir = new File(dirname_source)
+
+        println("Directories in: " + dir)
+        int c = 0
+        dir.eachDir {
+            print "${it} "
+            c++
+        }
+        println ""
+        assert c > 0
+    }
+
+    void testEachFileMatch() {
+        def file = new File(dirname_source)
+
+        print "Files with the text Groovy: "
+        file.eachFileMatch(~"^Groovy.*") {
+            print "${it} "
+        }
+        println ""
+
+        print "Files with the text Closure: "
+        file.eachFileMatch(~"^Closure.*") {
+            print "${it} "
+        }
+        println ""
+
+        print "This file is here: "
+        int c = 0
+        file.eachFileMatch(~"^GroovyClosureMethodsTest.groovy") {
+            print "${it} "
+            c++
+        }
+        assert c == 1
+        println ""
+    }
+
+    void testEachFileOnNonExistingDir() {
+        shouldFail {
+            File dir = new File("SomeNonExistingDir")
+            dir.eachFile {
+                println "${it} "
+            }
+        }
+    }
+
+    void testEachFileOnNonDirFile() {
+        shouldFail {
+            File dir = new File("${dirname_source}/GroovyClosureMethodsTest.groovy")
+            dir.eachFile {
+                println "${it} "
+            }
+        }
+    }
+
+    void testRunAfter() {
+        def timer = new Timer()
+        boolean status = false
+        timer.runAfter(2000) {
+            println "Running after 2 seconds wait"
+            status = true
+        }
+        println "I should run first"
+        assert status == false
+        Thread.sleep(3000)
+        println "I should run last"
+        assert status == true
+    }
+
+    void testSplitEachLine() {
+        String s = """A B C D
+E F G H
+1 2 3 4
+"""
+        Reader reader = new StringReader(s)
+        def all_lines = []
+        reader.splitEachLine(" ") { list ->
+            all_lines << list
+        }
+        assert all_lines == [["A", "B", "C", "D"], ["E", "F", "G", "H"], ["1", "2", "3", "4"]]
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/GroovyInterceptableTest.groovy b/groovy-core/src/test/groovy/GroovyInterceptableTest.groovy
new file mode 100644
index 0000000..51d3993
--- /dev/null
+++ b/groovy-core/src/test/groovy/GroovyInterceptableTest.groovy
@@ -0,0 +1,38 @@
+import org.codehaus.groovy.runtime.ReflectionMethodInvoker
+
+class GroovyInterceptableTest extends GroovyTestCase {
+
+    void testMethodInterception() {
+        def g = new GI()
+        assert g.someInt() == 2806
+        assert g.someUnexistingMethod() == 1
+        assert g.toString() == "invokeMethodToString"
+    }
+
+    void testProperties() {
+        def g = new GI()
+        assert g.foo == 89
+        g.foo = 90
+        assert g.foo == 90
+        // should this be 1 or 90?
+        assert g.getFoo() == 1
+    }
+}
+
+class GI implements GroovyInterceptable {
+
+    def foo = 89
+
+    int someInt() { 2806 }
+    String toString() { "originalToString" }
+
+    Object invokeMethod(String name, Object args) {
+        if ("toString" == name)
+            return "invokeMethodToString"
+        else if ("someInt" == name)
+            return ReflectionMethodInvoker.invoke(this, name, args)
+        else
+            return 1
+    }
+}
+
diff --git a/groovy-core/src/test/groovy/GroovyMethodsTest.groovy b/groovy-core/src/test/groovy/GroovyMethodsTest.groovy
new file mode 100644
index 0000000..afdef26
--- /dev/null
+++ b/groovy-core/src/test/groovy/GroovyMethodsTest.groovy
@@ -0,0 +1,385 @@
+import java.io.InputStreamReader
+import java.awt.Dimension
+import org.codehaus.groovy.runtime.typehandling.GroovyCastException
+
+/** 
+ * Tests the various new Groovy methods
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Guillaume Laforge
+ * @author Dierk Koenig
+ * @author Paul King
+ * @version $Revision$
+ */
+class GroovyMethodsTest extends GroovyTestCase {
+    void testCollect() {
+        assert [2, 4, 6].collect { it * 2} == [4, 8, 12]
+
+        def answer = [2, 4, 6].collect(new Vector()) { it * 2}
+
+        assert answer[0] == 4
+        assert answer[1] == 8
+        assert answer[2] == 12
+
+        assert [1:'a', 2:'b', 3:'c'].collect{k,v -> k + v} == ['1a','2b','3c']
+
+        assert [1:'a', 2:'b', 3:'c'].collect{it.getKey() + "*" + it.getValue()} == ['1*a','2*b','3*c']
+
+    }
+
+    void testAsCoercion() {
+        def d0 = new Dimension(100, 200)
+        assert d0 == new Dimension(width:100, height:200)
+        assert d0 == [100,200] as Dimension
+        assert d0 == [width:100, height:200] as Dimension
+    }
+
+    void testSum() {
+    	assert [].sum() == null
+    	assert [1].sum() == 1
+    	assert [1, 2, 3].sum() == 6
+
+    	assert [].sum() {it.length()} == 0
+    	assert ["abc"].sum() {it.length()} == 3
+    	assert ["a", "bc", "def"].sum() {it.length()} == 6
+    }
+
+    void testJoin() {
+        assert [2, 4, 6].join("-") == "2-4-6"
+        assert ["edam", "cheddar", "brie"].join(", ") == 'edam, cheddar, brie'
+
+        println( ["abc", 5, 2.34].join(", ") )
+    }
+
+    void testTimes() {
+        def count = 0
+        5.times { i -> count = count + i }
+        assert count == 10
+
+        count = 0
+        def temp = 5
+        temp.times { i -> count = count + i }
+
+        assert count == 10
+    }
+
+    void testArraySubscript() {
+        def list = [1, 2, 3, 4]
+        def array = list.toArray()
+
+        def value = array[2]
+
+        assert value == 3
+
+        array[0] = 9
+
+       assert array[0] == 9
+    }
+
+    void testToCharacterMethod() {
+        def s = 'c'
+        def x = s.toCharacter()
+
+        assert x instanceof Character
+    }
+
+    void testListGrep() {
+        def list = ["James", "Bob", "Guillaume", "Sam"]
+        def answer = list.grep(~".*a.*")
+
+        assert answer == ["James", "Guillaume", "Sam"]
+
+        answer = list.grep(~"B.b")
+
+        assert answer == ["Bob"]
+    }
+
+    void testCollectionToList() {
+        def c = [1, 2, 3, 4, 5] // but it's a list
+        def l = c.toList()
+        assert l.containsAll(c)
+        assert c.size() == l.size()
+    }
+
+    void testCollectionAsList() {
+        Integer[] nums = [1, 2, 3, 4, 5]
+        def numList = nums as List
+        nums.each{ assert numList.contains(it) }
+        assert nums.size() == numList.size()
+    }
+
+    void testCollectionAsLinkedList() {
+        Integer[] nums = [1, 2, 3, 4, 5]
+        def numList = nums as LinkedList
+        nums.each{ assert numList.contains(it) }
+        assert nums.size() == numList.size()
+        assert numList.class == LinkedList.class
+    }
+
+    void testArrayListAsLinkedList() {
+        ArrayList nums = [1, 2, 3, 4, 5]
+        shouldFail(GroovyCastException.class) {
+            def numList = nums as LinkedList
+        }
+    }
+
+    void testFileSize() {
+        assert new File('project.properties').size()
+    }
+
+    void testMatcherSize() {
+        assertEquals 3, ( 'aaa' =~ /./ ).count
+        assertEquals 3, ( 'aaa' =~ /./ ).size()
+        assertEquals 1, ( 'a' =~ /./ ).size()
+        assertEquals 0, ( 'a' =~ /x/ ).size()
+    }
+
+    void testJoinString() {
+        String[] arr = ["a", "b", "c", "d"]
+        def joined = arr.join(", ")
+
+        assert joined == "a, b, c, d"
+    }
+
+    void testReverseEach() {
+        def l = ["cheese", "loves", "Guillaume"]
+        def expected = ["Guillaume", "loves", "cheese"]
+
+        def answer = []
+        l.reverseEach{ answer << it }
+
+        assert answer == expected
+    }
+
+    void testGrep() {
+        def list = ["Guillaume", "loves", "cheese"]
+
+        def answer = list.grep(~".*ee.*")
+        assert answer == ["cheese"]
+
+        list = [123, "abc", 4.56]
+        answer = list.grep(String)
+        assert answer == ["abc"]
+
+        list = [4, 2, 7, 3, 6, 2]
+        answer = list.grep(2..3)
+        assert answer == [2, 3, 2]
+    }
+
+    void testMapGetWithDefault() {
+        def map = [:]
+
+        assert map.foo == null
+
+        map.get("foo", []).add(123)
+
+        assert map.foo == [123]
+
+        map.get("bar", [:]).get("xyz", [:]).cheese = 123
+
+        assert map.bar.xyz.cheese == 123
+        assert map.size() == 2
+    }
+
+    String getCmd() {
+        def cmd = "ls -l"
+        if (System.properties.'os.name'.contains('Win')) {
+            cmd = "cmd /c dir"
+        }
+        return cmd
+    }
+
+    void testExecuteCommandLineProcessUsingAString() {
+
+        println "executing command: ${cmd}"
+
+        def process = cmd.execute()
+
+        // lets have an easier way to do this!
+        def count = 0
+
+        println "Read the following lines..."
+
+        /** @todo we should simplify the following line!!! */
+        new InputStreamReader(process.in).eachLine { line ->
+            println line
+            ++count
+        }
+        println ""
+
+        process.waitFor()
+        def value = process.exitValue()
+        println "Exit value of command line is ${value}"
+
+        assert count > 1
+    }
+
+    /*
+    void testExecuteCommandLineProcessAndUseWaitForOrKill_FAILS_ON_WINDOWS() {
+        if (System.properties.'os.name'.contains('Windows') && notYetImplemented()) return
+
+        println "executing command: ${cmd}"
+
+        def process = cmd.execute()
+
+        process.consumeProcessOutput()
+        process.waitForOrKill(1000)
+        def value = process.exitValue()
+        println "Exit value of command line is ${value}"
+
+        process = cmd.execute()
+
+        process.consumeProcessOutput()
+        process.waitForOrKill(10) // This fails on RLW's workstation with parameter 1, >=8 is required.
+        value = process.exitValue()
+        println "Exit value of command line is ${value}"
+        
+    }
+    */
+    
+    void testExecuteCommandLineUnderWorkingDirectory_FAILS() { if (notYetImplemented()) return
+
+        def envp = java.util.Array.newInstance(String, 0)
+        def workDir = new File(".")
+
+        println "executing command: ${cmd} under the directory ${workDir.canonicalPath}"
+
+        def process = cmd.execute(envp, workDir)
+
+        // lets have an easier way to do this!
+        def count = 0
+
+        println "Read the following lines under the directory ${workDir} ..."
+
+        /** @todo we should simplify the following line!!! */
+        new InputStreamReader(process.in).eachLine { line ->
+            println line
+            ++count
+        }
+        println ""
+
+        process.waitFor()
+        def value = process.exitValue()
+        println "Exit value of command line is ${value}"
+
+        assert count > 1
+    }
+    
+    void testDisplaySystemProperties() {
+        println "System properties are..."
+        def properties = System.properties
+        def keys = properties.keySet().sort()
+        for (k in keys) {
+            println "${k} = ${properties[k]}"
+        }
+    }
+
+    void testMax() {
+        assert [-5, -3, -1, 0, 2, 4].max{ it * it } == -5
+    }
+
+    void testMin() {
+        assert [-5, -3, -1, 0, 2, 4].min{ it * it } == 0
+    }
+    
+    void testSort() {
+        assert [-5, -3, -1, 0, 2, 4].sort { it*it } == [0, -1, 2, -3, 4, -5]
+    }
+
+    void testReplaceAllClosure() {
+        assert "1 a 2 b 3 c 4".replaceAll("\\p{Digit}") { it * 2 } == "11 a 22 b 33 c 44"
+    }
+
+    void testObjectSleep(){
+        long start = System.currentTimeMillis()
+        sleep 1000
+        long slept = System.currentTimeMillis() - start
+        long epsilon = 100
+        assertTrue("should have slept >= 1s but was ${slept}ms", slept >= 1000 - epsilon)
+    }
+
+    void testObjectSleepInterrupted(){
+        def interruptor = new groovy.TestInterruptor(Thread.currentThread())
+        new Thread(interruptor).start()
+        long start = System.currentTimeMillis()
+        sleep 1000
+        long slept = System.currentTimeMillis() - start
+        long epsilon = 100
+        assertTrue("should have slept >= 1s but was ${slept}ms", slept >= 1000-epsilon)
+    }
+    void testObjectSleepWithOnInterruptHandler(){
+        def log = ''
+        def interruptor = new groovy.TestInterruptor(Thread.currentThread())
+        new Thread(interruptor).start()
+        long start = System.currentTimeMillis()
+        sleep(1000){ log += it.toString() }
+        long slept = System.currentTimeMillis() - start
+        assert slept < 1000, "should have been interrupted but slept ${slept}ms > 2s"
+        assertEquals 'java.lang.InterruptedException: sleep interrupted', log.toString()
+    }
+
+    void testObjectIdentity() {
+        def a = new Object()
+        def b = a
+        assert a.is(b)
+        assert ! a.is(null)
+        assert ! 1.is(2)
+        // naive impl would fall for this trap
+        assert ! new WackyHashCode().is(new WackyHashCode())
+    }
+
+    void testGroupByList() {
+        def expected = [Integer: [1, 2], String: ["a", "b"], BigDecimal: [3.5, 4.6]]
+        def list = [1, "a", 2, "b", 3.5, 4.6]
+        def result = list.groupBy{ it.class }
+        assert [1, 2] == result[Integer]
+        assert ["a", "b"] == result[String]
+        assert [3.5, 4.6] == result[BigDecimal]
+        assert 3 == result.size()
+    }
+
+/* Removed for 1.0, to be discussed for 1.1
+    void testGroupByMap() {
+		def expectedKeys = [Integer: [1, 3], String: [2, 4], BigDecimal: [5, 6]]
+		def expectedVals = [Integer: [1, 2], String: ["a", "b"], BigDecimal: [3.5, 4.6]]
+		def map = [1:1, 2:"a", 3:2, 4:"b", 5:3.5, 6:4.6]
+		def result = map.groupBy{ it.value.class }
+		assert expectedKeys.Integer == result[Integer].collect{it.key}
+		assert expectedVals.Integer == result[Integer].collect{it.value}
+		assert expectedKeys.String == result[String].collect{it.key}
+		assert expectedVals.String == result[String].collect{it.value}
+		assert expectedKeys.BigDecimal == result[BigDecimal].collect{it.key}
+		assert expectedVals.BigDecimal == result[BigDecimal].collect{it.value}
+		assert 3 == result.size()
+    }
+*/
+    
+    def leftCol  = ["2"]
+    def rightCol = ["1","2","3"]
+
+    void testList() {
+      def lst  = [] as LinkedList
+      doIt(lst)
+    }
+
+    void testSet() {
+      def set  = [] as HashSet 
+      doIt(set)
+    }
+                    
+    void testVector() {
+      def vctr  = [] as Vector
+      doIt(vctr)
+    }
+
+    void doIt(col) {
+      col.clear();
+      col.addAll(leftCol);
+      // not really concerned about  correctness, rather that the method can be called, however..
+      assert col.intersect(rightCol) == ["2"]
+    }
+}
+
+class WackyHashCode {
+    int hashCode(){ return 1;}
+}
diff --git a/groovy-core/src/test/groovy/HeredocsTest.groovy b/groovy-core/src/test/groovy/HeredocsTest.groovy
new file mode 100644
index 0000000..17c56b1
--- /dev/null
+++ b/groovy-core/src/test/groovy/HeredocsTest.groovy
@@ -0,0 +1,32 @@
+class HeredocsTest extends GroovyTestCase {
+
+    void testHeredocs() {
+        def name = "James"
+        def s = """
+abcd
+efg
+
+hijk
+     
+hello ${name}
+        
+"""
+        println s
+        assert s != null
+        assert s instanceof GString
+
+        assert s.contains("i")
+        assert s.contains("James")
+    }
+    
+    void testDollarEscaping() {
+        def s = """
+hello \${name}
+"""
+        println s
+        assert s != null
+        assert s.contains('$')
+        def c = s.count('$')
+        assert c == 1
+    }
+}
diff --git a/groovy-core/src/test/groovy/HomepageTest.groovy b/groovy-core/src/test/groovy/HomepageTest.groovy
new file mode 100644
index 0000000..ffcb329
--- /dev/null
+++ b/groovy-core/src/test/groovy/HomepageTest.groovy
@@ -0,0 +1,6 @@
+class HomepageTest extends GroovyTestCase {
+
+	void testHomePage() {
+	    
+	}
+}
diff --git a/groovy-core/src/test/groovy/IdentityClosureTest.groovy b/groovy-core/src/test/groovy/IdentityClosureTest.groovy
new file mode 100644
index 0000000..c20b4c4
--- /dev/null
+++ b/groovy-core/src/test/groovy/IdentityClosureTest.groovy
@@ -0,0 +1,72 @@
+/**
+ * Check that Object.identity(Closure) method works as expected
+ *
+ * @author Jeremy Rayner
+ * @author Guillaume Laforge
+ */
+class IdentityClosureTest extends GroovyTestCase {
+    
+    def foo = [[1,2,3],[4,5,6],[7,8,9]]
+    def bar = " bar "
+    def mooky = 1
+
+    /** most useful perceived usecase, almost like with(expr) */
+    void testIdentity0() {
+        assert " bar " == bar
+
+        bar.toUpperCase().trim().identity{
+            assert "BAR" == it
+            assert 3 == it.size()
+            assert it.indexOf("A") > 0
+        }
+    }  
+
+    /** check the basics */
+    void testIdentity1() {
+        mooky.identity{ spooky->
+            assert spooky == mooky
+        }
+    }
+
+    /** test temp shortcut to an element of an array */
+    void testIdentity2() {
+        assert 6 == foo[1][2]
+        
+        foo[1].identity{ myArray->
+            myArray[2] = 12
+        }
+        
+        assert 12 == foo[1][2]
+    }
+
+    /** check nested identity usage */
+    void testIdentity3() {
+        mooky.toString().identity{ m->
+            assert "1" == m
+            m += "234567890"
+            m.identity{ n->
+                assert "1234567890" == n
+            }
+        }
+    }
+
+    /** Test the closure delegate */
+    void testClosureDelegate1() {
+        bar.toUpperCase().trim().identity{
+            assert "BAR" == it
+            assert 3 == size()
+            assert indexOf("A") > 0
+        }
+    }
+
+    /** Test the closure delegate with Expandos */
+    void testClosureDelegate2() {
+        def a = new Expando()
+        a.foobar = "foobar"
+        a.barfoo = 555
+        a.identity{
+            assert foobar == "foobar"
+            assert barfoo == 555
+        }
+    }
+}
diff --git a/groovy-core/src/test/groovy/IfElseCompactTest.groovy b/groovy-core/src/test/groovy/IfElseCompactTest.groovy
new file mode 100644
index 0000000..239c98c
--- /dev/null
+++ b/groovy-core/src/test/groovy/IfElseCompactTest.groovy
@@ -0,0 +1,23 @@
+class IfElseCompactTest extends GroovyTestCase {
+
+    void testIf_NoElse() {
+
+        def x = false
+
+        if ( true ) {x = true}
+
+        assert x == true
+    }
+
+    void testIf_WithElse_MatchIf() {
+
+        def x = false
+        def y = false
+
+        if ( true ) {x = true} else {y = true}
+
+        assert x == true
+        assert y == false
+
+    }
+}
diff --git a/groovy-core/src/test/groovy/IfElseTest.groovy b/groovy-core/src/test/groovy/IfElseTest.groovy
new file mode 100644
index 0000000..f79295e
--- /dev/null
+++ b/groovy-core/src/test/groovy/IfElseTest.groovy
@@ -0,0 +1,131 @@
+class IfElseTest extends GroovyTestCase {
+
+    void testIf_NoElse() {
+
+        def x = false
+
+        if ( true ) {
+            x = true
+        }
+
+        assert x == true
+    }
+
+    void testIf_WithElse_MatchIf() {
+
+        def x = false
+        def y = false
+
+        if ( true ) {
+            x = true
+        } else {
+            y = true
+        }
+
+        assert x == true
+        assert y == false
+
+    }
+
+    void testIf_WithElse_MatchElse() {
+
+        def x = false
+        def y = false
+
+        if ( false ) {
+            x = true
+        } else {
+            y = true
+        }
+
+        assertEquals( false, x )
+        assertEquals( true, y )
+    }
+
+    void testIf_WithElseIf_MatchIf() {
+
+        def x = false
+        def y = false
+
+        if ( true ) {
+            x = true
+        } else if ( false ) {
+            y = true
+        }
+
+        assert x == true
+        assert y == false
+    }
+
+    void testIf_WithElseIf_MatchElseIf() {
+
+        def x = false
+        def y = false
+
+        if ( false ) {
+            x = true
+        } else if ( true ) {
+            y = true
+        }
+
+        assertEquals( false, x )
+        assertEquals( true, y )
+    }
+
+    void testIf_WithElseIf_WithElse_MatchIf() {
+
+        def x = false
+        def y = false
+        def z = false
+
+        if ( true ) {
+            x = true
+        } else if ( false ) {
+            y = true
+        } else {
+            z = true
+        }
+
+        assert x == true
+        assert y == false
+        assertEquals( false, z )
+    }
+
+    void testIf_WithElseIf_WithElse_MatchElseIf() {
+
+        def x = false
+        def y = false
+        def z = false
+
+        if ( false ) {
+            x = true
+        } else if ( true ) {
+            y = true
+        } else {
+            z = true
+        }
+
+        assertEquals( false, x )
+        assertEquals( true, y )
+        assertEquals( false, z )
+    }
+
+    void testIf_WithElseIf_WithElse_MatchElse() {
+
+        def x = false
+        def y = false
+        def z = false
+
+        if ( false ) {
+            x = true
+        } else if ( false ) {
+            y = true
+        } else {
+            z = true
+        }
+
+        assertEquals( false, x )
+        assert y == false
+        assertEquals( true, z )
+    }
+}
diff --git a/groovy-core/src/test/groovy/IfPropertyTest.groovy b/groovy-core/src/test/groovy/IfPropertyTest.groovy
new file mode 100644
index 0000000..d2e67d1
--- /dev/null
+++ b/groovy-core/src/test/groovy/IfPropertyTest.groovy
@@ -0,0 +1,38 @@
+class IfPropertyTest extends GroovyTestCase {
+	
+    def dummy
+    
+	// This is because normal classes are not extensible, but scripts are extensible by default.
+    Object get(String key) {
+        println("asking for def " + key)
+        return dummy
+    }
+
+    void set(Object key, Object value) {
+        println("setting the def " + key + " to: " + value)
+        dummy = value
+    }
+
+    void testIfNullPropertySet() {
+        def cheese = null
+        if (cheese == null) {
+            cheese = 1
+        }
+        if (cheese != 1) {
+            fail("Didn't change cheese")
+        }
+        assert cheese == 1
+    }
+    
+    void testIfNullPropertySetRecheck() {
+        def cheese = null
+        if (cheese == null) {
+            cheese = 1
+        }
+        if (cheese == 1) {
+            cheese = 2
+        }
+        assert cheese == 2
+    }
+    
+}
diff --git a/groovy-core/src/test/groovy/IfTest.groovy b/groovy-core/src/test/groovy/IfTest.groovy
new file mode 100644
index 0000000..fedda5e
--- /dev/null
+++ b/groovy-core/src/test/groovy/IfTest.groovy
@@ -0,0 +1,43 @@
+class IfTest extends GroovyTestCase {
+
+    void testUsingNumber() {
+        def x = 1
+
+        if (x) {
+            println "${x} is true"
+        }
+        else {
+            fail("should not be false")
+        }
+
+        x = 0
+
+        if (x) {
+            fail("should not be true")
+        }
+        else {
+            println "${x} is false"
+        }
+
+    }
+
+    void testUsingString() {
+        def x = "abc"
+
+        if (x) {
+            println "${x} is true"
+        }
+        else {
+            fail("should not be false")
+        }
+
+        x = ""
+
+        if (x) {
+            fail("should not be true")
+        }
+        else {
+            println "${x} is false"
+        }
+    }
+}
diff --git a/groovy-core/src/test/groovy/IfWithMethodCallTest.groovy b/groovy-core/src/test/groovy/IfWithMethodCallTest.groovy
new file mode 100644
index 0000000..873a140
--- /dev/null
+++ b/groovy-core/src/test/groovy/IfWithMethodCallTest.groovy
@@ -0,0 +1,13 @@
+class IfWithMethodCallTest extends GroovyTestCase {
+
+    void testIfWithMethodCall() {
+        def x = ["foo", "cheese"]
+
+        if ( x.contains("cheese") ) {
+            // ignore
+        }
+        else {
+            assert false , "x should contain cheese!"
+        }
+    }
+}
diff --git a/groovy-core/src/test/groovy/ImmutableModificationTest.groovy b/groovy-core/src/test/groovy/ImmutableModificationTest.groovy
new file mode 100644
index 0000000..d041252
--- /dev/null
+++ b/groovy-core/src/test/groovy/ImmutableModificationTest.groovy
@@ -0,0 +1,24 @@
+/**
+ * check that the new asImmutable() method works
+ * as specified in GROOVY-623
+ *
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+class ImmutableModificationTest extends GroovyTestCase {
+    void testCollectionAsImmutable() {
+        def challenger = ["Telson", "Sharna", "Darv", "Astra"]
+        def hopefullyImmutable = challenger.asImmutable()
+        try {
+            challenger.add("Angel One")
+            challenger << "Angel Two"
+
+            // @todo fail("'challenger' is supposed to be an immutable collection.")
+
+        } catch (UnsupportedOperationException e) {
+            // success if this exception is thrown
+            assert 4 == challenger.size()
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/ImportTest.groovy b/groovy-core/src/test/groovy/ImportTest.groovy
new file mode 100644
index 0000000..32c450e
--- /dev/null
+++ b/groovy-core/src/test/groovy/ImportTest.groovy
@@ -0,0 +1,27 @@
+import java.io.*
+import java.util.Map
+import java.util.List
+
+class ImportTest extends GroovyTestCase {
+
+    void testImportAll() {
+        def file = new File("foo.txt")
+        assert file instanceof File
+        assert file.getClass().name == "java.io.File"
+    }
+    
+    void testImportByName() {
+        def x = [:]
+        assert x instanceof Map
+        /**
+         * For maps, map.getClass() should be used instead of map.class,
+         * when map has no member, named as "class"
+         */
+        assert x.getClass() != null
+        assert x.getClass().name.startsWith("java.util.")
+        
+        def y = [1, 2, 3]
+        assert y instanceof List
+        assert y.getClass().name.startsWith("java.util.")
+    }
+}
diff --git a/groovy-core/src/test/groovy/InstanceofTest.groovy b/groovy-core/src/test/groovy/InstanceofTest.groovy
new file mode 100644
index 0000000..312ba88
--- /dev/null
+++ b/groovy-core/src/test/groovy/InstanceofTest.groovy
@@ -0,0 +1,54 @@
+import java.util.Map
+
+class InstanceofTest extends GroovyTestCase {
+
+    void testTrue() {
+
+        def x = false
+        def o = 12
+        
+        if ( o instanceof Integer ) {
+            x = true
+        }
+
+        assert x == true
+    }
+    
+    void testFalse() {
+
+        def x = false
+        def o = 12
+        
+        if ( o instanceof Double ) {
+            x = true
+        }
+
+        assert x == false
+    }
+    
+    void testImportedClass() {
+        def m = ["xyz":2]
+        assert m instanceof Map
+        assert !(m instanceof Double)
+        
+        assertTrue(m instanceof Map)
+        assertFalse(m instanceof Double)
+    }
+    
+    void testFullyQualifiedClass() {
+        def l = [1, 2, 3]
+        assert l instanceof java.util.List
+        assert !(l instanceof Map)
+        
+        assertTrue(l instanceof java.util.List)
+        assertFalse(l instanceof Map)
+    }
+    
+    void testBoolean(){
+       assert true instanceof Object
+       assert true==true instanceof Object
+       assert true==false instanceof Object
+       assert true==false instanceof Boolean
+       assert !new Object() instanceof Boolean
+    }
+}
diff --git a/groovy-core/src/test/groovy/IntegerOperationTest.groovy b/groovy-core/src/test/groovy/IntegerOperationTest.groovy
new file mode 100644
index 0000000..2d0ecc4
--- /dev/null
+++ b/groovy-core/src/test/groovy/IntegerOperationTest.groovy
@@ -0,0 +1,183 @@
+class IntegerOperationTest extends GroovyTestCase {
+
+    def x
+    def y
+    def z
+    
+    void testPlus() {
+        x = 2 + 2
+        assert x == 4
+        
+        y = x + 1
+        assert y == 5
+
+        z = y + x + 1 + 2
+        assert z == 12
+    }
+    
+    void testCharacterPlus() {
+        Character c1 = 1
+        Character c2 = 2
+
+        x = c2 + 2
+        assert x == 4
+
+        x = 2 + c2
+        assert x == 4
+
+        x = c2 + c2
+        assert x == 4
+          
+        y = x + c1
+        assert y == 5
+          
+        y = c1 + x
+        assert y == 5
+
+        z = y + x + c1 + 2
+        assert z == 12
+
+        z = y + x + 1 + c2
+        assert z == 12
+
+        z = y + x + c1 + c2
+        assert z == 12
+    }
+    
+    void testMinus() {
+        x = 6 - 2
+        assert x == 4
+        
+        y = x - 1
+        assert y == 3
+    }
+    
+    void testCharacterMinus() {
+        Character c1 = 1
+        Character c2 = 2
+        Character c6 = 6
+
+        x = c6 - 2
+        assert x == 4
+
+        x = 6 - c2
+        assert x == 4
+
+        x = c6 - c2
+        assert x == 4
+        
+        y = x - c1
+        assert y == 3
+    }
+    
+    void testMultiply() {
+        x = 3 * 2
+        assert x == 6
+        
+        y = x * 2
+        assert y == 12        
+    }
+    
+    void testDivide() {
+        x = 80 / 4
+        assert x == 20.0 , "x = " + x
+        
+        y = x / 2
+        assert y == 10.0 , "y = " + y
+    }
+    
+    void testIntegerDivide() {
+        x = 52.intdiv(3)
+        assert x == 17 , "x = " + x
+        
+        y = x.intdiv(2)
+        assert y == 8 , "y = " + y 
+        
+        y = 11
+        y = y.intdiv(3)
+        assert y == 3       
+    }
+    
+    void testMod() {
+        x = 100 % 3
+
+        assert x == 1
+
+        y = 11
+        y %= 3
+        assert y == 2
+    }
+    
+    void testAnd() {
+        x = 1 & 3
+
+        assert x == 1
+
+        x = 1.and(3)
+
+        assert x == 1
+    }
+     
+     void testOr() {
+         x = 1 | 3
+
+         assert x == 3
+
+         x = 1 | 4
+
+         assert x == 5
+
+         x = 1.or(3)
+
+         assert x == 3
+
+         x = 1.or(4)
+
+         assert x ==5
+    }
+    
+    void testShiftOperators() {
+
+        x = 8 >> 1
+        assert x == 4
+        assert x instanceof Integer
+
+        x = 8 << 2
+        assert x == 32
+        assert x instanceof Integer
+
+        x = 8L << 2
+        assert x == 32
+        assert x instanceof Long
+
+        x = -16 >> 4
+        assert x == -1
+
+        x = -16 >>> 4
+        assert x == 0xFFFFFFF
+
+        //Ensure that the type of the right operand (shift distance) is ignored when calculating the
+        //result.  This is how java works, and for these operators, it makes sense to keep that behavior.
+        x = Integer.MAX_VALUE << 1L
+        assert x == -2
+        assert x instanceof Integer
+
+        x = new Long(Integer.MAX_VALUE).longValue() << 1
+        assert x == 0xfffffffe
+        assert x instanceof Long
+
+        //The left operand (shift value) must be an integral type
+        try {
+            x = 8.0F >> 2
+            fail("Should catch UnsupportedOperationException");
+        } catch (UnsupportedOperationException uoe) {
+        }
+
+        //The right operand (shift distance) must be an integral type
+        try {
+            x = 8 >> 2.0
+            fail("Should catch UnsupportedOperationException");
+        } catch (UnsupportedOperationException uoe) {
+        }
+    }
+}
diff --git a/groovy-core/src/test/groovy/InvokeNormalMethodsFirstTest.groovy b/groovy-core/src/test/groovy/InvokeNormalMethodsFirstTest.groovy
new file mode 100644
index 0000000..58f6691
--- /dev/null
+++ b/groovy-core/src/test/groovy/InvokeNormalMethodsFirstTest.groovy
@@ -0,0 +1,60 @@
+
+/**
+ * Invoke normal methods first: if no statically typed method exist, use invokeMethod().
+ *
+ * @author Guillaume Laforge
+ */
+class InvokeNormalMethodsFirstTest extends GroovyTestCase {
+
+    void testPrintln() {
+        println "call global println function"
+    }
+
+    void testStaticMethodOnJdkObject() {
+        def myString = " static method "
+        def newString = myString.trim()
+
+        assert newString == "static method"
+    }
+
+    void testCallClosure() {
+        def clos = { msg -> msg + " is Groovy" }
+        def str = clos("Guillaume")
+
+        assert str == "Guillaume is Groovy"
+    }
+
+    void testCallNormalMethodFromAGroovyDefinedClass() {
+        def p = new Printer()
+        def str = "Guillaume"
+        def result = p.returnSelf(str)
+
+        assert result == str
+    }
+
+    void testCallNormalMethodFirstFromWackyObject() {
+        def w = new Wacky()
+        def str = "Groovy"
+        def staticResult = w.returnSelf(str)
+        def invokeResult = w.nonExistingMethod(str)
+
+        assert staticResult == str
+        assert invokeResult == "invokerMethod call"
+    }
+}
+
+class Printer {
+    String returnSelf(msg) {
+        return msg
+    }
+}
+
+class Wacky {
+    String returnSelf(msg) {
+        return msg
+    }
+
+    Object invokeMethod(String name, Object args) {
+        return "invokerMethod call"
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/LeftShiftTest.groovy b/groovy-core/src/test/groovy/LeftShiftTest.groovy
new file mode 100644
index 0000000..c3dcc8f
--- /dev/null
+++ b/groovy-core/src/test/groovy/LeftShiftTest.groovy
@@ -0,0 +1,33 @@
+class LeftShiftTest extends GroovyTestCase {
+
+    def foo = [1, 2, 3]
+
+    void testShift() {
+        def x = 4
+
+        def y = x << 2
+
+        println "Value is $y"
+
+        assert y == 16
+
+        assert x << 2 == 16
+    }
+
+    void testShiftList() {
+        def list = []
+
+        for (i in 1..10) {
+            list << i
+        }
+
+        println "List is $list"
+    }
+
+    void testLeftShiftOnExpression() {
+        this.foo << 4
+
+        assert foo == [1, 2, 3, 4]
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/ListIteratingTest.groovy b/groovy-core/src/test/groovy/ListIteratingTest.groovy
new file mode 100644
index 0000000..52ebfa1
--- /dev/null
+++ b/groovy-core/src/test/groovy/ListIteratingTest.groovy
@@ -0,0 +1,59 @@
+import java.util.ArrayList
+
+/** 
+ * Tests iterating using Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class ListIteratingTest extends GroovyTestCase {
+
+/** @todo parser
+    testIteratingWithTuples() {
+        def s = 1, 2, 3, 4
+        assertSequence(s)
+    }
+
+    testIteratingWithTuplesAsParameter() {
+        assertSequence(1, 2, 3, 4)
+    }
+*/
+
+    void testIteratingWithSequences() {
+        def s = [1, 2, 3, 4 ]
+        assertSequence(s)
+    }
+    
+    void testIteratingWithSequencesAsParameter() {
+        assertSequence([1, 2, 3, 4 ])
+    }
+    
+    def testIteratingWithList() {
+        def s = new ArrayList()
+        s.add(1)
+        s.add(2)
+        s.add(3)
+        s.add(4)
+        assertSequence(s)
+    }
+
+    protected void assertSequence(s) {
+        def result = 0
+        for ( i in s ) {
+            result = result + i
+        }
+	    
+        assert(result == 10)
+        assert(s.size() == 4)
+        
+        assert(s[2] == 3)
+        // @todo parser (Why @todo here?)
+        //   s[1,2] or s[1..2] should be used instead of s[1:2],
+        //   since [1:2] is a map literal syntax.
+        result = 0
+        for ( i in s[1,2] ) {    // or s[1..2]
+            result += i
+        }
+        assert(result == 2+3)
+    }
+}
diff --git a/groovy-core/src/test/groovy/ListTest.groovy b/groovy-core/src/test/groovy/ListTest.groovy
new file mode 100644
index 0000000..b9ae1c6
--- /dev/null
+++ b/groovy-core/src/test/groovy/ListTest.groovy
@@ -0,0 +1,405 @@
+class ListTest extends GroovyTestCase {
+
+    void testList() {
+        def x = [10, 11]
+
+        assert x.size() == 2
+
+        x.add("cheese")
+
+        assert x.size() == 3
+
+        assert x.contains(10)
+        assert x.contains(11)
+        assert x.contains("cheese")
+
+        assert x.get(0) == 10
+        assert x.get(1) == 11
+        assert x.get(2) == "cheese"
+
+        // subscript operator
+        assert x[0] == 10
+        assert x[1] == 11
+        assert x[2] == "cheese"
+
+        x[3] = 12
+
+        assert x[3] == 12
+
+        if ( x.contains("cheese") ) {
+            // ignore
+        } else {
+            assert false , "x should contain cheese!"
+        }
+
+        if ( x.contains(10) ) {
+            // ignore
+        } else {
+            assert false , "x should contain 1!"
+        }
+    }
+    
+    void testEmptyList() {
+        def x = []
+        
+        assert x.size() == 0
+        
+        x.add("cheese")
+
+        assert x.get(0) == "cheese"
+
+        assert x.size() == 1
+
+        assert x[0] == "cheese"
+    }
+    
+    void testSubscript() {
+        def x = []
+        x[1] = 'cheese'
+        
+        assert x[0] == null
+        assert x[1] == 'cheese'
+        
+        x[2] = 'gromit'
+        x[3] = 'wallace'
+        
+        assert x.size() == 4
+        
+        x[-1] = 'nice'
+        
+        assert x[3] == 'nice'
+        
+        x[-2] = 'cheese'
+        
+        assert x[2] == 'cheese'
+    }
+    
+    void testClosure() {
+        def l = [1, 2, 3, "abc"]
+        def block = {i -> println(i) }
+        l.each(block)
+
+        l.each {i-> println(i) }
+    }
+    
+    void testMax() {
+        def l = [1, 2, 5, 3, 7, 1]
+        assert l.max() == 7
+        
+        l = [7, 2, 3]
+        assert l.max() == 7
+        
+        l = [1, 2, 7]
+        assert l.max() == 7
+
+        // GROOVY-1006        
+        l = [1, 3.2, 4L, (short)7]
+        assert l.max() == (short)7
+    }
+    
+    void testMin() {
+        def l = [6, 4, 5, 1, 7, 2]
+        assert l.min() == 1
+        
+        l = [7, 1, 3]
+        assert l.min() == 1
+        
+        l = [1, 2, 7]
+        assert l.min() == 1
+
+        // GROOVY-1006        
+        l = [(long)1, 3.2, 4L, (short)7]
+        assert l.min() == (long)1
+    }
+    
+    void testPlus() {
+        def l1 = [6, 4, 5, 1, 7, 2]
+        def l2 = [6, 4, 5, 1, 7, [4,5]]
+        def l3 = l1 + l2
+        assert l3 == [6, 4, 5, 1, 7, 2, 6, 4, 5, 1, 7, [4,5]]
+
+        l1 = [1, 5.2, 9]
+        l2 = [3, 4L]
+        l3 = [1, 5.2, 9, 3, 4L]
+        assert l1 + l2 == l3
+    }
+    
+    void testPlusOneElement() {
+        def l1 = [6, 4, 5, 1, 7, 2]
+        def l2 = "erererer"
+        assert l1 + l2 == [6, 4, 5, 1, 7, 2, "erererer"]            
+    }
+
+    void testListAppend() {
+        def list = [1, 2]
+        
+        list << 3 << 4 << 5
+        
+        assert list == [1, 2, 3, 4, 5]
+        
+        def x = [] << 'a' << 'hello' << [2, 3] << 5
+        
+        assert x == ['a', 'hello', [2, 3], 5]
+    }
+
+    void testTimes() {
+        def l = [4,7,8]
+        assert l * 3 == [4, 7, 8, 4, 7, 8, 4, 7, 8]
+    }
+
+    // GROOVY-1006
+    void testMinus() {
+        def l1 = [1, 1, 2, 2, 3, 3, 3, 4, 5, 3, 5]
+        def l2 = [1, 2.0, 4L]
+        assert l1 - l2 == [3, 3, 3, 5, 3, 5] 
+    }
+
+    // GROOVY-1006
+    void testMinusDifferentTypes() {
+        def l1 = [1, 1, "wrer", 2, 3, 3, "wrewer", 4, 5, "w", "w"]
+        def l2 = [1, 2, "w"]
+        assert l1 - l2 == ["wrer", 3, 3, "wrewer", 4, 5] 
+    }
+
+    void testMinusEmptyCollection(){
+        // GROOVY-790
+        def list = [1,1]
+        assert list - [] == list
+
+        // GROOVY-1006    
+        list = [1,2,2,3,1]
+        assert list - [] == list
+    }
+     
+    void testIntersect() {
+        def l1 = [1, 1, "wrer", 2, 3, 3, "wrewer", 4, 5, "w", "w"]
+        def l2 = [1, 2, "f", "w"]
+        assert l1.intersect(l2) == [1, 2, "w"] 
+
+        // GROOVY-1006    
+        l1 = [1, 1.0, "wrer", 2, 3, 3L, "wrewer", 4, 5, "w", "w"]
+        l2 = [(double)1, 2L, "f", "w"]
+        assert l1.intersect(l2) == [1, 2, "w"] 
+    }
+      
+    // GROOVY-1006
+    void testListEqual() {
+        assert [1, 2.0, 3L, (short)4] == [1, 2, 3, 4]
+    }
+      
+    // GROOVY-1006
+    void testSortNumbersMixedType() {
+        assert [1, (short)3, 4L, 2.9, (float)5.2].sort() == [1, 2.9, (short)3, 4L, (float)5.2] 
+    }
+      
+    // GROOVY-1006
+    void testUnique() {
+        def a = [1, 4L, 1.0]
+        def b = a.unique()
+        assert (b == a && a == [1, 4])
+        a =[1, "foo", (short)3, 4L, 1.0, (float)3.0]
+        b = a.unique()
+        assert (b == a && a == [1, "foo", (short)3, 4L])
+    }
+      
+    void testFlatten() {
+        def l = [[[4, 5, 6, [46, 7, "erer"]], 4, [3, 6, 78]], 4]
+        assert l.flatten() == [4, 5, 6, 46, 7, "erer", 4, 3, 6, 78, 4]
+    }
+    
+    void testFlattenWithRanges() {
+        def flat = [1, 3, 20..24, 33].flatten()
+        assert flat == [1, 3, 20, 21, 22, 23, 24, 33]
+    }
+    
+    void testListsAndRangesCompare() {
+        def l = [1, 2, 3]
+        def r = 1..3
+        assert r == l
+        assert l == r
+    }
+    
+    void testRemove() {
+        def l = ['a', 'b', 'c']
+        l.remove(1)
+        assert l == ['a', 'c']
+        l.remove(0)
+        assert l == ['c']
+        assert l.size() == 1
+    }
+    
+    void testPop() {
+        def l = []
+        l << 'a' << 'b'
+        def value = l.pop()
+        assert value == 'b'
+        assert l == ['a']
+        
+        l.add('c')
+        value = l.pop()
+        assert value == 'c'
+        value = l.pop()
+        assert value == 'a'
+        try {
+            value = l.pop()
+            fail("Should have thrown an exception")
+        }
+        catch (NoSuchElementException e) {
+            println "Worked: caught expected exception: ${e}"
+        }
+    }
+
+    void testBoolCoerce() {
+        // Explicit coercion
+        assertFalse((Boolean) [])
+        assertTrue((Boolean) [1])
+
+        // Implicit coercion in statements
+        List list = null
+        if (list) {
+            fail("null should have evaluated to false, but didn't")
+        }
+        list = []
+        if (list) {
+            fail("[] should have evaluated to false, but didn't")
+        }
+        list = [1]
+        if (list) {
+            // OK
+        } else {
+            fail("[] should have evaluated to false, but didn't")
+        }
+    }
+
+    // see also SubscriptTest
+    void testGetAtRange(){
+        def list = [0,1,2,3]
+        assert list[0..3] == list           , 'full list'
+        assert list[0..0] == [0]            , 'one element range'
+        assert list[0..<0] == []            , 'empty range'
+        assert list[3..0] == [3,2,1,0]      , 'reverse range'
+        assert list[3..<0] == [3,2,1]       , 'reverse exclusive range'
+        assert list[-2..-1] == [2,3]        , 'negative index range'
+        assert list[-2..<-1] == [2]         , 'negative index range exclusive'
+        assert list[-1..-2] == [3,2]        , 'negative index range reversed'
+        assert list[-1..<-2] == [3]         , 'negative index range reversed exclusive'  // aaaahhhhh !
+        assert list[0..-1] == list          , 'pos - neg value'
+        assert list[0..<-1] == [0]          , 'pos - neg value exclusive -> empty'
+        assert list[0..<-2] == list         , 'pos - neg value exclusive -> full'
+        // TODO reinstate this test
+        //shouldFail (NullPointerException.class)      { list[null] }
+        shouldFail (IndexOutOfBoundsException.class) { list[5..6] }
+    }
+
+    void testPutAtSplice(){
+        // usual assignments
+        def list = [0,1,2,3]
+        list[1,2] = [11,12]
+        assert list == [0, 11, 12, 3 ]      , 'same length assignment'
+        list = [0,1,2,3]
+        list[1,1] = [11]
+        assert list == [0, 11, 2, 3 ]       , 'length 1 assignment'
+        list = [0,1,2,3]
+        list[1,0] = [ ]
+        assert list == [0, 1, 2, 3 ]        , 'length 0 assignment, empty splice'
+        // assignments at bounds
+        list = [0,1,2,3]
+        list[0,0] = [10]
+        assert list == [10, 1, 2, 3 ]       , 'left border assignment'
+        list = [0,1,2,3]
+        list[3,3] = [13]
+        assert list == [0, 1, 2, 13 ]       , 'right border assignment'
+        // assignments outside current bounds
+        list = [0,1,2,3]
+        list[-1,-1] = [-1]
+        assert list == [0, 1, 2, -1]        , 'left of left border'
+        list = [0,1,2,3]
+        shouldFail (IndexOutOfBoundsException.class) {
+            list[3,4] = [3,4]
+            assert list == [0, 1, 2, 3, 4]
+        }
+        // structural changes
+        list = [0,1,2,3]
+        list[1,2] = ['x']
+        assert list == [0, 'x', 3]          , 'compacting'
+        list = [0,1,2,3]
+        list[1,2] = ['x','x','x']
+        assert list == [0, 'x','x','x', 3]  , 'extending'
+    }
+
+    void testPutAtRange(){
+        // usual assignments
+        def list = [0,1,2,3]
+        list[1..2] = [11,12]
+        assert list == [0, 11, 12, 3 ]      , 'same length assignment'
+        list = [0,1,2,3]
+        list[1..1] = [11]
+        assert list == [0, 11, 2, 3 ]       , 'length 1 assignment'
+        list = [0,1,2,3]
+        list[0..<0] = []
+        assert list == [0, 1, 2, 3 ]        , 'length 0 assignment, empty splice'
+        // assignments at bounds
+        list = [0,1,2,3]
+        list[0..0] = [10]
+        assert list == [10, 1, 2, 3 ]       , 'left border assignment'
+        list = [0,1,2,3]
+        list[3..3] = [13]
+        assert list == [0, 1, 2, 13 ]       , 'right border assignment'
+        // assignments outside current bounds
+        list = [0,1,2,3]
+        list[-1..-1] = [-1]
+        assert list == [0, 1, 2, -1]        , 'left of left border'
+        list = [0,1,2,3]
+        shouldFail (IndexOutOfBoundsException.class) {
+            list[3..4] = [3,4]
+            assert list == [0, 1, 2, 3, 4]
+        }
+        // structural changes
+        list = [0,1,2,3]
+        list[1..2] = ['x']
+        assert list == [0, 'x', 3]          , 'compacting'
+        list = [0,1,2,3]
+        list[1..2] = ['x','x','x']
+        assert list == [0, 'x','x','x', 3]  , 'extending'
+    }
+
+    void testCrazyPutAtRange(){
+        def list = []
+        list[0..<0] = [0,1,2,3]
+        assert list == [0, 1, 2, 3 ]        , 'fill by empty Range'
+        list = [0,1,2,3]
+        list[3..0] = []
+        assert list == []                   , 'delete by reverse Range'
+        list = [0,1,2,3]
+        list[-4..-1] = []
+        assert list == []                   , 'delete by negativ Range'
+        list = [0,1,2,3]
+        list[0..-1] = []
+        assert list == []                   , 'delete by pos-negativ Range'
+    }
+
+    // GROOVY-1128
+    void testAsSynchronized() {
+        def synclist = [].asSynchronized() << 1
+        assert synclist == [1]
+    }
+
+    // GROOVY-1128
+    void testAsImmutable() {
+        def immlist = [1,2,3].asImmutable()
+        assert immlist == [1,2,3]
+        def testlist = ['a','b','c','d','e']
+        assert testlist[immlist] == ['b','c','d']
+        assert immlist[0] == 1
+        assert immlist[0..-1] == immlist
+        shouldFail(UnsupportedOperationException.class){
+            immlist << 1
+        }
+        shouldFail(UnsupportedOperationException.class){
+            immlist[0..<0] = [0]
+        }
+        shouldFail(UnsupportedOperationException.class){
+            immlist[0] = 1
+        }
+    }
+}
diff --git a/groovy-core/src/test/groovy/LiteralTypesTest.groovy b/groovy-core/src/test/groovy/LiteralTypesTest.groovy
new file mode 100644
index 0000000..7a0812e
--- /dev/null
+++ b/groovy-core/src/test/groovy/LiteralTypesTest.groovy
@@ -0,0 +1,146 @@
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/**
+ * Test numeric literal types (with and without suffixes)
+ * @see org.codehaus.groovy.syntax.parser/ASTBuilder#createIntegralNumber()
+ * @see org.codehaus.groovy.syntax.parser/ASTBuilder#createDecimalNumber()
+ *
+ * @author Brian Larson
+ */
+class LiteralTypesTest extends GroovyTestCase {
+
+    void testIntegral() {
+        def x = 42;
+        assert x instanceof Integer;
+
+        x = 42I;
+        assert x instanceof Integer;
+
+        x = 42i;
+        assert x instanceof Integer;
+
+        x = 42L;
+        assert x instanceof Long;
+
+        x = 42G;
+        assert x instanceof BigInteger;
+
+        x = 0xFF; //Hex
+        assert x instanceof Integer;
+        assert x == new Integer("255");
+
+        x = 0xFFL; //Hex
+        assert x instanceof Long;
+        assert x == new Long("255");
+
+        x = 0xFFG; //Hex
+        assert x instanceof BigInteger;
+        assert x == new BigInteger("FF",16);
+
+        x = 0x9000000000000000;
+        assert x instanceof BigInteger;
+        assert x == new BigInteger("9000000000000000",16);
+
+        x = 077; //octal
+        assert x instanceof Integer;
+        assert x == new Integer("63");
+
+        x = 077l; //octal
+        assert x instanceof Long;
+        assert x == new Long("63");
+
+        x = 077g; //octal
+        assert x instanceof BigInteger;
+        assert x == new BigInteger("77",8);
+
+        x = 2147483647;           // max integer value
+        assert x instanceof Integer;
+        assert x == new Integer("2147483647");
+
+        x = -2147483648;          // min integer constant
+        assert x < 0
+        assert x == new Integer("-2147483648");
+        assert x instanceof Integer, x.class;
+
+        x = -2147483649;          // min integer value - 1
+        assert x == new Long("-2147483649");
+        assert x instanceof Long;
+
+        x = 2147483648;           // 1 + max integer value
+        assert x == new Long("2147483648");
+        assert x instanceof Long;
+
+        x = 9223372036854775807;  // max long value
+        assert x == new Long("9223372036854775807");
+        assert x instanceof Long;
+
+        x = -9223372036854775808; // min long value
+        assert x == new Long("-9223372036854775808");
+        assert x instanceof Long;
+
+        x = -9223372036854775809; // min long value - 1
+        assert x == new BigInteger("-9223372036854775809");
+        assert x instanceof BigInteger;
+
+        x = 9223372036854775808;  // 1 + max long value
+        assert x == new BigInteger("9223372036854775808");
+        assert x instanceof BigInteger;
+    }
+
+    void testDecimal() {
+        def x = 3.2;
+        assert x instanceof BigDecimal;
+        assert x == new BigDecimal("3.2");
+
+        x = 3.2G;
+        assert x instanceof BigDecimal;
+        assert x == new BigDecimal("3.2");
+
+        x = 3.2g;
+        assert x instanceof BigDecimal;
+        assert x == new BigDecimal("3.2");
+
+        x = -3.2;
+        assert x instanceof BigDecimal;
+        assert x == new BigDecimal("-3.2");
+
+        x = 3.2D;
+        assert x instanceof Double;
+        assert x == new Double("3.2");
+
+        x = -3.2d;
+        assert x instanceof Double;
+        assert x == new Double("-3.2");
+
+        x = 3.2F;
+        assert x instanceof Float;
+        assert x == new Float("3.2");
+
+        x = -3.2f;
+        assert x instanceof Float;
+        assert x == new Float("-3.2");
+    }
+
+    void testExponential() {
+        def x = 3.1415926535e42;
+        assert x instanceof BigDecimal;
+        assert x == new BigDecimal("3.1415926535e42");
+
+        x = 3.2e+2;
+        assert x instanceof BigDecimal;
+        assert x == new BigDecimal("3.2e+2");
+
+        x = 3.2e-2;
+        assert x instanceof BigDecimal;
+        assert x == new BigDecimal("3.2e-2");
+
+        x = 3.2e2d;
+        assert x instanceof Double;
+        assert x == new Double("3.2e2");
+
+        x = 3.2e2f;
+        assert x instanceof Float;
+        assert x == new Float("3.2e2");
+    }
+}
diff --git a/groovy-core/src/test/groovy/LittleClosureTest.groovy b/groovy-core/src/test/groovy/LittleClosureTest.groovy
new file mode 100644
index 0000000..9471c23
--- /dev/null
+++ b/groovy-core/src/test/groovy/LittleClosureTest.groovy
@@ -0,0 +1,6 @@
+class LittleClosureTest extends GroovyTestCase {
+
+    void testClosure() {
+        def block = {x-> return x > 5}
+    }
+}
diff --git a/groovy-core/src/test/groovy/LocalFieldTest.groovy b/groovy-core/src/test/groovy/LocalFieldTest.groovy
new file mode 100644
index 0000000..a62f948
--- /dev/null
+++ b/groovy-core/src/test/groovy/LocalFieldTest.groovy
@@ -0,0 +1,11 @@
+class LocalFieldTest extends GroovyTestCase {
+
+    private def x
+	
+    void testAssert() {
+        this.x = "abc"
+
+        assert this.x == "abc"
+        assert this.x != "def"
+    }
+}
diff --git a/groovy-core/src/test/groovy/LocalPropertyTest.groovy b/groovy-core/src/test/groovy/LocalPropertyTest.groovy
new file mode 100644
index 0000000..0cb87cb
--- /dev/null
+++ b/groovy-core/src/test/groovy/LocalPropertyTest.groovy
@@ -0,0 +1,18 @@
+class LocalPropertyTest extends GroovyTestCase {
+
+    def x
+    
+	void testNormalPropertyAccess() {
+	    x = "abc"
+	    
+	    assert x == "abc"
+        assert x != "def"
+	}
+	
+	void testPropertyWithThis() {
+        this.x = "abc"
+	    
+	    assert this.x == "abc"
+	    assert this.x != "def"
+	}
+}
diff --git a/groovy-core/src/test/groovy/LocalVariableTest.groovy b/groovy-core/src/test/groovy/LocalVariableTest.groovy
new file mode 100644
index 0000000..cae784c
--- /dev/null
+++ b/groovy-core/src/test/groovy/LocalVariableTest.groovy
@@ -0,0 +1,23 @@
+class LocalVariableTest extends GroovyTestCase {
+
+    void testAssert() {
+        def x = "abc"
+
+        assert x != "foo"
+        assert x !=  null
+        assert x != "def"
+        assert x == "abc"
+        
+        assert x.equals("abc")
+    }
+    
+    void testUnknownVariable() {
+
+        shouldFail {
+            def shell = new GroovyShell()
+            shell.evaluate """
+                def y = x
+            """
+        }
+    }
+}
diff --git a/groovy-core/src/test/groovy/LogTest.groovy b/groovy-core/src/test/groovy/LogTest.groovy
new file mode 100644
index 0000000..53600b1
--- /dev/null
+++ b/groovy-core/src/test/groovy/LogTest.groovy
@@ -0,0 +1,24 @@
+/** 
+ * Tests the use of GroovyLog
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class LogTest extends GroovyTestCase {
+
+    void testUseLog() {
+        def file = "something.txt"
+
+        def log = GroovyLog.newInstance(getClass())
+        
+        log.starting("Hey I'm starting up...")
+        
+        log.openFile("Am about to open file ${file}")
+
+        // ...
+
+        log.closeFile("Have closed the file ${file}")
+
+        log.stopping("..Finished")
+	}
+}
diff --git a/groovy-core/src/test/groovy/LogicTest.groovy b/groovy-core/src/test/groovy/LogicTest.groovy
new file mode 100644
index 0000000..0eb42f2
--- /dev/null
+++ b/groovy-core/src/test/groovy/LogicTest.groovy
@@ -0,0 +1,75 @@
+class LogicTest extends GroovyTestCase {
+
+    void testAndWithTrue() {
+
+        def x = false
+        def n = 2
+        
+        if ( n > 1 && n < 10 ) {
+            x = true
+        }
+
+        assert x == true
+    }
+
+    void testAndWithFalse() {
+
+        def x = false
+        def n = 20
+        
+        if ( n > 1 && n < 10 ) {
+            x = true
+        }
+
+        assert x == false
+
+        n = 0
+        
+        if ( n > 1 && n < 10 ) {
+            x = true
+        }
+
+        assert x == false
+    }
+
+    void testOrWithTrue() {
+
+        def x = false
+        def n = 2
+        
+        if ( n > 1 || n < 10 ) {
+            x = true
+        }
+
+        assert x == true
+
+        x = false
+        n = 0
+        
+        if ( n > 1 || n == 0 ) {
+            x = true
+        }
+
+        assert x == true
+    }
+
+    void testOrWithFalse() {
+
+        def x = false
+        def n = 11
+        
+        if ( n < 10 || n > 20 ) {
+            x = true
+        }
+
+        assert x == false
+
+        n = 11
+        
+        if ( n < 10 || n > 20 ) {
+            x = true
+        }
+    
+        assert x == false
+    }
+}
diff --git a/groovy-core/src/test/groovy/LoopBreakTest.groovy b/groovy-core/src/test/groovy/LoopBreakTest.groovy
new file mode 100644
index 0000000..fe812eb
--- /dev/null
+++ b/groovy-core/src/test/groovy/LoopBreakTest.groovy
@@ -0,0 +1,51 @@
+class LoopBreakTest extends GroovyTestCase {
+
+    void testWhileWithBreak() {
+        def x = 0
+        while (true) {
+            if (x == 5) {
+                break
+            }
+            ++x
+
+            assert x < 10 , "Should never get here"
+        }
+        
+        println "worked: while completed with value ${x}"
+    }
+    
+    /**
+
+      We currently do not support do ... while in the JSR syntax
+
+    void testDoWhileWithBreak() {
+        def x = 0
+        do {
+            //println "in do-while loop and x = ${x}"
+
+            if (x == 5) {
+                break
+            }
+            ++x
+
+            assert x < 10 , "Should never get here"
+        }
+        while (true)
+
+        println "worked: do-while completed with value ${x}"
+    }
+    */
+
+    void testForWithBreak() {
+        def returnValue
+        for (x in 0..20) {
+            if (x == 5) {
+                returnValue = x
+                break
+            }
+            assert x < 10 , "Should never get here"
+        }
+        
+        println "worked: for loop completed with value ${returnValue}"
+    }
+ }
diff --git a/groovy-core/src/test/groovy/MapConstructionTest.groovy b/groovy-core/src/test/groovy/MapConstructionTest.groovy
new file mode 100644
index 0000000..249ff65
--- /dev/null
+++ b/groovy-core/src/test/groovy/MapConstructionTest.groovy
@@ -0,0 +1,53 @@
+import java.util.HashMap
+import java.util.Map
+
+/** 
+ * Tests creating Maps in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class MapConstructionTest extends GroovyTestCase {
+
+    void testMap() {
+        def m = [ 1 : 'abc', 2 : 'def', 3 : 'xyz' ]
+
+        println(m)
+
+        def mtoo = [ 1 : [ "innerKey" : "innerValue" ], 2 : m ]
+
+        println(mtoo)
+
+        assertMap(m)
+    }
+
+    def testMapAsParameter() {
+        assertMap([ 1 : 'abc', 2 : 'def', 3 : 'xyz' ])
+    }
+
+    def testMapViaHashMap() {
+        def m = new HashMap()
+        m.put(1, 'abc')
+        m.put(2, 'def')
+        m.put(3, 'xyz')
+        assertMap(m)
+    }
+
+    void assertMap(m) {
+        assert m instanceof Map
+        assert m.getClass().getName() == "java.util.HashMap"
+
+        def result = 0
+        def text = ""
+        for ( e in m ) {
+            result = result + e.key
+            text = text + e.value
+        }
+        assert result == 6
+        assert text == "abcdefxyz"
+	    
+        assert m.size() == 3
+
+        assert m[2] == 'def'
+    }
+}
diff --git a/groovy-core/src/test/groovy/MapPropertyTest.groovy b/groovy-core/src/test/groovy/MapPropertyTest.groovy
new file mode 100644
index 0000000..5d701ad
--- /dev/null
+++ b/groovy-core/src/test/groovy/MapPropertyTest.groovy
@@ -0,0 +1,34 @@
+/** 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class MapPropertyTest extends GroovyTestCase {
+
+    void testGetAndSetProperties() {
+        def m = [ 'name' : 'James', 'location' : 'London', 'id':1 ]
+        
+        assert m.name == 'James'
+        assert m.location == 'London'
+        assert m.id == 1
+        
+        m.name = 'Bob'
+        m.location = 'Atlanta'
+        m.id = 2
+        
+        assert m.name == 'Bob'
+        assert m.location == 'Atlanta'
+        assert m.id == 2
+    }
+
+    void testSetupAndEmptyMap() {
+        def m = [:]
+        
+        m.name = 'Bob'
+        m.location = 'Atlanta'
+        m.id = 2
+        
+        assert m.name == 'Bob'
+        assert m.location == 'Atlanta'
+        assert m.id == 2
+    }
+}
diff --git a/groovy-core/src/test/groovy/MapTest.groovy b/groovy-core/src/test/groovy/MapTest.groovy
new file mode 100644
index 0000000..6fbfd76
--- /dev/null
+++ b/groovy-core/src/test/groovy/MapTest.groovy
@@ -0,0 +1,95 @@
+class MapTest extends GroovyTestCase {
+
+    void testMap() {
+
+        def m = [1:'one', '2':'two', 3:'three']
+
+        assert m.size() == 3
+        assert m.get(1) == 'one'
+        assert m.get('2') == 'two'
+        assert m.get(3) == 'three'
+        
+        assert m.containsKey(1)
+        assert m.containsKey('2')
+        assert m.containsKey(3)
+
+        assert m.containsValue('one')
+        assert m.containsValue('two')
+        assert m.containsValue('three')
+
+        assert m.keySet().size() == 3
+        assert m.values().size() == 3
+        assert m.keySet().contains(1)
+        assert m.values().contains('one')
+
+        m.remove(1)
+        m.remove('2')
+
+        assert m.size() == 1
+        assert m.get('1') == null
+        assert m.get('2') == null
+        
+        m.put('cheese', 'cheddar')
+
+        assert m.size() == 2
+
+        assert m.containsKey("cheese")
+        assert m.containsValue("cheddar")
+
+
+        if ( m.containsKey("cheese") ) {
+            // ignore
+        }
+        else {
+            assert false , "should contain cheese!"
+        }
+
+        if ( m.containsKey(3) ) {
+            // ignore
+        }
+        else {
+            assert false , "should contain 3!"
+        }
+    }
+    
+    void testEmptyMap() {
+        def m = [:]
+
+        assert m.size() == 0
+        assert !m.containsKey("cheese")
+
+        m.put("cheese", "cheddar")
+
+        assert m.size() == 1
+        assert m.containsKey("cheese")
+    }
+    
+    void testMapMutation() {    
+        def m = [ 'abc' : 'def', 'def' : 134, 'xyz' : 'zzz' ]
+
+        assert m['unknown'] == null
+
+        assert m['def'] == 134
+
+        println(m['xyz'])
+        
+        m['def'] = 'cafebabe'
+
+        assert m['def'] == 'cafebabe'
+
+        assert m.size() == 3
+
+        m.remove('def')
+
+        assert m['def'] == null
+        assert m.size() == 2
+    }
+
+    void testFindAll(){
+        assert [a:1] == ['a':1, 'b':2].findAll {it.value == 1}
+        assert [a:1] == ['a':1, 'b':2].findAll {it.key == 'a'}
+        assert [a:1] == ['a':1, 'b':2].findAll {key,value -> key == 'a'}
+        assert [a:1] == ['a':1].findAll {true}
+        assert [:]   == ['a':1].findAll {false}
+    }
+}
diff --git a/groovy-core/src/test/groovy/MethodCallTest.groovy b/groovy-core/src/test/groovy/MethodCallTest.groovy
new file mode 100644
index 0000000..7549581
--- /dev/null
+++ b/groovy-core/src/test/groovy/MethodCallTest.groovy
@@ -0,0 +1,29 @@
+class MethodCallTest extends GroovyTestCase {
+
+    void testMethodCall() {
+        System.out.print("hello")
+        println("world!")
+    }
+
+    void testObjectMethodCall() {
+        def c = getClass()
+        assert c != null
+        assert c.name.endsWith("MethodCallTest")
+        assert c.getName().endsWith("MethodCallTest")
+    }
+
+    void testObjectMethodCall2() {
+        def s = "hello"
+        def c = s.getClass()
+        assert c != null
+        assert c.name == "java.lang.String"
+        assert c.getName() == "java.lang.String"
+    }
+
+    void testGetNameBug() {
+        def c = getClass()
+        def n = c.getName()
+        assert c.getName().endsWith("MethodCallTest")
+        assert n.endsWith("MethodCallTest")
+    }
+}
diff --git a/groovy-core/src/test/groovy/MethodCallWithoutParenthesisTest.groovy b/groovy-core/src/test/groovy/MethodCallWithoutParenthesisTest.groovy
new file mode 100644
index 0000000..4013f8e
--- /dev/null
+++ b/groovy-core/src/test/groovy/MethodCallWithoutParenthesisTest.groovy
@@ -0,0 +1,47 @@
+class MethodCallWithoutParenthesisTest extends GroovyTestCase {
+
+    def flag
+
+    void testMethodCallWithOneParam() {
+        flag = false
+        
+        methodWithOneParam "hello"
+        
+        assert flag
+    }
+    
+    void testMethodCallWithOneParamUsingThis() {
+        flag = false
+        
+        this.methodWithOneParam "hello"
+        
+        assert flag
+    }
+    
+    void methodWithOneParam(text) {
+        println("Called method with parameter ${text}")
+        assert text == "hello"
+        flag = true
+    }
+    
+    void testMethodCallWithTwoParams() {
+        methodWithTwoParams 5, 6
+
+        // not allowed in New Groovy
+        // value = methodWithTwoParams 5, 6
+        def value = methodWithTwoParams(5, 6)
+
+        assert value == 11
+    }
+    
+    void testMethodCallWithTwoParamsUsingThis() {
+        def value = this.methodWithTwoParams(5, 6)
+        
+        assert value == 11
+    }
+
+    def methodWithTwoParams(a, b) {
+        println("Called method with parameters ${a} and ${b}")
+        return a + b
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/MethodParameterAccessWithinClosureTest.groovy b/groovy-core/src/test/groovy/MethodParameterAccessWithinClosureTest.groovy
new file mode 100644
index 0000000..c682f0f
--- /dev/null
+++ b/groovy-core/src/test/groovy/MethodParameterAccessWithinClosureTest.groovy
@@ -0,0 +1,48 @@
+/**
+ * To test access to method scoped variable within closure
+ * 
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+class MethodParameterAccessWithinClosureTest extends GroovyTestCase { 
+    def cheese
+    def shop
+       
+    void setUp() {
+        cheese = null
+        shop = ["wensleydale"]
+    }              
+    void testSimpleMethodParameterAccess() { 
+        assert "wensleydale" == vendor1("wensleydale") 
+    }
+    void testMethodParameterWithDifferentNameToPropertyUsingClosure() {
+        assert "wensleydale" == vendor2("wensleydale")
+    }
+    void testMethodParameterWithSameNameAsPropertyUsingClosure() {
+        //@todo fails in 1.0b6   
+        println vendor3("wensleydale")
+        // assert "wensleydale" == vendor3("wensleydale")
+    }
+    
+    private String vendor1(cheese) {
+        cheese
+    }
+    
+    private String vendor2(aCheese) {
+        shop.find() {it == aCheese}
+    }
+    
+    private String vendor3(cheese) {
+        // problem is that cheese here refers to def 'cheese'
+        // and not the method parameter 'cheese'
+        println "shop = $shop"
+        println "cheese = $cheese"
+        def a  = shop.find() {println (it == cheese)}
+        println ([1, 2, 3].find() {it == 2})
+        println (["wensleydale"].find() {it == "wensleydale"})
+        println (shop.find() {it == "wensleydale"})
+        println (shop.find() {it == cheese})
+        println "a = $a"
+    }
+} 
diff --git a/groovy-core/src/test/groovy/MinMaxTest.groovy b/groovy-core/src/test/groovy/MinMaxTest.groovy
new file mode 100644
index 0000000..7576d63
--- /dev/null
+++ b/groovy-core/src/test/groovy/MinMaxTest.groovy
@@ -0,0 +1,50 @@
+/** 
+ * Tests the min() and max() functions
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class MinMaxTest extends GroovyTestCase {
+
+    void testSimpleMinMax() {
+        def list = [5, 2, 6, 1, 9, 8]
+        
+        def n = list.min()
+        assert n == 1
+        
+        n = list.max()
+        assert n == 9
+    }
+    
+    void testMinMaxWithComparator() {
+        def people = getPeople()
+
+        // lets find the maximum by name
+
+        def order = new OrderBy( { it.get('@cheese') } )
+
+        println("People ${people}")
+
+        def p = people.min(order)
+
+        println("Found ${p}")
+
+        assert p.get("@name") == "Joe" , "found person ${p}"
+
+        p = people.max(order)
+        assert p.get("@name") == "Chris" , "found person ${p}"
+    }
+    
+    def getPeople() {
+        def builder = new NodeBuilder()
+        def tree = builder.people {
+            person(name:'James', cheese:'Edam', location:'London')
+            person(name:'Bob', cheese:'Cheddar', location:'Atlanta')
+            person(name:'Chris', cheese:'Red Leicester', location:'London')
+            person(name:'Joe', cheese:'Brie', location:'London')
+        }
+        
+        return tree.children()
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/MinusEqualsTest.groovy b/groovy-core/src/test/groovy/MinusEqualsTest.groovy
new file mode 100644
index 0000000..e84aa4c
--- /dev/null
+++ b/groovy-core/src/test/groovy/MinusEqualsTest.groovy
@@ -0,0 +1,45 @@
+class MinusEqualsTest extends GroovyTestCase {
+
+    void testIntegerMinusEquals() {
+        def x = 4
+        def y = 2
+        x -= y
+        
+        assert x == 2
+        
+        y -= 1
+        
+        assert y == 1
+    }
+
+    void testCharacterMinusEquals() {
+        Character x = 4
+        Character y = 2
+        x -= y
+        
+        assert x == 2
+        
+        y -= 1
+        
+        assert y == 1
+    }
+    
+    void testNumberMinusEquals() {
+        def x = 4.2
+        def y = 2
+        x -= y
+        
+        assert x == 2.2
+        
+        y -= 0.1
+        
+        assert y == 1.9
+    }
+    
+    void testStringMinusEquals() {
+        def foo = "nice cheese"
+        foo -= "cheese"
+        
+        assert foo == "nice "
+    }
+}
diff --git a/groovy-core/src/test/groovy/ModuloTest.groovy b/groovy-core/src/test/groovy/ModuloTest.groovy
new file mode 100644
index 0000000..f0abfb8
--- /dev/null
+++ b/groovy-core/src/test/groovy/ModuloTest.groovy
@@ -0,0 +1,22 @@
+class ModuloTest extends GroovyTestCase {
+  int modulo = 100
+
+  void testModuloLesser() {
+    for (i in 0..modulo-1) {
+      assert (i%modulo)==i
+    }
+  }
+
+  void testModuloEqual() {
+    for (i in 0..modulo) {
+      assert ((i*modulo) % modulo)==0
+    }
+  }
+
+  void testModuloBigger() {
+    for (i in 0..modulo-1) {
+      assert ((i*modulo+i) % modulo)==i
+    }
+  }
+
+}
diff --git a/groovy-core/src/test/groovy/MultiDimArraysTest.groovy b/groovy-core/src/test/groovy/MultiDimArraysTest.groovy
new file mode 100644
index 0000000..2f50420
--- /dev/null
+++ b/groovy-core/src/test/groovy/MultiDimArraysTest.groovy
@@ -0,0 +1,61 @@
+/**
+ * Expose how to deal with multi-dimensional Arrays until this is supported at the language level.
+ * @author Dierk Koenig
+ * @author Jochen Theodorou
+ */
+ 
+package groovy;
+
+public class MultiDimArraysTest extends GroovyTestCase {
+
+    // todo: enable as soon as multi dims are supported
+    void testCallTwoDimStringArray(){
+        def someArrayOfStringArrays =  new SomeClass().anArrayOfStringArrays()
+        assert 1 == someArrayOfStringArrays.size()
+    }
+    
+    void testCallTwoDimStringArrayWorkaround(){
+        def someArrayOfStringArrays =  new SomeClass().anArrayOfStringArraysWorkaround()
+        assert 1 == someArrayOfStringArrays.size()
+        assert "whatever" == someArrayOfStringArrays[0][0]
+        for (i in 0..<someArrayOfStringArrays.size()) {
+            assert someArrayOfStringArrays[i]
+        }
+    }
+
+    void testCallTwoDimStringArrayWorkaroundWithNull(){
+        def someArrayOfStringArrays =  new SomeClass().anArrayOfStringArraysWorkaround()
+        assert 1 == someArrayOfStringArrays.size()
+        assert "whatever" == someArrayOfStringArrays[0][0]
+        someArrayOfStringArrays.each(){ assert it}
+    }
+
+    void testInsideGroovyMultiDimReplacement(){
+        Object[] someArrayOfStringArrays = [["a","a","a"],["b","b","b",null]]
+        assert "a" == someArrayOfStringArrays[0][0]
+        someArrayOfStringArrays.each(){ assert it}
+    }
+    
+    void testMultiDimCreationWithSizes(){
+        Object[][] objectArray = new Object[2][5]
+        assert objectArray.length == 2
+        objectArray.each { 
+          assert it.length == 5 
+          it.each { assert it == null }
+        }
+    }
+    
+    void testMultiDimCreationWithoutSizeAtEnd() {
+       def array = new int[5][6][]
+       assert array.class.name == "[[[I"
+       assert array[0].class.name == "[[I"
+       assert array[0][0] == null
+    }
+    
+    void testMultiDimArrayForCustomClass() {
+		def ff = new MultiDimArraysTest[3][4]
+		assert "[[Lgroovy.MultiDimArraysTest;" == ff.class.name;
+    }
+
+}
+
diff --git a/groovy-core/src/test/groovy/MultilineChainExpressionTest.groovy b/groovy-core/src/test/groovy/MultilineChainExpressionTest.groovy
new file mode 100644
index 0000000..a66b4dd
--- /dev/null
+++ b/groovy-core/src/test/groovy/MultilineChainExpressionTest.groovy
@@ -0,0 +1,16 @@
+class MultilineChainExpressionTest extends GroovyTestCase {
+   void testMultiLineChain() {
+       // the code below should be compileable
+       assert (
+	       System
+	           .out
+	           .class 
+ 	       == 
+	       PrintStream
+	           .class
+       )
+       assert System
+              .err
+              .class == PrintStream.class
+   }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/MultilineStringTest.groovy b/groovy-core/src/test/groovy/MultilineStringTest.groovy
new file mode 100644
index 0000000..1a92ba5
--- /dev/null
+++ b/groovy-core/src/test/groovy/MultilineStringTest.groovy
@@ -0,0 +1,15 @@
+class MultilineStringTest extends GroovyTestCase {
+
+    void testMultilineString() {
+        def s = """abcd
+efg
+
+        hijk
+        
+"""
+        println(s)
+        assert s != null
+        def idx = s.indexOf("i")
+        assert idx > 0
+    }
+}
diff --git a/groovy-core/src/test/groovy/MultiplyDivideEqualsTest.groovy b/groovy-core/src/test/groovy/MultiplyDivideEqualsTest.groovy
new file mode 100644
index 0000000..7714714
--- /dev/null
+++ b/groovy-core/src/test/groovy/MultiplyDivideEqualsTest.groovy
@@ -0,0 +1,80 @@
+class MultiplyDivideEqualsTest extends GroovyTestCase {
+
+    void testIntegerMultiplyEquals() {
+        def x = 2
+        def y = 3
+        x *= y
+        
+        assert x == 6
+        
+        y *= 4
+        
+        assert y == 12
+    }
+
+    void testCharacterMultiplyEquals() {
+        Character x = 2
+        Character y = 3
+        x *= y
+        
+        assert x == 6
+        
+        y *= 4
+        
+        assert y == 12
+    }
+    
+    void testNumberMultiplyEquals() {
+        def x = 1.2
+        def y = 2
+        x *= y
+        
+        assert x == 2.4
+    }
+    
+    void testStringMultiplyEquals() {
+        def x = "bbc"
+        def y = 2
+        x *= y
+        
+        assert x == "bbcbbc"
+
+        x = "Guillaume"
+        y = 0
+        x *= y
+        assert x == ""
+    }
+    
+    
+    void testIntegerDivideEquals() {
+        def x = 18
+        def y = 6
+        x /= y
+        
+        assert x == 3.0
+        
+        y /= 3
+        
+        assert y == 2.0
+    }
+    
+    void testCharacterDivideEquals() {
+        Character x = 18
+        Character y = 6
+        x /= y
+        
+        assert x == 3.0
+        
+        y /= 3
+        
+        assert y == 2.0
+    }
+    
+    void testNumberDivideEquals() {
+        def x = 10.4
+        def y = 2
+        x /= y
+        
+        assert x == 5.2
+    }
+}
diff --git a/groovy-core/src/test/groovy/NamedParameterTest.groovy b/groovy-core/src/test/groovy/NamedParameterTest.groovy
new file mode 100644
index 0000000..0f75085
--- /dev/null
+++ b/groovy-core/src/test/groovy/NamedParameterTest.groovy
@@ -0,0 +1,13 @@
+class NamedParameterTest extends GroovyTestCase {
+
+    void testPassingNamedParametersToMethod() {
+        someMethod(name:"gromit", eating:"nice cheese", times:2)
+    }
+    
+    protected void someMethod(args) {
+        assert args.name == "gromit"
+        assert args.eating == "nice cheese"
+        assert args.times == 2
+        assert args.size() == 3
+    }
+}
diff --git a/groovy-core/src/test/groovy/NegateListsTest.groovy b/groovy-core/src/test/groovy/NegateListsTest.groovy
new file mode 100644
index 0000000..23039c7
--- /dev/null
+++ b/groovy-core/src/test/groovy/NegateListsTest.groovy
@@ -0,0 +1,77 @@
+/** 
+ * Test to negate lists in Classic Groovy.
+ * Test to check whether a given function is even/odd on a given domain.
+ * 
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+class NegateListsTest extends GroovyTestCase {
+
+    void testNegateList() {
+        assert -[1, 2, 3] == [-1, -2, -3]
+
+        def x = [1, 2, 3]
+        assert -x == [-1, -2, -3]
+        assert x == -[-1, -2, -3]
+        assert -(-x) == x
+
+        def y = [-1, -2, -3]
+        assert -x == y
+        assert x == -y
+    }
+
+    void testBitwiseNegateList() {
+        assert ~[1, 2, 3] == [-2, -3, -4]
+
+        def x = [1, 2, 3]
+        assert ~x == [-2, -3, -4]
+        assert x == ~[-2, -3, -4]
+        assert ~~x == x
+        assert ~(~x) == x
+
+        def y = [-2, -3, -4]
+        assert ~x == [-2, -3, -4]
+        assert x == ~y
+    }
+
+    void testEvenFunction() {
+        def PI = Math.PI
+
+        /////////////////////////////////////////////////////////////////////
+        // A case of partition having 10 subintervals.
+        // x = [0.0*PI/2, 0.1*PI/2, 0.2*PI/2, 0.3*PI/2, 0.4*PI/2, 0.5*PI/2, 
+        //               0.6*PI/2, 0.7*PI/2, 0.8*PI/2, 0.9*PI/2, 1.0*PI/2]
+
+        /////////////////////////////////////////////////////////////////////
+        // Generate a domain of function used om testing.
+        def n = 1000    // the number of partitions for the interval 0..2/PI
+        def x = []
+        for (i in 0..n) {
+            x << i*PI/n
+        }
+        // println x
+
+        def cos = { Math.cos(it) }
+        assertTrue(isEvenFn(cos, x))
+
+        def sin = { Math.sin(it) }
+        assertTrue(isOddFn(sin, x))
+
+        def tan = { Math.tan(it) }
+        assertTrue(isOddFn(tan, x))
+    }
+
+    boolean isEvenFn(f, domain) {
+        // println domain.collect(f)
+        // println( (-domain).collect(f) )
+        println( (domain.collect(f)) == ((-domain).collect(f)) )
+        return (domain.collect(f)) == ((-domain).collect(f))
+    }
+
+    boolean isOddFn(f, domain) {
+        // println domain.collect(f)
+        // println(  (-domain).collect(f) )
+        println( domain.collect(f) == -((-domain).collect(f)) )
+        return domain.collect(f) == -((-domain).collect(f))
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/NegationTests.groovy b/groovy-core/src/test/groovy/NegationTests.groovy
new file mode 100644
index 0000000..a7d50e8
--- /dev/null
+++ b/groovy-core/src/test/groovy/NegationTests.groovy
@@ -0,0 +1,25 @@
+class NegationTests extends GroovyTestCase {
+
+    void testNegateInteger() {
+        def a = -1
+        assert a == -1
+    }
+
+    void testNegateIntegerExpression() {
+        def a = -1
+        a = -a
+        assert a == 1
+    }
+
+    void testNegateDouble() {
+        def a = -1.0
+        assert a == -1.0
+    }
+
+    void testNegateDoubleExpression() {
+        def a = -1.0
+        a = -a
+        assert a == 1.0
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/NewExpressionTest.groovy b/groovy-core/src/test/groovy/NewExpressionTest.groovy
new file mode 100644
index 0000000..f43042d
--- /dev/null
+++ b/groovy-core/src/test/groovy/NewExpressionTest.groovy
@@ -0,0 +1,54 @@
+import org.codehaus.groovy.runtime.DummyBean
+
+class NewExpressionTest extends GroovyTestCase {
+
+    void testNewInstance() {
+        def cheese = new String( "hey you hosers" )
+        
+        assert cheese != null
+        
+        println(cheese)
+    }
+
+    void testNewBeanNoArgs() {
+        def bean = new DummyBean()
+        assert bean.name == "James"
+        assert bean.i == 123
+    }
+
+    void testNewBean1Args() {
+        def bean = new DummyBean("Bob")
+        assert bean.name == "Bob"
+        assert bean.i == 123
+    }
+
+    void testNewBean2Args() {
+        def bean = new DummyBean("Bob", 1707)
+        assert bean.name == "Bob"
+        assert bean.i == 1707
+    }
+
+    void testNewInstanceWithFullyQualifiedName() {
+        def bean = new org.codehaus.groovy.runtime.DummyBean("Bob", 1707)
+        assert bean.name == "Bob"
+        assert bean.i == 1707
+    }
+
+    void testNewInstanceWithFullyQualifiedNameNotImported() {
+        def bean = new java.io.File("Foo")
+
+        println "Created $bean"
+
+        assert bean != null
+    }
+    
+    void testNewOnMultipleLines() {
+        def bean = 
+          new
+            File
+            ("Foo")
+
+        assert bean != null
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/NoPackageTest.groovy b/groovy-core/src/test/groovy/NoPackageTest.groovy
new file mode 100644
index 0000000..0df76f7
--- /dev/null
+++ b/groovy-core/src/test/groovy/NoPackageTest.groovy
@@ -0,0 +1,6 @@
+class NoPackageTest extends GroovyTestCase {
+
+    void testClassDef() {
+        assert getClass().name == "NoPackageTest"
+    }
+}
diff --git a/groovy-core/src/test/groovy/NullPropertyTest.groovy b/groovy-core/src/test/groovy/NullPropertyTest.groovy
new file mode 100644
index 0000000..d6c1715
--- /dev/null
+++ b/groovy-core/src/test/groovy/NullPropertyTest.groovy
@@ -0,0 +1,12 @@
+/**
+ * @author Jeremy Rayner 
+ */
+class NullPropertyTest extends GroovyTestCase { 
+    def wensleydale = null
+
+    void testNullProperty() { 
+        assert wensleydale == null 
+    } 
+} 
+
+
diff --git a/groovy-core/src/test/groovy/NumberMathTest.groovy b/groovy-core/src/test/groovy/NumberMathTest.groovy
new file mode 100644
index 0000000..b520fae
--- /dev/null
+++ b/groovy-core/src/test/groovy/NumberMathTest.groovy
@@ -0,0 +1,141 @@
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/** 
+ * Basic NumberMath test.
+ * @see org.codehaus.groovy.runtime.NumberMath
+ */
+class NumberMathTest extends GroovyTestCase {
+
+    void testPromotions() {
+    	def C = '1'.toCharacter();
+    	def B = new Byte("1");
+    	def I = new Integer(1);
+    	def L = new Long(1);
+    	def F = new Float("1.0");
+    	def D = new Double("1.0");
+    	def BI = new BigInteger("1");
+    	def BD = new BigDecimal("1.0");
+    	
+    	//+, -, and * all promote the same way, so sample the matrix
+    	assert C+B instanceof Integer;
+    	assert C-BD instanceof BigDecimal;
+    	assert B+F instanceof Double;
+    	assert B+I instanceof Integer;
+    	
+    	assert I+I instanceof Integer;
+    	assert I-F instanceof Double;
+    	assert I*D instanceof Double;
+    	assert I+BI instanceof BigInteger;
+    	assert I-BD instanceof BigDecimal;
+    	
+    	assert F*L instanceof Double;
+    	assert D+L instanceof Double;
+    	assert BI-L instanceof BigInteger;
+    	assert BD*L instanceof BigDecimal;
+    	
+    	assert F+F instanceof Double;
+    	assert F-BI instanceof Double;
+    	assert F*BD instanceof Double;
+    	
+    	assert F+D instanceof Double;
+    	assert BI-D instanceof Double;
+    	assert BD*D instanceof Double;
+    	
+    	assert BI+BI instanceof BigInteger;
+    	assert BD-BI instanceof BigDecimal;
+    	assert BD*BD instanceof BigDecimal;
+    	
+    	//Division (/) promotes differently so change the expected results:
+    	assert I/I instanceof BigDecimal;
+    	assert I/F instanceof Double;
+    	assert I/D instanceof Double;
+    	assert I/BI instanceof BigDecimal;
+    	assert I/BD instanceof BigDecimal;
+    	
+    	assert F/L instanceof Double;
+    	assert D/L instanceof Double;
+    	assert BI/L instanceof BigDecimal;
+    	assert BD/L instanceof BigDecimal;
+    	
+    	assert F/F instanceof Double;
+    	assert F/BI instanceof Double;
+    	assert F/BD instanceof Double;
+    	
+    	assert F/D instanceof Double;
+    	assert BI/D instanceof Double;
+    	assert BD/D instanceof Double;
+    	
+    	assert BI/BI instanceof BigDecimal;
+    	assert BD/BI instanceof BigDecimal;
+    	assert BD/BD instanceof BigDecimal;
+    }
+    
+    void testOperations() {
+    	def I1 = new Integer(1);
+    	def I2 = new Integer(2);
+    	def I3 = new Integer(3);
+    	def L1 = new Long(1);
+    	def L2 = new Long(2);
+    	def L3 = new Long(3);
+    	def F1 = new Float("1.0");
+    	def F2 = new Float("2.0");
+    	def D1 = new Double("1.0");
+    	def D2 = new Double("2.0");
+    	def BI1 = new BigInteger("1");
+    	def BI2 = new BigInteger("2");
+    	def BD1 = new BigDecimal("1.0");
+    	def BD2 = new BigDecimal("2.0");
+    	def BD20 = new BigDecimal("2.00");
+
+    	
+    	assert I1/I2 instanceof BigDecimal;
+    	assert I1/I2 == new BigDecimal("0.5");
+
+    	assert I1.intdiv(I2) instanceof Integer;
+    	assert I1.intdiv(I2) == 0;
+
+    	assert I3.intdiv(I2) instanceof Integer;
+    	assert I3.intdiv(I2) == 1;
+    	
+    	assert L1.intdiv(I2) instanceof Long;
+    	assert L1.intdiv(I2) == 0;
+
+    	assert L3.intdiv(L2) instanceof Long;
+    	assert L3.intdiv(L2) == 1;
+    	
+    	assert BI1.intdiv(BI2) instanceof BigInteger;
+    	assert BI1.intdiv(BI2) == 0;
+    	
+    	assert I1/I3 instanceof BigDecimal;
+    	assert I1/I3 == new BigDecimal("0.3333333333");
+    	
+    	assert I2/I3 instanceof BigDecimal;
+    	assert I2/I3 == new BigDecimal("0.6666666667");
+    	    	
+    	assert I1/BD2 instanceof BigDecimal;
+    	
+    	//Test keeping max scale of (L, R or 10)
+    	def BBD1 = new BigDecimal("0.12345678901234567");
+    	assert BD1 + BBD1 == new BigDecimal("1.12345678901234567");
+
+    	def BBD2 = new BigDecimal(".000000000000000008");
+    	assert BBD1 + BBD2 == new BigDecimal("0.123456789012345678");
+	}
+	
+	void testUnsupportedIntDivision() {
+	   	try {
+    		1.0 .intdiv(3);
+    	} catch (UnsupportedOperationException uoe) {
+    		return
+    	}
+    	fail("Should catch an UnsupportedOperationException")
+    	
+	   	try {
+    		1.0G .intdiv(3);
+    	} catch (UnsupportedOperationException uoe) {
+    		return
+    	}
+    	fail("Should catch an UnsupportedOperationException")
+	} 
+}
diff --git a/groovy-core/src/test/groovy/OptionalReturnTest.groovy b/groovy-core/src/test/groovy/OptionalReturnTest.groovy
new file mode 100644
index 0000000..788dc5a
--- /dev/null
+++ b/groovy-core/src/test/groovy/OptionalReturnTest.groovy
@@ -0,0 +1,103 @@
+class OptionalReturnTest extends GroovyTestCase {
+
+	def y
+	
+    void testSingleExpression() {
+        def value = foo()
+		
+        assert value == 'fooReturn'
+    }
+
+    void testLastExpressionIsSimple() {
+        def value = bar()
+        
+        assert value == 'barReturn'
+    }
+
+    void testLastExpressionIsBooleanExpression() {
+        def value = foo2()
+        
+        assert value
+
+        value = foo3()
+        
+        assert value == false
+    }
+
+    void testLastExpressionIsAssignment() {
+        def value = assign()
+        
+        assert value == 'assignReturn'
+        
+        value = assignField()
+        
+        assert value == 'assignFieldReturn'
+    }
+
+    void testLastExpressionIsMethodCall() {
+        def value = methodCall()
+        
+        assert value == 'fooReturn'
+    }
+
+    void testEmptyExpression() {
+        def value = nullReturn()
+        
+        assert value == null
+    }
+
+    //  now this is not a compile time error in jsr-03
+    void testVoidMethod() {
+        def value = voidMethod()
+
+        assert value == null
+    }
+
+    void testNonAssignmentLastExpressions() {
+        def value = lastIsAssert()
+        
+        assert value == null
+    }
+
+    def foo() {
+        'fooReturn'
+    }	
+	
+    def bar() {
+        def x = 'barReturn'
+        x
+    }
+	
+    def foo2() {
+        def x = 'cheese'
+        x == 'cheese'
+    }
+	
+    def foo3() {
+        def x = 'cheese'
+        x == 'edam'
+    }
+	
+    def assign() {
+        def x = 'assignReturn'
+    }
+	
+    def assignField() {
+        y = 'assignFieldReturn'
+    }
+    
+    def nullReturn() {
+    }
+
+    def lastIsAssert() {
+        assert 1 == 1
+    }
+
+    def methodCall() {
+        foo()
+    }
+    
+    void voidMethod() {
+        foo()
+    }
+}
diff --git a/groovy-core/src/test/groovy/OuterUser.java b/groovy-core/src/test/groovy/OuterUser.java
new file mode 100644
index 0000000..fc30054
--- /dev/null
+++ b/groovy-core/src/test/groovy/OuterUser.java
@@ -0,0 +1,74 @@
+package groovy;
+
+/**
+ * <p>Sample class used for testing that groovy can call inner classes contructors.</p>
+ * 
+ * @author Guillaume Laforge
+ * 
+ * @cvs.revision $Revision$
+ */
+public class OuterUser
+{
+    private String name;
+    private Integer age;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Integer getAge() {
+        return age;
+    }
+
+    public void setAge(Integer age) {
+        this.age = age;
+    }
+
+    public static class InnerAddress
+    {
+        private String city;
+        private Integer zipcode;
+
+        public String getCity() {
+            return city;
+        }
+
+        public void setCity(String city) {
+            this.city = city;
+        }
+
+        public Integer getZipcode() {
+            return zipcode;
+        }
+
+        public void setZipcode(Integer zipcode) {
+            this.zipcode = zipcode;
+        }
+
+        public static class Street
+        {
+            private String name;
+            private int number;
+
+            public String getName() {
+                return name;
+            }
+
+            public void setName(String name) {
+                this.name = name;
+            }
+
+            public int getNumber() {
+                return number;
+            }
+
+            public void setNumber(int number) {
+                this.number = number;
+            }
+        }
+    }
+}
diff --git a/groovy-core/src/test/groovy/OverloadInvokeMethodTest.groovy b/groovy-core/src/test/groovy/OverloadInvokeMethodTest.groovy
new file mode 100644
index 0000000..73bec6b
--- /dev/null
+++ b/groovy-core/src/test/groovy/OverloadInvokeMethodTest.groovy
@@ -0,0 +1,33 @@
+/**
+ * @version $Revision: 1.4 $
+ */
+class OverloadInvokeMethodTest extends GroovyTestCase {
+    
+    void testBug() {
+        def value = foo(123)
+        assert value == 246
+    }
+
+    /**
+     * Lets overload the invokeMethod() mechanism to provide an alias
+     * to an existing method
+     */
+    def invokeMethod(String name, Object args) {
+        try {
+            return metaClass.invokeMethod(this, name, args)
+        }
+        catch (MissingMethodException e) {
+            if (name == 'foo') {
+                return metaClass.invokeMethod(this, 'bar', args)
+            }
+            else {
+                throw e
+            }
+        }
+    }
+    
+    def bar(param) {
+        return param * 2
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/OverridePropertyGetterTest.groovy b/groovy-core/src/test/groovy/OverridePropertyGetterTest.groovy
new file mode 100644
index 0000000..4f3de9c
--- /dev/null
+++ b/groovy-core/src/test/groovy/OverridePropertyGetterTest.groovy
@@ -0,0 +1,25 @@
+/**
+ * test to ensure that overriding getter doesn't throw a NPE on access
+ * 
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+class OverridePropertyGetterTest extends GroovyTestCase { 
+    def cheese
+       
+    void testSimpleMethodParameterAccess() { 
+        def o = new OverridePropertyGetterTest()
+        def p = new OverridePropertyGetterTest()
+        try {          
+            //@todo
+            //p.cheese = o.cheese
+        } catch (Exception e) {
+            fail(e.getMessage())
+        }
+    }
+    
+    public String getCheese() {
+        return cheese
+    }
+} 
diff --git a/groovy-core/src/test/groovy/PlusEqualsTest.groovy b/groovy-core/src/test/groovy/PlusEqualsTest.groovy
new file mode 100644
index 0000000..27ab2b7
--- /dev/null
+++ b/groovy-core/src/test/groovy/PlusEqualsTest.groovy
@@ -0,0 +1,51 @@
+class PlusEqualsTest extends GroovyTestCase {
+
+    void testIntegerPlusEquals() {
+        def x = 1
+        def y = 2
+        x += y
+        
+        assert x == 3
+        
+        y += 10
+        
+        assert y == 12
+    }
+
+    void testCharacterPlusEquals() {
+        Character x = 1
+        Character y = 2
+        x += y
+        
+        assert x == 3
+        
+        y += 10
+        
+        assert y == 12
+    }
+    
+    void testNumberPlusEquals() {
+        def x = 1.2
+        def y = 2
+        x += y
+        
+        assert x == 3.2
+        
+        y += 10.1
+        
+        assert y == 12.1
+    }
+    
+    void testStringPlusEquals() {
+        def x = "bbc"
+        def y = 2
+        x += y
+        
+        assert x == "bbc2"
+        
+        def foo = "nice cheese"
+        foo += " gromit"
+        
+        assert foo == "nice cheese gromit"
+    }
+}
diff --git a/groovy-core/src/test/groovy/PostfixTest.groovy b/groovy-core/src/test/groovy/PostfixTest.groovy
new file mode 100644
index 0000000..c3cadd3
--- /dev/null
+++ b/groovy-core/src/test/groovy/PostfixTest.groovy
@@ -0,0 +1,30 @@
+class PostfixTest extends GroovyTestCase {
+
+    void testIntegerPostfix() {
+        def x = 1
+        
+        def y = x++
+        
+        assert y == 1
+        assert x == 2
+        
+        assert x++ == 2
+        assert x == 3
+    }
+    
+    void testDoublePostfix() {
+        def x = 1.2
+        def y = x++
+
+        assert y == 1.2
+        assert x++ == 2.2
+        assert x == 3.2
+    }
+
+     void testStringPostfix() {
+        def x = "bbc"
+        x++
+        
+        assert x == "bbd"
+    }
+}
diff --git a/groovy-core/src/test/groovy/PowerOperationTest.groovy b/groovy-core/src/test/groovy/PowerOperationTest.groovy
new file mode 100644
index 0000000..cf70411
--- /dev/null
+++ b/groovy-core/src/test/groovy/PowerOperationTest.groovy
@@ -0,0 +1,72 @@
+/** 
+ * Test Math Power Operation in Classic/New Groovy
+ * 
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+class PowerOperationTest extends GroovyTestCase {
+
+    void testConstantPowerOperation() {
+        assert 2**5 == 32
+        assert -2**5 == -32
+        assert 3**4 == 81
+        assert -3**4 == -81
+        assert 3**-4 == 3.power(-4)
+        assert -3**-4 == -3.power(-4)
+        assert 7**2 - 7*3 + 2 == 30         //  49 - 21 + 2 = 30
+        assert -7**2 - 7*3 + 2 == -68       // -49 - 21 + 2 = -68
+        assert -(7**2) - 7*3 + 2 == -68     // -49 - 21 + 2 = -68
+        assert (-7)**2 - 7*3 + 2 == 30     //  49 - 21 + 2 = 30
+    }
+
+    void testPowerOperation() {
+        def x = 9
+        --x
+        assert x == 8
+        println(--x)
+        assert x == 7
+        println(--x)
+        assert x == 6
+        println((--x)**3)
+        assert x == 5
+        assert (--x)**3 == 64
+        assert (-x**3) == -64
+        assert x == 4
+        assert (++x)**3 == 125
+        assert x == 5
+        assert (x++)**3 == 125
+        assert x == 6
+        println((x++)**3)
+        assert x == 7
+        println(x)
+        println("${x**2}")
+        println("${-x**2}")
+        assert x == 7
+        println("${(--x)**2}")
+        assert x == 6
+        assert (--x)**2 + x*2 - 1 == 34      // 5**2 + 5*2 - 1 = 34
+        assert x == 5
+        assert (x--)**2 + x*2 - 1 == 32      // 5**2 + 4*2 - 1 = 32
+        assert x == 4
+    }
+
+    void testConstantPowerAssignmentOperation() {
+        def x = 5
+        x **= 2
+        assert x == 25
+        assert x**2 == 625
+        assert -x**2 != 625
+        assert -x**2 == -625
+    }
+
+    void testPowerAssignmentOperation() {
+        def x = 5
+        def y = 2
+        x **= y
+        assert x == 25
+        assert x**y == 625
+        assert x**-1 == 1/25
+        assert x**-y == 1/625
+        assert x**-y == x**(-y)
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/PrefixTest.groovy b/groovy-core/src/test/groovy/PrefixTest.groovy
new file mode 100644
index 0000000..0d96925
--- /dev/null
+++ b/groovy-core/src/test/groovy/PrefixTest.groovy
@@ -0,0 +1,35 @@
+class PrefixTest extends GroovyTestCase {
+
+    void testIntegerPrefix() {
+        def x = 1
+        
+        def y = ++x
+        
+        assert y == 2
+        assert x == 2
+        
+        assert ++x == 3
+    }
+    
+    void testDoublePrefix() {
+        def x = 1.2
+        def y = ++x
+        
+        assert y == 2.2
+        assert x == 2.2
+        assert ++x == 3.2
+        assert x == 3.2
+    }
+
+    void testStringPrefix() {
+        def x = "bbc"
+        ++x
+        
+        assert x == "bbd"
+        
+        --x
+        --x
+        
+        assert x == "bbb"
+    }
+}
diff --git a/groovy-core/src/test/groovy/PrimitiveArraysTest.groovy b/groovy-core/src/test/groovy/PrimitiveArraysTest.groovy
new file mode 100644
index 0000000..49dd953
--- /dev/null
+++ b/groovy-core/src/test/groovy/PrimitiveArraysTest.groovy
@@ -0,0 +1,112 @@
+class PrimitiveArraysTest extends GroovyTestCase {
+
+    def c1Field = [] as char[]
+    char[] c2Field = [] as char[]
+    
+    def i1Field = [] as int[]
+    int[] i2Field = [] as int[]
+
+    def d1Field = [] as double[]
+    double[] d2Field = [] as double[]
+
+    def f1Field = [] as float[]
+    float[] f2Field = [] as float[]
+    
+    def l1Field = [] as long[]
+    long[] l2Field = [] as long[]    
+
+    def b1Field = [] as byte[]
+    byte[] b2Field = [] as byte[]
+    
+    def s1Field = [] as short[]
+    short[] s2Field = [] as short[]
+    
+    void testChar() {
+        assert c1Field.class == c2Field.class
+        def ca = ['l','l'] as char[]
+        char[] cb = ['l','l']
+        assert ca.class == cb.class
+        assert c1Field.class == ca.class
+        assert ca.class.name == "[C"
+        
+        ca.each{ assert it=='l' }
+        cb.each{ assert it=='l' }
+    }
+
+
+    void testInt() {
+        assert i1Field.class == i2Field.class
+        def ia = [1,1] as int[]
+        int[] ib = [1,1]
+        assert ia.class == ib.class
+        assert i1Field.class == ia.class
+        assert ia.class.name == "[I"
+        
+        ia.each{ assert it==1 }
+        ib.each{ assert it==1 }
+    }
+
+
+    void testLong() {
+        assert l1Field.class == l2Field.class
+        def la = [1,1] as long[]
+        long[] lb = [1,1]
+        assert la.class == lb.class
+        assert l1Field.class == la.class
+        assert la.class.name == "[J"
+        
+        la.each{ assert it==1l }
+        lb.each{ assert it==1l }
+    }
+
+
+    void testShort() {
+        assert s1Field.class == s2Field.class
+        def sa = [1,1] as short[]
+        short[] sb = [1,1]
+        assert sa.class == sb.class
+        assert s1Field.class == sa.class
+        assert sa.class.name == "[S"
+        
+        sa.each{ assert it==1 }
+        sb.each{ assert it==1 }
+    }
+
+    void testByte() {
+        assert b1Field.class == b2Field.class
+        def ba = [1,1] as byte[]
+        byte[] bb = [1,1]
+        assert ba.class == bb.class
+        assert b1Field.class == ba.class
+        assert ba.class.name == "[B"
+        
+        ba.each{ assert it==1 }
+        bb.each{ assert it==1 }
+    }
+    
+    
+    void testDouble() {
+        assert d1Field.class == d2Field.class
+        def da = [1,1] as double[]
+        double[] db = [1,1]
+        assert da.class == db.class
+        assert d1Field.class == da.class
+        assert da.class.name == "[D"
+        
+        da.each{ assert it==1.0d }
+        db.each{ assert it==1.0d }
+    }
+
+    void testFloat() {
+        assert f1Field.class == f2Field.class
+        def fa = [1,1] as float[]
+        float[] fb = [1,1]
+        assert fa.class == fb.class
+        assert f1Field.class == fa.class
+        assert fa.class.name == "[F"
+        
+        fa.each{ assert it==1.0f }
+        fb.each{ assert it==1.0f }
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/PrimitiveDefaultValueTest.groovy b/groovy-core/src/test/groovy/PrimitiveDefaultValueTest.groovy
new file mode 100644
index 0000000..59e7d39
--- /dev/null
+++ b/groovy-core/src/test/groovy/PrimitiveDefaultValueTest.groovy
@@ -0,0 +1,89 @@
+/**
+ * @TODO: GROOVY-1037
+ *
+ *    $Revision 1.0
+ *    Test for non-initialized fields or variables of the primitive types.
+ *
+ * @author Pilho Kim
+ */
+
+class PrimitiveDefaultValueTest extends GroovyTestCase {
+
+    private int x
+    private long y
+    private double z
+    private byte b
+    private short s
+    private float f
+    private boolean flag
+    private char c
+
+    void testThisPrimitiveDefaultValues() {
+        this.x == 0
+        this.y == 0L
+        this.z == 0.0
+        this.b == (byte) 0
+        this.s == (short) 0
+        this.f == 0.0F
+        this.flag == false
+        this.c == (char) 0
+    }
+
+    void testPrimitiveDefaultValues() {
+        def a = new ClassForPrimitiveDefaultValue()
+        a.x == 0
+        a.y == 0L
+        a.z == 0.0
+        a.b == (byte) 0
+        a.s == (short) 0
+        a.f == 0.0F
+        a.flag == false
+        a.c == (char) 0
+    }
+
+    void testDefaultPrimitiveValuesForAttributes() {
+        def a = new ClassForPrimitiveDefaultValue()
+        a.@x == 0
+        a.@y == 0L
+        a.@z == 0.0
+        a.@b == (byte) 0
+        a.@s == (short) 0
+        a.@f == 0.0F
+        a.@flag == false
+        a.@c == (char) 0
+    }
+
+    void testDefaultPrimitiveValuesForProperties() {
+        def a = new ClassForPrimitiveDefaultValue()
+        a.x1 == 0
+        a.y1 == 0L
+        a.z1 == 0.0
+        a.b1 == (byte) 0
+        a.s1 == (short) 0
+        a.f1 == 0.0F
+        a.flag1 == false
+        a.c1 == (char) 0
+    }
+}
+
+class ClassForPrimitiveDefaultValue {
+    int x
+    long y
+    double z
+    byte b
+    short s
+    float f
+    boolean flag
+    char c
+
+    int x1
+    long y1
+    double z1
+    byte b1
+    short s1
+    float f1
+    boolean flag1
+    char c1
+}
+
+
diff --git a/groovy-core/src/test/groovy/PrimitiveTypeFieldTest.groovy b/groovy-core/src/test/groovy/PrimitiveTypeFieldTest.groovy
new file mode 100644
index 0000000..587d6ee
--- /dev/null
+++ b/groovy-core/src/test/groovy/PrimitiveTypeFieldTest.groovy
@@ -0,0 +1,57 @@
+class PrimitiveTypeFieldTest extends GroovyTestCase {
+    private long longField
+    private static short shortField
+
+    void setValue() {
+        longField = 1
+    }
+
+    def getValue() {
+        def x = longField
+        return x
+    }
+
+    void testPrimitiveField() {
+        setValue()
+
+        def value = getValue()
+        assert value == 1
+
+        assert longField == 1
+    }
+
+    void testIntParamBug() {
+        assert bugMethod(123) == 246
+        assert bugMethod2(123) == 246
+
+        // @todo GROOVY-133
+        def closure = {int x-> x * 2 }
+        assert closure.call(123) == 246
+
+    }
+
+    int bugMethod(int x) {
+        x * 2
+    }
+
+    def bugMethod2(int x) {
+        x * 2
+    }
+    void testStaticPrimitiveField() {
+        shortField = (Short) 123
+
+        assert shortField == 123
+    }
+
+    void testIntLocalVariable() {
+        int x = 123
+        def y = x + 1
+        assert y == 124
+    }
+
+    void testLongLocalVariable() {
+        long x = 123
+        def y = x + 1
+        assert y == 124
+    }
+}
diff --git a/groovy-core/src/test/groovy/PrimitiveTypesTest.groovy b/groovy-core/src/test/groovy/PrimitiveTypesTest.groovy
new file mode 100644
index 0000000..1141fc4
--- /dev/null
+++ b/groovy-core/src/test/groovy/PrimitiveTypesTest.groovy
@@ -0,0 +1,65 @@
+class PrimitiveTypesTest extends GroovyTestCase {
+
+	int getInt() {
+		return 1;
+	}
+	
+	short getShort() {
+		return 1;
+	}
+	
+	boolean getBoolean() {
+		return true;
+	}
+	
+	double getDouble() {
+		return 1.0;
+	}
+	
+	float getFloat() {
+		return 1.0;
+	}
+	
+	byte getByte() {
+		return 1;
+	}
+	
+	long getLong() {
+		return 1;
+	}
+
+	char getChar() {
+		return 'a';
+	}
+	
+	int getNextInt(int i) {
+		return i + 1
+	}
+	
+	short getNextShort(short i) {
+		return i + 1
+	}
+	
+	void testPrimitiveTypes() {
+		assert 1 == getInt()
+		assert 1 == getShort()
+		assert 1 == getByte()
+		assert 1 == getLong()
+		assert getBoolean()
+		assert getDouble() > 0.99
+		assert getFloat() > 0.99
+		assert 'a' == getChar()
+	}
+
+	void testPrimitiveParameters() {		
+		assert getNextInt(1) == 2
+		assert 3 == getNextInt(2)
+		
+		assert getNextShort((Short) 1) == 2
+		assert 3 == getNextShort((Short) 2)
+	}
+		
+	static void main(args) {
+		new PrimitiveTypesTest().testPrimitiveTypes()
+	}
+}
diff --git a/groovy-core/src/test/groovy/PrintTest.groovy b/groovy-core/src/test/groovy/PrintTest.groovy
new file mode 100644
index 0000000..d7e5147
--- /dev/null
+++ b/groovy-core/src/test/groovy/PrintTest.groovy
@@ -0,0 +1,34 @@
+class PrintTest extends GroovyTestCase {
+
+    void testToString_FAILS() { if (notYetImplemented()) return
+        assertToString("hello", 'hello')
+        
+        assertToString([], "[]")
+        assertToString([1, 2, "hello"], '[1, 2, hello]')
+        
+        assertToString([1:20, 2:40, 3:'cheese'], '[1=20, 2=40, 3=cheese]')
+        assertToString([:], "[:]")
+
+        assertToString([['bob':'drools', 'james':'geronimo']], '[[james:geronimo, bob:drools]]')
+        assertToString([5, ["bob", "james"], ["bob":"drools", "james":"geronimo"], "cheese"], '[5, [bob, james], [james:geronimo, bob:drools], cheese]')
+    }
+
+    void testInspect() {
+        assertInspect("hello", '"hello"')
+        
+        assertInspect([], "[]")
+        assertInspect([1, 2, "hello"], '[1, 2, "hello"]')
+        
+        assertInspect([1:20, 2:40, 3:'cheese'], '[1:20, 2:40, 3:"cheese"]')
+        assertInspect([:], "[:]")
+
+        assertInspect([['bob':'drools', 'james':'geronimo']], '[["james":"geronimo", "bob":"drools"]]')
+        assertInspect([5, ["bob", "james"], ["bob":"drools", "james":"geronimo"], "cheese"], '[5, ["bob", "james"], ["james":"geronimo", "bob":"drools"], "cheese"]')
+    }
+    
+    void testCPlusPlusStylePrinting() {
+        def endl = "\n"
+        
+        System.out << "Hello world!" << endl
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/PrivateVariableAccessFromAnotherInstanceTest.groovy b/groovy-core/src/test/groovy/PrivateVariableAccessFromAnotherInstanceTest.groovy
new file mode 100644
index 0000000..9f876d1
--- /dev/null
+++ b/groovy-core/src/test/groovy/PrivateVariableAccessFromAnotherInstanceTest.groovy
@@ -0,0 +1,34 @@
+/**
+ * test to ensure that private instance variables are visible to 
+ * other instance variables of the same class
+ * 
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+class PrivateVariableAccessFromAnotherInstanceTest extends GroovyTestCase implements Cloneable { 
+    def foo
+    private def bar
+              
+    public PrivateVariableAccessFromAnotherInstanceTest() {
+        super()
+        foo = "foo"
+        bar = "bar"
+    }
+              
+    public Object clone() {
+        def result = new PrivateVariableAccessFromAnotherInstanceTest()
+        result.foo = foo
+        result.bar = bar
+        return result
+    }
+    
+    void testClone() {
+        def fred = new PrivateVariableAccessFromAnotherInstanceTest()
+        //@todo fails due to private access to 'bar'
+        //barney = fred.clone()
+
+        // TODO identity comparison
+        //assert !(barney === fred)
+    }
+} 
diff --git a/groovy-core/src/test/groovy/ProcessTest.groovy b/groovy-core/src/test/groovy/ProcessTest.groovy
new file mode 100644
index 0000000..baa499a
--- /dev/null
+++ b/groovy-core/src/test/groovy/ProcessTest.groovy
@@ -0,0 +1,96 @@
+/**
+ * check that groovy Process methods do their job.
+ *
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+import java.io.*
+import java.util.*
+
+class ProcessTest extends GroovyTestCase {
+    def myProcess
+    
+    void setUp() {
+        myProcess = new MockProcess()
+    }
+    
+    void testProcessAppendBytes() {
+        def myBytes = "mooky".getBytes()
+                  
+        myProcess << myBytes
+                  
+        def result = myProcess.outputStream.toByteArray()
+        assert result != null
+        assert Arrays.equals(myBytes,result)
+    }
+    void testProcessAppendTwoByteArrays() {
+        def myBytes1 = "foo".getBytes()
+        def myBytes2 = "bar".getBytes()
+                  
+        myProcess << myBytes1 << myBytes2
+                  
+        def result = myProcess.outputStream.toByteArray()
+        assert result != null
+        assert result.size() == myBytes1.size() + myBytes2.size()          
+    }
+    
+    void testProcessAppend() {
+        myProcess << "mooky"
+        assert "mooky" == myProcess.outputStream.toString()
+    }
+    
+    void testProcessInputStream() {
+        assert myProcess.in instanceof InputStream
+        assert myProcess.in != null
+    }
+    
+    void testProcessText() {
+        assert "" == myProcess.text
+    }
+    
+    void testProcessErrorStream() {
+        assert myProcess.err instanceof InputStream
+        assert myProcess.err != null
+    }
+    
+    void testProcessOutputStream() {
+        assert myProcess.out instanceof OutputStream
+        assert myProcess.out != null
+    }
+    
+    // @todo - ps.waitForOrKill(secs) creates it's own thread, leave this out of test suite for now...
+    
+    void tearDown() {
+        myProcess.destroy()
+    }
+}
+
+/**
+ * simple Process, used purely for test cases
+ */
+class MockProcess extends Process {
+    private def e
+    private def i
+    private def o
+    
+    public MockProcess() {
+        e = new AnotherMockInputStream()
+        i = new AnotherMockInputStream()
+        o = new ByteArrayOutputStream()
+    }
+    void destroy() {}
+    int exitValue() { return 0 }
+    InputStream getErrorStream() { return e }
+    public InputStream getInputStream() { return i }
+    public OutputStream getOutputStream() { return o }
+    int waitFor() { return 0 }
+}
+
+/**
+ * only needed for workaround in groovy, 
+ *     new ByteArrayInputStream(myByteArray) doesn't work at mo... (28-Sep-2004)
+ */
+class AnotherMockInputStream extends InputStream {
+    int read() { return -1 }
+}
diff --git a/groovy-core/src/test/groovy/Property2Test.groovy b/groovy-core/src/test/groovy/Property2Test.groovy
new file mode 100644
index 0000000..72b9363
--- /dev/null
+++ b/groovy-core/src/test/groovy/Property2Test.groovy
@@ -0,0 +1,87 @@
+/** 
+ * was: Tests the use of new def methods in Groovy: eachProperty(), eachPropertyName(), and
+ * allProperties().
+ * New Method: getMetaPropertyValues
+ * Method name has changed: getProperties
+ * Remove: eachProperty(), eachPropertyName() use properties.each {key,value -> } instead
+ *
+ * @author john stump
+ * @author dierk koenig
+ * @version $Revision$
+ */
+class Property2Test extends GroovyTestCase {
+
+    void testEachPropertyName() {
+        def foo = new Foo()
+		
+		// these are the properties that should be there
+		def props = ['name', 'count', 'location', 'blah']
+		foo.properties.each { name, value ->
+			//println "looking for ${prop} in ${props}"
+
+			// todo: GROOVY-996
+                                    // We should see protected properties, but not  private ones.
+			assert name != "invisible"
+
+			// remove this one from the list
+			props = props - [name]
+		}
+
+		// make sure there are none left over
+		//println "count left in props list is ${props.count()}"
+		assert props.count() == 0
+    }
+
+    void testMetaPropertyValuesFromObject() {
+         def foo = new Foo()
+		def metaProps = foo.metaPropertyValues
+		assert metaProps[0] instanceof PropertyValue
+		assertNotNull metaProps[0].name
+		assertNotNull metaProps[0].value
+		assertNotNull metaProps[0].type
+    }
+
+	void testEachProperty() {
+        def foo = new Foo()
+
+		// these are the properties and their values that should be there
+		def props = ['name':'James', 'count':1, 'location':'London', 'blah':9]
+		foo.properties.each { name, value ->
+			//println "looking for ${prop.name} in ${props}"
+			
+			// todo: GROOVY-996
+                                    // We should see protected properties, but not  private ones.
+			assert name != "invisible"
+			
+			def pvalue = props[name]
+			if(pvalue != null)
+				assert pvalue == value
+			
+			// remove this one from the map
+			props.remove(name)
+		}
+		
+		// make sure there are none left over
+		//println "count left in props map is ${props.size()}"
+		assert props.size() == 0
+	}
+	
+	// make sure allProperties() works with expando objects too
+    void testAllPropertiesExpando() {
+        def foo = new Expando()
+		
+		foo.name = 'John'
+		foo.location = 'Colorado'
+		foo.count = 23
+		foo.blah = true
+		
+		// these are the properties that should be there
+		def props = ['name', 'count', 'location', 'blah']
+		foo.properties.each { name, value -> props -= [name] }
+		
+		// there should be none left
+		//println props
+		assert props.size() == 0
+    }
+}
+
diff --git a/groovy-core/src/test/groovy/PropertyTest.groovy b/groovy-core/src/test/groovy/PropertyTest.groovy
new file mode 100644
index 0000000..c1ab9ef
--- /dev/null
+++ b/groovy-core/src/test/groovy/PropertyTest.groovy
@@ -0,0 +1,133 @@
+/** 
+ * Tests the use of properties in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class PropertyTest extends GroovyTestCase {
+
+    void testNormalPropertyGettersAndSetters() {
+        
+        println("About to create Foo")
+        
+        def foo = new Foo()
+
+        println("created ${foo}")
+        
+        def value = foo.getMetaClass()
+        
+        println("metaClass ${value}")
+        
+        println(foo.inspect())
+        
+        println("name ${foo.name}, blah ${foo.blah}")
+        
+        assert foo.name == "James"
+        assert foo.getName() == "James"
+        
+        assert foo.location == "London"
+        assert foo.getLocation() == "London"
+        
+        assert foo.blah == 9
+        assert foo.getBlah() == 9
+        
+        foo.name = "Bob"
+        foo.location = "Atlanta"
+        
+        assert foo.name == "Bob"
+        assert foo.getName() == "Bob"
+        
+        assert foo.location == "Atlanta"
+        assert foo.getLocation() == "Atlanta"
+    }
+    
+    void testOverloadedGetter() {
+        
+        def foo = new Foo()
+
+        println("count ${foo.count}")
+        
+        assert foo.getCount() == 1
+        assert foo.count == 1
+        
+        foo.count = 7
+        
+        assert foo.count == 7
+        assert foo.getCount() == 7
+    }
+
+    void testNoSetterAvailableOnPrivateProperty() {
+        def foo = new Foo()
+        
+        // methods should fail on non-existent method calls
+        //shouldFail { foo.blah = 4 }
+        shouldFail { foo.setBlah(4) }
+    }
+    
+    void testCannotSeePrivateProperties() {
+        def foo = new Foo()
+
+        // def access fails on non-existent def
+        //shouldFail { def x = foo.invisible } //todo: correct handling of access rules
+
+        // methods should fail on non-existent method calls
+        shouldFail { foo.getQ() }
+    }
+
+    void testConstructorWithNamedProperties() {
+        def foo = new Foo(name:'Gromit', location:'Moon')
+        
+        assert foo.name == 'Gromit'
+        assert foo.location == 'Moon'
+        
+        println("created bean ${foo.inspect()}")
+    }
+    
+    void testToString() {
+        def foo = new Foo(name:'Gromit', location:'Moon')
+
+        println foo
+    }
+
+    void testArrayLengthProperty() {
+        // create two arrays, since all use the same MetaArrayLengthProperty object -
+        // make sure it can work for all types and sizes
+        def i = new Integer[5]
+        def s = new String[10]
+
+        // put something in it to make sure we're returning the *allocated* length, and
+        // not the *used* length
+        s[0] = "hello"
+
+        assert i.length == 5
+        assert s.length == 10
+
+        // this def does not mean there is a getLength() method
+        shouldFail { i.getLength() }
+
+        // verify we can't set this def, it's read-only
+        shouldFail { i.length = 6 }
+    }
+
+    void testGstringAssignment() {
+        def foo = new Foo()
+        foo.body = "${foo.name}"
+        assert foo.body == "James"
+    }
+    
+    void testFinalProperty() {
+      def shell = new GroovyShell();
+      def text = """
+        class A {
+           final foo = 1
+        }
+        A.class.declaredMethods.each {
+          assert it.name!="setFoo"
+          
+        }
+        assert new A().foo==1
+      """
+      shell.evaluate(text);
+    }
+}
+
diff --git a/groovy-core/src/test/groovy/PropertyWithoutDotTest.groovy b/groovy-core/src/test/groovy/PropertyWithoutDotTest.groovy
new file mode 100644
index 0000000..276f874
--- /dev/null
+++ b/groovy-core/src/test/groovy/PropertyWithoutDotTest.groovy
@@ -0,0 +1,11 @@
+class PropertyWithoutDotTest extends GroovyTestCase {
+    def getFoo() {
+        return "cheese"
+    }
+    
+    void testProperty() {
+        def value = foo
+        
+        assert value == "cheese"
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/RangeTest.groovy b/groovy-core/src/test/groovy/RangeTest.groovy
new file mode 100644
index 0000000..da20a04
--- /dev/null
+++ b/groovy-core/src/test/groovy/RangeTest.groovy
@@ -0,0 +1,241 @@
+class RangeTest extends GroovyTestCase {
+	
+	void testRange() {
+	    def x = 0
+
+	    for ( i in 0..9 ) {
+	        x = x + i
+	    }
+
+	    assert x == 45
+	    
+	    x = 0
+
+	    for ( i in 0..<10 ) {
+	        x = x + i
+	    }
+
+	    assert x == 45
+	    
+	    x = 0
+
+	    for ( i in 0..'\u0009' ) {
+	        x = x + i
+	    }
+
+	    assert x == 45
+	}
+	
+	void testRangeEach() {
+	    def x = 0
+
+	    (0..9).each {
+	        x = x + it
+	    }
+
+	    assert x == 45
+	    
+	    x = 0
+
+	    (0..<10).each {
+	        x = x + it
+	    }
+
+	    assert x == 45
+	}
+
+	void testIntStep() {
+	    assertStep(0..9, 3, [0, 3, 6, 9])
+	    assertStep(0..<10, 3, [0, 3, 6, 9])
+	    
+	    assertStep(9..0, 3, [9, 6, 3, 0])
+	    assertStep(9..<0, 3, [9, 6, 3])
+	}
+	
+	void testObjectStep() {
+	    assertStep('a'..'f', 2, ['a', 'c', 'e'])
+	    assertStep('a'..<'e', 2, ['a', 'c'])
+	    
+	    assertStep('z'..'v', 2, ['z', 'x', 'v'])
+	    assertStep('z'..<'v', 2, ['z', 'x'])
+	}
+	
+	void testIterateIntRange() {
+	    assertIterate(0..9, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
+	    assertIterate(1..<8, [1, 2, 3, 4, 5, 6, 7])
+	    assertIterate(7..1, [7, 6, 5, 4, 3, 2, 1])
+	    assertIterate(6..<1, [6, 5, 4, 3, 2])
+	}
+	
+	void testIterateObjectRange() {
+	    assertIterate('a'..'d', ['a', 'b', 'c', 'd'])
+	    assertIterate('a'..<'d', ['a', 'b', 'c'])
+	    assertIterate('z'..'x', ['z', 'y', 'x'])
+	    assertIterate('z'..<'x', ['z', 'y'])
+	}
+	
+	void testRangeContains() {
+	    def range = 0..10
+	    assert range.contains(0)
+	    assert range.contains(10)
+	    
+	    range = 0..<5
+	    assert range.contains(0)
+	    assert ! range.contains(5)
+	}
+	
+	void testBackwardsRangeContains() {
+	    def range = 10..0
+	    assert range.contains(0)
+	    assert range.contains(10)
+	    
+	    range = 5..<1
+	    assert range.contains(5)
+	    assert ! range.contains(1)
+	}
+	
+	void testObjectRangeContains() {
+	    def range = 'a'..'x'
+	    assert range.contains('a')
+	    assert range.contains('x')
+	    assert range.contains('z') == false
+	    
+	    range = 'b'..<'f'
+	    assert range.contains('b')
+	    assert ! range.contains('g')
+	    assert ! range.contains('f')
+	    assert ! range.contains('a')
+	}
+	
+	void testBackwardsObjectRangeContains() {
+	    def range = 'x'..'a'
+	    assert range.contains('a')
+	    assert range.contains('x')
+	    assert range.contains('z') == false
+	    
+	    range = 'f'..<'b'
+	    assert ! range.contains('g')
+	    assert range.contains('f')
+	    assert range.contains('c')
+	    assert ! range.contains('b')
+	}
+	
+	void testIntRangeToString() {
+	    assertToString(0..10, "0..10")
+	    assertToString([1, 4..10, 9], "[1, 4..10, 9]")
+	    
+	    assertToString(0..<11, "0..10")
+	    assertToString([1, 4..<11, 9], "[1, 4..10, 9]")
+	    
+	    
+	    assertToString(10..0, "10..0")
+	    assertToString([1, 10..4, 9], "[1, 10..4, 9]")
+	    
+	    assertToString(11..<0, "11..1")
+	    assertToString([1, 11..<4, 9], "[1, 11..5, 9]")
+	}
+	
+	void testObjectRangeToString() {
+	    assertToString('a'..'d', 'a..d', '"a".."d"')
+	    assertToString('a'..<'d', 'a..c', '"a".."c"')
+	    assertToString('z'..'x', 'z..x', '"z".."x"')
+	    assertToString('z'..<'x', 'z..y', '"z".."y"')
+	}
+	
+	void testRangeSize() {
+	    assertSize(1..10, 10)
+	    assertSize(11..<21, 10)
+	    assertSize(30..21, 10)
+	    assertSize(40..<30, 10)
+	}
+
+	void testBorderCases() {
+	    assertIterate(0..1, [0,1])
+	    assertIterate(0..0, [0])
+	    assertIterate(0..-1, [0,-1])
+	    assertIterate(0..<-1, [0])
+	}
+
+	void testEmptyRanges(){
+	    assertSize(0..<0, 0)
+	    assertSize(1..<1, 0)
+	    assertSize(-1..<-1, 0)
+	    assertSize('a'..<'a', 0)
+	    assertSize(0.0G..<0.0G, 0)
+	    (0..<0).each{assert false}
+	    (0..<0).step(1){assert false}
+	    for (i in 0..<0) assert false
+	    assertToString(0..<0, '0..<0', '0..<0')
+	    assertToString('a'..<'a', 'a..<a', '"a"..<"a"')
+	    assertToString(null..<null, 'null..<null', 'null..<null')
+	    assertStep(0..<0, 3, [])
+	    assertIterate(0..<0, [])
+	}
+	
+	void testStringRange() {
+	    def range = 'a'..'d'
+	    
+	    def list = []
+	    range.each { list << it }
+	    assert list == ['a', 'b', 'c', 'd']
+	    
+	    def s = range.size()
+	    assert s == 4
+	}
+	
+	void testBackwardsStringRange() {
+	    def range = 'd'..'a'
+	    
+	    def list = []
+	    range.each { list << it }
+	    assert list == ['d', 'c', 'b', 'a']
+	    
+	    def s = range.size()
+	    assert s == 4
+	}
+	
+	protected void assertIterate(range, expected) {
+	    def list = []
+	    for (it in range) {
+	        list << it
+	    }
+	    assert list == expected , "for loop on ${range}"
+	    
+		list = []
+	    range.each { list << it}
+	    assert list == expected , "each() on ${range}"
+	}
+	
+	protected void assertSize(range, expected) {
+	    def size = range.size()
+	    assert size == expected , range
+	}
+	
+	protected void assertToString(range, expected) {
+	    def text = range.toString()
+	    assert text == expected , "toString() for ${range}"
+	    text = range.inspect()
+	    assert text == expected , "inspect() for ${range}"
+	}
+	
+	protected void assertToString(range, expectedString, expectedInspect) {
+	    def text = range.toString()
+	    assert text == expectedString , "toString() for ${range}"
+	    text = range.inspect()
+	    assert text == expectedInspect , "inspect() for ${range}"
+	}
+	
+	protected void assertStep(range, stepValue, expected) {
+	    def list = []
+	    range.step(stepValue) {
+	        list << it
+	    }
+	    assert list == expected
+
+	    list = []
+	    for (it in range.step(stepValue)) {
+	        list << it
+	    }
+	    assert list == expected
+	}
+}
diff --git a/groovy-core/src/test/groovy/ReadLineTest.groovy b/groovy-core/src/test/groovy/ReadLineTest.groovy
new file mode 100644
index 0000000..41f1e26
--- /dev/null
+++ b/groovy-core/src/test/groovy/ReadLineTest.groovy
@@ -0,0 +1,26 @@
+import java.io.File
+
+/**
+ * Test to ensure that readLine() method works on Reader/InputStream
+ * 
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+class ReadLineTest extends GroovyTestCase {
+    def file
+    void setUp() {
+        file = new File("src/test/groovy/ReadLineTest.groovy")
+    }
+    void testReadOneLineFromReader() {
+        def line
+        file.withReader() {line = it.readLine()}
+        assert line == "import java.io.File"
+    }
+    
+    void testReadOneLineFromInputStream() {
+        def line
+        file.withInputStream() {line = it.readLine()}
+        assert line == "import java.io.File"
+    }
+}
diff --git a/groovy-core/src/test/groovy/RegExpGroupMatchTest.groovy b/groovy-core/src/test/groovy/RegExpGroupMatchTest.groovy
new file mode 100644
index 0000000..38c46c3
--- /dev/null
+++ b/groovy-core/src/test/groovy/RegExpGroupMatchTest.groovy
@@ -0,0 +1,100 @@
+/**
+ * Test for fixing the Jira issue GROOVY-1000
+ *
+ *    Fix an infinite loop when getting after group matching in regular expression.
+ *    Graham Miller has given this idea.
+ *
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+
+import java.util.regex.Matcher
+import java.util.regex.Pattern
+
+class RegExpGroupMatchTest extends GroovyTestCase {
+
+    void testFirst() {
+        assert "cheesecheese" =~ "cheese"
+        assert "cheesecheese" =~ /cheese/
+        assert "cheese" == /cheese/   /*they are both string syntaxes*/
+    }
+
+    void testSecond() {
+        // Lets create a regex Pattern
+        def pattern = ~/foo/
+        assert pattern instanceof Pattern
+        assert pattern.matcher("foo").matches()
+    }
+
+    void testThird() {
+        // Lets create a Matcher
+        def matcher = "cheesecheese" =~ /cheese/
+        assert matcher instanceof Matcher
+
+        def answer = matcher.replaceAll("edam")
+        println answer
+    }
+
+    void testFourth() {
+        // Lets do some replacement
+        def cheese = ("cheesecheese" =~ /cheese/).replaceFirst("nice")
+        assert cheese == "nicecheese"
+    }
+
+    void testFifth() {
+        // Group demo
+        def matcher = "\$abc." =~ "\\\$(.*)\\."
+        matcher.matches();                   // must be invoked
+        assert matcher.group(1) == "abc"     // is one, not zero
+        // assert matcher[1] == "abc"     // This has worked only before jsr-03-release
+        println (matcher[0])
+        assert matcher[0] == ["\$abc.", "abc"]
+        assert matcher[0][1] == "abc"
+    }
+
+    void testSixth() {
+        // Group demo
+        // Avoid having to double all the backslash escaping characters.
+        def matcher = "\$abc." =~ /\$(.*)\./    // no need to double-escape!
+        assert "\\\$(.*)\\." == /\$(.*)\./
+        matcher.matches();                      // must be invoked
+        assert matcher.group(1) == "abc"        // is one, not zero
+        // assert matcher[1] == "abc"     // This has worked only before jsr-03-release
+        println (matcher[0])
+        assert matcher[0] == ["\$abc.", "abc"]
+        assert matcher[0][1] == "abc"
+    }
+
+    // Test no group match.
+    void testNoGroupMatcherAndGet() {
+        def p = /ab[d|f]/
+        def m = "abcabdabeabf" =~ p 
+
+        for (i in 0..<m.count) { 
+            println( "m.groupCount() = " + m.groupCount())
+            println( "  " + i + ": " + m[i] )   // m[i] is a String
+        }
+    }
+
+    // Test group matches.
+    void testGroupMatcherAndGet() {
+        def p = /(?:ab([c|d|e|f]))/
+        def m = "abcabdabeabf" =~ p 
+
+        for (i in 0..<m.count) { 
+            println( "m.groupCount() = " + m.groupCount())
+            println( "  " + i + ": " + m[i] )   // m[i] is a String
+        }
+    }
+
+    // Test group matches.
+    void testAnotherGroupMatcherAndGet() {
+        def m = "abcabdabeabfabxyzabx" =~ /(?:ab([d|x-z]+))/
+
+        m.count.times { 
+            println( "m.groupCount() = " + m.groupCount())
+            println( "  " + it + ": " + m[it] )   // m[it] is a String
+        }
+    }
+}
+
diff --git a/groovy-core/src/test/groovy/RegularExpressionsTest.groovy b/groovy-core/src/test/groovy/RegularExpressionsTest.groovy
new file mode 100644
index 0000000..f71a18e
--- /dev/null
+++ b/groovy-core/src/test/groovy/RegularExpressionsTest.groovy
@@ -0,0 +1,120 @@
+/**
+ * Tests the regular expression syntax.
+ *
+ * @author Sam Pullara
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+ 
+import java.util.regex.Matcher
+import java.util.regex.Pattern
+
+class RegularExpressionsTest extends GroovyTestCase {
+
+     void testSubscript() {
+         def a = "cheesecheese"
+         def b = a =~ "e+"
+         def value = b[2]
+         assert value == "ee"
+
+         value = b[0, 2]
+
+         assert value == "eeee"
+
+         value = b[0, 1..2]
+
+         assert value == "eeeee"
+     }
+
+     void testFindRegex() {
+         assert "cheese" =~ "cheese"
+
+         def regex = "cheese"
+         def string = "cheese"
+         assert string =~ regex
+
+         def i = 0
+         def m = "cheesecheese" =~ "cheese"
+
+         assert m instanceof Matcher
+
+         while(m) { i = i + 1 }
+         assert i == 2
+
+         i = 0
+         m = "cheesecheese" =~ "e+"
+         while(m) { i = i + 1 }
+         assert i == 4
+
+         m.reset()
+         m.find()
+         m.find()
+         m.find()
+         assert m.group() == "ee"
+     }
+
+     void testMatchRegex() {
+         assert "cheese" ==~ "cheese"
+
+         assert !("cheesecheese" ==~ "cheese")
+
+     }
+
+     void testRegexEach() {
+         def i = 0
+         ("cheesecheese" =~ "cheese").each {value -> println(value); i = i + 1}
+         assert i == 2
+
+         i = 0
+         ("cheesecheese" =~ "ee+").each { println(it); i = i + 1}
+         assert i == 2
+     }
+
+     void testSimplePattern() {
+         def pattern = ~"foo"
+         assert pattern instanceof Pattern
+         assert pattern.matcher("foo").matches()
+         assert !pattern.matcher("bar").matches()
+     }
+
+     void testMultiLinePattern() {
+         def pattern = ~"""foo"""
+
+         assert pattern instanceof Pattern
+         assert pattern.matcher("foo").matches()
+         assert !pattern.matcher("bar").matches()
+     }
+
+     void testPatternInAssertion() {
+         assert "foofoofoo" =~ ~"foo"
+     }
+
+
+     void testMatcher() {
+         def matcher = "cheese-cheese" =~ "cheese"
+         def answer = matcher.replaceAll("edam")
+         assert answer == 'edam-edam'
+
+         def cheese = ("cheese cheese!" =~ "cheese").replaceFirst("nice")
+         assert cheese == "nice cheese!"
+     }
+
+    void testGetLastMatcher() {
+        assert "cheese" ==~ "cheese"
+        assert Matcher.getLastMatcher().matches()
+
+        switch("cheesefoo") {
+            case ~"cheesecheese":
+                assert false;
+            case ~"(cheese)(foo)":
+                def m = Matcher.getLastMatcher();
+                assert m.group(0) == "cheesefoo"
+                assert m.group(1) == "cheese"
+                assert m.group(2) == "foo"
+                assert m.groupCount() == 2
+                break;
+            default:
+                assert false
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/ReturnTest.groovy b/groovy-core/src/test/groovy/ReturnTest.groovy
new file mode 100644
index 0000000..68a10e4
--- /dev/null
+++ b/groovy-core/src/test/groovy/ReturnTest.groovy
@@ -0,0 +1,68 @@
+/** 
+ * Tests the use of returns in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class ReturnTest extends GroovyTestCase {
+    void testIntegerReturnValues() {
+        def value = foo(5)
+        assert value == 10
+    }
+
+    void testBooleanReturnValues() {
+        def value = bar(6)
+        assert value
+    }
+
+    def foo(x) {
+        return ( x * 2 )
+    }
+
+    def bar(x) {
+        return x > 5
+    }
+    
+    void testVoidReturn() {
+        explicitVoidReturn()
+        implicitVoidReturn()
+        explicitVoidReturnWithoutFinalReturn()
+        implicitVoidReturnWithoutFinalReturn()
+    }
+
+    void explicitVoidReturn() {
+        return
+    }
+
+    def implicitVoidReturn() {
+        return
+    }
+
+    void explicitVoidReturnWithoutFinalReturn() {
+        def x = 4;
+        if (x == 3) {
+            return;
+        } else {
+            try {
+                x = 3;
+                return;
+            } finally {
+                //do nothing
+            }
+        }
+    }
+
+    def implicitVoidReturnWithoutFinalReturn() {
+        def x = 4;
+        if (x == 3) {
+            return;
+        } else {
+            try {
+                x = 3;
+                return;
+            } finally {
+                //do nothing
+            }
+        }
+    } 
+}
diff --git a/groovy-core/src/test/groovy/SafeNavigationTest.groovy b/groovy-core/src/test/groovy/SafeNavigationTest.groovy
new file mode 100644
index 0000000..49d7ae3
--- /dev/null
+++ b/groovy-core/src/test/groovy/SafeNavigationTest.groovy
@@ -0,0 +1,50 @@
+class SafeNavigationTest extends GroovyTestCase {
+
+    void testNullNavigation() {
+        def x = null
+        def y = x?.bar
+
+        assert y == null
+    }
+
+    void testNormalPropertyNavigation() {
+        def x = ['a':456, 'foo':['bar':123, 'x':456], 'z':99]
+        
+        def y = x?.foo?.bar
+        
+        println("found y ${x?.foo?.bar}")
+        
+        assert y == 123
+    }
+
+    void testNullPropertyNavigation() {
+        def x = null
+        
+        def y = x?.foo?.bar
+        
+        assert y == null
+
+
+        def java.awt.Color color = null
+        def a = color?.alpha
+        assert a == null
+
+    }
+    
+    void testNormalMethodCall() {
+        def x = 1234
+        
+        def y = x?.toString()
+        
+        assert y == "1234"
+    }
+
+    void testNullMethodCall() {
+        def x = null
+        
+        def y = x?.toString()
+        
+        assert y == null
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/SampleMain.groovy b/groovy-core/src/test/groovy/SampleMain.groovy
new file mode 100644
index 0000000..2daeb2e
--- /dev/null
+++ b/groovy-core/src/test/groovy/SampleMain.groovy
@@ -0,0 +1,7 @@
+class SampleMain {
+    static void main(args) {
+        for (arg in args) {
+            println("Argument: " + arg)
+        }
+    }
+}
diff --git a/groovy-core/src/test/groovy/SerializeTest.groovy b/groovy-core/src/test/groovy/SerializeTest.groovy
new file mode 100644
index 0000000..66aa628
--- /dev/null
+++ b/groovy-core/src/test/groovy/SerializeTest.groovy
@@ -0,0 +1,47 @@
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+import java.io.ObjectInputStream
+import java.io.ObjectOutputStream
+
+class SerializeTest extends GroovyTestCase {
+
+    void testFoo() {
+        def foo = new Foo()
+        
+        println("Created ${foo}")
+        
+        foo.name = "Gromit"
+        foo.location = "Moon"
+        
+        def buffer = write(foo)
+        def object = read(buffer)
+        
+        println("Found ${object}")
+        println("Found ${object} with name ${object.name} and location ${object.location}")
+        assert object != null
+        assert object.getMetaClass() != null , "Should have a metaclass!"
+        
+        assert object.name == "Gromit"
+        
+        assert object.class.name == "Foo" 
+        assert object instanceof Foo
+        assert object.location == "Moon"
+    }
+    
+    
+    def write(object) {
+        def buffer = new ByteArrayOutputStream()
+        def out = new ObjectOutputStream(buffer)
+        out.writeObject(object)
+        out.close()
+        return buffer.toByteArray()
+    }
+    
+    def read(buffer) {
+        def input = new ObjectInputStream(new ByteArrayInputStream(buffer))
+        def object = input.readObject()
+        input.close()
+        return object
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/ShellTest.groovy b/groovy-core/src/test/groovy/ShellTest.groovy
new file mode 100644
index 0000000..998b208
--- /dev/null
+++ b/groovy-core/src/test/groovy/ShellTest.groovy
@@ -0,0 +1,33 @@
+class ShellTest extends GroovyTestCase {
+
+    void testReadAndWriteVariable() {
+        def shell = new GroovyShell()
+        
+        shell.foo = 1
+        
+        def value = shell.evaluate("""
+println('foo is currently ' + foo)
+foo = 2 
+println('foo is now ' + foo)                
+return foo
+""", "Dummy1.groovy")
+
+        
+        assert value == 2
+        assert shell.foo == 2 , "Value is now ${shell.foo}"
+	}
+    
+    void testDefineNewVariable() {
+        def shell = new GroovyShell()
+        
+        def value = shell.evaluate( """
+bar = 3 
+println('bar is now ' + bar)                
+return bar
+""", "Dummy2.groovy")
+
+        
+        assert value == 3
+        assert shell.bar == 3 , "Value is now ${shell.bar}"
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/SimpleGStringTemplateEngineTest.groovy b/groovy-core/src/test/groovy/SimpleGStringTemplateEngineTest.groovy
new file mode 100644
index 0000000..408aaac
--- /dev/null
+++ b/groovy-core/src/test/groovy/SimpleGStringTemplateEngineTest.groovy
@@ -0,0 +1,26 @@
+package groovy;
+
+import java.io.StringWriter;
+
+import groovy.text.Template;
+import groovy.text.GStringTemplateEngine;
+import junit.framework.TestCase;
+
+/**
+ * @author andy
+ * @since Jan 11, 2006 1:05:23 PM
+ */
+public class SimpleGStringTemplateEngineTest extends GroovyTestCase
+{
+  public void testRegressionCommentBug() throws Exception
+  {
+    final Template template = new GStringTemplateEngine().createTemplate(
+        "<% // This is a comment that will be filtered from output %>\n" +
+        "Hello World!"
+    );
+
+    final StringWriter sw = new StringWriter();
+    template.make().writeTo(sw);
+    assertEquals("\nHello World!", sw.toString());
+  }
+}
diff --git a/groovy-core/src/test/groovy/SimplePostfixTest.groovy b/groovy-core/src/test/groovy/SimplePostfixTest.groovy
new file mode 100644
index 0000000..b9dd9de
--- /dev/null
+++ b/groovy-core/src/test/groovy/SimplePostfixTest.groovy
@@ -0,0 +1,11 @@
+class SimplePostfixTest extends GroovyTestCase {
+
+    void testPostfix() {
+        def x = 1
+        ++x
+        println(x)
+
+        assert x == 2
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/SingletonBugTest.groovy b/groovy-core/src/test/groovy/SingletonBugTest.groovy
new file mode 100644
index 0000000..1b2eb18
--- /dev/null
+++ b/groovy-core/src/test/groovy/SingletonBugTest.groovy
@@ -0,0 +1,98 @@
+// TODO: GROOVY-435
+
+class SingletonBugTest extends GroovyTestCase {
+
+    public void testPrivate() {
+        def x = SingletonBugPrivate.getInstance()
+        def y = SingletonBugPrivate.getInstance()
+        println "Get one private instance: $x"
+        println "Get another private instance: $y"
+        assert x == y
+
+         println(SingletonBugPrivateSecond.getInstanceSecond())
+         println(SingletonBugPrivateSecond.doTestSecond())
+        // shouldFail { println(SingletonBugPrivateSecond.getInstanceSecond()) }
+        // shouldFail { println(SingletonBugPrivateSecond.doTestSecond()) }
+    }
+
+    public void testProtected() {
+        def x = SingletonBugProtected.getInstance()
+        def y = SingletonBugProtected.getInstance()
+        println "Get one protected instance: $x"
+        println "Get another protected instance: $y"
+        assert x == y
+
+        println(SingletonBugProtectedSecond.getInstanceSecond())
+        println(SingletonBugProtectedSecond.doTestSecond())
+        x = SingletonBugProtectedSecond.getInstanceSecond()
+        y = SingletonBugProtectedSecond.doTestSecond()
+        assert x != y
+    }
+
+}
+
+
+class SingletonBugPrivate {
+
+    private static SingletonBugPrivate instance1 = null
+
+    private SingletonBugPrivate() {
+    }
+    
+    static SingletonBugPrivate getInstance() {
+        if (instance1 == null)
+            instance1 = new SingletonBugPrivate()
+        return instance1
+    }
+    
+    // private static SingletonBugPrivate getInstance2() {
+    //     if (instance1 == null)
+    //         instance1 = new SingletonBugPrivate()
+    //     return instance1
+    // }
+}
+
+
+class SingletonBugProtected {
+
+    private static SingletonBugProtected instance1 = null
+
+    protected SingletonBugProtected() {
+    }
+    
+    static SingletonBugProtected getInstance() {
+        if (instance1 == null)
+            instance1 = new SingletonBugProtected()
+        return instance1
+    }
+    
+    // private static SingletonBugProtected getInstance2() {
+    //     if (instance1 == null)
+    //         instance1 = new SingletonBugProtected()
+    //     return instance1
+    // }
+}
+
+
+class SingletonBugPrivateSecond extends SingletonBugPrivate {
+
+    static SingletonBugPrivate getInstanceSecond() {
+        return doTestSecond()
+    }
+
+    static SingletonBugPrivate doTestSecond() {
+        return new SingletonBugPrivate()
+    }
+}
+
+
+class SingletonBugProtectedSecond extends SingletonBugProtected {
+
+    static SingletonBugProtected getInstanceSecond() {
+        return doTestSecond()
+    }
+
+    static SingletonBugProtected doTestSecond() {
+        return new SingletonBugProtected()
+    }
+}
diff --git a/groovy-core/src/test/groovy/SliceTest.groovy b/groovy-core/src/test/groovy/SliceTest.groovy
new file mode 100644
index 0000000..61bbb5c
--- /dev/null
+++ b/groovy-core/src/test/groovy/SliceTest.groovy
@@ -0,0 +1,14 @@
+class SliceTest extends GroovyTestCase {
+
+    void testListSlice() {
+        def list = [1, 2, 3, 4]
+        list[1,2] = 5
+
+        assert list == [1, 5, 4]
+
+        list[0,1] = [5, 6, 7, 8, 9]
+
+        assert list == [5, 6, 7, 8, 9, 4]
+
+    }
+}
diff --git a/groovy-core/src/test/groovy/SocketTest.groovy b/groovy-core/src/test/groovy/SocketTest.groovy
new file mode 100644
index 0000000..0ce1780
--- /dev/null
+++ b/groovy-core/src/test/groovy/SocketTest.groovy
@@ -0,0 +1,80 @@
+/**
+ * check that groovy Socket methods do their job.
+ *
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+import java.io.*
+import java.net.*
+
+class SocketTest extends GroovyTestCase {
+    def mySocket
+    
+    void setUp() {
+        mySocket = new MockSocket()
+    }
+    
+    void testSocketAppendBytes() {
+        def myBytes = "mooky".getBytes()
+                  
+        mySocket << myBytes
+                  
+        def result = mySocket.outputStream.toByteArray()
+        assert result != null
+        assert Arrays.equals(myBytes,result)
+    }
+    void testSocketAppendTwoByteArrays() {
+        def myBytes1 = "foo".getBytes()
+        def myBytes2 = "bar".getBytes()
+                  
+        mySocket << myBytes1 << myBytes2
+                  
+        def result = mySocket.outputStream.toByteArray()
+        assert result != null
+        assert result.size() == myBytes1.size() + myBytes2.size()          
+    }
+    
+    void testSocketAppend() {
+        mySocket << "mooky"
+        assert "mooky" == mySocket.outputStream.toString()
+    }
+    
+    void testSocketWithStreamsClosure() {
+        mySocket.withStreams {i,o->
+            assert i instanceof InputStream
+            assert i != null
+                      
+            assert o instanceof OutputStream          
+            assert o != null          
+        }
+    }
+    
+    void tearDown() {
+        mySocket.close()
+    }
+}
+
+/**
+ * simple, unconnected Socket, used purely for test cases
+ */
+class MockSocket extends Socket {
+    private def i
+    private def o
+
+    public MockSocket() {
+        i = new MockInputStream()
+        o = new ByteArrayOutputStream()
+    }
+
+    public InputStream getInputStream() { return i }
+    public OutputStream getOutputStream() { return o }
+}
+
+/**
+ * only needed for workaround in groovy, 
+ *     new ByteArrayInputStream(myByteArray) doesn't work at mo... (28-Sep-2004)
+ */
+class MockInputStream extends InputStream {
+    int read() { return -1 }
+}
diff --git a/groovy-core/src/test/groovy/SomeClass.java b/groovy-core/src/test/groovy/SomeClass.java
new file mode 100644
index 0000000..c067c2b
--- /dev/null
+++ b/groovy-core/src/test/groovy/SomeClass.java
@@ -0,0 +1,16 @@
+package groovy;
+
+/**
+ * Arbitrary holder for Java Methods to be called by Groovy TestCases.
+ * @author Dierk Koenig
+ */
+
+public class SomeClass {
+    // currently not supported to be called from Groovy
+    public String[][] anArrayOfStringArrays(){
+        return new String[][]{{"whatever"}};
+    }
+    public Object[] anArrayOfStringArraysWorkaround(){
+        return new Object[]{ new String[]{"whatever",null}};
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/SortTest.groovy b/groovy-core/src/test/groovy/SortTest.groovy
new file mode 100644
index 0000000..97137d7
--- /dev/null
+++ b/groovy-core/src/test/groovy/SortTest.groovy
@@ -0,0 +1,39 @@
+/** 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class SortTest extends GroovyTestCase {
+
+    void testSortWithOrderBy() {
+        def list = getPeople()
+        def order = new OrderBy( { it.cheese } )
+        list.sort(order)
+        
+        assert list[0].name == 'Joe'
+        assert list[-1].name == 'Chris'
+        assert list.name == ['Joe', 'Bob', 'James', 'Chris']
+
+        println "Sorted by cheeee"
+        list.each { println it.dump() }
+    }
+    
+    void testSortWithClosure() {
+        def list = getPeople()
+        list.sort { it.cheese }
+        
+        assert list.name == ['Joe', 'Bob', 'James', 'Chris']
+
+        println "Sorted by cheeee"
+        list.each { println it.dump() }
+    }
+    
+    def getPeople() {
+        def answer = []
+        answer << new Expando(name:'James', cheese:'Edam', location:'London')
+        answer << new Expando(name:'Bob', cheese:'Cheddar', location:'Atlanta')
+        answer << new Expando(name:'Chris', cheese:'Red Leicester', location:'London')
+        answer << new Expando(name:'Joe', cheese:'Brie', location:'London')
+        return answer
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/SpreadDotTest.groovy b/groovy-core/src/test/groovy/SpreadDotTest.groovy
new file mode 100644
index 0000000..6018418
--- /dev/null
+++ b/groovy-core/src/test/groovy/SpreadDotTest.groovy
@@ -0,0 +1,84 @@
+/*
+ * SpreadDotTest.groovy
+ *
+ * @author  Pilho Kim
+ */
+
+
+/**
+ * Test for the spread dot operator "*.".
+ *
+ * For an example,
+ *          list*.property
+ * means
+ *          list.collect { it?.property }
+ */
+public class SpreadDotTest extends GroovyTestCase {
+    public void testSpreadDot() {
+        def m1 = ["a":1, "b":2]
+        def m2 = ["a":11, "b":22]
+        def m3 = ["a":111, "b":222]
+        def x = [m1,m2,m3]
+        println x*.a
+        println x*."a"
+        assert x == [m1, m2, m3]
+
+        def m4 = null
+        x << m4
+        println x*.a
+        println x*."a"
+        assert x == [m1, m2, m3, null]
+
+        def d = new SpreadDotDemo()
+        x << d
+        println x*."a"
+        assert x == [m1, m2, m3, null, d]
+
+        def y = new SpreadDotDemo2()
+        println y."a"
+        println y.a
+
+        x << y
+        println x*."a"
+        assert x == [m1, m2, m3, null, d, y]
+    }
+
+    public void testSpreadDot2() {
+        def a = new SpreadDotDemo()
+        def b = new SpreadDotDemo2()
+        def x = [a, b]
+
+        println ([a,b]*.fnB("1"))
+        assert [a,b]*.fnB("1") == [a.fnB("1"), b.fnB("1")]
+
+        println ([a,b]*.fnB())
+        assert [a,b]*.fnB() == [a.fnB(), b.fnB()]
+    }
+}
+
+class SpreadDotDemo {
+    public java.util.Date getA() {
+        return new Date()
+    }
+    public String fnB() {
+        return "bb"
+    }
+    public String fnB(String m) {
+        return "BB$m"
+    }
+}
+
+class SpreadDotDemo2 {
+    public String getAttribute(String key) {
+        return "Attribute $key"
+    }
+    public String get(String key) {
+        return getAttribute("Get $key")
+    }
+    public String fnB() {
+        return "cc"
+    }
+    public String fnB(String m) {
+        return "CC$m"
+    }
+}
diff --git a/groovy-core/src/test/groovy/SpreadListOperatorTest.groovy b/groovy-core/src/test/groovy/SpreadListOperatorTest.groovy
new file mode 100644
index 0000000..1d2b711
--- /dev/null
+++ b/groovy-core/src/test/groovy/SpreadListOperatorTest.groovy
@@ -0,0 +1,62 @@
+/**
+ * @version $Revision$
+ *
+ * <code>[2, 3].toSpreadList() equals to *[2, 3]</code> <br><br>
+ *
+ * For an example, <pre>
+ *        assert [1, *[2, 3], 4] == [1, 2, 3, 4]
+ * </pre>
+ *
+ * @author Pilho Kim
+ * @author Jochen Theodorou
+ */
+
+class SpreadListOperatorTest extends GroovyTestCase {
+
+    void testSpreadingInList() {
+        println([1, *[222, 333], 456])
+
+        assert [1, *[222, 333], 456] == [1, 222, 333, 456]
+
+        def y = [1,2,3]
+
+        assert [*y] == y
+    }
+
+    void testSpreadingRange() {
+        def r = 1..10
+
+        assert [*r] == r
+        assert [*1..10] == r
+
+    }
+
+    void testSpreadingInMethodParameters() {
+        assert sum(1, *[2, 3], 4) == 10
+        assert sum(*[10, 20, 30, 40]) == 100
+
+        def z = [11, 22, 33]
+
+        assert sum(1, *z) == 67
+
+        assert sum(*z, 2) == 68
+
+        assert sum(*z, 44) == 110
+
+        def x = ["foo", "Bar-"]
+
+        assert sum(*x, *x) == "fooBar-fooBar-"
+    }
+
+    def sum(a, b, c, d) {
+        return a + b + c + d
+    }
+
+    void testSpreadingInClosureParameters() {
+        def twice = {it*2}
+        assert twice(3) == 6
+        assert twice("abcd") == 'abcdabcd'
+
+        assert twice(*[11]) == 22
+    }
+}
diff --git a/groovy-core/src/test/groovy/SpreadMapOperatorTest.groovy b/groovy-core/src/test/groovy/SpreadMapOperatorTest.groovy
new file mode 100644
index 0000000..02114d1
--- /dev/null
+++ b/groovy-core/src/test/groovy/SpreadMapOperatorTest.groovy
@@ -0,0 +1,96 @@
+/**
+ * Test the spread map operator "*:".
+ *
+ *   For an example,
+ *            m = ['a':11, 'aa':22, 'aaa':33]
+ *            z = ['c':100, *:m]
+ *
+ *            m = ['a':11, 'aa':22, 'aaa':33]
+ *            w = ['c':100]
+ *            m.each {w[it.key] = it.value }
+ *
+ *            assert z == w
+ *
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+
+public class SpreadMapOperatorTest extends GroovyTestCase {
+    def f(m) {
+        println m.c
+    }
+
+    def func(m, i, j, k) {
+        // The first argument m is a map.
+        println m
+        println i
+        println j
+        println k
+    }
+
+    def fn() {
+        return [ 1:'ein', 2:'zwei', 3:'drei' ]
+    }
+
+    void testSpreadMap() {
+        try {
+            def m = ["a":100, "b":200]
+            def x = ['tt':55, *:m]
+            println x.size()
+            println x
+            x = ['tt':55, 'yy':77]
+            println x
+            x = [*:m, *:m]
+            println x
+            assert x == m
+
+            x = [*:x, *:fn(), 100:'hundred']
+            println x
+            println(x.getClass())
+            assert x.getClass() == java.util.HashMap
+
+            def y = [1:1, 2:2, *:[3:3, 4:4, *:[5:5], 6:6], 7:7]
+            println y
+            println(y.getClass())
+            assert y == [1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7]
+        }
+        catch (Exception e) {
+            e.printStackTrace()
+        }
+    }
+
+    void testSpreadMapVsWithClosure() {
+        def m = ['a':11, 'aa':22, 'aaa':33]
+        def z = ['c':100, *:m]
+ 
+        def w = ['c':100]
+        m.each { w[it.key] = it.value }
+
+        println z 
+        println w 
+        assert z == w
+
+        def z2 = [*:m, 'c':100]
+        def w2 = m
+        w2['c'] = 100
+        println z2 
+        println w2 
+        assert z2 == w2
+        assert z == z2
+        assert w == w2
+    }
+
+    void testSpreadMapFunctionCall() {
+             def m = ['a':10, 'b':20, 'c':30]
+             f(*:m)                 // Call with only one spread map argument
+             f(*:m, 'e':50)      // Call with one spread map argument and one named argument
+             f('e':100, *:m)     // Call with one named argument and one spread map argument
+
+             func('e':100, 1, 2, 3, *:m)       // Call with one named argument, three usual arguments,  and one spread map argument
+
+             def l = [4, 5]
+             func('e':100, *l, *:m, 6)       // Call with one named argument, one spread list argument, one spread map argument, and  one usual argument
+             func(7, 'e':100, *l, *:m)       // Call with one usual argument, one named argument, one spread list argument, and one spread map argument 
+    }
+}
+
diff --git a/groovy-core/src/test/groovy/SqlDateTest.groovy b/groovy-core/src/test/groovy/SqlDateTest.groovy
new file mode 100644
index 0000000..1e41664
--- /dev/null
+++ b/groovy-core/src/test/groovy/SqlDateTest.groovy
@@ -0,0 +1,48 @@
+package groovy;
+
+class SqlDateTest extends GroovyTestCase {
+
+    void testIncrement() {
+        def rightNowMillis = System.currentTimeMillis()
+        def sqlDate = new java.sql.Date(rightNowMillis)
+        sqlDate++
+        
+        assertTrue  "incrementing a java.sql.Date returned an incorrect type: ${sqlDate.class}", sqlDate instanceof java.sql.Date
+        
+        def diff = sqlDate.getTime() - rightNowMillis
+        assertEquals "incrementing a java.sql.Date did not work properly", 1000 * 60 * 60 * 24, diff
+    }
+
+      void testDecrement() {
+        def rightNowMillis = System.currentTimeMillis()
+        def sqlDate = new java.sql.Date(rightNowMillis)
+        sqlDate--
+        
+        assertTrue  "decrementing a java.sql.Date returned an incorrect type: ${sqlDate.class}", sqlDate instanceof java.sql.Date
+        
+        def diff = rightNowMillis - sqlDate.getTime()
+        assertEquals "decrementing a java.sql.Date did not work properly", 1000 * 60 * 60 * 24, diff
+    }
+      
+    void testPlusOperator() {
+        def rightNowMillis = System.currentTimeMillis()
+        def sqlDate = new java.sql.Date(rightNowMillis)
+        sqlDate += 1
+        
+        assertTrue  "the plus operator applied to a java.sql.Date returned an incorrect type: ${sqlDate.class}", sqlDate instanceof java.sql.Date
+        
+        def diff = sqlDate.getTime() - rightNowMillis
+        assertEquals "decrementing a java.sql.Date did not work properly", 1000 * 60 * 60 * 24, diff
+    }
+    
+    void testMinusOperator() {
+        def rightNowMillis = System.currentTimeMillis()
+        def sqlDate = new java.sql.Date(rightNowMillis)
+        sqlDate -= 1
+        
+        assertTrue  "the minus operator applied to a java.sql.Date returned an incorrect type: ${sqlDate.class}", sqlDate instanceof java.sql.Date
+        
+        def diff = rightNowMillis - sqlDate.getTime()
+        assertEquals "decrementing a java.sql.Date did not work properly", 1000 * 60 * 60 * 24, diff
+    }
+}
diff --git a/groovy-core/src/test/groovy/StackTraceTest.groovy b/groovy-core/src/test/groovy/StackTraceTest.groovy
new file mode 100644
index 0000000..50822b9
--- /dev/null
+++ b/groovy-core/src/test/groovy/StackTraceTest.groovy
@@ -0,0 +1,31 @@
+/**
+* This test case is added to ensure an exception thrown from inside
+* groovy does always contain a valid line number and file name for
+* the script method the exception is thrown from.
+*
+* See also GROOVY-726
+*/
+class StackTraceTest extends GroovyTestCase {
+
+
+	public void testTrace() {
+		def className = this.class.name
+		def assertDone = false	
+		try {
+		  throw new Exception("e")
+		} catch (Exception e) {
+		  assert e.message == "e"
+		  def trace = e.stackTrace
+		  trace.each {
+		    if (it.className == className && it.methodName == "testTrace") {
+		      assert it.lineNumber>0
+		      assert it.fileName != null
+		      assert it.fileName.length() > 0
+		      assertDone = true
+		    }
+		  }
+		}
+		assert assertDone==true
+	}
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/StaticMessage.groovy b/groovy-core/src/test/groovy/StaticMessage.groovy
new file mode 100755
index 0000000..24ba397
--- /dev/null
+++ b/groovy-core/src/test/groovy/StaticMessage.groovy
@@ -0,0 +1,19 @@
+class StaticMessageTest extends GroovyTestCase {

+

+   void testStaticMissingMethodException() {

+      try {

+         Integer.foobarbaz()

+      } catch (MissingMethodException mme) {

+         assert mme.message ==~ '.*static.*'

+      }

+   }

+

+   void testInstanceMissingMethodException() {

+      try {

+         Integer x = 5;

+         x.foobarbaz()

+      } catch (MissingMethodException mme) {

+         assert ! (mme.message ==~ '.*static.*')

+      }

+   }

+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/StaticThisTest.groovy b/groovy-core/src/test/groovy/StaticThisTest.groovy
new file mode 100644
index 0000000..0dba229
--- /dev/null
+++ b/groovy-core/src/test/groovy/StaticThisTest.groovy
@@ -0,0 +1,22 @@
+class StaticThisTest extends GroovyTestCase {
+
+    void testThisFail() {
+        staticMethod()
+    }
+
+    static def staticMethod() {
+        def foo = this
+
+        assert foo != null
+        assert foo.name.endsWith("StaticThisTest")
+
+        println("this: " + this)
+
+        def s = super
+
+        assert s != null
+        assert s.name.endsWith("GroovyTestCase")
+
+        println("super: " + super)
+    }
+}
diff --git a/groovy-core/src/test/groovy/StringBufferTest.groovy b/groovy-core/src/test/groovy/StringBufferTest.groovy
new file mode 100644
index 0000000..344ae77
--- /dev/null
+++ b/groovy-core/src/test/groovy/StringBufferTest.groovy
@@ -0,0 +1,25 @@
+class StringBufferTest extends GroovyTestCase {
+    void testSize() {
+        def x = new StringBuffer()
+        assert x.size() == x.length()
+        x = new StringBuffer('some text')
+        assert x.size() == x.length()
+    }
+
+    void testPutAt(){
+        def buf = new StringBuffer('0123')
+        buf[1..2] = 'xx'
+        assert '0xx3' == buf.toString()  , 'replace with String'
+        buf = new StringBuffer('0123')
+        buf[1..2] = 99
+        assert '0993' == buf.toString()  , 'replace with obj.toString()'
+        buf = new StringBuffer('0123')
+        buf[0..<0] = 'xx'
+        assert 'xx0123' == buf.toString(), 'border case left'
+        buf = new StringBuffer('0123')
+        buf[4..4] = 'xx'
+        println buf.toString()
+        assert '0123xx' == buf.toString(), 'border case right'
+        // more weird Ranges already tested in ListTest
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/StringOperationTest.groovy b/groovy-core/src/test/groovy/StringOperationTest.groovy
new file mode 100644
index 0000000..22e3536
--- /dev/null
+++ b/groovy-core/src/test/groovy/StringOperationTest.groovy
@@ -0,0 +1,41 @@
+class StringOperationTest extends GroovyTestCase {
+
+    def x
+    def y
+    
+    void testPlus() {
+        x = "hello " + "there"
+        assert x == "hello there"
+        
+        x = "hello " + 2
+        assert x == "hello 2"
+        
+        x = "hello " + 1.2
+        assert x == "hello 1.2"
+        
+        y = x + 1
+        assert y == "hello 1.21"        
+    }
+
+	void testLongPlus() {
+	    x = "hello" + " " + "there" + " nice" + " day"
+	    
+	    assert x == "hello there nice day"
+	}
+	
+    void testMinus() {
+		x = "the quick brown fox" - "quick "
+		
+		assert x == "the brown fox"
+		
+		y = x - "brown "
+		
+		assert y == "the fox"
+    }
+    
+    void testOperationsOnConstantString() {
+        assert "hello".size() == 5
+
+        assert "the quick brown".substring(4).substring(0,5) == "quick"
+    }
+}
diff --git a/groovy-core/src/test/groovy/StringTest.groovy b/groovy-core/src/test/groovy/StringTest.groovy
new file mode 100644
index 0000000..2f3a988
--- /dev/null
+++ b/groovy-core/src/test/groovy/StringTest.groovy
@@ -0,0 +1,145 @@
+class StringTest extends GroovyTestCase {
+
+    void testString() {
+        def s = "abcd"
+        assert s.length() == 4
+        assert 4 == s.length()
+        
+        // test polymorphic size() method like collections
+        assert s.size() == 4
+        
+        s = s + "efg" + "hijk"
+        
+        assert s.size() == 11
+        assert "abcdef".size() == 6
+    }
+
+    void testStringPlusNull() {
+        def y = null
+        
+        def x = "hello " + y
+        
+        assert x == "hello null"
+    }
+    
+    void testNextPrevious() {
+    	def x = 'a'
+    	def y = x.next()
+    	assert y == 'b'
+    
+    	def z = 'z'.previous()
+    	assert z == 'y'
+    	
+    	z = 'z'
+    	def b = z.next()
+    	assert b != 'z'
+    	
+    	println(z.charAt(0))
+    	println(b.charAt(0))
+    	
+    	assert b > z
+    	
+    	println "Incremented z: " + b
+    }
+    
+    void testApppendToString() {
+        def name = "Gromit"
+        def result = "hello " << name << "!"
+        
+        assert result.toString() == "hello Gromit!"
+    }
+    
+    void testApppendToStringBuffer() {
+        def buffer = new StringBuffer()
+        
+        def name = "Gromit"
+        buffer << "hello " << name << "!" 
+        
+        assert buffer.toString() == "hello Gromit!"
+    }
+
+    void testApppendAndSubscipt() {
+        def result =  'hello' << " Gromit!"
+        result[1..4] = 'i'
+        assert result.toString() == "hi Gromit!"
+    }
+
+    void assertLength(s, len) {
+        if (s.length() != len)  println "*** length != $len: $s"
+        assert s.length() == len
+    }
+    void assertContains(s, len, subs) {
+        assertLength(s, len)
+        if (s.indexOf(subs) < 0)  println "*** missing $subs: $s"
+        assert s.indexOf(subs) >= 0
+    }
+
+    void testSimpleStringLiterals() {
+        assertLength("\n", 1)
+        assertLength("\"", 1)
+        assertLength("\'", 1)
+        assertLength("\\", 1)
+        assertContains("\${0}", 4, "{0}")
+        assertContains("x\
+y", 2, "xy")
+
+        assertLength('\n', 1)
+        assertLength('\'', 1)
+        assertLength('\\', 1)
+        assertContains('${0}', 4, '{0}')
+        assertContains('x\
+y', 2, 'xy')
+    }
+
+    void testMultilineStringLiterals() {
+        assertContains(""""x""", 2, '"x');
+        assertContains("""""x""", 3, '""x');
+        assertContains("""x
+y""", 3, 'x\ny');
+        assertContains("""\n
+\n""", 3, '\n\n\n');
+
+        assertContains(''''x''', 2, "'x");
+        assertContains('''''x''', 3, "''x");
+        assertContains('''x
+y''', 3, 'x\ny');
+        assertContains('''\n
+\n''', 3, '\n\n\n');
+
+    }
+
+    void testRegexpStringLiterals() {
+        assert "foo" == /foo/
+        assert '\\$$' == /\$$/
+        assert "\\/\\*" == /\/\*/
+        // Backslash before newline disappears (all others are preserved):
+        assert "\n" == /\
+/
+    }
+
+
+    void testBoolCoerce() {
+
+        // Explicit coercion
+        assertFalse((Boolean) "")
+        assertTrue((Boolean) "content")
+
+        // Implicit coercion in statements
+        String s = null
+        if (s) {
+            fail("null should have evaluated to false, but didn't")
+        }
+        s = ''
+        if (s) {
+            fail("'' should have evaluated to false, but didn't")
+        }
+        s = 'something'
+        if (s) {
+            // OK
+        } else {
+            fail("'something' should have evaluated to false, but didn't")
+        }
+        
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/SubscriptTest.groovy b/groovy-core/src/test/groovy/SubscriptTest.groovy
new file mode 100644
index 0000000..7c419d7
--- /dev/null
+++ b/groovy-core/src/test/groovy/SubscriptTest.groovy
@@ -0,0 +1,209 @@
+class SubscriptTest extends GroovyTestCase {
+
+    void testListRange() {
+        def list = ['a', 'b', 'c', 'd', 'e']
+
+        def sub = list[2..4]
+        assert sub == ['c', 'd', 'e']
+        
+        sub = list[2..<5]
+        assert sub == ['c', 'd', 'e']
+        
+        def value = list[-1]
+        assert value == 'e'
+        
+        sub = list[-4..-2]
+        assert sub == ['b', 'c', 'd']
+        
+        // backwards ranges
+        sub = list[-1..-3]
+        assert sub == ['e', 'd', 'c']
+        
+        sub = list[-3..-1]
+        assert sub == ['c', 'd', 'e']
+        
+        sub = list[3..1]
+        assert sub == ['d', 'c', 'b']
+        
+        sub = list[1..-3]
+        assert sub == ['b', 'c']
+    }
+    
+    void testObjectRangeRange() {
+        def list = 'a'..'e'
+        
+        def sub = list[2..4]
+        assert sub == ['c', 'd', 'e']
+        
+        def value = list[-1]
+        assert value == 'e'
+        
+        sub = list[-4..-2]
+        assert sub == ['b', 'c', 'd']
+        
+        // backwards ranges
+        sub = list[-1..-3]
+        assert sub == ['e', 'd', 'c']
+        
+        sub = list[3..1]
+        assert sub == ['d', 'c', 'b']
+    }
+    
+    void testStringArrayRange() {
+        String[] list = ['a', 'b', 'c', 'd', 'e']
+        
+        def sub = list[2..4]
+        assert sub == ['c', 'd', 'e']
+        
+        def value = list[-1]
+        assert value == 'e'
+        
+        sub = list[-4..-2]
+        assert sub == ['b', 'c', 'd']
+        
+        // backwards ranges
+        sub = list[-1..-3]
+        assert sub == ['e', 'd', 'c']
+        
+        sub = list[3..1]
+        assert sub == ['d', 'c', 'b']
+    }
+    
+    void testIntRangeRange() {
+        def list = 10..15
+        
+        def sub = list[2..4]
+        assert sub == [12, 13, 14]
+        
+        def value = list[-1]
+        assert value == 15
+        
+        sub = list[-4..-2]
+        assert sub == [12, 13, 14]
+        
+        // backwards ranges
+        sub = list[-1..-3]
+        assert sub == [15, 14, 13]
+        
+        sub = list[3..1]
+        assert sub == [13, 12, 11]
+    }
+    
+    void testIntArrayRange() {
+        Integer[] list = [ 10, 11, 12, 13, 14, 15 ]
+        
+        def sub = list[2..4]
+        assert sub == [12, 13, 14]
+        
+        def value = list[-1]
+        assert value == 15
+        
+        sub = list[-4..-2]
+        assert sub == [12, 13, 14]
+        
+        // backwards ranges
+        sub = list[-1..-3]
+        assert sub == [15, 14, 13]
+        
+        sub = list[3..1]
+        assert sub == [13, 12, 11]
+    }
+    
+    void testStringSubscript() {
+        def text = "nice cheese gromit!"
+        
+        def x = text[2]
+        
+        assert x == "c"
+        assert x.class == String
+        
+        def sub = text[5..10]
+        assert sub == 'cheese'
+        
+        sub = text[10..5]
+        assert sub == 'eseehc'
+        
+        sub = text[-2..-7]
+        assert sub == 'timorg'
+        
+        sub = text[1..-3]
+        assert sub == "ice cheese gromi"
+        
+    }
+
+    void testStringPutAtRange(){
+        def text = "0123"
+    }
+    
+    void testListSubscriptWithList() {
+        def list = ['a', 'b', 'c', 'd', 'e']
+        
+        def indices = [0, 2, 4]
+        def sub = list[indices]
+        assert sub == ['a', 'c', 'e']
+        
+        // verbose but valid
+        sub = list[[1, 3]]
+        assert sub == ['b', 'd']
+     
+        // syntax sugar
+        sub = list[2, 4]
+        assert sub == ['c', 'e']
+    }
+    
+    
+    void testListSubscriptWithListAndRange() {
+        def list = 100..200
+
+        def sub = list[1, 3, 20..25, 33]
+        assert sub == [101, 103, 120, 121, 122, 123, 124, 125, 133]
+
+        // now lets try it on an array
+        def array = list.toArray()
+
+        sub = array[1, 3, 20..25, 33]
+        assert sub == [101, 103, 120, 121, 122, 123, 124, 125, 133]
+    }
+
+    void testStringWithSubscriptList() {
+
+        def text = "nice cheese gromit!"
+        
+        def sub = text[1, 2, 3, 5..10]
+        
+        assert sub == "icecheese"
+    }
+    
+    void testSubMap() {
+        def map = ['a':123, 'b':456, 'c':789]
+        
+        def keys = ['b', 'a']
+        def sub = map.subMap(keys)
+        
+        assert sub.size() == 2
+        assert sub['a'] == 123
+        assert sub['b'] == 456
+        assert ! sub.containsKey('c')
+    }
+    
+    void testListWithinAListSyntax() {
+        def list = [1, 2, 3, 4..10, 5, 6]
+        
+        assert list.size() == 6
+        def sublist = list[3]
+        assert sublist == 4..10
+        assert sublist == [4, 5, 6, 7, 8, 9, 10]
+    }
+
+
+    void testBeanProperties() {
+        def foo = new Foo()
+
+        foo['name'] = 'Gromit'
+
+        assert foo.name == 'Gromit'
+
+        def value = foo['name']
+        assert value == 'Gromit'
+    }
+}
diff --git a/groovy-core/src/test/groovy/SwitchTest.groovy b/groovy-core/src/test/groovy/SwitchTest.groovy
new file mode 100644
index 0000000..be7bdb9
--- /dev/null
+++ b/groovy-core/src/test/groovy/SwitchTest.groovy
@@ -0,0 +1,105 @@
+class SwitchTest extends GroovyTestCase {
+
+    void testSwitch() {
+        callSwitch("foo", "foo")
+        callSwitch("bar", "barfoo")
+        callSwitch("barbar", "barfoo")
+        callSwitch("dummy", "d*")
+        callSwitch("xyz", "xyzDefault")
+        callSwitch("zzz", "Default")
+        callSwitch(4, "List")
+        callSwitch(5, "List")
+        callSwitch(6, "List")
+        callSwitch("inList", "List")
+        callSwitch(1, "Integer")
+        callSwitch(1.2, "Number")
+        callSwitch(null, "null")
+    }
+
+    def callSwitch(x, expected) {
+        println("Calling switch with ${x}")
+
+        def result = ""
+
+        switch (x) {
+        	case null:
+        		result = "null"
+                break
+
+        	case ~/d.*/:
+        		result = "d*"
+                break
+
+            case "barbar":
+            case "bar":
+                result = result + "bar"
+
+            case "foo":
+                result = result + "foo"
+                break
+
+            case [4, 5, 6, 'inList']:
+                result = "List"
+                break
+
+            case Integer:
+                result = "Integer"
+                break
+
+            case Number:
+                result = "Number"
+                break
+
+            case "xyz":
+                result = result + "xyz"
+
+            default:
+                result = result + "Default"
+
+                // unnecessary just testing compiler
+                break;
+        }
+        println("Found result ${result}")
+
+        assert result == expected , "when calling switch with ${x}"
+    }
+    
+    // test the continue in switch, which should jump to the the while start
+    void testSwitchScope() {
+        def i = 0
+        def j = 0
+        while (true) {
+            ++i;
+            switch(i) {
+                case 4:
+                    continue
+                case 5:
+                    break;
+                default:
+                    j += i;
+                    break;
+            }
+            if (i == 5) break;
+        }
+        assert j == 6
+    }
+
+    void testSwitchWithClosure(){
+        switch(0){
+            case {true}: break
+            default: assert false
+        }
+        switch(0){
+            case {false}: assert false
+        }
+        switch(0){
+            case {it == 0}: break
+            default: assert false
+        }
+        switch(0){
+            case { candidate -> candidate == 0}: break
+            default: assert false
+        }
+    }
+    
+}
diff --git a/groovy-core/src/test/groovy/SwitchWithDifferentTypesTest.groovy b/groovy-core/src/test/groovy/SwitchWithDifferentTypesTest.groovy
new file mode 100644
index 0000000..490efda
--- /dev/null
+++ b/groovy-core/src/test/groovy/SwitchWithDifferentTypesTest.groovy
@@ -0,0 +1,111 @@
+
+import java.util.Date
+
+/** 
+ * A test case for switch statement with different types
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+class SwitchWithDifferentTypesTest extends GroovyTestCase {
+
+    void testSwitchWithIntValues() {
+        assertSwitch(1, 2, 3, 4)
+    }
+
+    void testSwitchWithDoubleValues() {
+        assertSwitch(1.5, 2.4, 3.2, 4.1)
+    }
+    
+    void testSwitchWithStringValues() {
+        assertSwitch("abc", "def", "xyz", "unknown")
+    }
+
+    void testSwitchWithMixedTypeValues() {
+        assertSwitch("abc", new Date(), 5.32, 23)
+    }
+
+
+    void assertSwitch(a, b, c, d) {
+        assertSwitchMatch1(a, a, b, c)
+        assertSwitchMatch2(b, a, b, c)
+        assertSwitchMatch3(c, a, b, c)
+        assertSwitchMatchDefault(d, a, b, c)
+    }
+    
+    void assertSwitchMatch1(value, case1Value, case2Value, case3Value) {
+        switch (value) {
+            case case1Value: 
+                // worked
+                break
+            case case2Value: 
+                failNotEquals(value, case2Value)
+                break
+            case case3Value: 
+                failNotEquals(value, case3Value)
+                break
+            default:
+                failNotDefault(value)
+                break
+        }
+    }
+
+    void assertSwitchMatch2(value, case1Value, case2Value, case3Value) {
+        switch (value) {
+            case case1Value: 
+                failNotEquals(value, case1Value)
+                break
+            case case2Value: 
+                // worked
+                break
+            case case3Value: 
+                failNotEquals(value, case3Value)
+                break
+            default:
+                failNotDefault(value)
+                break
+        }
+    }
+    
+    void assertSwitchMatch3(value, case1Value, case2Value, case3Value) {
+        switch (value) {
+            case case1Value: 
+                failNotEquals(value, case1Value)
+                break
+            case case2Value: 
+                failNotEquals(value, case2Value)
+                break
+            case case3Value: 
+                // worked
+                break
+            default:
+                failNotDefault(value)
+                break
+        }
+    }
+    
+    void assertSwitchMatchDefault(value, case1Value, case2Value, case3Value) {
+        switch (value) {
+            case case1Value: 
+                failNotEquals(value, case1Value)
+                break
+            case case2Value: 
+                failNotEquals(value, case2Value)
+                break
+            case case3Value: 
+                failNotEquals(value, case3Value)
+                break
+            default:
+                // worked
+                break
+        }
+    }
+
+    void failNotEquals(value, expectedCaseValue) {
+        fail("value: " + value + " is not equal to case value: " + expectedCaseValue)
+    }
+
+    void failNotDefault(value) {
+        fail("value: " + value + " should not match the default switch clause" )
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/TernaryOperatorTest.groovy b/groovy-core/src/test/groovy/TernaryOperatorTest.groovy
new file mode 100644
index 0000000..84535f5
--- /dev/null
+++ b/groovy-core/src/test/groovy/TernaryOperatorTest.groovy
@@ -0,0 +1,32 @@
+class TernaryOperatorTest extends GroovyTestCase {
+
+    void testSimpleUse() {
+        def y = 5
+
+        def x = (y > 1) ? "worked" : "failed"
+        assert x == "worked"
+
+
+        x = (y < 4) ? "failed" : "worked"
+        assert x == "worked"
+    }
+
+    void testUseInParameterCalling() {
+        def z = 123
+        assertCalledWithFoo(z > 100 ? "foo" : "bar")
+        assertCalledWithFoo(z < 100 ? "bar" : "foo")
+       }
+
+    def assertCalledWithFoo(param) {
+        println "called with param ${param}"
+        assert param == "foo"
+    }
+    
+    void testwithBoolean(){
+        def a = 1
+        def x = a!=null ? a!=2 : a!=1
+        assert x == true
+        def y = a!=1 ? a!=2 : a!=1
+        assert y == false
+    }
+}
diff --git a/groovy-core/src/test/groovy/TestInterruptor.java b/groovy-core/src/test/groovy/TestInterruptor.java
new file mode 100644
index 0000000..4e01ede
--- /dev/null
+++ b/groovy-core/src/test/groovy/TestInterruptor.java
@@ -0,0 +1,18 @@
+package groovy;
+
+public class TestInterruptor implements Runnable{
+    private Thread caller;
+
+    public TestInterruptor(Thread caller) {
+        this.caller = caller;
+    }
+
+    public void run(){
+        try {
+            Thread.currentThread().sleep(100); // enforce yield, so we have something to interrupt
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        caller.interrupt();
+    }
+}
diff --git a/groovy-core/src/test/groovy/TextPropertyTest.groovy b/groovy-core/src/test/groovy/TextPropertyTest.groovy
new file mode 100644
index 0000000..f4cc007
--- /dev/null
+++ b/groovy-core/src/test/groovy/TextPropertyTest.groovy
@@ -0,0 +1,44 @@
+/**
+ * check that text def is available on...
+ *
+ * myFile.text,  myFile.text(charset),  
+ * myURL.text,  myURL.text(charset),
+ * myInputStream.text,  myInputStream.text(charset),
+ * myReader.text,
+ * myBufferedReader.text,
+ * myProcess.text
+ * 
+ * @author <a href="mailto:jeremy.rayner@bigfoot.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+
+import java.io.*
+
+class TextPropertyTest extends GroovyTestCase {
+    def myReader
+    def myInputStream
+    def myBigEndianEncodedInputStream
+    
+    void setUp() {
+        myReader = new StringReader("digestive")
+        myInputStream = new ByteArrayInputStream("chocolate chip".bytes)
+        myBigEndianEncodedInputStream = new ByteArrayInputStream("shortbread".getBytes("UTF-16BE"))
+    }
+    
+    void testBigEndianEncodedInputStreamText() {
+        assert "shortbread" == myBigEndianEncodedInputStream.getText("UTF-16BE")
+    }
+    
+    void testInputStreamText() {
+        assert "chocolate chip" == myInputStream.text
+    }
+    
+    void testReaderText() {
+        assert "digestive" == myReader.text
+    }
+    
+    void tearDown() {
+        myInputStream = null
+        myReader = null
+    }
+}
diff --git a/groovy-core/src/test/groovy/ThisAndSuperTest.groovy b/groovy-core/src/test/groovy/ThisAndSuperTest.groovy
new file mode 100644
index 0000000..7c6b5b2
--- /dev/null
+++ b/groovy-core/src/test/groovy/ThisAndSuperTest.groovy
@@ -0,0 +1,119 @@
+class ThisAndSuperTest extends GroovyTestCase{

+	void testOverwrittenSuperMethod(){

+		def helper = new TestForSuperHelper2()

+		assert helper.foo() == 2

+		assert helper.callFooInSuper() == 1

+	}

+		

+	void testClosureUsingSuperAndThis(){

+		def helper = new TestForSuperHelper2()

+		assert helper.aClosureUsingThis() == 2

+		assert helper.aClosureUsingSuper() == 1

+  		// accessing private method should not be changed

+  		// by a public method of the same name and signature!

+		assert helper.closureUsingPrivateMethod() == "bar"

+		assert helper.bar() == "no bar"

+		

+		assert helper.aField == "I am a field"

+		helper.closureFieldAccessUsingImplicitThis(1)

+        assert helper.aField == 1

+ 		helper.closureFieldAccessUsingExplicitThis(2)

+ 		assert helper.aField == 2

+	}

+	

+	void testClosureDelegateAndThis(){

+		def map = [:]

+		def helper = new TestForSuperHelper2()

+		

+		helper.aField = "I am a field"

+		helper.closureFieldAccessUsingExplicitThis.delegate = map

+		helper.closureFieldAccessUsingExplicitThis(3)

+ 		assert helper.aField == 3

+ 		assert map.aField == null

+

+		helper.aField = "I am a field"

+		helper.closureFieldAccessUsingImplicitThis.delegate = map

+		helper.closureFieldAccessUsingImplicitThis(4)

+ 		assert helper.aField == 4

+ 		assert map.aField == null

+ 		

+ 		def closure = {this.foo = 1}

+		shouldFail {

+		  closure()

+		}

+		closure.delegate = map

+		shouldFail {

+		  closure()

+		}

+		assert map.foo == null

+		

+		closure = {foo = 1}

+		shouldFail {

+		  closure()

+		}

+		closure.delegate = map

+		closure()

+		assert map.foo == 1

+	}

+	

+	void testConstructorChain() {

+		def helper = new TestForSuperHelper4()

+		assert helper.x == 1

+		helper = new TestForSuperHelper4("foo")

+		assert helper.x == "Object"

+	}

+	

+	void testChainingForAsType() {

+		def helper = new TestForSuperHelper1()

+		def ret = helper as Object[]

+		assert ret instanceof Object[]

+		assert ret[0] == helper

+		

+		shouldFail(ClassCastException) {

+		  helper as Integer

+		}

+	}

+

+}

+

+

+class TestForSuperHelper1 {

+  def foo(){1}

+  private bar(){"bar"}

+  def closureUsingPrivateMethod() {bar()}

+  def asType(Class c) {

+    if (c==Object[]) return [this] as Object[]

+    return super.asType(c)

+  }

+}

+

+class TestForSuperHelper2 extends TestForSuperHelper1{

+  def foo(){2}

+  def callFooInSuper(){super.foo()}

+  def aClosureUsingSuper = {super.foo()}

+  def aClosureUsingThis = {this.foo()}

+  def bar(){"no bar"}

+  public aField = "I am a field"

+  def closureFieldAccessUsingImplicitThis = {x-> aField=x}

+  def closureFieldAccessUsingExplicitThis = {x-> this.aField=x}

+}

+

+class TestForSuperHelper3 {

+  def x

+  TestForSuperHelper3(int i) {

+    this("1")

+    x=1

+  }

+  TestForSuperHelper3(Object j) {

+    x = "Object"

+  }

+}

+

+class TestForSuperHelper4 extends TestForSuperHelper3{

+  TestForSuperHelper4() {

+    super(1)

+  }

+  TestForSuperHelper4(Object j) {

+    super(j)

+  }

+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/ThrowTest.groovy b/groovy-core/src/test/groovy/ThrowTest.groovy
new file mode 100644
index 0000000..76718e8
--- /dev/null
+++ b/groovy-core/src/test/groovy/ThrowTest.groovy
@@ -0,0 +1,18 @@
+import java.util.Arrays
+
+class ThrowTest extends GroovyTestCase {
+    
+    void testThrow() {
+        
+        try {
+	        throw new Exception("abcd")
+	        
+	        fail("Should have thrown an exception by now")
+        }
+        catch (Exception e) {
+            assert e.message == "abcd"
+            
+            println("Caught exception ${e}")
+        }
+    }
+}
diff --git a/groovy-core/src/test/groovy/ToArrayBugTest.groovy b/groovy-core/src/test/groovy/ToArrayBugTest.groovy
new file mode 100644
index 0000000..a796ff6
--- /dev/null
+++ b/groovy-core/src/test/groovy/ToArrayBugTest.groovy
@@ -0,0 +1,29 @@
+import java.util.Arrays
+
+class ToArrayBugTest extends GroovyTestCase {
+    
+    void testToArrayBug() {
+        
+        def array = getArray()
+
+        callArrayMethod(array)
+    }
+    
+    protected def getArray() {
+        def list = [1, 2, 3, 4]
+        def array = list.toArray()
+        
+        assert array != null
+        
+        return array
+    }
+    
+    protected def callArrayMethod(array) {
+        System.out.println("Called method with ${array}")
+        
+        def list = Arrays.asList(array)
+        
+        assert list.size() == 4
+        assert list == [1, 2, 3, 4]
+    }
+}
diff --git a/groovy-core/src/test/groovy/TripleQuotedStringTest.groovy b/groovy-core/src/test/groovy/TripleQuotedStringTest.groovy
new file mode 100644
index 0000000..0ab2fb0
--- /dev/null
+++ b/groovy-core/src/test/groovy/TripleQuotedStringTest.groovy
@@ -0,0 +1,20 @@
+class TripleQuotedStringTest extends GroovyTestCase {
+
+    void testTripleQuotedString() {
+        def s = """
+        Lots of 'text' with a variety of ""quoting "" and
+   a few lines
+    and some escaped \""" quoting and
+    an ending""".trim()
+
+        println(s)
+        assert s != null
+        def idx = s.indexOf("quoting and")
+        assert idx > 0
+    }
+
+    static void main( String[] args ) { 
+        def o = new TripleQuotedStringTest();
+        o.testTripleQuotedString();
+    }
+}
diff --git a/groovy-core/src/test/groovy/TryCatchTest.groovy b/groovy-core/src/test/groovy/TryCatchTest.groovy
new file mode 100644
index 0000000..fb50b18
--- /dev/null
+++ b/groovy-core/src/test/groovy/TryCatchTest.groovy
@@ -0,0 +1,83 @@
+class TryCatchTest extends GroovyTestCase {
+
+    def exceptionCalled
+    def finallyCalled
+	
+    void testTryCatch() {
+        try {
+            failingMethod()
+        }
+        catch (AssertionError e) {
+            onException(e)
+        }
+        finally {
+            onFinally()
+        }
+        afterTryCatch()
+        assert exceptionCalled , "should have invoked the catch clause"
+        assert finallyCalled , "should have invoked the finally clause"
+        println("After try/catch")
+     }
+
+
+     void testTryFinally() {
+         Boolean touched = false;
+         
+         try {
+         }
+         finally {
+             touched = true;
+         }
+
+         assert touched , "finally not called with empty try"
+     }
+
+
+
+     void testWorkingMethod() {
+         /** @todo causes inconsistent stack height
+          assert exceptionCalled == false , "should not invoked the catch clause"
+          */
+         
+         try {
+	    	 workingMethod()
+	     }
+	     catch (AssertionError e) {
+		     onException(e)
+	     }
+	     finally {
+		     onFinally()
+	     }
+	     assert exceptionCalled == false , "should not invoked the catch clause"
+	     assert finallyCalled , "should have invoked the finally clause"
+	     println("After try/catch")
+    }
+    
+    void failingMethod() {
+        assert false , "Failing on purpose"
+	}
+	
+    void workingMethod() {
+        assert true , "Should never fail"
+    }
+    
+    void onException(e) {
+	    assert e != null
+	    exceptionCalled = true
+	}
+	
+    void onFinally() {
+        finallyCalled = true
+	}
+
+    void afterTryCatch() {
+        assert exceptionCalled , "should have invoked the catch clause"        
+        assert finallyCalled , "should have invoked the finally clause"
+        println("After try/catch")
+    }
+    
+    protected void setUp() {
+        exceptionCalled = false
+        finallyCalled = false
+    }
+}
diff --git a/groovy-core/src/test/groovy/TypesafeMethodTest.groovy b/groovy-core/src/test/groovy/TypesafeMethodTest.groovy
new file mode 100644
index 0000000..7238cc3
--- /dev/null
+++ b/groovy-core/src/test/groovy/TypesafeMethodTest.groovy
@@ -0,0 +1,12 @@
+class TypesafeMethodTest extends GroovyTestCase {
+
+    void testTypesafeMethod() {
+        def y = someMethod(1)
+
+        assert y == 2
+    }
+
+    Integer someMethod(Integer i) {
+        return i + 1
+    }
+}
diff --git a/groovy-core/src/test/groovy/UnaryMinusTest.groovy b/groovy-core/src/test/groovy/UnaryMinusTest.groovy
new file mode 100644
index 0000000..38f8be1
--- /dev/null
+++ b/groovy-core/src/test/groovy/UnaryMinusTest.groovy
@@ -0,0 +1,29 @@
+class UnaryMinusTest extends GroovyTestCase {
+
+    void testUnaryMinus() {
+        def value = -1
+        
+        assert value == -1
+        
+        def x = value + 2
+        assert x == 1
+        
+        def y = -value
+        assert y == 1
+    }   
+    
+    void testBug() {
+        def a = 1
+        def b = -a
+        
+        assert b == -1
+    }
+    
+    void testShellBug() {
+        assertScript("""
+def a = 1
+def b = -a
+assert b == -1            
+""")
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/UniqueTest.groovy b/groovy-core/src/test/groovy/UniqueTest.groovy
new file mode 100644
index 0000000..ed7e0e4
--- /dev/null
+++ b/groovy-core/src/test/groovy/UniqueTest.groovy
@@ -0,0 +1,31 @@
+/** 

+ * @author Michael Baehr

+ */

+class UniqueTest extends GroovyTestCase {

+    

+	void testUnique() {

+		def list = [-1, 0, 1, 1, 0, -1]

+    assert list.unique() == [-1, 0, 1]

+	}

+	

+	void testUniqueWithComparator() {

+		def list = [-1, 0, 1, 1, 0, -1]

+		def comparator = new ClosureComparator() {a,b -> Math.abs(a) <=> Math.abs(b)} 

+    assert list.unique(comparator) == [-1, 0]

+	}    

+	

+	// new functionality - see GROOVY-1236

+	void testUniqueWithTwoParameterClosure() {

+		def list = [-1, 0, 1, 1, 0, -1]

+		def closure = {a,b -> Math.abs(a) <=> Math.abs(b)} 

+    assert list.unique(closure) == [-1, 0]

+	}   

+

+	// new functionality - see GROOVY-1236	

+	void testUniqueWithOneParameterClosure() {

+		def list = [-1, 0, 1, 1, 0, -1]

+		def closure = {a -> Math.abs(a)} 

+    assert list.unique(closure) == [-1, 0]

+	}   

+		

+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/UnitTestAsScriptTest.groovy b/groovy-core/src/test/groovy/UnitTestAsScriptTest.groovy
new file mode 100644
index 0000000..bf0f93a
--- /dev/null
+++ b/groovy-core/src/test/groovy/UnitTestAsScriptTest.groovy
@@ -0,0 +1,4 @@
+a = 123
+a *= 2
+println "Running unit test with a = ${a}"
+assert a == 246
diff --git a/groovy-core/src/test/groovy/UnsafeNavigationTest.groovy b/groovy-core/src/test/groovy/UnsafeNavigationTest.groovy
new file mode 100644
index 0000000..9283111
--- /dev/null
+++ b/groovy-core/src/test/groovy/UnsafeNavigationTest.groovy
@@ -0,0 +1,14 @@
+class UnsafeNavigationTest extends GroovyTestCase {
+
+    void testUnsafePropertyNavigations() {
+        def x = null
+        
+        try {
+            def y = x.foo
+            fail("should fail")
+        }
+        catch (NullPointerException e) {
+            assert e != null
+        }
+    }
+}
diff --git a/groovy-core/src/test/groovy/VArgsTest.groovy b/groovy-core/src/test/groovy/VArgsTest.groovy
new file mode 100644
index 0000000..46afcda
--- /dev/null
+++ b/groovy-core/src/test/groovy/VArgsTest.groovy
@@ -0,0 +1,54 @@
+class VArgsTest extends GroovyTestCase {
+
+  def primitiveMethod(){0}
+  def primitiveMethod(int i) {1}  
+  def primitiveMethod(int i, int j) {2}
+  def primitiveMethod(int[] is) {10+is.length}
+  
+  void testPrimitiveMethod() {
+    assert primitiveMethod()==0
+    assert primitiveMethod(1)==1
+    assert primitiveMethod(1,1)==2
+    assert primitiveMethod(1,1,1)==13 
+    assert primitiveMethod([1,2,2,2] as int[])==14
+  }
+  
+  def objectMethod(){0}
+  def objectMethod(Object i) {1}  
+  def objectMethod(Object i, Object j) {2}
+  def objectMethod(Object[] is) {10+is.length}
+  
+  void testObjectMethod() {
+    assert objectMethod()==0
+    assert objectMethod(1)==1
+    assert objectMethod(1,1)==2
+    assert objectMethod(1,1,1)==13
+    assert objectMethod([1,2,2,2] as Object[])==14
+  }
+  
+  def gstringMethod(GString[] gstrings){gstrings.length}
+  
+  void testGStringVargsMethod() {
+    def content = 1
+    def gstring ="$content"
+    assert gstringMethod() == 0
+    assert gstringMethod(gstring) == 1
+    assert gstringMethod(gstring,gstring,gstring) == 3
+    assert gstringMethod([gstring] as GString[]) == 1
+  }
+  
+  def stringMethod(String[] strings) {strings.length}
+  
+  void testStringMethod() {
+    def content = 1
+    def gstring ="$content"
+    assert stringMethod() == 0
+    assert stringMethod(gstring) == 1
+    assert stringMethod(gstring,gstring,gstring) == 3
+    assert stringMethod([gstring] as GString[]) == 1
+    assert stringMethod() == 0
+    assert stringMethod("a") == 1
+    assert stringMethod("a","a","a") == 3
+    assert stringMethod(["a"] as String[]) == 1
+  }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/VarargsMethodTest.groovy b/groovy-core/src/test/groovy/VarargsMethodTest.groovy
new file mode 100644
index 0000000..9189d45
--- /dev/null
+++ b/groovy-core/src/test/groovy/VarargsMethodTest.groovy
@@ -0,0 +1,67 @@
+/** 
+ * VarargsMethodTest.groovy
+ *
+ *   1) Test to fix the Jira issues GROOVY-1023 and GROOVY-1026.
+ *   2) Test the feature that the length of arguments can be variable
+ *      when invoking methods with or without parameters.
+ *
+ * @author Dierk Koenig
+ * @author Pilho Kim
+ * @author Hein Meling
+ * @version $Revision$
+ */
+
+class VarargsMethodTest extends GroovyTestCase {  
+
+    void testVarargsOnly() {  
+        assertEquals 1, varargsOnlyMethod('')  
+        assertEquals 1, varargsOnlyMethod(1)  
+        assertEquals 2, varargsOnlyMethod('','')  
+        assertEquals 1, varargsOnlyMethod( ['',''] )  
+        assertEquals 2, varargsOnlyMethod( ['',''] as Object[])  
+        assertEquals 2, varargsOnlyMethod( *['',''] )  
+
+        // todo: GROOVY-1023
+        assertEquals 0, varargsOnlyMethod()
+
+        // todo: GROOVY-1026
+        assertEquals(-1, varargsOnlyMethod(null))
+        assertEquals(2, varargsOnlyMethod(null, null))
+     }  
+
+     Integer varargsOnlyMethod(Object[] args) {  
+         println("args = " + args)
+         // (1) todo: GROOVY-1023 (Java 5 feature)
+         //     If this method having varargs is invoked with no parameter,
+         //     then args is not null, but an array of length 0.
+         // (2) todo: GROOVY-1026 (Java 5 feature)
+         //     If this method having varargs is invoked with one parameter
+         //     null, then args is null, and so -1 is returned here.
+         if (args == null)
+               return -1
+         return args.size()  
+     }  
+  
+     void testVarargsLast() {  
+         assertEquals 0, varargsLastMethod('')  
+         assertEquals 0, varargsLastMethod(1)  
+         assertEquals 1, varargsLastMethod('','')  
+         assertEquals 2, varargsLastMethod('','','')  
+         assertEquals 1, varargsLastMethod('', ['',''] )  
+         assertEquals 2, varargsLastMethod('', ['',''] as Object[])  
+         assertEquals 2, varargsLastMethod('', *['',''] )  
+
+         // todo: GROOVY-1026
+         assertEquals(-1, varargsLastMethod('',null))
+         assertEquals(2, varargsLastMethod('',null, null))
+     }  
+  
+     Integer varargsLastMethod(Object first, Object[] args) {  
+         // (1) todo: GROOVY-1026 (Java 5 feature)
+         //     If this method having varargs is invoked with two parameters
+         //     1 and null, then args is null, and so -1 is returned here.
+         if (args == null)
+               return -1
+         return args.size()  
+     }  
+}  
diff --git a/groovy-core/src/test/groovy/VerbatimGStringTest.groovy b/groovy-core/src/test/groovy/VerbatimGStringTest.groovy
new file mode 100644
index 0000000..58d2648
--- /dev/null
+++ b/groovy-core/src/test/groovy/VerbatimGStringTest.groovy
@@ -0,0 +1,58 @@
+class VerbatimGStringTest extends GroovyTestCase {
+
+    void testWithOneVariable() {
+        
+        def name = "Bob"
+        
+        def template = """
+hello ${name} how are you?
+"""
+
+        assert template instanceof GString
+
+        def count = template.getValueCount()
+        assert count == 1
+
+        def value = template.getValue(0)
+        assert value == "Bob"
+        assert template.getValue(0) == "Bob"
+
+        def string = template.toString().trim()
+        assert string == "hello Bob how are you?"
+    }
+    
+    void testWithVariableAtEnd() {
+        def name = "Bob"
+
+        def template = """
+hello ${name}
+"""
+
+        def string = template.toString().trim()
+        
+        assert string == "hello Bob"
+    }
+    
+    void testWithVariableAtBeginning() {
+        def name = "Bob"
+
+        def template = """
+${name} hey,
+hello
+"""
+        def string = template.toString().trim()
+        
+        assert fixEOLs(string) == "Bob hey,\nhello"
+    }
+
+    void testWithJustVariable() {
+        def name = "Bob"
+
+        def template = """
+${name}
+"""
+        def string = template.toString().trim()
+        
+        assert string == "Bob"
+    }
+}
diff --git a/groovy-core/src/test/groovy/WhileLoopTest.groovy b/groovy-core/src/test/groovy/WhileLoopTest.groovy
new file mode 100644
index 0000000..e81b752
--- /dev/null
+++ b/groovy-core/src/test/groovy/WhileLoopTest.groovy
@@ -0,0 +1,31 @@
+class WhileLoopTest extends GroovyTestCase {
+
+    void testVerySimpleWhile() {
+        def val = doWhileMethod(0, 5)
+        println(val)
+    }
+
+    void testMoreComplexWhile() {
+        def x = 0
+        def y = 5
+
+        while ( y > 0 ) {
+            x = x + 1
+            y = y - 1
+        }
+
+        assert x == 5
+    }
+
+    def doWhileMethod(x, m) {
+        while ( x < m ) {
+            x = increment(x)
+        }
+
+        return x
+    }
+
+    def increment(x) {
+        x + 1
+    }
+}
diff --git a/groovy-core/src/test/groovy/benchmarks/createLoop.groovy b/groovy-core/src/test/groovy/benchmarks/createLoop.groovy
new file mode 100644
index 0000000..b467d28
--- /dev/null
+++ b/groovy-core/src/test/groovy/benchmarks/createLoop.groovy
@@ -0,0 +1,7 @@
+c = {
+  for (i in 1..it){
+    x = new Object()
+  }
+}
+c.call(30000)
+
diff --git a/groovy-core/src/test/groovy/benchmarks/loop.groovy b/groovy-core/src/test/groovy/benchmarks/loop.groovy
new file mode 100644
index 0000000..22a77c8
--- /dev/null
+++ b/groovy-core/src/test/groovy/benchmarks/loop.groovy
@@ -0,0 +1,26 @@
+import java.util.ArrayList
+
+class Loop {
+  def array = new ArrayList()
+  def pos = 0
+
+  void push(obj){
+     array[pos] = obj
+     pos = pos + 1
+  }
+  Object pop(){
+     pos = pos - 1
+     return array[pos]
+  }
+
+  static void main(args){
+     def s = new Loop()
+     for (i in 1..1000000){
+       s.push(i)
+     }
+     for (i in 1..1000000){
+       s.pop()
+     }
+  }
+}
+
diff --git a/groovy-core/src/test/groovy/benchmarks/loop2.groovy b/groovy-core/src/test/groovy/benchmarks/loop2.groovy
new file mode 100644
index 0000000..d4e7c85
--- /dev/null
+++ b/groovy-core/src/test/groovy/benchmarks/loop2.groovy
@@ -0,0 +1,29 @@
+import java.util.ArrayList
+
+class Loop2 {
+  def array = new ArrayList()
+  def pos = 0
+
+  void push(obj){
+     array[pos] = obj
+     pos = pos + 1
+  }
+
+  Object pop(){
+     pos = pos - 1
+     return array[pos]
+  }
+
+  static void main(args){
+     println "Starting the Loop2 test"
+      
+     def s = new Loop2()
+     for (i in 1..1000000){
+       s.push(i)
+     }
+     for (i in 1..1000000){
+       s.pop()
+     }
+  }
+}
+
diff --git a/groovy-core/src/test/groovy/bugs/AmbigousListOrMethodTest.groovy b/groovy-core/src/test/groovy/bugs/AmbigousListOrMethodTest.groovy
new file mode 100644
index 0000000..f9f7bba
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/AmbigousListOrMethodTest.groovy
@@ -0,0 +1,39 @@
+class AmbigousListOrMethodTest extends GroovyTestCase {
+
+    void testLocalVariableVersion() {
+        def foo = [3, 2, 3]
+
+        def val = foo [0]
+        println val
+        assert val == 3
+    }
+
+    void testUndefinedPropertyVersion() {
+        try {
+            def val = this.foo [0]
+            println val
+        }
+        catch (MissingPropertyException e) {
+            println "Worked! Caught missing property $e"
+        }
+    }
+
+    void testMethodCallVersion() {
+        def val = foo([0])
+        println val
+        assert val == 1
+    }
+
+
+    def foo(int val) {
+        println "Calling foo method with a int param of val"
+        println val
+        return null
+    }
+
+    def foo(List myList) {
+        println "Calling foo method with a list param of $myList"
+        return myList.size()
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/ArrayMethodCallBug.groovy b/groovy-core/src/test/groovy/bugs/ArrayMethodCallBug.groovy
new file mode 100644
index 0000000..b8b31b6
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ArrayMethodCallBug.groovy
@@ -0,0 +1,13 @@
+package groovy.bugs
+
+class ArrayMethodCallBug extends TestSupport {
+
+    void testMethodCallingWithArrayBug() {
+        def array = getMockArguments()
+        
+        dummyMethod(array)
+    }
+    
+    protected void dummyMethod(array) {
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/AsBoolBug.groovy b/groovy-core/src/test/groovy/bugs/AsBoolBug.groovy
new file mode 100644
index 0000000..61dfa84
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/AsBoolBug.groovy
@@ -0,0 +1,71 @@
+package groovy.bugs
+
+/**
+ * Test to fix the Jira issues GROOVY-810 and GROOVY-811.
+ * Test of "string as Boolean" against the issue GROOVY-812.
+ *
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+
+public class AsBoolBug extends GroovyTestCase {
+
+    void testMapAsBool() {
+        def a = ["A":123]
+        println ("$a : ${a as Boolean}")
+        assert a as Boolean == true
+        a = [:]
+        println ("$a : ${a as Boolean}")
+        assert a as Boolean == false
+    }
+
+    void testListAsBool() {
+        def b = [123]
+        println ("$b : ${b as Boolean}")
+        assert b as Boolean == true
+        b = []
+        println ("$b : ${b as Boolean}")
+        assert b as Boolean == false
+    }
+
+    /**
+     * void testStringAsBool().
+     *
+     * <code>string as Boolean</code> is equivalent to
+     *     <code>string != null && string.length() > 0</code>.
+     */
+    // Unfortunately, it contradicts several other test cases, and
+    // it has already been decided to handle string-to-boolean conversions
+    // differently. Commented out temporarily on 10 May 2005.
+    // This is a test case against GROOVY-812
+    void testStringAsBool() {
+        def c = "false"
+        println ("$c : ${c as Boolean}")
+        assert c as Boolean == true
+        assert c as Boolean == (c != null && c.length() > 0)
+        boolean z = c
+        println ("$z")
+        assert z == true
+        if (c)
+           println "It is true!!"
+        else
+           println "It is false!!"
+
+        c = "123"
+        println ("$c : ${c as Boolean}")
+        assert c as Boolean == true
+        assert c as Boolean == (c != null && c.length() > 0)
+
+        c = "False"
+        println ("$c : ${c as Boolean}")
+        assert c as Boolean == true
+        assert c as Boolean == (c != null && c.length() > 0)
+        if (c)
+           println "It is true!!"
+        else
+           println "It is false!!"
+        z = c
+        println ("$z")
+        assert z
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/AssignmentInsideExpressionBug.groovy b/groovy-core/src/test/groovy/bugs/AssignmentInsideExpressionBug.groovy
new file mode 100644
index 0000000..a937b20
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/AssignmentInsideExpressionBug.groovy
@@ -0,0 +1,28 @@
+/**
+ * @version $Revision$
+ */
+class AssignmentInsideExpressionBug extends GroovyTestCase {
+    
+    void testBug() {
+        def x
+        if ((x = someMethod()) != null) {
+            println x
+        }
+        def y
+        if ((y = getFoo()) > 5) {
+            println "y is greater than 5"
+        }
+        
+        def a = 123, b = 123
+        assert a == 123
+        assert b == 123
+    }
+
+    def someMethod() {
+        return "worked!"
+    }
+    
+    def getFoo() {
+        return 7
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/AttributeSetExpressionBug.groovy b/groovy-core/src/test/groovy/bugs/AttributeSetExpressionBug.groovy
new file mode 100644
index 0000000..4270ea9
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/AttributeSetExpressionBug.groovy
@@ -0,0 +1,28 @@
+/**
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+
+package groovy.bugs
+
+class AttributeSetExpressionBug extends GroovyTestCase {
+    void testAttributeSetAccess() {
+        def a = new HasStaticFieldSomeClass()
+        a.name = a.name * 3
+        assert a.@name == "gettter" * 3 
+        assert a.name == "gettter"
+
+        new HasStaticFieldSomeClass().@name = "changed bar"
+        assert( HasStaticFieldSomeClass.class.@name == "changed bar" )
+
+        HasStaticFieldSomeClass.class.@name = "changed static bar"
+        assert( HasStaticFieldSomeClass.class.@name == "changed static bar" )
+    }
+}
+
+class HasStaticFieldSomeClass {
+    public static String name = "bar" 
+    static String getName() {
+        return "gettter"
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/AutoboxingOfComparisonsBug.groovy b/groovy-core/src/test/groovy/bugs/AutoboxingOfComparisonsBug.groovy
new file mode 100644
index 0000000..3169486
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/AutoboxingOfComparisonsBug.groovy
@@ -0,0 +1,8 @@
+class AutoboxingOfComparisonsBug extends GroovyTestCase {
+    void testBug() {
+        def y = true
+        def x = y == true
+        def z = y != false
+        assert x && z
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/BadScriptNameBug.groovy b/groovy-core/src/test/groovy/bugs/BadScriptNameBug.groovy
new file mode 100644
index 0000000..6762e67
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/BadScriptNameBug.groovy
@@ -0,0 +1,11 @@
+/**
+ * @author Sergey Udovenko 
+ * @version $Revision: 1.3 $
+ */
+class BadScriptNameBug extends GroovyTestCase {
+    
+    void testBug() {
+		GroovyClassLoader cl = new GroovyClassLoader(); 
+		cl.parseClass("println 'oops!'", "/script.groovy");
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/BenchmarkBug.groovy b/groovy-core/src/test/groovy/bugs/BenchmarkBug.groovy
new file mode 100644
index 0000000..aedf3e2
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/BenchmarkBug.groovy
@@ -0,0 +1,30 @@
+/**
+ * A little performance test
+ * @version $Revision$
+ */
+class BenchmarkBug extends GroovyTestCase {
+    
+    void testPerformance() {
+        def start = System.currentTimeMillis()
+
+        def total = 0
+        def size = 10000
+        for (i in 0..size) {
+            total = total + callSomeMethod("hello", total)
+        }
+
+        def end = System.currentTimeMillis()
+
+        def time = end - start
+
+        println "Performed ${size} iterations in ${time / 1000} seconds which is ${time / size} ms per iteration"
+
+        // TODO: parser bug
+        // assert total == size * 10 + 10
+        assert total == 100010
+    }
+    
+    def callSomeMethod(text, total) {
+        return 10
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/BlockAsClosureBug.groovy b/groovy-core/src/test/groovy/bugs/BlockAsClosureBug.groovy
new file mode 100644
index 0000000..3108017
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/BlockAsClosureBug.groovy
@@ -0,0 +1,49 @@
+/**
+ * @version $Revision: 1.4 $
+ */
+class BlockAsClosureBug extends GroovyTestCase {
+    
+   void testBug() {
+        def c = 0
+        
+        block: { 
+            c = 9 
+        } 
+
+        println(c) 
+        
+        assert c == 9
+    }
+    
+    void testStaticBug() {
+        staticMethod(null)		
+    }
+    
+    void testNonVoidMethod() {
+        foo()		
+    }
+    
+    static void staticMethod(args) {
+        def c = 0
+        
+        block: {
+            c = 9 
+        }
+
+        println(c) 
+        
+        assert c == 9
+    }
+    
+    def foo() {
+        def c = 0 
+        
+        block: { 
+            c = 9 
+        } 
+        println(c) 
+        
+        assert c == 9
+        return 5
+    }
+   }
diff --git a/groovy-core/src/test/groovy/bugs/BooleanBug.groovy b/groovy-core/src/test/groovy/bugs/BooleanBug.groovy
new file mode 100644
index 0000000..1876d26
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/BooleanBug.groovy
@@ -0,0 +1,31 @@
+/**
+ * @version $Revision$
+ */
+class BooleanBug extends GroovyTestCase {
+    
+    void testBug() {
+        def x = new BooleanBean(name:'James', foo:true)
+        def y = new BooleanBean(name:'Bob', foo:false)
+
+        assert x.foo
+        assert ! y.foo
+        y.foo = true
+        assert y.foo
+    }
+    
+    void testBug2() {
+        BooleanBean bean = new BooleanBean(name:'Gromit', foo:false)
+        def value = isApplicableTo(bean)
+        assert value
+    }
+    
+    public boolean isApplicableTo(BooleanBean field) {
+        return !field.isFoo();
+    }
+
+}
+
+class BooleanBean {
+    String name
+    boolean foo
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/ByteIndexBug.groovy b/groovy-core/src/test/groovy/bugs/ByteIndexBug.groovy
new file mode 100644
index 0000000..9537f5d
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ByteIndexBug.groovy
@@ -0,0 +1,16 @@
+/**
+ * @author Robert Fuller 
+ * @version $Revision$
+ */
+class ByteIndexBug extends GroovyTestCase {
+    // TODO: this tests a string with 128 nulls - is that what is intended?
+    void testBug() {
+        def sb = new StringBuffer("\"\"\"\n")
+        for (j in 0..127){ // 126 is okay.
+            sb.append('$').append("{x}")
+        }
+        sb.append("\n\"\"\"\n")
+        def b = new Binding(x:null)
+        new GroovyShell(b).evaluate(sb.toString(),"foo")
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/Bytecode2Bug.groovy b/groovy-core/src/test/groovy/bugs/Bytecode2Bug.groovy
new file mode 100644
index 0000000..fd0fdec
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Bytecode2Bug.groovy
@@ -0,0 +1,53 @@
+/**
+ * @version $Revision$
+ */
+class Bytecode2Bug extends GroovyTestCase {
+
+    Integer count = 0
+    
+    void testBytecodeBug() {
+        getCollection().each { count += it }
+    }
+    
+    void testTedsBytecodeBug() {
+        //doTest(getCollection())
+        def a = [1, 2, 3, 4]
+        doTest(a)
+
+    }
+    
+    void doTest(args) {
+        def m = [:]
+        def i = 1
+        args.each { m.put(it, i++) }     
+        
+        assert m[1] == 1
+        assert m[2] == 2
+        assert m[3] == 3
+        assert m[4] == 4
+        
+        println("created: ${m}")
+        
+        assert i == 5
+    }
+    
+    
+    void testTedsBytecode2Bug() {
+        def m = [:]
+        def i = 1
+        getCollection().each { m.put(it, i++) }     
+        
+        assert m[1] == 1
+        assert m[2] == 2
+        assert m[3] == 3
+        assert m[4] == 4
+        
+        println("created: ${m}")
+        
+        assert i == 5
+    }
+    
+    def getCollection() {
+        [1, 2, 3, 4]
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/Bytecode3Bug.groovy b/groovy-core/src/test/groovy/bugs/Bytecode3Bug.groovy
new file mode 100644
index 0000000..fd8da41
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Bytecode3Bug.groovy
@@ -0,0 +1,21 @@
+/**
+ * @version $Revision$
+ */
+class Bytecode3Bug extends GroovyTestCase {
+    
+    def count
+         
+    void testIncrementPropertyInclosure() {
+        def args = [1, 2, 3]
+        def m = [:]
+        count = 0
+        doLoop(args, m)
+        assert count == 3
+    }
+    
+    void doLoop(args, m) {
+        args.each { 
+            m.put(it, count++)
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/Bytecode4Bug.groovy b/groovy-core/src/test/groovy/bugs/Bytecode4Bug.groovy
new file mode 100644
index 0000000..b527602
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Bytecode4Bug.groovy
@@ -0,0 +1,28 @@
+/**
+ * @version $Revision$
+ */
+class Bytecode4Bug extends GroovyTestCase {
+
+    def count = 0
+     
+    void testInject() {
+        def x = [1, 2, 3].inject(0) { c, s -> c += s }
+        assert x == 6
+    }
+     
+    void testUsingProperty() {
+        count = 0
+        getCollection().each { count += it }       
+        assert count == 10
+    }
+    
+    void testUsingIncrementingProperty() {
+        count = 0
+        getCollection().each { count++ }       
+        assert count == 4
+    }
+    
+    def getCollection() {
+        [1, 2, 3, 4]
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/Bytecode5Bug.groovy b/groovy-core/src/test/groovy/bugs/Bytecode5Bug.groovy
new file mode 100644
index 0000000..444425a
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Bytecode5Bug.groovy
@@ -0,0 +1,15 @@
+/**
+ * @version $Revision$
+ */
+class Bytecode5Bug extends GroovyTestCase {
+
+    void testUsingLocalVar() {
+        def c = 0
+        getCollection().each { c += it }       
+        assert c == 10
+    }
+    
+    def getCollection() {
+        [1, 2, 3, 4]
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/Bytecode6Bug.groovy b/groovy-core/src/test/groovy/bugs/Bytecode6Bug.groovy
new file mode 100644
index 0000000..f3195b6
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Bytecode6Bug.groovy
@@ -0,0 +1,23 @@
+/**
+ * @version $Revision$
+ */
+class Bytecode6Bug extends GroovyTestCase {
+
+    void testPostFixReturn() {
+        def i = 1
+        def closure = { i++ }
+        def value = closure()
+        
+        assert value == 1
+        assert i == 2
+    }
+    
+    void testPreFixReturn() {
+        def i = 1
+        def closure = { return ++i }
+        def value = closure()
+        
+        assert value == 2
+        assert i == 2
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/Bytecode7Bug.groovy b/groovy-core/src/test/groovy/bugs/Bytecode7Bug.groovy
new file mode 100644
index 0000000..f02cfd3
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Bytecode7Bug.groovy
@@ -0,0 +1,25 @@
+/**
+ * @version $Revision$
+ */
+class Bytecode7Bug extends GroovyTestCase {
+
+    void testDuplicateVariables() {
+        if (true) {
+            def a = 123
+        }
+        if (true) {
+            def a = 456
+        }
+    }
+
+    void testDuplicateVariablesInClosures() {
+        def coll = [1]
+
+        coll.each {
+            def a = 123
+        }
+        coll.each {
+            def a = 456
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/BytecodeBug.groovy b/groovy-core/src/test/groovy/bugs/BytecodeBug.groovy
new file mode 100644
index 0000000..80f8092
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/BytecodeBug.groovy
@@ -0,0 +1,28 @@
+/**
+ * @version $Revision$
+ */
+class BytecodeBug extends GroovyTestCase {
+     
+    void testTedsBytecodeBug() {
+        //def a = ['tom','dick','harry']
+        def a = [1, 2, 3, 4]
+        doTest(a)
+    }
+    
+    void doTest(args) {
+        def m = [:]
+        def i = 1
+        args.each { 
+            talk(it)
+            m.put(it, i++)
+        }
+        assert i == 5
+        m.each {
+            println(it)
+        }
+    }
+    
+    def talk(a) {
+        println("hello "+a)
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/CallingClosuresWithClosuresBug.groovy b/groovy-core/src/test/groovy/bugs/CallingClosuresWithClosuresBug.groovy
new file mode 100644
index 0000000..ac08850
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/CallingClosuresWithClosuresBug.groovy
@@ -0,0 +1,16 @@
+/**
+ * @version $Revision$
+ */
+class CallingClosuresWithClosuresBug extends GroovyTestCase {
+
+    void testBug() {
+        def a = {1}
+        // old workaround
+        //def b = {a.call()}
+        def b = {a()}
+        
+        def value = b()
+        
+        assert value == 1
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/CastWhenUsingClosuresBug.groovy b/groovy-core/src/test/groovy/bugs/CastWhenUsingClosuresBug.groovy
new file mode 100644
index 0000000..cf659f3
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/CastWhenUsingClosuresBug.groovy
@@ -0,0 +1,12 @@
+/**
+ * @version $Revision$
+ */
+class CastWhenUsingClosuresBug extends GroovyTestCase {
+
+    void testBug() {
+        def a = 1
+
+        def list = [1]
+        list.each { a = it }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/ChristofsPropertyBug.groovy b/groovy-core/src/test/groovy/bugs/ChristofsPropertyBug.groovy
new file mode 100644
index 0000000..c93016a
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ChristofsPropertyBug.groovy
@@ -0,0 +1,15 @@
+/**
+ * @version $Revision: 1.4 $
+ */
+class ChristofsPropertyBug extends GroovyTestCase {
+     
+    def mixedCaseProperty
+
+    void testChristofsPropertyBug() {
+    	this.mixedCaseProperty = "test"
+    	shouldFail({this.mixedcaseproperty = "test"})
+    }
+    
+    def getMixedCaseProperty()    { mixedCaseProperty }
+    def setMixedCaseProperty(val) { this.mixedCaseProperty = val }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/ClassGeneratorFixesTest.groovy b/groovy-core/src/test/groovy/bugs/ClassGeneratorFixesTest.groovy
new file mode 100644
index 0000000..15ebe55
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ClassGeneratorFixesTest.groovy
@@ -0,0 +1,78 @@
+package groovy.bugs
+
+
+class ClassGeneratorFixesTest extends GroovyTestCase {
+    def count = 0;
+
+    def pf(int p) {
+        int i = p
+        boolean b = true
+    }
+
+    void testPrimitvesInFunc() { // groovy-373, 453, 385, 451, 199
+        pf(10)
+    }
+
+    void testPlusEqual() { // 372
+        count += 1
+        assert count == 1
+
+        def foo =
+            {i->
+                return {j->
+                    i += j
+                    i
+                }
+            }
+        def x = foo(1)
+        x(5)
+        foo(3)
+        println x(2.3)
+    }
+
+    void testIfAndSwitchInClosure (){ // 321, 324, 412
+
+        def a = 1
+        1.times {
+            if (a ==1) {
+                a = 2
+            }
+        }
+
+        def noneYet=true;
+        ["a","b","c","d"].each { c ->
+          if (noneYet) {
+            noneYet=false;
+          } else {
+            print(" > ");
+          }
+          print( c );
+        }
+
+        a = 1
+        switch (a) {
+        case 1:
+            a = 2;
+        case 2:
+            break;
+        default:
+            break;
+        }
+    }
+
+    void returnVoid() {
+        return
+    }
+
+    void testReturnVoid() { // groovy-405, 387
+        returnVoid()
+    }
+    
+    void testBooleanValue() { // groovy-385
+            /** @todo
+            boolean value
+            */
+        }
+
+}
+
diff --git a/groovy-core/src/test/groovy/bugs/ClassInNamedParamsBug.groovy b/groovy-core/src/test/groovy/bugs/ClassInNamedParamsBug.groovy
new file mode 100644
index 0000000..afdf7b5
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ClassInNamedParamsBug.groovy
@@ -0,0 +1,20 @@
+import java.util.Map
+
+class ClassInNamedParamsBug extends GroovyTestCase {
+    
+    void testBug() {
+        def foo = method(class:'cheese', name:'cheddar')
+        
+        assert foo.name == "cheddar"
+        assert foo.class == "cheese"
+        
+        foo = method(name:'cheddar', class:'cheese')
+        
+        assert foo.name == "cheddar"
+        assert foo.class == "cheese"
+    }
+    
+    def method(Map data) {
+        data
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/ClassInScriptBug.java b/groovy-core/src/test/groovy/bugs/ClassInScriptBug.java
new file mode 100644
index 0000000..8527640
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ClassInScriptBug.java
@@ -0,0 +1,61 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.bugs;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+
+/**
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ClassInScriptBug extends TestSupport {
+
+    public void testBug() throws Exception {
+        assertScript( "class X {}\nx = new X()\nprintln(x)" );
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/ClosureInClosureBug.groovy b/groovy-core/src/test/groovy/bugs/ClosureInClosureBug.groovy
new file mode 100644
index 0000000..d33f0e7
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ClosureInClosureBug.groovy
@@ -0,0 +1,31 @@
+/**
+ * Bug illustrating the nested closures variable scope visibility issue.
+ * l.each is ClosureInClosureBug$1 and it.each is ClosureInClosureBug$2
+ * The variable text is not visible from ClosureInClosureBug$2.
+ * Indeed, a closure can only see the variable defined outside this closure (one level up)
+ * but cannot see what's in the second level.
+ *
+ * In order to make the test work, do not forget to uncomment the line "println(text)"
+ *
+ * @authour Guillaume Laforge
+ */
+class ClosureInClosureBug extends GroovyTestCase {
+
+    void testInvisibleVariable() {
+        def text = "test "
+
+        def l = [1..11, 2..12, 3..13, 4..14]
+
+        l.each {
+            //println(text)
+            it.each{
+                println(text)
+            }
+        }
+    }
+
+    static void main(args) {
+        def bug = new ClosureInClosureBug()
+        bug.testInvisibleVariable()
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/ClosureParameterPassingBug.groovy b/groovy-core/src/test/groovy/bugs/ClosureParameterPassingBug.groovy
new file mode 100644
index 0000000..06b5406
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ClosureParameterPassingBug.groovy
@@ -0,0 +1,41 @@
+import org.codehaus.groovy.classgen.TestSupport
+
+/**
+ * @author John Wilson
+ * @version $Revision$
+ */
+class ClosureParameterPassingBug extends TestSupport {
+    
+    void testBugInMethod() {
+        def c = { x ->
+            def y = 123
+            def c1 = {
+                println y
+                println x
+                println x[0]
+            }
+
+            c1()
+        }
+
+        c([1])
+    }
+
+    void testBug() {
+        assertScript """
+def c = { x ->
+    def y = 123
+    def c1 = { 
+        assert x != null , "Could not find a value for x"
+        assert y == 123 , "Could not find a value for y"
+        println x[0]
+    }
+
+    c1()
+} 
+
+c([1]) 
+"""
+    }
+   
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/ClosureTypedVariableBug.groovy b/groovy-core/src/test/groovy/bugs/ClosureTypedVariableBug.groovy
new file mode 100644
index 0000000..12de086
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ClosureTypedVariableBug.groovy
@@ -0,0 +1,52 @@
+/**
+ * @version $Revision$
+ */
+class ClosureTypedVariableBug extends GroovyTestCase {
+    
+    void testBug2() {
+        def count = makeClosure(0)
+        assert count == 1
+        
+        count = makeClosure2(0)
+        assert count == 1
+    }
+
+
+    def makeClosure(Number count) {
+        def closure = { count = it }
+        closure(1)
+        return count
+    }
+
+    def makeClosure2(Number c) {
+        def count = c
+        def closure = { count = it }
+        closure(1)
+        return count
+    }
+
+    void testBug() {
+        Integer count = 0
+        def closure = { count = it }
+        closure(1)
+        assert count == 1
+    }
+    
+    void testBug3() {
+        def closure = getElementClosure("p")
+        def answer = closure("b")
+        def value = answer("c")
+        println "returned : ${value}"
+    }
+    
+    Closure getElementClosure(tag) {
+        return { body ->
+            if (true) {
+                return {"${body}"}
+            }
+            else {
+                body = null
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/ClosureVariableBug.groovy b/groovy-core/src/test/groovy/bugs/ClosureVariableBug.groovy
new file mode 100644
index 0000000..fd689ff
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ClosureVariableBug.groovy
@@ -0,0 +1,41 @@
+/**
+ * @version $Revision$
+ */
+class ClosureVariableBug extends GroovyTestCase {
+    
+    void testClosurePassingBug() {
+        def count = 0
+        def closure = { assert count == it }
+        closure(0)
+        
+        count = 1
+        closure(1)
+    }
+    
+    void testPassingClosureAsNamedParameter() {
+        def x = 123
+        
+        def foo = new Expando(a:{x}, b:456)
+    
+        assert foo.a != null
+        
+        println "Foo has a = ${foo.a}"
+        
+        def value = foo.a()
+        assert value == 123
+    }
+    
+    void testBug() {
+        def value = callClosure([1, 2])
+        assert value == 2
+    }
+    
+    protected Integer callClosure(collection) {
+        Integer x
+        /** @todo
+        Integer x = 0
+        */
+        collection.each { x = it }
+        return x
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/ClosureWithBitwiseDefaultParamTest.groovy b/groovy-core/src/test/groovy/bugs/ClosureWithBitwiseDefaultParamTest.groovy
new file mode 100644
index 0000000..65e2806
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ClosureWithBitwiseDefaultParamTest.groovy
@@ -0,0 +1,13 @@
+class ClosureWithBitwiseDefaultParamTest extends GroovyTestCase {
+    void testAmbiguousStuff() {
+        def c = { x, y = 1 | 2, z = 0->
+            println x
+            println y
+            println z
+        }
+
+        // now lets invoke c
+        // TODO when closures support default parameters
+        //c.call()
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/ClosureWithStaticVariablesBug.groovy b/groovy-core/src/test/groovy/bugs/ClosureWithStaticVariablesBug.groovy
new file mode 100644
index 0000000..f66ece8
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ClosureWithStaticVariablesBug.groovy
@@ -0,0 +1,33 @@
+package groovy.bugs
+
+import org.codehaus.groovy.classgen.TestSupport
+
+/**
+ * @version $Revision: 1.5 $
+ */
+class ClosureWithStaticVariablesBug extends TestSupport {
+    
+    static def y = [:]
+    
+    void testBug() {
+        def c = { x ->
+            return {
+                def foo = Cheese.z
+                println foo
+                assert foo.size() == 0
+
+                println y
+                assert y.size() == 0
+
+                return 6
+            }
+        }
+        def c2 = c(5)
+        def answer = c2()
+        assert answer == 6
+    }
+}
+
+class Cheese {
+    public static z = [:]
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/ClosuresInScriptBug.java b/groovy-core/src/test/groovy/bugs/ClosuresInScriptBug.java
new file mode 100644
index 0000000..16ec1a2
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ClosuresInScriptBug.java
@@ -0,0 +1,61 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.bugs;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+
+/**
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ClosuresInScriptBug extends TestSupport {
+
+    public void testBug() throws Exception {
+        assertScript( "a = 1\n [2].each { a = it }\n assert a == 2" );
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/ConstructorBug.groovy b/groovy-core/src/test/groovy/bugs/ConstructorBug.groovy
new file mode 100644
index 0000000..1d3d3a4
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ConstructorBug.groovy
@@ -0,0 +1,37 @@
+import org.codehaus.groovy.runtime.InvokerHelper
+import java.io.File
+
+/**
+ * @author Jason Thomas
+ * @version $Revision$
+ */
+class ConstructorBug extends GroovyTestCase {
+    
+    void testBug() {
+        def type = new GroovyClassLoader().parseClass(new File("src/test/groovy/bugs/TestBase.groovy"))
+        assert type != null
+
+        println "created type: ${type}"
+        
+        type = new GroovyClassLoader().parseClass(new File("src/test/groovy/bugs/TestDerived.groovy"))
+        assert type != null
+
+        println "created type: ${type} of type: ${type.class}"
+
+        def mytest = InvokerHelper.invokeConstructorOf(type, ["Hello"] as Object[])
+        assert mytest.foo == "Hello"
+        /** @todo fix bug
+        */
+        
+        /*
+        def test = type.newInstance()
+        assert test.foo == null
+        */
+        
+//foo = new type('hello')
+        /*
+        */
+        mytest = new TestDerived("Hello")
+        assert mytest.foo == "Hello"
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/ConstructorParameterBug.groovy b/groovy-core/src/test/groovy/bugs/ConstructorParameterBug.groovy
new file mode 100644
index 0000000..f4fcf6c
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ConstructorParameterBug.groovy
@@ -0,0 +1,17 @@
+package groovy.bugs
+
+class ConstructorParameterBug extends GroovyTestCase {
+
+    void testMethodWithNativeArray() {
+        int[] value = [2*2]
+        println "${value} of type ${value.class}"
+        /** @todo fixme!
+    	blah2(value)
+    	*/
+    }
+
+    def blah2(int[] wobble) {
+       println(wobble)
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/bugs/ConstructorThisCallBug.groovy b/groovy-core/src/test/groovy/bugs/ConstructorThisCallBug.groovy
new file mode 100644
index 0000000..e58a4c5
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ConstructorThisCallBug.groovy
@@ -0,0 +1,62 @@
+/**
+ * ConstructorThisCallBug.groovy
+ *
+ *     Test Script for the Jira issue: GROOVY-994.
+ *
+ * @author    Pilho Kim
+ * @date      2005.08.05.06.21
+ */
+
+package groovy.bugs
+
+public class ConstructorThisCallBug extends GroovyTestCase {
+    public void testCallA() {
+        println "Testing for a class without call()"
+        def a1 = new ConstructorCallA("foo") 
+        def a2 = new ConstructorCallA(9) 
+        def a3 = new ConstructorCallA() 
+    }
+
+    void testCallB() {
+        println "Testing for a class with call()"
+        def b1 = new ConstructorCallB('bar') 
+        def b2 = new ConstructorCallB(9) 
+        def b3 = new ConstructorCallB() 
+    }
+}
+
+public class ConstructorCallA { 
+    public ConstructorCallA() {
+        this(19)               // call another constructor
+        println "(1) no argument consructor"
+    } 
+
+    public ConstructorCallA(String a) {
+        println "(2) String value a = $a"
+    } 
+
+    public ConstructorCallA(int a) {
+        this("" + (a*a))       // call another constructor
+        println "(3) int value a = $a"
+    } 
+} 
+
+public class ConstructorCallB { 
+    public ConstructorCallB() {
+        println '1: no argument consructor'
+        this(19)              // call the method call()
+    } 
+
+    public ConstructorCallB(String b) {
+        println """2: String value b = $b"""
+    } 
+
+    public ConstructorCallB(int b) {
+        println """3: int value b = $b"""
+        this('' + (b + b))     // call the method call()
+    } 
+
+    void call(Object o) {
+        println "Hello, $o"
+    } 
+} 
diff --git a/groovy-core/src/test/groovy/bugs/DefVariableBug.groovy b/groovy-core/src/test/groovy/bugs/DefVariableBug.groovy
new file mode 100644
index 0000000..3ad3066
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/DefVariableBug.groovy
@@ -0,0 +1,19 @@
+/**
+ * @version $Revision: 1.3 $
+ */
+class DefVariableBug extends GroovyTestCase {
+    
+    void testBug() {
+
+     /* cpoirier - "def" can be refered to as a variable name,
+        but cannot be declared as one (due to ambiguities)
+
+        def = 123
+        
+        assert def == 123
+     */
+        
+        def foo = new Expando(a:123, def:456)
+        assert foo.def == 456
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/DoubleSizeParametersBug.groovy b/groovy-core/src/test/groovy/bugs/DoubleSizeParametersBug.groovy
new file mode 100644
index 0000000..a13aa84
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/DoubleSizeParametersBug.groovy
@@ -0,0 +1,70 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.bugs;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+
+/**
+ * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
+ * @version $Revision$
+ */
+class DoubleSizeParametersBug extends TestSupport {
+
+    void testBug() {
+        assertScript( """
+def foo(double x, y) {
+   println "x: "+x
+   println "y: "+y
+}
+
+foo(10.0d, 0)
+""" );
+    }
+}
+
+
diff --git a/groovy-core/src/test/groovy/bugs/ForAndSqlBug.groovy b/groovy-core/src/test/groovy/bugs/ForAndSqlBug.groovy
new file mode 100644
index 0000000..c63ab29
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ForAndSqlBug.groovy
@@ -0,0 +1,38 @@
+import groovy.sql.TestHelper
+
+/**
+ * @author Jonathan Carlson
+ * @version $Revision$
+ */
+class ForAndSqlBug extends GroovyTestCase {
+    
+    void testBugInNormalMethod() {
+        def sql = TestHelper.makeSql()
+        
+        def li = ["a", "b"]
+        for (x in li) {
+            sql.eachRow("SELECT count(*) FROM FOOD") { e ->
+            	println " ${x}"
+
+	            assert x != null
+            }
+        }
+    }
+
+    void testBugInsideScript() {
+        assertScript( """
+import groovy.sql.TestHelper
+def sql = TestHelper.makeSql()
+
+def li = ["a", "b"]
+for (x in li) {
+    sql.eachRow("SELECT count(*) FROM FOOD") { e ->
+    	println " \${x}"
+    	
+    	assert x != null
+    }
+}
+""")        
+	}
+
+}
diff --git a/groovy-core/src/test/groovy/bugs/ForLoopBug.groovy b/groovy-core/src/test/groovy/bugs/ForLoopBug.groovy
new file mode 100644
index 0000000..13c99a3
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ForLoopBug.groovy
@@ -0,0 +1,64 @@
+/**
+ * @author John Wilson
+ * @version $Revision$
+ */
+class ForLoopBug extends GroovyTestCase {
+    
+    void testBug() {
+        assertScript( """
+def list = []
+def a = 1
+def b = 5
+for (c in a..b) {
+    list << c
+}
+assert list == [1, 2, 3, 4, 5]
+""")
+    }
+    
+    void testSeansBug() {
+        assertScript( """
+for (i in 1..10) {
+    println i
+}
+""")        
+    }
+
+    void testNormalMethod() {
+        def list = []
+        def a = 1
+        def b = 5
+        for (c in a..b) {
+            list << c
+        }
+        assert list == [1, 2, 3, 4, 5]
+    }
+    
+     void testBytecodeGenBug() {
+        def a = 1
+        def b = 5
+
+        def lastIndex
+        for (i in a..b) {
+            println i
+            lastIndex = i
+        }
+        a = lastIndex
+        
+		assert a == 5
+    }
+
+
+    void testVisibility() {
+        assertScript( """
+
+def array = [ true, true, true ];
+for( boolean i in array ) {
+   1.times {
+       assert i == true;
+   }
+}
+""")
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/bugs/FullyQualifiedClassBug.groovy b/groovy-core/src/test/groovy/bugs/FullyQualifiedClassBug.groovy
new file mode 100644
index 0000000..6afd214
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/FullyQualifiedClassBug.groovy
@@ -0,0 +1,10 @@
+/**
+ * @version $Revision$
+ */
+class FullyQualifiedClassBug extends GroovyTestCase {
+
+    void testBug() {
+        java.lang.System.err.println("Hello world")
+    }
+    
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/FullyQualifiedMethodReturnTypeBug.groovy b/groovy-core/src/test/groovy/bugs/FullyQualifiedMethodReturnTypeBug.groovy
new file mode 100644
index 0000000..ea88477
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/FullyQualifiedMethodReturnTypeBug.groovy
@@ -0,0 +1,15 @@
+/**
+ * @version $Revision$
+ */
+class FullyQualifiedMethodReturnTypeBug extends GroovyTestCase {
+
+    void testBug() {
+        def s = foo()
+        assert s.length() == 3
+    }
+
+    java.lang.String foo() {
+        return "hey"
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/FullyQualifiedVariableTypeBug.groovy b/groovy-core/src/test/groovy/bugs/FullyQualifiedVariableTypeBug.groovy
new file mode 100644
index 0000000..4010cf3
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/FullyQualifiedVariableTypeBug.groovy
@@ -0,0 +1,11 @@
+/**
+ * @version $Revision$
+ */
+class FullyQualifiedVariableTypeBug extends GroovyTestCase {
+
+    void testBug() {
+        java.lang.String s = "hey"
+        assert s.length() == 3
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/GetterBug.groovy b/groovy-core/src/test/groovy/bugs/GetterBug.groovy
new file mode 100644
index 0000000..538884e
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/GetterBug.groovy
@@ -0,0 +1,64 @@
+/**
+ * @version $Revision$
+ */
+class GetterBug extends GroovyTestCase {
+     
+    String foo
+    def bar
+
+    String getFoo() {
+    	if (foo == null) { 
+    		foo = "James"
+    	}
+    	return foo
+    }
+    
+    void setFoo(String foo) {
+    	this.foo = foo
+   	}
+    
+    void testTypedGetterAndSetter() {
+    	println "Running test"
+    	
+    	def value = getFoo()
+    	
+    	println "Value is ${value}"
+    	
+    	assert value == "James"
+    	
+    	setFoo("Bob")
+    	
+    	value = getFoo()
+    	
+    	assert value == "Bob"
+    }
+    
+    def getBar() {
+    	if (this.bar == null) {
+    		this.bar = "James"
+    	}
+    	bar
+    }
+    
+    void setBar(bar) {
+    	this.bar = bar
+    }
+    
+    
+    void testUntypedGetterAndSetter() {
+    	println "Running test"
+    	
+    	def value = getBar()
+    	
+    	println "Value is ${value}"
+    	
+    	assert value == "James"
+    	
+    	setBar("Bob")
+    	
+    	value = getBar()
+    	
+    	assert value == "Bob"
+    }
+    
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/Groovy1018_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy1018_Bug.groovy
new file mode 100644
index 0000000..6e0489a
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy1018_Bug.groovy
@@ -0,0 +1,33 @@
+package groovy.bugs
+
+/**
+ * Test to fix the Jira issues GROOVY-1018 and GROOVY-732.
+ * Access to a static field member by a class name:
+ *      ClassName.fieldName or ClassName.@fieldName.
+ *
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+
+class Groovy1018_Bug extends GroovyTestCase { 
+
+    public static Object Class = "bar" 
+
+    // todo: GROOVY-1018
+    void testGetPublicStaticField() {
+        def a = new Groovy1018_Bug()
+        println( a.Class )
+        println( a.@Class )
+        println( Groovy1018_Bug.Class )
+        println( Groovy1018_Bug.@Class )
+        assert a.Class == "bar" && a.@Class == "bar"
+        assert Groovy1018_Bug.Class == "bar" && Groovy1018_Bug.@Class == "bar"
+    }
+
+    // todo: GROOVY-732
+    void testSetPublicStaticField() {
+        Groovy1018_Bug.Class = 'bar-'
+        assert Groovy1018_Bug.Class == "bar-" && Groovy1018_Bug.@Class == "bar-"
+    }
+
+} 
diff --git a/groovy-core/src/test/groovy/bugs/Groovy1059_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy1059_Bug.groovy
new file mode 100644
index 0000000..5608d02
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy1059_Bug.groovy
@@ -0,0 +1,53 @@
+package groovy.bugs
+
+/**
+ * TODO: GROOVY-1059
+ *
+ *    Accessible to a closure attribute of an abject with the operator ".@".
+ *    For examples, all of the expressions
+ *
+ *            object.@closure()
+ *            object.@closure.call()
+ *            object.@closure.doCall()
+ *            (object.@closure)()
+ *
+ *    have the same meaning.
+ *
+ * @author  John Wilson
+ * @author  Pilho Kim
+ */
+
+class Groovy1059_Bug extends GroovyTestCase {
+
+    void testClosureAsAttribute() {
+        def x = new Groovy1059Foo()
+
+        println( x.say() )
+        println( (x.@say)() )
+        println( x.@say() )  // TODO: Groovy-1059 should work
+        println( x.@say.call() )
+        println( x.@say.doCall() )
+        println( x.@say2() )
+
+        assert "I am a Method" == x.say()
+        assert "I am a Method" == x.@say2()
+        assert "I am a Closure" == (x.@say)()
+        assert "I am a Closure" == x.@say()
+        assert x.@say() == (x.@say)()
+        assert x.@say() == x.@say.call()
+        assert x.@say() == x.@say.doCall()
+        assert x.@say() != x.say()
+        assert x.@say2() == x.say()
+    }
+
+}
+
+class Groovy1059Foo {
+
+    def public say = { it -> return "I am a Closure" }
+    def public say2 = this.&say
+
+    public Object say() {
+       return "I am a Method"
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/Groovy1081_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy1081_Bug.groovy
new file mode 100644
index 0000000..8157db5
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy1081_Bug.groovy
@@ -0,0 +1,18 @@
+/**
+ *  Verifies that DefaultGroovyMethods.transformLine(Reader, Writer, Closure)
+ *  actually writes its output.
+ */
+
+class Groovy1081_Bug extends GroovyTestCase {
+ 
+    void testShort() {
+     	def reader = new StringReader('abc')
+		def writer = new StringWriter()
+
+		reader.transformLine(writer) { it }
+		
+		// Implementation was creating a BufferedWriter, but not flushing it
+		assertTrue(writer.toString().startsWith('abc'))
+    }
+    
+}
diff --git a/groovy-core/src/test/groovy/bugs/Groovy239_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy239_Bug.groovy
new file mode 100644
index 0000000..cad05f1
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy239_Bug.groovy
@@ -0,0 +1,40 @@
+/**
+ * @author John Wilson
+ * @version $Revision$
+ */
+class Groovy239_Bug extends GroovyTestCase {
+    
+    void testBug() {
+        def a = makeClosure()
+        def b = makeClosure()
+        def c = makeClosure()
+
+        a() {
+            println("A")
+            b() {
+                println("B")
+                c() {
+                    println("C")
+                }
+            }
+        }
+    }
+
+    def makeClosure() {
+        return { it() }
+    }
+
+    void testBug2() {
+        def a = { it() }
+        def b = { it() }
+        def c = { it() }
+
+        a() {
+            b() {
+                c() {
+                }
+            }
+        }
+    }
+   
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/Groovy249_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy249_Bug.groovy
new file mode 100644
index 0000000..e6fa5a1
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy249_Bug.groovy
@@ -0,0 +1,63 @@
+import groovy.xml.MarkupBuilder
+
+/**
+ * @author Merrick Schincariol 
+ * @version $Revision$
+ */
+class Groovy249_Bug extends GroovyTestCase {
+
+    void testBug() {
+		def t = new Bean249()
+		t.b = "hello"
+		println t.b
+		println "test: ${t.b}"
+		
+		def xml = new MarkupBuilder()
+		def root = xml.foo {
+			bar {
+				// works
+				baz("test")
+				// fails
+				baz(t.b)
+				// fails
+				baz("${t.b}")
+			}
+		} 
+	}
+	
+/** @todo don't know why this fails
+
+    void testBugInScript() {
+    	assertScript <<<EOF
+			import groovy.xml.MarkupBuilder;
+			
+			class Bean {
+				String b
+			};
+			
+			def t = new Bean()
+			t.b = "hello"
+			println t.b
+			println "test: ${t.b}"
+			
+			def xml = new MarkupBuilder()
+			root = xml.foo {
+				bar {
+					// works
+					baz("test")
+					// fails
+					baz(t.b)
+					// fails
+					baz("${t.b}")
+				}
+			} 
+
+EOF    	
+	}
+*/
+   
+}
+
+class Bean249 {
+	String b
+}
diff --git a/groovy-core/src/test/groovy/bugs/Groovy252_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy252_Bug.groovy
new file mode 100644
index 0000000..20ae574
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy252_Bug.groovy
@@ -0,0 +1,36 @@
+/**
+ * @version $Revision$
+ */
+class Groovy252_Bug extends GroovyTestCase {
+    
+    def count = 0
+    
+    void testBug() {
+        def value = f()
+        assert value == null
+        
+        value = g()
+        assert value == null
+        
+        value = h()
+        assert value == null
+    }
+    
+    
+    def f() {
+         if (count++ == 5)
+            return null
+         else
+            return null
+    } 
+    
+    def g() {
+         ++count
+         return null
+    } 
+    
+    def h() {
+         ++count
+         return null
+    } 
+}
diff --git a/groovy-core/src/test/groovy/bugs/Groovy278_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy278_Bug.groovy
new file mode 100644
index 0000000..2b698be
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy278_Bug.groovy
@@ -0,0 +1,21 @@
+package groovy.bugs
+
+/**
+ * @author John Wilson
+ * @version $Revision$
+ */
+class Groovy278_Bug extends GroovyTestCase {
+    
+    void testBug() {
+        def value = new MyRange()
+        println value
+        assert value != null
+    }
+}
+
+
+class MyRange extends IntRange {
+    MyRange() {
+        super(1, 2)
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/Groovy303_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy303_Bug.groovy
new file mode 100644
index 0000000..9f696f0
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy303_Bug.groovy
@@ -0,0 +1,47 @@
+package groovy.bugs
+
+import java.awt.*
+import java.awt.event.*
+import javax.swing.*
+
+
+/**
+ * @author Bing Ran
+ * @author Andy Dwelly
+ * @version $Revision$
+ */
+class Groovy303_Bug extends GroovyTestCase {
+    
+    void testBug() {
+        try {
+            def scholastic = new Scholastic()
+               scholastic.createUI()
+           }
+           catch (HeadlessException e) {
+               // called from a non-UI environment
+           }
+    }
+}
+
+
+class Scholastic implements ActionListener {
+
+    void createUI() {
+       println('createUI called')
+       def frame = new JFrame("Hello World")
+       def contents = frame.getContentPane()
+       def pane = new JPanel()
+       pane.setLayout(new BorderLayout())
+       def button = new JButton("A button")
+       button.addActionListener(this)
+       pane.add(button, BorderLayout.CENTER)
+       contents.add(pane)
+       frame.setSize(100, 100)
+       //frame.setVisible(true)
+       button.doClick()
+    }
+
+    public void actionPerformed(ActionEvent event) {
+       println "hello"
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/Groovy308_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy308_Bug.groovy
new file mode 100644
index 0000000..8ebaaee
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy308_Bug.groovy
@@ -0,0 +1,26 @@
+package groovy.bugs
+
+import java.io.*
+
+/**
+ * @version $Revision$
+ */
+class Groovy308_Bug extends GroovyTestCase {
+    
+    void testBug() {
+    	def out = new StringWriter()
+    	out << "hello " << "world!"
+    	
+    	def value = out.toString()
+    	assert value == "hello world!"
+    	
+    	out = new ByteArrayOutputStream()
+    	out << "hello " << "world!"
+
+		value = new String(out.toByteArray())
+		assert value == "hello world!"
+    	    	
+    	System.out << "hello" << " world!"
+    }
+}
+
diff --git a/groovy-core/src/test/groovy/bugs/Groovy325_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy325_Bug.groovy
new file mode 100644
index 0000000..b1acc77
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy325_Bug.groovy
@@ -0,0 +1,10 @@
+class Groovy325_Bug extends GroovyTestCase {
+  static boolean staticMethod() {
+    return true
+  }
+
+  void testCallStaticMethodFromClosure() {
+    def c = { staticMethod() }
+    assert c()
+  }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/Groovy389_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy389_Bug.groovy
new file mode 100644
index 0000000..f291847
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy389_Bug.groovy
@@ -0,0 +1,21 @@
+/**
+ *  Verifies that closures work inside case blocks.
+ *
+ */
+
+class Groovy389_Bug extends GroovyTestCase {
+ 
+    void testBug() {
+       def a = [10, 11, 12]
+       def b = 0
+       
+       switch( "list" ) {
+          case "list":
+             a.each { b = b + 1 }
+             break
+       }
+
+       assert b == 3
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/bugs/Groovy513_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy513_Bug.groovy
new file mode 100644
index 0000000..956f19c
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy513_Bug.groovy
@@ -0,0 +1,16 @@
+/**

+ *  Verifies that comparisons to Integer.MIN_VALUE work

+ */

+

+class Groovy513_Bug extends GroovyTestCase {

+ 

+    void testMinMaxValueComparison() {

+    	assertTrue(8 < Integer.MAX_VALUE);

+    	assertTrue(8 > Integer.MIN_VALUE);

+    	assertTrue(8L < Long.MAX_VALUE);

+    	assertTrue(8L > Long.MIN_VALUE);

+    	assertTrue(8.0 < Double.MAX_VALUE);

+    	assertTrue(8.0 > Double.MIN_VALUE);

+    }

+    

+}

diff --git a/groovy-core/src/test/groovy/bugs/Groovy558_616_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy558_616_Bug.groovy
new file mode 100644
index 0000000..793440f
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy558_616_Bug.groovy
@@ -0,0 +1,45 @@
+package groovy.bugs
+
+import groovy.util.Dummy
+
+/**
+  * Fixes GROOVY-558 and GROOVY-616.
+  * A fully qualified class name ending with .class or not were not recognized properly.
+  *
+  * @author Jochen Theodorou
+  * @author Guillaume Laforge
+  */
+class Groovy558_616_Bug extends GroovyTestCase {
+
+    void testListClass() {
+        assert java.util.ArrayList.class == ArrayList.class
+        assert java.util.ArrayList.class == ArrayList
+        assert ArrayList != Class
+        def list = new ArrayList()
+        assert list.class == ArrayList
+    }
+
+    void testStringClass() {
+        assert java.lang.String.class == String.class
+        assert java.lang.String.class == String
+        assert String != Class
+        def st = ""
+        assert st.class == String
+    }
+
+    void testDummyClass() {
+        assert groovy.util.Dummy.class == Dummy.class
+        assert groovy.util.Dummy.class == Dummy
+        assert Dummy != Class
+        def dum = new Dummy()
+        assert dum.class == Dummy
+    }
+
+    void testFooClass() {
+        assert groovy.bugs.Groovy558_616_Bug.class == Groovy558_616_Bug
+        assert Groovy558_616_Bug != Class
+        def f = new Groovy558_616_Bug()
+        assert f.class == Groovy558_616_Bug
+    }
+}
+
diff --git a/groovy-core/src/test/groovy/bugs/Groovy593_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy593_Bug.groovy
new file mode 100644
index 0000000..4da678e
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy593_Bug.groovy
@@ -0,0 +1,58 @@
+package groovy.bugs
+
+import java.io.StringWriter
+import groovy.xml.MarkupBuilder
+
+/** 
+ * Tests that special XML chars are entitized by MarkupBuilder.
+ *
+ * @author <a href="mailto:scottstirling@rcn.com">Scott Stirling</a>
+ *
+ * @version $Revision: 1.4 $
+ *
+ *   Fix the cr lf handling of multiline stringon both of linux and Windows XP.
+ *   This test should success on Windows XP.
+ *
+ *   @author Pilho Kim
+ */
+class Groovy593_Bug extends GroovyTestCase {
+    
+    StringWriter writer = new StringWriter()
+    MarkupBuilder chars = new MarkupBuilder(writer)
+    XmlParser parser = new XmlParser()
+    String expectedXML = 
+"""<chars>
+  <ampersand a='&amp;'>&amp;</ampersand>
+  <quote attr='"'>"</quote>
+  <apostrophe attr='&apos;'>'</apostrophe>
+  <lessthan attr='value'>chars: &amp; &lt; &gt; '</lessthan>
+  <element attr='value 1 &amp; 2'>chars: &amp; &lt; &gt; " in middle</element>
+  <greaterthan>&gt;</greaterthan>
+</chars>"""
+
+    void testBug() {
+        // XML characters to test with
+        chars.chars {
+            ampersand(a: "&", "&")
+            quote(attr: "\"", "\"")
+            apostrophe(attr: "'", "'")
+            lessthan(attr: "value", "chars: & < > '") 
+            element(attr: "value 1 & 2", "chars: & < > \" in middle")
+            greaterthan(">")
+        }
+        //DEBUG
+        //println writer
+
+        // Test MarkupBuilder state with expectedXML
+  	    // Handling the cr lf characters, depending on operating system. 
+        def outputValue = writer.toString()
+        if (expectedXML.indexOf("\r\n") >= 0)  expectedXML = expectedXML.replaceAll("\r\n", "\n");
+        if (outputValue.indexOf("\r\n") >= 0)  outputValue = outputValue.replaceAll("\r\n", "\n");
+        assertEquals(expectedXML.replaceAll("\r\n", "\n"), outputValue)
+        
+        // parser will throw a SAXParseException if XML is not valid
+        parser.parseText(writer.toString())
+    }
+    
+}
+
diff --git a/groovy-core/src/test/groovy/bugs/Groovy662.groovy b/groovy-core/src/test/groovy/bugs/Groovy662.groovy
new file mode 100644
index 0000000..ceecbe7
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy662.groovy
@@ -0,0 +1,66 @@
+package groovy.bugs
+
+//  The order of the classes is crucial, the first must be the GroovyTestCase.  Its name doesn't
+//  matter it just has to be first.
+
+/**
+ * Test class and support to realize the GROOVY-662 test.  There is a difference between
+ * improper uses of properties between Groovy defined classes and Java defined classes.  There
+ * is no difference between correct uses so this is not a problem just an anti-regression test.
+ *
+ *  @author Russel Winder
+ *  @version $Revision$
+ */ 
+class Groovy662 extends GroovyTestCase {
+  private String expected = "Hello"
+  private usePropertyCorrectly ( def object ) { return object.@myProperty }
+  private usePropertyIncorrectly ( def object ) { return object.myProperty }
+  private useMethod ( def object ) { return object.getMyProperty ( ) }
+  private void doAssertions ( def object ) {
+    assertTrue ( useMethod ( object ) == expected )
+    assertTrue ( usePropertyCorrectly ( object ) == expected )
+  }
+  private String theTestScriptDefinitions = """
+String expected = "Hello"
+def usePropertyCorrectly ( def object ) { return object.@myProperty }
+def usePropertyIncorrectly ( def object ) { return object.myProperty }
+def useMethod ( def object ) { return object.getMyProperty ( ) }
+"""
+  private String theTestScriptAssertions = """
+assert useMethod ( object ) == expected
+assert usePropertyCorrectly ( object ) == expected
+"""
+  public void testJavaClass ( ) {
+    def object = new groovy.bugs.Groovy662_JavaClass ( ) 
+    doAssertions ( object )
+    assertTrue ( usePropertyIncorrectly ( object ) == null )
+  }
+  public void testGroovyClass ( ) {
+    def object = new Groovy662_GroovyClass ( ) 
+    doAssertions ( object )
+    assertTrue ( usePropertyIncorrectly ( object ) == expected )
+  }
+  public void testJavaClassAsScript ( ) { assertScript ( theTestScriptDefinitions + """
+def object = new groovy.bugs.Groovy662_JavaClass ( )
+""" + theTestScriptAssertions + """
+assert usePropertyIncorrectly ( object ) == null
+""") }
+  public void testGroovyClassAsScript ( ) {
+    assertScript ( theTestScriptDefinitions + """
+class Groovy662_GroovyClass extends HashMap {
+  String myProperty = "Hello"
+  public String getMyProperty ( ) { return myProperty }
+}
+def object = new Groovy662_GroovyClass ( )
+""" + theTestScriptAssertions + """
+assert usePropertyIncorrectly ( object ) == expected
+""")
+  }
+}
+
+class Groovy662_GroovyClass extends HashMap {
+  String myProperty = "Hello"
+  public String getMyProperty ( ) {
+    return myProperty
+  }
+}
diff --git a/groovy-core/src/test/groovy/bugs/Groovy662_JavaClass.java b/groovy-core/src/test/groovy/bugs/Groovy662_JavaClass.java
new file mode 100644
index 0000000..22096ea
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy662_JavaClass.java
@@ -0,0 +1,15 @@
+package groovy.bugs;
+
+import java.util.HashMap ;
+/**
+ * Class to support the GROOVY-662 test.  There is a difference between improper uses of
+ * properties between Groovy defined classes and Java defined classes.  There is no difference
+ * between correct uses so this is not a problem just an anti-regression test.
+ *
+ *  @author Russel Winder
+ *  @version $Revision$
+ */ 
+public class Groovy662_JavaClass extends HashMap {
+  String myProperty = "Hello" ;
+  public String getMyProperty() { return myProperty ; }
+}
diff --git a/groovy-core/src/test/groovy/bugs/Groovy666_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy666_Bug.groovy
new file mode 100644
index 0000000..6980841
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy666_Bug.groovy
@@ -0,0 +1,11 @@
+package groovy.bugs
+
+/**
+ *  @author Russel Winder
+ *  @version $Revision$
+ */ 
+class Groovy666_Bug extends GroovyTestCase {
+  void testRunScript() {
+    (new GroovyShell ()).evaluate("x = 1")
+  }
+}
diff --git a/groovy-core/src/test/groovy/bugs/Groovy674_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy674_Bug.groovy
new file mode 100644
index 0000000..ca6b551
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy674_Bug.groovy
@@ -0,0 +1,55 @@
+package groovy.bugs
+
+/**
+ *  Test to ensure all the right exceptions are thrown for all the right/wrong combinations of
+ *  parentheses and no parameters for print and println.
+ *
+ *  @author Russel Winder
+ *  @version $Revision$
+ */
+class Groovy674_Bug extends GroovyTestCase {
+  void testTopLevelPrintParenthesesNoParameter ( ) {
+    try { ( new GroovyShell ( ) ).evaluate ( "print ( )" ) }
+    catch ( GroovyRuntimeException gre ) { return }
+    fail ( "Should have thrown GroovyRuntimeException" ) ;
+  }
+  void testTopLevelPrintlnParenthesesNoParameter ( ) {
+    assertScript ( "println ( )" )
+  }
+  void testClosurePrintParenthesesNoParameter ( ) {
+    try { ( new GroovyShell ( ) ).evaluate ( "[ 1 , 2 , 3 , 4 , 5 ].each { print ( ) }" ) }
+    catch ( GroovyRuntimeException gre ) { return }
+    fail ( "Should have thrown GroovyRuntimeException" ) ;
+  }
+  void testClosurePrintlnParenthesesNoParameter ( ) {
+    assertScript ( "[ 1 , 2 , 3 , 4 , 5 ].each { println ( ) }" )
+  }
+  void testTopLevelPrintNoParenthesesParameter ( ) { assertScript ( "print ( '' )" ) }
+  void testTopLevelPrintlnNoParenthesesParameter ( ) { assertScript ( "println ( '' )" ) }
+  void testClosurePrintNoParenthesesParameter ( ) { assertScript ( "[ 1 , 2 , 3 , 4 , 5 ].each { print ( '' ) }" ) }
+  void testClosurePrintlnNoParenthesesParameter ( ) { assertScript ( "[ 1 , 2 , 3 , 4 , 5 ].each { println ( '' ) }" ) }
+  void testTopLevelPrintParenthesesParameter ( ) { assertScript ( "print ''" ) }
+  void testTopLevelPrintlnParenthesesParameter ( ) { assertScript ( "println ''" ) }
+  void testClosurePrintParenthesesParameter ( ) { assertScript ( "[ 1 , 2 , 3 , 4 , 5 ].each { print '' }" ) }
+  void testClosurePrintlnParenthesesParameter ( ) { assertScript ( "[ 1 , 2 , 3 , 4 , 5 ].each { println '' }" ) }
+  void testTopLevelPrintProperty ( ) {
+    try { ( new GroovyShell ( ) ).evaluate ( "print" ) }
+    catch ( MissingPropertyException mpe ) { return ; }
+    fail ( "Should have thrown MissingPropertyException" ) ;
+  }
+  void testTopLevelPrintlnProperty  ( ) {
+    try { ( new GroovyShell ( ) ).evaluate ( "println" ) }
+    catch ( MissingPropertyException mpe ) { return ; }
+    fail ( "Should have thrown MissingPropertyException" ) ;
+  }
+  void testInClosurePrintProperty  ( ) {
+    try { ( new GroovyShell ( ) ).evaluate ( "[ 1 , 2 , 3 , 4 , 5 ].each { print }" ) }
+    catch ( MissingPropertyException mpe ) { return ; }
+    fail ( "Should have thrown MissingPropertyException" ) ;
+  }
+  void testInClosurePrintlnProperty  ( ) {
+    try { ( new GroovyShell ( ) ).evaluate ( "[ 1 , 2 , 3 , 4 , 5 ].each { println }" ) }
+    catch ( MissingPropertyException mpe ) { return ; }
+    fail ( "Should have thrown MissingPropertyException" ) ;
+  }
+}
diff --git a/groovy-core/src/test/groovy/bugs/Groovy675_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy675_Bug.groovy
new file mode 100644
index 0000000..5f2969e
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy675_Bug.groovy
@@ -0,0 +1,28 @@
+package groovy.bugs
+
+/**
+ *  @author Pilho Kim
+ *  @version $Revision$
+ */ 
+class Groovy675_Bug extends GroovyTestCase {
+    void testStringAndGString() {
+	assert "\\"!="\\\\" 
+	assert "\\\$"=="\\"+"\$" 
+	assert "\\"+"\\\\" == "\\"+"\\"+"\\" && "\\\\"+"\\" == "\\"+"\\"+"\\"
+	assert ("\\\\"+"\\").length() == 3
+	assert "\\3 \$1\$2" == "\\" + "3" + " " + "\$" + "1" + "\$" + "2"
+	assert "\\\\3 \\\$1\$2" == "\\" + "\\" + "3" + " " + "\\"+ "\$" + "1" + "\$" + "2"
+	assert "\\\\\\3 \\\\\$1\$2" == "\\" + "\\\\" + "3" + " " + "\\\\"+ "\$" + "1" + "\$" + "2"
+	assert "\\\\\\\\3 \\\\\\\$1\$2" == "\\\\" + "\\\\" + "3" + " " + "\\\\\\"+ "\$" + "1" + "\$" + "2"
+
+	assert "\\\\" == "\\" + "\\"
+	assert "\\\\".length() == 2
+
+	def z = 100 + 200
+	assert "\\\\ \\ ${z}" == "\\\\ \\ 300"
+	assert "\\\\ \\ ${z}" == "\\" + "\\" + " " + "\\" + " " + "300"
+	assert "Hello\\, \\World\\".charAt(4) == "o".charAt(0)
+	assert "Hello\\, \\World\\".charAt(5) == "\\".charAt(0)
+	assert "Hello\\, \\World\\".charAt(6) == ",".charAt(0)
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/Groovy770_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy770_Bug.groovy
new file mode 100644
index 0000000..76718a1
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy770_Bug.groovy
@@ -0,0 +1,47 @@
+/**
+ * @version $Revision$
+ */
+
+package groovy.bugs
+
+class Groovy770_Bug extends GroovyTestCase {
+     
+    void testBug() {
+        def a = new Pair(sym:"x")
+        def b = new Pair(sym:"y")
+        def c = new Pair(sym:"y")
+
+        def l1 = [a, b]
+        def l2 = [c]
+        println (l1)
+        println (l2)
+        println (l1 - l2)
+        assert l1 - l2 == l1
+
+
+        a = new CPair(sym:"x")
+        b = new CPair(sym:"y")
+        c = new CPair(sym:"y")
+        l1 = [a, b]
+        l2 = [c]
+        println (l1)
+        println (l2)
+        println (l1 - l2)
+        assert l1 - l2 == [a]
+    }
+}
+
+import java.util.*
+
+class Pair {
+  String sym
+}
+
+class CPair implements Comparable {
+  public String sym
+  int compareTo(Object o) {
+      return sym.compareTo(((CPair) o).sym);
+  }
+}
+
+
diff --git a/groovy-core/src/test/groovy/bugs/Groovy779_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy779_Bug.groovy
new file mode 100644
index 0000000..87deb4c
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy779_Bug.groovy
@@ -0,0 +1,104 @@
+package groovy.bugs
+
+class Groovy779_Bug extends GroovyTestCase {
+
+    def boolean exceptionCalled = false
+    def boolean finallyCalled = false
+
+    public static void main(String[] args) {
+        Groovy779_Bug app = new Groovy779_Bug()
+        app.testFieldProperty()
+        app.testBeanProperty()
+        app.testAutoboxingProperty()
+    }
+
+    public void testFieldProperty() {
+
+        try {
+            def p = new Groovy779OnePerson(nameID:"foo-", age:12.2)
+            assert p.age == 12
+            assert p.nameID == "foo-"
+            p = new Groovy779OnePerson(nameID:"foo-", age:"12")
+            println p.age
+            println p.nameID
+        }
+        catch (ClassCastException e) {
+            onException(e)
+        }
+        finally {
+            onFinally()
+        }
+        assert exceptionCalled , "should have invoked the catch clause"
+        assert finallyCalled , "should have invoked the finally clause"
+        // println("Success!")
+    }
+
+    public void testBeanProperty() {
+
+        try {
+            def p2 = new Groovy779AnotherPerson(nameID:1234, age:12.2)
+            assert p2.age == 12
+            assert p2.nameID == "1234"
+            p2 = new Groovy779AnotherPerson(nameID:111, age:"12")
+            println p2.age
+            println p2.nameID
+        }
+        catch (ClassCastException e) {
+            onException(e)
+        }
+        finally {
+            onFinally()
+        }
+        assert exceptionCalled , "should have invoked the catch clause"
+        assert finallyCalled , "should have invoked the finally clause"
+        // println("Success!")
+    }
+
+    public void testAutoboxingProperty() {
+        def p = new Groovy779OneProfit(signal:"bar", rate:15)
+        assert p.signal == "bar"
+        assert p.rate == 15.0
+
+        p = new Groovy779OneProfit(signal:111+22, rate:new java.math.BigDecimal("15"))
+        assert p.signal == "133"
+        assert p.rate == 15.0
+
+        def p2 = new Groovy779AnotherProfit(signal:"bar~", rate:15)
+        assert p2.signal == "bar~"
+        assert p2.rate == 15.0
+
+        p2 = new Groovy779AnotherProfit(signal:111-22, rate:new java.math.BigDecimal("15"))
+        assert p2.signal == "89"
+        assert p2.rate == 15.0
+    }
+
+    void onException(e) {
+        assert e != null
+        exceptionCalled = true
+    }
+	
+    void onFinally() {
+        finallyCalled = true
+    }
+
+}
+
+class Groovy779OnePerson {
+   def public String nameID
+   def public int age
+}
+
+class Groovy779AnotherPerson {
+   String nameID
+   int age
+}
+
+class Groovy779OneProfit {
+   public String signal
+   public double rate
+}
+
+class Groovy779AnotherProfit {
+   String signal
+   double rate
+}
diff --git a/groovy-core/src/test/groovy/bugs/Groovy831_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy831_Bug.groovy
new file mode 100644
index 0000000..f87fe69
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy831_Bug.groovy
@@ -0,0 +1,38 @@
+package groovy.bugs
+
+/**
+ * Test for fixing the Jira issue GROOVY-831
+ *
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+class Groovy831_Bug extends GroovyTestCase {
+    
+    String[] cities = ['Seoul', 'London', 'Wasington']
+    int[] intArrayData = [1, 3, 5]
+
+    public String[] countries = [ 'Republic of Korea', 'United Kingdom', 'United State of America']
+    public  int[] intArray  = [ 2, 4, 6 ]
+
+    void testSetFieldProperty() {
+        assert cities.size() == 3
+        assert cities[0] == 'Seoul'
+        assert cities[1] == 'London'
+        assert cities[2] == 'Wasington'
+        assert intArrayData.size() == 3
+        assert intArrayData[0] == 1
+        assert intArrayData[1] == 3
+        assert intArrayData[2] == 5
+    }
+
+    void testSetFieldVariable() {
+        assert countries.size() == 3
+        assert countries[0] == 'Republic of Korea'
+        assert countries[1] == 'United Kingdom'
+        assert countries[2] == 'United State of America'
+        assert intArray[0] == 2
+        assert intArray[1] == 4
+        assert intArray[2] == 6
+    }
+}
+
diff --git a/groovy-core/src/test/groovy/bugs/Groovy872.groovy b/groovy-core/src/test/groovy/bugs/Groovy872.groovy
new file mode 100644
index 0000000..d6abf16
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy872.groovy
@@ -0,0 +1,22 @@
+package groovy.bugs
+
+class Groovy872 extends GroovyTestCase {
+  void testScript ( ) {
+    assertScript ( """
+def cal = new GregorianCalendar ( )
+cal.set ( Calendar.DAY_OF_MONTH , 1 )
+println ( cal.get ( Calendar.DAY_OF_MONTH ) )
+""")
+  }
+  void testCode ( ) {
+    new MyCalendar ( ).tryit ( )
+  }   
+}
+
+class MyCalendar {
+  void tryit ( )  {
+    def cal = new GregorianCalendar ( )
+    cal.set ( Calendar.DAY_OF_MONTH , 1 )
+    println ( cal.get ( Calendar.DAY_OF_MONTH ) )
+  }
+}
diff --git a/groovy-core/src/test/groovy/bugs/Groovy965_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy965_Bug.groovy
new file mode 100644
index 0000000..e1810f9
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy965_Bug.groovy
@@ -0,0 +1,37 @@
+package groovy.bug
+
+/**
+ *  A test case to ensure that Groovy can compile class names and variable names with non-ASCII
+ *  characters and that non-ASCII characters in Strings do the right thing.
+ *
+ *  <p>Unfortunately, we cannot actually have this test in the Subversion store since it
+ *  requires having an encoding.  Java internally uses UTF-16.  Most Linux/UNIX/Mac OS X users
+ *  use UTF-8 (or if they haven't caught up yet ISO-8859-{1..15], in Europe anyway).  Windows
+ *  internally is UTF-16 LE but it appears that the Europe region defaults to ISO-8859-1 which
+ *  is very silly.  All in all we cannot gurantee an ecoding so we cannot have the tests.</p>
+ *
+ *  <p>If anyone spots any errors in the rationale or finds a way to fix things please update at
+ *  will.</p>
+ *
+ *  @suthor Russel Winder
+ *  @version $LastChangedRevision$ $LastChangedDate$
+ */
+class Groovy965_Bug extends GroovyTestCase {
+  /* void test to avoid assertion failure because of the lack of test method in the class */
+  void testVoid() {}
+  /*
+  void testUnicodeVariableNamesAndStrings ( ) {
+    def âøñè = 'âøñè'
+    assertEquals ( 'âøñè' , âøñè )
+  }
+  void testUnicodeMëthødName ( ) { }
+  void testUnicodeClassName ( ) {
+    def object = new Bläh ( ) 
+    assert true
+  }
+  */
+}
+
+/*
+class Bläh { }
+*/
diff --git a/groovy-core/src/test/groovy/bugs/Groovy996_Bug.groovy b/groovy-core/src/test/groovy/bugs/Groovy996_Bug.groovy
new file mode 100644
index 0000000..e160738
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/Groovy996_Bug.groovy
@@ -0,0 +1,18 @@
+package groovy.bugs
+
+class Groovy996_Bug extends GroovyTestCase {
+    void testAccessToSuperProtectedField() {
+        def a = new Groovy996_SubClass()
+        a.out()
+    }
+}
+
+class Groovy996_SuperClass {
+    protected String x = 'This is an X'
+}
+
+class Groovy996_SubClass extends Groovy996_SuperClass {
+    void out() {
+       println( x )
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/GuillaumesBug.groovy b/groovy-core/src/test/groovy/bugs/GuillaumesBug.groovy
new file mode 100644
index 0000000..dd635ee
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/GuillaumesBug.groovy
@@ -0,0 +1,11 @@
+/**
+ * @author Guillaume Laforge 
+ * @version $Revision$
+ */
+class GuillaumesBug extends GroovyTestCase {
+    
+    void testBug() {
+        if (true) 
+            println("true")
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/GuillaumesMapBug.groovy b/groovy-core/src/test/groovy/bugs/GuillaumesMapBug.groovy
new file mode 100644
index 0000000..79f7703
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/GuillaumesMapBug.groovy
@@ -0,0 +1,40 @@
+/**
+ * @author Guillaume Laforge
+ * @version $Revision$
+ */
+class GuillaumesMapBug extends GroovyTestCase {
+    
+    void testBug2() {
+        def list = [1, 2, 3]
+        def map = [:]
+        
+        doLoop(list, map)
+    
+        assert map[0] == 1 
+        assert map[1] == 2 
+        assert map[2] == 3 
+    }
+    
+    void doLoop(list, map) {
+        def i = 0
+        for (it in list) {
+            map[i++] = it
+        }
+    }
+    
+    
+    void testBug() {
+        def list = [1, 2, 3]
+        def map = [:]
+        doClosureLoop(list, map)
+        
+        assert map[0] == 1 
+        assert map[1] == 2 
+        assert map[2] == 3 
+    }
+    
+    void doClosureLoop(list, map) {
+        def i = 0
+        list.each { map[i++] = it }
+    }    
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/IanMaceysBug.java b/groovy-core/src/test/groovy/bugs/IanMaceysBug.java
new file mode 100644
index 0000000..3186ba7
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/IanMaceysBug.java
@@ -0,0 +1,66 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.bugs;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+/**
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class IanMaceysBug extends TestSupport {
+
+    public void testBug() throws Exception {
+        try {
+            assertScript("dummy = 0; for ( i in 0..9 ) {  dummy += i }\n println 'done'", "dummy.groovy");
+            fail("Should throw a syntax exception");
+        }
+        catch (Exception e) {
+            System.out.println("Worked. Caught: " + e);
+        }
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/InconsistentStackHeightBug.groovy b/groovy-core/src/test/groovy/bugs/InconsistentStackHeightBug.groovy
new file mode 100644
index 0000000..7d984aa
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/InconsistentStackHeightBug.groovy
@@ -0,0 +1,32 @@
+/**
+ * @version $Revision$
+ */
+class InconsistentStackHeightBug extends GroovyTestCase {
+
+    void testBug() {
+        def server = 0
+        def tmp = server + 1
+        try {
+        }
+        finally {
+        }
+    }
+
+    void testBug2() {
+        def server = 0
+        def tmp = server == 2
+        try {
+        }
+        finally {
+        }
+    }
+
+    void testBug3() {
+        def server = 0
+        def foo = server
+        try {
+        }
+        finally {
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/InterfaceImplBug.groovy b/groovy-core/src/test/groovy/bugs/InterfaceImplBug.groovy
new file mode 100644
index 0000000..99eabc0
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/InterfaceImplBug.groovy
@@ -0,0 +1,20 @@
+package groovy.bugs
+
+import java.io.Reader
+import org.codehaus.groovy.dummy.FooHandler
+
+/**
+ * @author Robert Fuller
+ * @version $Revision$
+ */
+class InterfaceImplBug extends GroovyTestCase implements FooHandler {
+
+    void testMethodCall() {
+        handle(null)
+    }
+    
+    void handle(Reader reader){
+        println("in handle method")
+        def called = true
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/InvokeNormalMethodFromBuilder_Bug657.groovy b/groovy-core/src/test/groovy/bugs/InvokeNormalMethodFromBuilder_Bug657.groovy
new file mode 100644
index 0000000..b7a43f8
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/InvokeNormalMethodFromBuilder_Bug657.groovy
@@ -0,0 +1,39 @@
+/**
+  * <p>
+  * Test that ensures that:
+  * <ul>
+  *   <li>it is possible to write a builder in Groovy</li>
+  *   <li>it is possible to call normal methods from the builder,
+  *       without the methods being trapped endlessly by createNode()</li>
+  * </ul>
+  * </p>
+  *
+  * @author Guillaume Laforge
+  */
+class InvokeNormalMethodFromBuilder_Bug657 extends GroovyTestCase {
+    void testInvokeNormalMethod() {
+        def b = new Builder()
+        assert b.callNormalMethod() == "first"
+
+        def value = b.someNode() {}
+        assert value == "second"
+    }
+}
+
+class Builder extends BuilderSupport {
+
+    void setParent(Object parent, Object child) {}
+
+    Object createNode(Object name)                 { return createNode(name, [:], null) }
+    Object createNode(Object name, Map attributes) { return createNode(name, attributes, null) }
+    Object createNode(Object name, Object value)   { return createNode(name, [:], value) }
+
+    Object createNode(Object name, Map attributes, Object value) {
+        println "create ${name}"
+        return callOtherStaticallyTypedMethod()
+    }
+
+    String callNormalMethod()               { println "normalMethod"; return "first" }
+    String callOtherStaticallyTypedMethod() { println "otherMethod";  return "second" }
+    
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/IterateOverCustomTypeBug.groovy b/groovy-core/src/test/groovy/bugs/IterateOverCustomTypeBug.groovy
new file mode 100644
index 0000000..36a54c6
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/IterateOverCustomTypeBug.groovy
@@ -0,0 +1,21 @@
+import groovy.bugs.TestSupport
+
+/**
+ * @version $Revision: 1.3 $
+ */
+class IterateOverCustomTypeBug extends TestSupport {
+    
+    void testBug() {
+        def object = this
+        
+        def answer = []
+        for (i in object) {
+            answer << i
+        }
+        assert answer == ['a', 'b', 'c']
+        
+        answer = []
+        object.each { answer << it }
+        assert answer == ['a', 'b', 'c']
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/MarkupAndMethodBug.groovy b/groovy-core/src/test/groovy/bugs/MarkupAndMethodBug.groovy
new file mode 100644
index 0000000..1755cf0
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/MarkupAndMethodBug.groovy
@@ -0,0 +1,42 @@
+/**
+ * Mixes variables, closures and method calls in markup
+ *
+ * @version $Revision$
+ */
+class MarkupAndMethodBug extends GroovyTestCase {
+    
+    void testBug() {
+        def tree = createTree()
+        def name = tree.person[0]['@name']
+        assert name == 'James'
+    }
+    
+    protected def createTree() {
+        def builder = NodeBuilder.newInstance()
+        
+        def root = builder.people() {
+            person(name:getTestName()) {
+            /*
+                location(name:'London')
+                projects {
+                    project(name:'geronimo')
+                }
+            }
+            person(name:'Bob') {
+                location(name:'Atlanta')
+                projects {
+                    project(name:'drools')
+                }
+            */
+            }
+        }
+        
+        assert root != null
+        
+        return root
+    }
+    
+    protected def getTestName() {
+        "James"
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/MarkupInScriptBug.java b/groovy-core/src/test/groovy/bugs/MarkupInScriptBug.java
new file mode 100644
index 0000000..d6552c4
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/MarkupInScriptBug.java
@@ -0,0 +1,60 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.bugs;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+
+/**
+ * @version $Revision$
+ */
+public class MarkupInScriptBug extends TestSupport {
+
+    public void testBug() throws Exception {
+        assertScriptFile( "src/test/groovy/script/AtomTestScript.groovy" );
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/MethodCallWithoutParensInStaticMethodBug.groovy b/groovy-core/src/test/groovy/bugs/MethodCallWithoutParensInStaticMethodBug.groovy
new file mode 100644
index 0000000..ecf1ebd
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/MethodCallWithoutParensInStaticMethodBug.groovy
@@ -0,0 +1,10 @@
+class MethodCallWithoutParensInStaticMethodBug extends GroovyTestCase {
+
+    void testBug() {
+        staticMethod()
+    }
+    
+    static void staticMethod() {
+        println 'hello'[1]
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/MethodClosureTest.groovy b/groovy-core/src/test/groovy/bugs/MethodClosureTest.groovy
new file mode 100644
index 0000000..9e1317a
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/MethodClosureTest.groovy
@@ -0,0 +1,36 @@
+package groovy.bugs
+
+import org.codehaus.groovy.runtime.MethodClosure
+
+class MethodClosureTest extends GroovyTestCase {
+
+    def aa(x) {
+        x
+    }
+    
+    static bb(it) { it}
+
+    void testMetodClosure() {   
+        Class[] c1 =  [ Exception.class, Throwable.class ]
+        Class[] c2 = [ IllegalStateException.class ]
+
+        def cl = this.&aa
+
+        assert cl instanceof Closure
+        assert cl instanceof MethodClosure
+
+        assert [c1, c2].collect(cl) == [c1,c2]
+    }
+    
+    void testStaticMethodAccess() {
+       def list = [1].collect (this.&bb)
+       assert list == [1]
+       list = [1].collect (MethodClosureTest.&bb)
+       assert list == [1]
+       def mct = new MethodClosureTest()
+       list = [1].collect (mct.&bb)
+       assert list == [1]
+    }
+}
+
+
diff --git a/groovy-core/src/test/groovy/bugs/MethodDispatchBug.groovy b/groovy-core/src/test/groovy/bugs/MethodDispatchBug.groovy
new file mode 100644
index 0000000..a3715c4
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/MethodDispatchBug.groovy
@@ -0,0 +1,44 @@
+/**
+ * @author Chris Poirier
+ * @version $Revision$
+ */
+class MethodDispatchBug extends GroovyTestCase {
+    void doit(Object parameter1, Object parameter2) {
+        System.out.println("TestChild::doit( Object, Object )");
+    }
+
+    void doit(Boolean parameter1, Object parameter2) {
+        System.out.println("TestChild::doit( Boolean, Object )");
+    }
+
+    void doit(Object parameter1, Boolean parameter2) {
+        System.out.println("TestChild::doit( Object, Boolean )");
+    }
+
+    void doit(Boolean parameter1, Boolean parameter2) {
+        System.out.println("TestChild::doit( Boolean, Boolean )");
+    }
+
+    void testBug() {
+    /* @todo
+    	strange - this works fine inside eclipse but fails inside Maven
+    	
+        o = this;
+
+        System.out.println("Calling Test.doit( Boolean, Boolean ) -- expect Boolean, Boolean");
+        o.doit(true, true);
+
+        System.out.println("");
+        System.out.println("Calling Test.doit( Boolean, Integer ) -- expect Boolean, Object");
+        o.doit(true, 9);
+
+        System.out.println("");
+        System.out.println("Calling Test.doit( Integer, Boolean ) -- expect Object, Boolean");
+        o.doit(9, true);
+
+        System.out.println("");
+        System.out.println("Calling Test.doit( Integer, Integer ) -- expect Object, Object");
+        o.doit(9, 9);
+    */
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/MethodPointerBug.groovy b/groovy-core/src/test/groovy/bugs/MethodPointerBug.groovy
new file mode 100644
index 0000000..bcc3e12
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/MethodPointerBug.groovy
@@ -0,0 +1,47 @@
+package groovy.bugs
+
+/**
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+class MethodPointerBug extends GroovyTestCase {
+
+    def void sayHello() { 
+        println "hello" 
+    } 
+
+    def MethodPointerBug getThisObject() { 
+        return this
+    } 
+
+    // Test a standard method pointer operator ".&".  For example, foo.&bar.
+    void testMethodPointer() {
+        def bug = new MethodPointerBug()
+        def x = bug.&sayHello
+        x()
+    } 
+
+    // Test a standard method pointer operator ".&" with this object.  For example, this.&bar.
+    void testThisMethodPointer() {
+        def y = this.&sayHello
+        y()
+    } 
+
+    ///////////////////////////////////////////////////////////////////////////////////////////
+    // Test a default method pointer operator "&" with this object.  For example, &bar.
+    // This shows that the issue GROOVY-826 has been fixed in groovy-1.0-jar-02.
+/*
+  todo - commented out due to groovy.g non-determinisms
+    void testDefaultMethodPointer() {
+        def z = &sayHello
+        z()
+    } 
+*/
+    // Test a default method pointer operator ".&" with returned object.  For example, someMethod().&bar.
+    void testMethodPointerWithReturn() {
+        def u = getThisObject().&sayHello
+        u()
+        def v = thisObject.&sayHello
+        v()
+    } 
+}
diff --git a/groovy-core/src/test/groovy/bugs/MorgansBug.groovy b/groovy-core/src/test/groovy/bugs/MorgansBug.groovy
new file mode 100644
index 0000000..37c2636
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/MorgansBug.groovy
@@ -0,0 +1,11 @@
+/**
+ * @author Morgan Hankins
+ * @version $Revision$
+ */
+class MorgansBug extends GroovyTestCase {
+
+    void testBug() {
+        def result = 4 + "x"
+        assert result == "4x"
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/NestedClosure2Bug.groovy b/groovy-core/src/test/groovy/bugs/NestedClosure2Bug.groovy
new file mode 100644
index 0000000..9f04339
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/NestedClosure2Bug.groovy
@@ -0,0 +1,68 @@
+import org.codehaus.groovy.classgen.TestSupport
+
+/**
+ * @version $Revision$
+ */
+class NestedClosure2Bug extends TestSupport {
+     
+    Object f
+     
+    void testFieldBug() {
+    	def closure = {
+    		return {
+	    		f = 123
+	    		return null
+	        }
+	    }
+        def value = closure()
+        value = value()
+        assert f == 123
+    }
+     
+    void testBugOutsideOfScript() {
+    	def a = 123
+    	def b = 456
+    	def closure = {
+    		println b
+    		def c = 999
+    		return {
+    			f = 2222111
+    			
+    			println f
+    			
+    			println c
+    			def d = 678
+    			return { 
+    				println f
+    				assert f == 2222111
+    				println d
+    				return a
+    			}
+    		}
+    	}
+    	def c2 = closure()
+    	def c3 = c2()
+    	def value = c3()
+
+		assert f == 2222111    	
+    	assert value == 123
+    }
+    
+    void testBug() {
+    	assertScript """
+	    	def a = 123
+	    	def closure = {
+	    		return {
+	    			return { 
+	    				return a
+	    			}
+	    		}
+	    	}
+	    	def c2 = closure()
+	    	def c3 = c2()
+	    	value = c3()
+	    	
+	    	assert value == 123
+"""
+	}
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/NestedClosureBug.groovy b/groovy-core/src/test/groovy/bugs/NestedClosureBug.groovy
new file mode 100644
index 0000000..f5f3b22
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/NestedClosureBug.groovy
@@ -0,0 +1,19 @@
+/**
+ * @version $Revision$
+ */
+class NestedClosureBug extends GroovyTestCase {
+     
+    void testBug() {
+    	def a = 123
+    	getValues().each { 
+    		println it
+    		it.each { 
+    			assert a == 123
+    		}
+    	}
+    }
+    
+    def getValues() {
+    	[5, 6, 7]
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/NullCompareBug.groovy b/groovy-core/src/test/groovy/bugs/NullCompareBug.groovy
new file mode 100644
index 0000000..3e6c409
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/NullCompareBug.groovy
@@ -0,0 +1,11 @@
+/**
+ * @version $Revision: 1.3 $
+ */
+class NullCompareBug extends GroovyTestCase {
+    
+    void testBug() {
+        assert "dog" > null
+        assert null < "dog"
+        assert null == null
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/OverloadInvokeMethodBug.groovy b/groovy-core/src/test/groovy/bugs/OverloadInvokeMethodBug.groovy
new file mode 100644
index 0000000..3108f32
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/OverloadInvokeMethodBug.groovy
@@ -0,0 +1,30 @@
+/**
+ * @version $Revision$
+ */
+ 
+class OverloadInvokeMethodBug extends GroovyTestCase {
+     
+    void testBug() {
+    	def a = new OverloadA()
+    	a.duh()
+    	
+    	def b = new OverloadB()
+    	b.duh()
+    }
+
+}
+
+class OverloadA {
+        def invokeMethod(String name, Object args) {
+                try {
+                        metaClass.invokeMethod(this, name, args)
+                } catch(MissingMethodException e) {
+                        println "Missing method: ${name}"
+                }
+        } 
+}
+
+class OverloadB extends OverloadA {
+
+}
+
diff --git a/groovy-core/src/test/groovy/bugs/PrimitivePropertyBug.groovy b/groovy-core/src/test/groovy/bugs/PrimitivePropertyBug.groovy
new file mode 100644
index 0000000..6b2db6f
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/PrimitivePropertyBug.groovy
@@ -0,0 +1,50 @@
+package groovy.bugs
+
+/**
+ * @version $Revision$
+ *
+ * Fix Bug GROOVY-683
+ * @author Pilho Kim
+ */
+class PrimitivePropertyBug extends GroovyTestCase {
+     
+    double x1
+    float x2
+    long x3
+    int x4
+    short x5
+    byte x6
+    char x7
+
+    void testBug() {
+        def y = new PrimitivePropertyBug()
+        y.x1 = 10.0
+        y.x2 = 10.0
+        y.x3 = 10.0
+        y.x4 = 10.0
+        y.x5 = 10.0
+        y.x6 = 10.0
+        y.x7 = 10.0
+        
+        assert y.x1 == 10.0
+        assert y.x2 == 10.0
+        assert y.x3 == 10.0
+        assert y.x4 == 10.0
+        assert y.x5 == 10.0
+        assert y.x6 == 10.0
+        assert y.x1.class == Double.class
+        assert y.x2.class == Float.class
+        assert y.x3.class == Long.class
+        assert y.x4.class == Integer.class
+        assert y.x5.class == Short.class
+        assert y.x6.class == Byte.class
+        assert y.x7.class == Character.class
+        assert y.x1 + y.x1 == y.x1 * 2
+        assert y.x2 - 1 == 9.0f
+        assert y.x3 * 2 == 20L
+        assert y.x4 == 10
+        assert y.x5 == 10
+        assert y.x6 + 3 == 13
+        assert "Hello" + y.x7 + "World!" == "Hello\nWorld!"
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/PrintlnWithNewBug.groovy b/groovy-core/src/test/groovy/bugs/PrintlnWithNewBug.groovy
new file mode 100644
index 0000000..353f83d
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/PrintlnWithNewBug.groovy
@@ -0,0 +1,11 @@
+/**
+ * @author Mark Volkmann 
+ * @version $Revision: 1.3 $
+ */
+class PrintlnWithNewBug extends GroovyTestCase {
+    
+    void testBug() {
+        println(new Foo(name:'abc')) 
+        println new Foo(name:'def') 
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/PropertyBug.groovy b/groovy-core/src/test/groovy/bugs/PropertyBug.groovy
new file mode 100644
index 0000000..98f8715
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/PropertyBug.groovy
@@ -0,0 +1,18 @@
+import javax.swing.JButton
+import javax.swing.JPanel
+
+/**
+ * @version $Revision$
+ */
+class PropertyBug extends GroovyTestCase {
+     
+    void testBug() {
+        def panel = new JPanel()
+        def bean = new JButton()
+        
+        panel.add(bean)
+        
+        def value = bean.parent
+        assert value != null
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/PropertyNameBug.groovy b/groovy-core/src/test/groovy/bugs/PropertyNameBug.groovy
new file mode 100644
index 0000000..630f9b0
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/PropertyNameBug.groovy
@@ -0,0 +1,34 @@
+package groovy.bugs
+
+/**
+ * Test to fix the issue GROOVY-843.
+ *
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+
+public class PropertyNameBug extends GroovyTestCase {
+    void testNonJavaIdentifierChacactersWithJavaSyntax() {
+        Map map = new HashMap()
+        map.put("foo.bar", "FooBar")
+        map.put("foo.bar-bar", "FooBar-Bar")
+        map.put("foo.=;&|^*-+-/\\'?.*:arbitrary()[]{}%#@!", "Any character")
+
+        println("foo.bar1 = ${map.get("foo.bar1")}")
+        println("foo.bar-bar = ${map.get("foo.bar-bar")}")
+        println("Specical Character Test: ${map.get("foo.=;&|^*-+-/\\'?.*:arbitrary()[]{}%#@!")}")
+    }
+
+    void testNonJavaIdentifierChacactersWithGroovySyntax() {
+        def map = [:]
+        map."foo.bar" = "FooBar"
+        map."foo.bar-bar" = "FooBar-Bar"
+        map."foo.=;&|^*-+-/\\'?.*:arbitrary()[]{}%#@!" = "Any character"
+
+        println("foo.bar1 = ${map."foo.bar1"}")
+        println("foo.bar-bar = ${map."foo.bar-bar"}")
+        println("Specical Character Test: ${map."foo.=;&|^*-+-/\\'?.*:arbitrary()[]{}%#@!"}")
+    }
+}
+
+
diff --git a/groovy-core/src/test/groovy/bugs/RodsBooleanBug.groovy b/groovy-core/src/test/groovy/bugs/RodsBooleanBug.groovy
new file mode 100644
index 0000000..3f1717e
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/RodsBooleanBug.groovy
@@ -0,0 +1,16 @@
+/**
+ * @version $Revision$
+ */
+class RodsBooleanBug extends GroovyTestCase {
+
+    def item = "hi"
+    
+    void testBug() {
+        assert isIt()
+    }
+    
+    def isIt() {
+        return item != null && item == "hi"
+    }
+    
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/RodsBug.groovy b/groovy-core/src/test/groovy/bugs/RodsBug.groovy
new file mode 100644
index 0000000..b68d70d
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/RodsBug.groovy
@@ -0,0 +1,43 @@
+/**
+ * @author Rod Cope
+ * @version $Revision$
+ */
+class RodsBug extends GroovyTestCase {
+    
+    void testBug() {
+        doTest(true)
+        /*
+         def x = 1
+         if (x > 0) {
+         String name = "Rod"
+         println(name)
+         }
+         */
+    }
+    
+    void testBug2() {
+        def x = 1
+        if (x > 0) {
+            //String name = "Rod"
+            def name = "Rod"
+            println(name)
+        }
+    }
+    
+    void doTest(flag) {
+        if (flag) {
+            String name = "Rod"
+            //def name = "Rod"
+            doAssert(name)
+        }
+    }
+    
+    void doTest() {
+        String name = "Rod"
+        doAssert(name)
+    }
+    
+    void doAssert(text) {
+        assert text != null
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/RussellsOptionalParenTest.groovy b/groovy-core/src/test/groovy/bugs/RussellsOptionalParenTest.groovy
new file mode 100644
index 0000000..215b886
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/RussellsOptionalParenTest.groovy
@@ -0,0 +1,9 @@
+class RussellsOptionalParenTest extends GroovyTestCase {
+
+    void testMethodCallWithOneParam() {
+        def adob = new ArrayList()
+        adob.add "hello"
+        println adob.get(0)
+        println adob.size()
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/ScriptBug.java b/groovy-core/src/test/groovy/bugs/ScriptBug.java
new file mode 100644
index 0000000..89852f4
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ScriptBug.java
@@ -0,0 +1,61 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.bugs;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+
+/**
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ScriptBug extends TestSupport {
+
+    public void testBug() throws Exception {
+        assertScript( "println 'hello world'" );
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/SeansBug.java b/groovy-core/src/test/groovy/bugs/SeansBug.java
new file mode 100644
index 0000000..88f0375
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/SeansBug.java
@@ -0,0 +1,93 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.bugs;
+
+import groovy.lang.GroovyShell;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+/**
+ * @author Sean Timm 
+ * @version $Revision$
+ */
+public class SeansBug extends TestSupport {
+
+    public void testBug() throws Exception {
+        String code = "for (i in 1..10) \n{\n  println(i)\n}";
+        GroovyShell shell = new GroovyShell();
+        shell.evaluate(code);
+    }
+
+    public void testMarkupBug() throws Exception {
+        String[] lines =
+            {
+                "package groovy.xml",
+                "",
+                "b = new MarkupBuilder()",
+                "",
+                "b.root1(a:5, b:7) { ",
+                "    elem1('hello1') ",
+                "    elem2('hello2') ",
+                "    elem3(x:7) ",
+                "}" };
+        String code = asCode(lines);
+        GroovyShell shell = new GroovyShell();
+        shell.evaluate(code);
+    }
+
+    /**
+     * Converts the array of lines of text into one string with newlines
+     */
+    protected String asCode(String[] lines) {
+        StringBuffer buffer = new StringBuffer();
+        for (int i = 0; i < lines.length; i++) {
+            buffer.append(lines[i]);
+            buffer.append("\n");
+        }
+        return buffer.toString();
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/SimpleModel.java b/groovy-core/src/test/groovy/bugs/SimpleModel.java
new file mode 100644
index 0000000..8bcd1d3
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/SimpleModel.java
@@ -0,0 +1,68 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.bugs;
+
+/**
+ * @author 
+ * @version $Revision$
+ */
+public class SimpleModel {
+    public String s;
+
+    SimpleModel () {
+        s="Hi!";
+    }
+
+    public void show() {
+        System.out.println(s);
+    }
+
+    public static void main(String[] args) {
+        SimpleModel simp = new SimpleModel();
+        simp.show();
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/StaticClosurePropertyBug.groovy b/groovy-core/src/test/groovy/bugs/StaticClosurePropertyBug.groovy
new file mode 100644
index 0000000..8382640
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/StaticClosurePropertyBug.groovy
@@ -0,0 +1,16 @@
+/** 
+ * @author Robert Kuzelj
+ * @version $Revision$
+ */
+class StaticClosurePropertyBug extends GroovyTestCase {
+
+    static def out = {System.out.println(it)}
+    
+    void testCallStaticClosure() {
+        callStaticClosure()
+    }
+    
+    static def callStaticClosure() {
+        out("TEST")
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/StaticMarkupBug.groovy b/groovy-core/src/test/groovy/bugs/StaticMarkupBug.groovy
new file mode 100644
index 0000000..6b4f0d8
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/StaticMarkupBug.groovy
@@ -0,0 +1,16 @@
+import groovy.xml.MarkupBuilder
+
+class StaticMarkupBug extends GroovyTestCase {
+
+    void testBug() {
+        doMarkup(new MarkupBuilder())
+    }
+    
+    static void doMarkup(builder) {
+        builder.html {
+            head {
+                title("Groovy")
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/StaticMethodCallBug.groovy b/groovy-core/src/test/groovy/bugs/StaticMethodCallBug.groovy
new file mode 100644
index 0000000..e85c377
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/StaticMethodCallBug.groovy
@@ -0,0 +1,17 @@
+package groovy.bugs
+
+/** 
+ * @version $Revision$
+ */
+class StaticMethodCallBug extends GroovyTestCase {
+
+    void testBug() {
+        def value = TestSupport.mockStaticMethod()
+        assert value == "cheese"
+    }
+    
+    void testStaticProperty() {
+        def value = TestSupport.mockStaticProperty
+        assert value == "cheese"
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/StaticMethodImportBug.groovy b/groovy-core/src/test/groovy/bugs/StaticMethodImportBug.groovy
new file mode 100644
index 0000000..ee2540b
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/StaticMethodImportBug.groovy
@@ -0,0 +1,13 @@
+package groovy.bugs;
+
+import org.codehaus.groovy.dummy.*
+
+/**
+ * Test case to check if imports can use wildcard (*) for static method calls.
+ * Bug reference: Explicit import needed to call static method, GROOVY-935
+ */
+class StaticMethodImportBug extends GroovyTestCase {
+    void testBug() {
+        assert ClassWithStaticMethod.staticMethod()
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/StaticMethodImportBug2.groovy b/groovy-core/src/test/groovy/bugs/StaticMethodImportBug2.groovy
new file mode 100644
index 0000000..f7f2ce3
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/StaticMethodImportBug2.groovy
@@ -0,0 +1,13 @@
+package groovy.bugs;
+
+import org.codehaus.groovy.dummy.ClassWithStaticMethod
+
+/**
+ * Test case to check if imports can use fully qualified classes for static method calls.
+ * Bug reference: Explicit import needed to call static method, GROOVY-935
+ */
+class StaticMethodImportBug2 extends GroovyTestCase {
+    void testBug() {
+        assert ClassWithStaticMethod.staticMethod()
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/SubscriptAndExpressionBug.groovy b/groovy-core/src/test/groovy/bugs/SubscriptAndExpressionBug.groovy
new file mode 100644
index 0000000..a148485
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/SubscriptAndExpressionBug.groovy
@@ -0,0 +1,60 @@
+class SubscriptAndExpressionBug extends GroovyTestCase {
+    
+    void testBug() {
+        def foo = ["nice cheese grommit"]
+        
+        def cheese = foo[0].startsWith("nice")
+        
+        assert cheese == true
+    }
+
+    void testSubscriptIncrement() {
+        def foo = [5, 6, 7]
+        foo[0] += 5
+        
+        assert foo[0] == 10
+        
+        def i = 0
+        foo[i++] = 1
+        assert foo[0] == 1
+        assert i == 1
+        
+        foo[i++] += 5
+        assert i == 2
+        assert foo[1] == 11
+    }
+
+    void testLargeSubscript() {
+        def foo = [1]
+        
+        foo[10] = 123
+        
+        assert foo[10] == 123
+        
+        foo.putAt(12, 55)
+        assert foo[12] == 55
+        
+        def i = 20
+        foo[i] = 1
+        foo[i++] += 5
+        
+        assert i == 21
+        assert foo[20] == 6
+    }
+    
+    void testDoubleSubscript() {
+        def foo = ["nice cheese grommit"]
+        
+        def cheese = foo[0][5..10]
+        
+        assert cheese == "cheese"
+    }
+    
+    void testSubscriptAndProperty() {
+        def foo = [['gromit':'cheese']]
+        
+        def cheese = foo[0].gromit
+        
+        assert cheese == "cheese"
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/SubscriptOnPrimitiveTypeArrayBug.groovy b/groovy-core/src/test/groovy/bugs/SubscriptOnPrimitiveTypeArrayBug.groovy
new file mode 100644
index 0000000..3f798e1
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/SubscriptOnPrimitiveTypeArrayBug.groovy
@@ -0,0 +1,32 @@
+package groovy.bugs
+
+class SubscriptOnPrimitiveTypeArrayBug extends TestSupport {
+    int[] ia;  // type is not necessary
+    int i1;
+
+    void testBug() {
+        def array = getIntArray() // this function returns [I, true primitive array
+        
+        def value = array[2]
+        
+        assert value == 3
+        
+        array[2] = 8
+
+        value = array[2]
+        assert value == 8
+        
+        // lets test a range
+        def range = array[1..2]
+        
+        assert range == [2, 8]
+    }
+
+    void testGroovyIntArray() {
+        int[] ia = [1, 2]
+        int[] ia1 = ia; // type is not necessary
+        def i1 = ia1[0]
+        int i2 = i1
+        assert i2 == 1
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/SubscriptOnStringArrayBug.groovy b/groovy-core/src/test/groovy/bugs/SubscriptOnStringArrayBug.groovy
new file mode 100644
index 0000000..b8fa0c8
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/SubscriptOnStringArrayBug.groovy
@@ -0,0 +1,22 @@
+package groovy.bugs
+
+class SubscriptOnStringArrayBug extends TestSupport {
+
+    void testArraySubscript() {
+        def array = getMockArguments()
+ 
+        assert array[1] == "b"
+        
+        array[0] = "d"
+        
+        assert array[0] == "d"
+        
+        println("Contents of array are ${array.inspect()}")
+    }
+    
+    void testRobsTestCase() {
+        def array = "one two three".split(" ")
+        
+        assert array[1] == "two"
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/SuperMethod2Bug.groovy b/groovy-core/src/test/groovy/bugs/SuperMethod2Bug.groovy
new file mode 100644
index 0000000..c040018
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/SuperMethod2Bug.groovy
@@ -0,0 +1,127 @@
+/**
+ * @version $Revision$
+ */
+ 
+class SuperMethod2Bug extends GroovyTestCase {
+     
+    void testBug() {
+    	def base = new SuperBase()
+    	def value = base.doSomething()
+    	assert value == "TestBase"
+    	
+    	
+    	base = new SuperDerived()
+    	value = base.doSomething()
+    	assert value == "TestDerivedTestBase"
+    }
+
+    void testBug2() {
+    	def base = new SuperBase()
+    	def value = base.foo(2)
+    	assert value == "TestBase2"
+    	
+    	
+    	base = new SuperDerived()
+    	value = base.foo(3)
+    	assert value == "TestDerived3TestBase3"
+    }
+
+    void testBug3() {
+    	def base = new SuperBase()
+    	def value = base.foo(2,3)
+    	assert value == "foo(x,y)Base2,3"
+    	
+    	
+    	base = new SuperDerived()
+    	value = base.foo(3,4)
+    	assert value == "foo(x,y)Derived3,4foo(x,y)Base3,4"
+    }
+
+    void testBug4() {
+    	def base = new SuperBase("Cheese")
+    	def value = base.name
+    	assert value == "Cheese"
+    	
+    	
+    	base = new SuperDerived("Cheese")
+    	value = base.name
+    	assert value == "CheeseDerived"
+    }
+    
+    void testCallsToSuperMethodsReturningPrimitives(){
+       def base = new SuperBase("super cheese")
+       assert base.longMethod() == 1
+       assert base.intMethod() == 1
+       assert base.boolMethod() == true
+       
+       base = new SuperDerived("derived super cheese")
+       assert base.longMethod() == 1
+       assert base.intMethod() == 1
+       assert base.boolMethod() == true       
+    }
+}
+
+class SuperBase {
+    String name
+
+    SuperBase() {
+    }
+    
+    SuperBase(String name) {
+        this.name = name
+    }
+    
+    def doSomething() {
+    	"TestBase"
+    }
+
+    def foo(param) {
+    	"TestBase" + param
+    }
+    
+    def foo(x, y) {
+    	"foo(x,y)Base" + x + "," + y
+    }
+    
+    boolean boolMethod(){true}
+    long longMethod(){1l}
+    int intMethod(){1i}
+}
+
+class SuperDerived extends SuperBase {
+    
+	def calls = 0
+	
+	SuperDerived() {
+	}
+	
+	SuperDerived(String name) {
+	    super(name + "Derived")
+	}
+	
+    def doSomething() {
+    	/** @todo ++calls causes bug */
+    	//calls++
+    	/*
+    	calls = calls + 1
+    	assert calls < 3
+    	*/
+    	
+    	"TestDerived" + super.doSomething()
+    }
+	
+    def foo(param) {
+    	"TestDerived" + param + super.foo(param)
+    }
+	
+    def foo(x, y) {
+    	"foo(x,y)Derived" + x + "," + y + super.foo(x, y)
+    }
+    
+    // we want to ensure that a call with super, which is directly added into 
+    // bytecode without calling MetaClass does correct boxing
+    boolean booMethod(){super.boolMethod()}
+    int intMethod(){super.intMethod()}
+    long longMethod(){super.longMethod()}
+}
+
diff --git a/groovy-core/src/test/groovy/bugs/SuperMethodBug.groovy b/groovy-core/src/test/groovy/bugs/SuperMethodBug.groovy
new file mode 100644
index 0000000..34bdf0b
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/SuperMethodBug.groovy
@@ -0,0 +1,16 @@
+/**
+ * @version $Revision$
+ */
+class SuperMethodBug extends GroovyTestCase {
+     
+    void testBug() {
+    	def base = new TestBase("yyy")
+    	def value = base.doSomething()
+    	assert value == "TestBase"
+    	
+    	base = new TestDerived("abc")
+    	value = base.doSomething()
+    	assert value == "TestDerivedTestBase"
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/bugs/SynchronizedBytecodeBug.groovy b/groovy-core/src/test/groovy/bugs/SynchronizedBytecodeBug.groovy
new file mode 100644
index 0000000..e767c11
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/SynchronizedBytecodeBug.groovy
@@ -0,0 +1,111 @@
+/**
+ * @author Guillaume Laforge
+ */
+class SynchronizedBytecodeBug extends GroovyTestCase {
+
+    /**
+     * Groovy's bytecode associated with syncrhonized(foo) construct used to generate invalid bytecode
+     * This test method shows that the standard wait()/notify() works.
+     */
+    void testSynchronized() {
+        Integer foo = 0
+
+        Thread.start{
+            println "sleeping for a moment"
+            sleep 1000
+            println "slept and synchronizing from thread"
+            synchronized(foo) {
+                println "notifying"
+                foo.notify()
+                println "notified"
+            }
+        }
+
+        println "synchronizing"
+        synchronized(foo) {
+            println "starting to wait"
+            foo.wait()
+            println "waited"
+        }
+
+        // if this point is reached, the test worked :-)
+        assert true
+    }
+  
+  /* more tests to ensure a monitor exit is done at the right place */
+    
+  void testBreakInSynchronized() {
+    Object lock = new Object()
+    while (true) {
+	    synchronized(lock) {
+    		break
+    	}
+    }
+    checkNotHavingAMonitor(lock)
+  }
+  
+  void testContinueInSynchronized() {
+    Object lock = new Object()  
+    boolean b = true
+    while (b) {
+	    synchronized(lock) {
+	        b = false
+    		continue
+    	}
+    }
+    checkNotHavingAMonitor(lock)
+  }
+  
+  void testReturnInSynchronized() {
+    Object lock = new Object()  
+    methodWithReturn(lock)
+    checkNotHavingAMonitor(lock)
+  }
+  
+  def methodWithReturn(lock) {
+    synchronized (lock) {
+      return
+    }
+  }
+  
+  void testBreakInClosureWithSynchronized() {
+    Object lock = new Object()
+    def c = {
+      while (true) {
+	      synchronized(lock) {
+    	    break
+    	  }
+      }
+      checkNotHavingAMonitor(lock)
+    }
+    c()
+    checkNotHavingAMonitor(lock)
+  }
+  
+  void testContinueInClosureWithSynchronized() {
+    Object lock = new Object()
+    def c = {
+      boolean b = true
+      while (b) {
+	      synchronized(lock) {
+    	    b = false
+    	    continue
+    	  }
+      }
+      checkNotHavingAMonitor(lock)
+    }
+    c()
+    checkNotHavingAMonitor(lock)
+  }
+  
+  def checkNotHavingAMonitor(Object lock){
+    // if we call notify* or wait without having the
+    // monitor, we get an exception.
+    try {
+      lock.notifyAll()
+      assert false,"should have no monitor!"
+    } catch (IllegalMonitorStateException imse) {
+      assert true
+    }
+  }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/TedsClosureBug.groovy b/groovy-core/src/test/groovy/bugs/TedsClosureBug.groovy
new file mode 100644
index 0000000..c30c723
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/TedsClosureBug.groovy
@@ -0,0 +1,91 @@
+import groovy.xml.MarkupBuilder
+
+/**
+ * @author Ted Leung
+ * @version $Revision$
+ */
+class TedsClosureBug extends GroovyTestCase {
+    def EXPECTED= '''<atom>
+  <title>Ted Leung off the air</title>
+  <link>http://www.sauria.com/noblog</link>
+  <author>
+    <person>
+      <name>Ted Leung</name>
+      <url>http://www.sauria.com/blog</url>
+      <email>twl@sauria.com</email>
+    </person>
+  </author>
+  <entry>
+    <title>one</title>
+    <summary>first post</summary>
+  </entry>
+  <entry>
+    <title>two</title>
+    <summary>the second post</summary>
+  </entry>
+  <entry>
+    <title>three</title>
+    <summary>post the third</summary>
+  </entry>
+  <entry>
+    <title>four</title>
+    <summary>the ponderous fourth post</summary>
+  </entry>
+</atom>'''
+
+    void testBug() {
+		def f = new Feed()
+		f.author = new Person(name:'Ted Leung',url:'http://www.sauria.com/blog', email:'twl@sauria.com')
+		f.entries = [ new Entry(title:'one',summary:'first post'), new Entry(title:'two',summary:'the second post'), new Entry(title:'three', summary:'post the third'), new Entry(title:'four',summary:'the ponderous fourth post') ]
+		def sw = new StringWriter()
+		def xml = new MarkupBuilder(sw)
+
+		def atom = xml.atom() {
+		  title("Ted Leung off the air")
+		  link("http://www.sauria.com/noblog")
+		  author() {
+		    person() {
+		      name(f.author.name)
+		      url(f.author.url)
+		      email(f.author.email)
+		    }
+		  }
+		  for (e in f.entries) {
+		    entry() {
+		      title(e.title)
+		      summary(e.summary)
+		    }
+		  }
+		}
+		StringTestUtil.assertMultilineStringsEqual(EXPECTED, sw.toString())
+	}
+}
+
+class Feed {
+    String title
+    String link
+    Person author
+    String tagline
+    String generator
+    String copyright
+    String modified
+    List entries
+}
+
+class Entry {
+    String title
+    String link
+    String id
+    String summary
+    String content
+    Person author
+    String created
+    String issued
+    String modified
+}
+
+class Person {
+    String name
+    String url
+    String email
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/TestBase.groovy b/groovy-core/src/test/groovy/bugs/TestBase.groovy
new file mode 100644
index 0000000..e829784
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/TestBase.groovy
@@ -0,0 +1,23 @@
+/**
+ * A base class for testing constructors
+ * 
+ * @version $Revision$
+ */
+
+ class TestBase {
+
+     String foo
+     
+     TestBase() {
+     }
+     
+     TestBase(String aFoo) {
+         this.foo = aFoo
+     }
+     /** @todo fix bug
+     */
+     
+     def doSomething() {
+     	"TestBase"
+     }
+ }
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/TestCaseBug.groovy b/groovy-core/src/test/groovy/bugs/TestCaseBug.groovy
new file mode 100644
index 0000000..1fdf75d
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/TestCaseBug.groovy
@@ -0,0 +1,22 @@
+import junit.framework.TestCase
+
+/**
+ * @version $Revision$
+ */
+class TestCaseBug extends TestCase {
+
+    // using def here is wrong
+    TestCaseBug(String name) {
+    		super(name)
+    	}
+    	
+    	void testDummy() {
+    		println "worked!"
+    	}
+
+    static void main(args) {
+        def foo = new TestCaseBug("hey")
+        foo.testDummy()
+    }
+    
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/TestDerived.groovy b/groovy-core/src/test/groovy/bugs/TestDerived.groovy
new file mode 100644
index 0000000..dbac2f1
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/TestDerived.groovy
@@ -0,0 +1,16 @@
+/**
+ * A base class for testing constructors
+ * 
+ * @version $Revision$
+ */
+
+ class TestDerived extends TestBase {
+
+     TestDerived(String aFoo) {
+         super(aFoo)
+     }
+     
+     def doSomething() {
+     	"TestDerived" + super.doSomething()
+     }
+ }
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/TestSupport.java b/groovy-core/src/test/groovy/bugs/TestSupport.java
new file mode 100644
index 0000000..4580891
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/TestSupport.java
@@ -0,0 +1,83 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.bugs;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import groovy.util.GroovyTestCase;
+
+/**
+ * Base class for test cases
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class TestSupport extends GroovyTestCase {
+
+    public String[] getMockArguments() {
+        return new String[] { "a", "b", "c" };
+    }
+    
+    public static String mockStaticMethod() {
+        return "cheese";
+    }
+    
+    public static String getMockStaticProperty() {
+        return "cheese";
+    }
+    
+    public static int[] getIntArray() {
+        return new int[] { 1, 2, 3, 4, 5 };
+    }
+    
+    public Iterator iterator() {
+        System.out.println("Calling custom iterator() method for " + this);
+        
+        return Arrays.asList(getMockArguments()).iterator();
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/ToStringBug.groovy b/groovy-core/src/test/groovy/bugs/ToStringBug.groovy
new file mode 100644
index 0000000..5be17bd
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ToStringBug.groovy
@@ -0,0 +1,19 @@
+/**
+ * @version $Revision$
+ */
+class ToStringBug extends GroovyTestCase {
+     
+    void testBug() {
+    	println "Starting test"
+    	
+    	def value = toString()
+    	assert value != null
+    	
+    	println value
+    	println "Found value ${value}"
+    }
+    
+    String toString() {
+    	return super.toString() + "[hey]"
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/TryCatch2Bug.groovy b/groovy-core/src/test/groovy/bugs/TryCatch2Bug.groovy
new file mode 100644
index 0000000..0e41e74
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/TryCatch2Bug.groovy
@@ -0,0 +1,19 @@
+/**
+ * @author Morgan Hankins 
+ * @version $Revision$
+ */
+class TryCatch2Bug extends GroovyTestCase {
+    
+    void testBug() {
+        try {
+        }
+        catch (Throwable t) { 
+        } 
+    }
+    
+    void testBug2() {
+    	try {
+    		def x = 123
+    	}
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/TryCatchBug.groovy b/groovy-core/src/test/groovy/bugs/TryCatchBug.groovy
new file mode 100644
index 0000000..4388abe
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/TryCatchBug.groovy
@@ -0,0 +1,15 @@
+/**
+ * @author John Wilson
+ * @version $Revision$
+ */
+class TryCatchBug extends GroovyTestCase {
+    
+    void testBug() {
+        try {
+            println("Hello")
+        }
+        finally {
+            println("Finally")
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/UnknownVariableBug.groovy b/groovy-core/src/test/groovy/bugs/UnknownVariableBug.groovy
new file mode 100644
index 0000000..7e20425
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/UnknownVariableBug.groovy
@@ -0,0 +1,17 @@
+/**
+ * @version $Revision$
+ */
+class UnknownVariableBug extends GroovyTestCase {
+    void testBug() {
+        def shell = new GroovyShell()
+        shouldFail {
+            shell.evaluate """
+                def x = foo
+            """
+        }
+        shell.evaluate """
+            foo = 1
+            def x = foo
+        """
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/UseClosureInClosureBug.groovy b/groovy-core/src/test/groovy/bugs/UseClosureInClosureBug.groovy
new file mode 100644
index 0000000..d84a19d
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/UseClosureInClosureBug.groovy
@@ -0,0 +1,12 @@
+/**
+ * @version $Revision$
+ */
+class UseClosureInClosureBug extends GroovyTestCase {
+    void testBugWithPrintln() {
+        def inner = { it * 3 }
+        def outer1 = { inner(it) + 5 }
+        def outer2 = { inner(it + 5) }
+        assert 17 == outer1(4)
+        assert 27 == outer2(4)
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/UseStaticInClosureBug.groovy b/groovy-core/src/test/groovy/bugs/UseStaticInClosureBug.groovy
new file mode 100644
index 0000000..ffd7ec6
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/UseStaticInClosureBug.groovy
@@ -0,0 +1,25 @@
+/**
+ * @version $Revision$
+ */
+class UseStaticInClosureBug extends GroovyTestCase {
+
+    static def stuff = [:]
+
+    void testBug() {
+        [1,2,3].each { stuff[it] = "dog" }
+
+        assert stuff.size() == 3
+        assert stuff[2] == "dog"
+    }
+
+    void testBug2() {
+        doStatic()
+    }
+
+    static def doStatic() {
+        [1,2,3].each { stuff[it] = "dog" }
+
+        assert stuff.size() == 3
+        assert stuff[2] == "dog"
+    }
+}
diff --git a/groovy-core/src/test/groovy/bugs/VariablePrecedence.groovy b/groovy-core/src/test/groovy/bugs/VariablePrecedence.groovy
new file mode 100644
index 0000000..2576599
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/VariablePrecedence.groovy
@@ -0,0 +1,53 @@
+/**
+ * @author John Wilson
+ * @version $Revision$
+ */
+class VariblePrecedence extends GroovyTestCase {
+    
+    void testVariablePrecedence() {
+ 
+        assertScript( """
+            class VariableFoo {
+                def x = 100
+                def y = 93
+                def c = {x -> assert x == 1; assert y == 93; }
+
+                static void main(args) {
+                    def vfoo = new VariableFoo()
+                    vfoo.c.call(1)
+
+                    def z = 874;
+                    1.times { assert vfoo.x == 100; assert z == 874; z = 39; }
+                    assert z == 39;
+
+                    vfoo.local();
+                }
+
+                void local() {
+                    c.call(1);
+
+                    def z = 874;
+                    1.times { assert x == 100; assert z == 874; z = 39; }
+                    assert z == 39;
+                }
+            }
+
+        """ );
+
+    }
+
+
+/*
+ * CURRENTLY BROKEN.  Variable scoping needs an overhaul to * fix it.
+ */
+    void testVariablePrecedenceInScript_FAILS() { if (notYetImplemented()) return
+        assertScript( """
+            c = { x -> assert x == 1; assert y == 93; }
+            x = 100;
+            y = 93;
+
+            c.call(1);
+        """);
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/bugs/VariablePrecedenceTest.groovy b/groovy-core/src/test/groovy/bugs/VariablePrecedenceTest.groovy
new file mode 100644
index 0000000..959d6bd
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/VariablePrecedenceTest.groovy
@@ -0,0 +1,26 @@
+class VariablePrecedenceTest extends GroovyTestCase {
+    def x = 100
+    def y = 93
+    def c = {x -> assert x == 1; assert y == 93; }
+
+    void testFoo() {
+        String[] args = ["a"]
+        main(args)
+    }
+
+    static void main(args) {
+        def vfoo = new VariablePrecedenceTest()
+        vfoo.c.call(1)
+        def z = 874;
+        1.times { assert vfoo.x == 100; assert z == 874; z = 39; }
+        assert z == 39;
+        vfoo.local();
+    }
+
+    void local() {
+        c.call(1);
+        def z = 874;
+        1.times { assert x == 100; assert z == 874; z = 39; }
+        assert z == 39;
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/VariableScopingBug.groovy b/groovy-core/src/test/groovy/bugs/VariableScopingBug.groovy
new file mode 100644
index 0000000..b5faae9
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/VariableScopingBug.groovy
@@ -0,0 +1,43 @@
+import org.codehaus.groovy.classgen.TestSupport
+
+/**
+ * @version $Revision$
+ */
+class VariableScopingBug extends TestSupport {
+    
+    void testBug() {
+        // undeclared variable x
+
+        shouldFail {
+            def shell = new GroovyShell()
+            shell.evaluate("""
+                class SomeTest {
+                    void run() {
+                        for (z in 0..2) {
+                            def x = [1, 2, 3]
+                        }
+
+                        for (t in 0..3) {
+                            for (y in x) {
+                                println x
+                            }
+                        }
+                    }
+               }
+               new SomeTest().run()""")
+           }
+    }
+
+    void testVariableReuse() {
+        def shell = new GroovyShell()
+        shell.evaluate("""
+            for (z in 0..2) {
+                def x = [1, 2, 3]
+            }
+
+            for (t in 0..3) {
+                def x = 123
+                println x
+            }""")
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/bugs/ZoharsBug.groovy b/groovy-core/src/test/groovy/bugs/ZoharsBug.groovy
new file mode 100644
index 0000000..de474ce
--- /dev/null
+++ b/groovy-core/src/test/groovy/bugs/ZoharsBug.groovy
@@ -0,0 +1,16 @@
+/**
+ * @author Zohar Melamed
+ * @version $Revision$
+ */
+class ZoharsBug extends GroovyTestCase {
+    
+    void testBug() {
+        def values = [1,2,3,4]
+        def result = bloo(values, {it > 1})
+        assert result == [2, 3, 4]
+    }
+    
+    def bloo(a,b){
+        return a.findAll{b.call(it)}
+    }    
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/gpath/GPathTest.groovy b/groovy-core/src/test/groovy/gpath/GPathTest.groovy
new file mode 100644
index 0000000..ba658e1
--- /dev/null
+++ b/groovy-core/src/test/groovy/gpath/GPathTest.groovy
@@ -0,0 +1,21 @@
+/**
+ * Some GPath tests using maps and lists
+ */
+class GPathTest extends GroovyTestCase {
+
+    void testSimpleGPathExpressions() {
+        def tree = createTree()
+        assert tree.people.find { it.name == 'James' }.location == 'London'
+        assert tree.people.name == ['James', 'Bob']
+        def expected = ['James works on 2 project(s)', 'Bob works on 2 project(s)']
+        assert tree.people.findAll { it.projects.size() > 1 }.collect { it.name + ' works on ' + it.projects.size() + " project(s)" } == expected
+    }
+    protected def createTree() {
+        return [	
+            'people': [
+                ['name' : 'James', 'location':'London', 'projects':['geronimo', 'groovy'] ],
+                ['name' : 'Bob', 'location':'Atlanta', 'projects':['drools', 'groovy'] ]
+			] 
+		]
+    }
+}
diff --git a/groovy-core/src/test/groovy/gpath/NodeGPathTest.groovy b/groovy-core/src/test/groovy/gpath/NodeGPathTest.groovy
new file mode 100644
index 0000000..f4cf9d6
--- /dev/null
+++ b/groovy-core/src/test/groovy/gpath/NodeGPathTest.groovy
@@ -0,0 +1,44 @@
+package groovy.gpath
+
+/**
+ * Some GPath tests using trees
+ */
+class NodeGPathTest extends GroovyTestCase {
+
+    void testFind() {
+        def tree = createTree()
+        assert tree.person.find { it['@name'] == 'James' }.location[0]['@name'] == 'London'
+    }
+
+    void testFindAll() {
+        def tree = createTree()
+        def peopleWithNameBob = tree.person.findAll { it['@name'] != 'Bob' }
+        assert peopleWithNameBob.size() == 1
+    }
+
+    void testCollect() {
+        def tree = createTree()
+        def namesOfAllPeople = tree.person.collect { it['@name'] }
+        assert namesOfAllPeople == ['James', 'Bob']
+    }
+
+    protected def createTree() {
+        def builder = NodeBuilder.newInstance()
+        def root = builder.people() {
+            person(name:'James') {
+                location(name:'London')
+                projects {
+                    project(name:'geronimo')
+                }
+            }
+            person(name:'Bob') {
+                location(name:'Atlanta')
+                projects {
+                    project(name:'drools')
+                }
+            }
+        }
+        assert root != null
+        return root
+    }
+}
diff --git a/groovy-core/src/test/groovy/gravy/Build.groovy b/groovy-core/src/test/groovy/gravy/Build.groovy
new file mode 100644
index 0000000..1feeda1
--- /dev/null
+++ b/groovy-core/src/test/groovy/gravy/Build.groovy
@@ -0,0 +1,64 @@
+package groovy.gravy
+
+
+/**
+ * Represents a build process
+ */
+class Build implements Runnable {
+    def ant = new AntBuilder()
+    def args
+    def pom
+    def defaultTargets = ['clean', 'compile']
+
+    static void main(args) {
+        // autogenerate this
+        def b = new Build(args)
+        //b.args = args
+        b.run()
+    }
+
+    Build(someArgs) {
+        args = someArgs;
+        if (args instanceof String) {
+            args = [args]
+        }
+        /*
+        if (args == null || args.size() == 0) {
+            args = defaultTargets
+        }
+        */
+    }
+
+    void run() {
+        for (a in args) {
+            println "Target: ${a}"
+            invokeMethod(a.toString(), null)
+        }
+    }
+
+    def getPom() {
+        if (pom == null) {
+            pom = parsePOM()
+        }
+        return pom
+    }
+
+
+    // Default goals
+    def clean() {
+        ant.rmdir(dir:'gravy')
+    }
+
+    def compile() {
+        ant.mkdir(dir:'gravy/classes')
+        ant.compile(srdir:'src/main/java', destdir:'gravy/classes') {
+            fileset {
+                includes(name:'**/*.java')
+            }
+        }
+    }
+
+    protected def parsePOM() {
+        return new XmlParser().parse("project.xml")
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/inspect/InspectorTest.java b/groovy-core/src/test/groovy/inspect/InspectorTest.java
new file mode 100644
index 0000000..c894043
--- /dev/null
+++ b/groovy-core/src/test/groovy/inspect/InspectorTest.java
@@ -0,0 +1,143 @@
+package groovy.inspect;
+
+import junit.framework.TestCase;
+
+import java.io.Serializable;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.*;
+
+public class InspectorTest extends TestCase implements Serializable {
+    public String someField = "only for testing";
+    public static final String SOME_CONST = "only for testing";
+
+    public InspectorTest(String name) {
+        super(name);
+    }
+
+    public void testCtor() {
+        new Inspector(new Object());
+        try {
+            new Inspector(null);
+            fail("should have thown IllegalArgumentException");
+        } catch (Exception expected) {
+        }
+    }
+
+    public void testClassProps() {
+        Inspector insp = new Inspector(this);
+        String[] classProps = insp.getClassProps();
+        assertEquals("package groovy.inspect",classProps[Inspector.CLASS_PACKAGE_IDX]);
+        assertEquals("public class InspectorTest",classProps[Inspector.CLASS_CLASS_IDX]);
+        assertEquals("implements Serializable ",classProps[Inspector.CLASS_INTERFACE_IDX]);
+        assertEquals("extends TestCase",classProps[Inspector.CLASS_SUPERCLASS_IDX]);
+        assertEquals("is Primitive: false, is Array: false, is Groovy: false",classProps[Inspector.CLASS_OTHER_IDX]);
+    }
+    public void testMethods() {
+        Inspector insp = new Inspector(new Object());
+        Object[] methods = insp.getMethods();
+        assertEquals(10, methods.length);
+        String[] names = {"hashCode","getClass","wait","wait","wait","equals","notify","notifyAll","toString","java.lang.Object"};
+        assertNameEquals(names, methods);
+        String[] details = {"JAVA","public final","Object","void","wait","long, int","InterruptedException"};
+        assertContains(methods, details);
+        // ctors are not considered static !
+        String[] ctorDetails = {"JAVA","public","Object","Object","java.lang.Object","",""};
+        assertContains(methods, ctorDetails);
+    }
+
+    public void testStaticMethods() {
+        Inspector insp = new Inspector(this);
+        Object[] methods = insp.getMethods();
+        for (int i = 0; i < methods.length; i++) {
+            String[] strings = (String[]) methods[i];
+            if(strings[1].indexOf("static") > -1) return; // ok, found one static method
+        }
+        fail("there should have been at least one static method in this TestCase, e.g. 'fail'.");
+    }
+    public void testMetaMethods() {
+        Inspector insp = new Inspector(new Object());
+        Object[] metaMethods = insp.getMetaMethods();
+        assertEquals(34, metaMethods.length);
+        String[] names = { "sleep", "sleep", "println", "println", "println", "find", "print", "print", "each", "invokeMethod", "asType",
+                           "inspect", "is", "isCase", "identity", "getAt", "putAt", "dump", "getMetaPropertyValues",  "getProperties",
+                           "use", "use", "use", "printf", "printf", "eachWithIndex", "every", "any", "grep", "collect", "collect", "findAll", 
+                           "findIndexOf", "iterator", "asType"
+                         };
+        assertNameEquals(names, metaMethods);
+        String[] details = {"GROOVY","public","Object","void","println","Object","n/a"};
+        assertContains(metaMethods, details);
+    }
+
+    public void testStaticMetaMethods() {
+        Matcher matcher = Pattern.compile("").matcher("");
+        Inspector insp = new Inspector(matcher);
+        Object[] metaMethods = insp.getMetaMethods();
+        assertUnique(Inspector.sort(Arrays.asList(metaMethods)));
+        String[] details = {"GROOVY","public static","Matcher","Matcher","getLastMatcher","","n/a"};
+        assertContains(metaMethods, details);
+    }
+
+    public void testFields() {
+        Inspector insp = new Inspector(this);
+        Object[] fields = insp.getPublicFields();
+        assertEquals(2, fields.length);
+        String[] names = { "someField","SOME_CONST" };
+        assertNameEquals(names, fields);
+        String[] details = {"JAVA","public","InspectorTest","String","someField","\"only for testing\""};
+        assertContains(fields, details);
+    }
+    
+    public void testProperties() {
+        Inspector insp = new Inspector(this);
+        Object[] properties = insp.getPropertyInfo();
+        assertEquals(2, properties.length);
+        String[] names = {"class","name" };
+        assertNameEquals(names, properties);
+        String[] details = {"GROOVY", "public", "n/a", "Class", "class", "class groovy.inspect.InspectorTest"};
+        assertContains(properties, details);
+    }
+
+    private void assertNameEquals(String[] names, Object[] metaMethods) {
+        Set metaSet = new HashSet();
+        for (int i = 0; i < metaMethods.length; i++) {
+            String[] strings = (String[]) metaMethods[i];
+            metaSet.add(strings[Inspector.MEMBER_NAME_IDX]);
+        }
+        Set nameSet = new HashSet(Arrays.asList(names));
+        assertEquals(nameSet, metaSet);
+    }
+
+    private void assertContains(Object[] candidates, String[] sample) {
+        String sampleBuffer = concat(sample);
+        for (int i = 0; i < candidates.length; i++) {
+            String[] entry = (String[]) candidates[i];
+            if (sampleBuffer.equals(concat(entry))) return;
+        }
+        fail("should have found sample: " + sampleBuffer);
+    }
+
+    private void assertUnique(Collection sortedMembers){
+        if (sortedMembers.size() < 2) return;
+        Comparator comp = new Inspector.MemberComparator();
+        Iterator iter = sortedMembers.iterator();
+        Object last = iter.next();
+        while (iter.hasNext()) {
+            Object element = iter.next();
+            if (0 == comp.compare(last, element)){
+                fail("found duplication for element "+element);
+            }
+            last = element;
+        }
+    }
+
+    private String concat(String[] details) {
+        StringBuffer detailBuffer = new StringBuffer();
+        for (int i = 0; i < details.length; i++) {
+            detailBuffer.append(details[i]);
+            detailBuffer.append(" ");
+        }
+        return detailBuffer.toString();
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/j2ee/CreateData.groovy b/groovy-core/src/test/groovy/j2ee/CreateData.groovy
new file mode 100644
index 0000000..2530c00
--- /dev/null
+++ b/groovy-core/src/test/groovy/j2ee/CreateData.groovy
@@ -0,0 +1,28 @@
+//import java.io.File
+
+//context = this.getProperty('context')
+
+//logDir = new File('logs')
+//logDir.mkdir()
+
+println("Called with context: " + context)
+
+db = context.lookup("/client/tools/DatabaseHome").create()
+
+println("About to do queries on: " + db) 
+
+queries = [  "CREATE TABLE account ( ssn CHAR(11) PRIMARY KEY, first_name CHAR(20), last_name CHAR(20), balance INT)",			 
+"CREATE TABLE entity ( id INT PRIMARY KEY AUTO INCREMENT, first_name CHAR(20), last_name CHAR(20) )"]
+
+for (sql in queries) {
+    println("evaluating: " + sql)
+	db.execute(sql)
+}
+
+println("creating entity bean")
+
+context.lookup("/client/tests/entity/bmp/BasicBmpHome").create("Groovy Dain")
+
+println("Done")
+
+"OK"
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/j2ee/J2eeConsole.java b/groovy-core/src/test/groovy/j2ee/J2eeConsole.java
new file mode 100644
index 0000000..ec7434f
--- /dev/null
+++ b/groovy-core/src/test/groovy/j2ee/J2eeConsole.java
@@ -0,0 +1,109 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.j2ee;
+
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyShell;
+
+import java.util.Properties;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * A J2EE console
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class J2eeConsole {
+
+    public static void main(String[] args) {
+        if (args.length <= 0) {
+            System.out.println("Usage: home [configuaration] [localcopy]");
+            return;
+        }
+
+        String home = args[0];
+
+        Properties p = new Properties();
+        System.setProperty("openejb.home", home);
+        p.put(Context.INITIAL_CONTEXT_FACTORY, "org.openejb.client.LocalInitialContextFactory");
+        p.put("openejb.loader", "embed");
+        p.put("openejb.home", home);
+
+        if (args.length > 1) {
+            String conf = args[1];
+            System.setProperty("openejb.configuration", conf);
+            p.put("openejb.configuration", conf);
+        }
+        if (args.length > 2) {
+            String copy = args[2];
+            System.setProperty("openejb.localcopy", copy);
+            p.put("openejb.localcopy", copy);
+        }
+        try {
+            InitialContext ctx = new InitialContext(p);
+            
+            GroovyShell shell = new GroovyShell();
+            shell.setVariable("context", ctx);
+            //shell.evaluate("src/test/groovy/j2ee/CreateData.groovy");
+            
+            //shell.evaluate("src/main/groovy/ui/Console.groovy");
+            GroovyObject console = (GroovyObject) InvokerHelper.invokeConstructorOf("groovy.ui.Console", null);
+            console.setProperty("shell", shell);
+            console.invokeMethod("run", null);
+            /*
+            */
+        }
+        catch (Exception e) {
+            System.out.println("Caught: " + e);
+        }
+    }
+}
diff --git a/groovy-core/src/test/groovy/lang/BenchmarkInterceptorTest.groovy b/groovy-core/src/test/groovy/lang/BenchmarkInterceptorTest.groovy
new file mode 100644
index 0000000..823dce8
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/BenchmarkInterceptorTest.groovy
@@ -0,0 +1,35 @@
+package groovy.lang
+
+/**
+* Test for the BenchmarkInterceptor
+* @author Dierk Koenig
+**/
+class BenchmarkInterceptorTest extends GroovyTestCase{
+
+    Interceptor benchmarkInterceptor
+    def proxy
+
+    void setUp() {
+        benchmarkInterceptor = new BenchmarkInterceptor()
+        proxy = ProxyMetaClass.getInstance(Date.class)
+        proxy.setInterceptor(benchmarkInterceptor)
+    }
+
+    void testSimpleInterception() {
+        proxy.use {
+             def x = new Date(0)
+             x++
+        }
+        def stats = benchmarkInterceptor.statistic()
+        assertEquals 2, stats.size()
+        assert stats.find{it[0] == 'ctor'}
+        assert stats.find{it[0] == 'next'}
+        assert stats.every{it[1] == 1}
+        assert stats.every{it[2] < 200}
+    }
+
+
+}
+
+
+
diff --git a/groovy-core/src/test/groovy/lang/ClassReloadingTest.groovy b/groovy-core/src/test/groovy/lang/ClassReloadingTest.groovy
new file mode 100644
index 0000000..9257071
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/ClassReloadingTest.groovy
@@ -0,0 +1,44 @@
+package groovy.lang
+
+class ClassReloadingTest extends GroovyTestCase {
+
+	public void testRealoding() {
+		def file = File.createTempFile("TestReload",".groovy", new File("target"))
+		file.deleteOnExit()
+		def className = file.name-".groovy"
+
+		def cl = new GroovyClassLoader(this.class.classLoader);
+		def currentDir = file.parentFile.absolutePath
+		cl.addClasspath(currentDir)
+		cl.shouldRecompile = true
+			
+		
+        try {
+     		file.write """
+    		  class $className {
+    		    def hello = "hello"
+    		  }
+    		  """
+    		def groovyClass = cl.loadClass(className,true,false)
+    		def object = groovyClass.newInstance()
+    		assert "hello"== object.hello
+
+            sleep 1000
+    					
+    		// change class
+    		file.write """
+    		  class $className {
+    		    def hello = "goodbye"
+    		  }
+    		  """
+    		file.lastModified = System.currentTimeMillis()
+    		
+    		// reload		
+    		groovyClass = cl.loadClass(className,true,false)
+    		object  = groovyClass.newInstance()
+    		assert "goodbye" == object.hello
+    	} finally {
+		  file.delete()
+		}
+	}
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/lang/DerivedScript.java b/groovy-core/src/test/groovy/lang/DerivedScript.java
new file mode 100644
index 0000000..66c3909
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/DerivedScript.java
@@ -0,0 +1,50 @@
+/*
+ * $Id$version
+ * Nov 23, 2003 9:02:55 PM $user Exp $
+ * 
+ * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package groovy.lang;
+
+/**
+ * A derived Script which adds some 'global' methods available to the script
+ */
+public abstract class DerivedScript extends Script {
+
+    public String getCheese() {
+        return "Cheddar";
+    }
+    
+    public String doSomething(String food) {
+        return "I like " + food;
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/lang/DummyGString.java b/groovy-core/src/test/groovy/lang/DummyGString.java
new file mode 100644
index 0000000..5305db1
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/DummyGString.java
@@ -0,0 +1,88 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.lang;
+
+import groovy.lang.GString;
+import groovy.lang.MetaClass;
+
+
+/**
+ * A hand crafted example GString
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class DummyGString extends GString {
+
+    private String[] strings;
+    private MetaClass metaClass;
+    
+    public DummyGString(Object[] values) {
+        this(values, new String[] { "Hello ", "!" });
+    }
+    
+    public DummyGString(Object[] values, String[] strings) {
+        super(values);
+        this.strings = strings;
+    }
+    
+    public String[] getStrings() {
+        return strings;
+    }
+
+    public MetaClass getMetaClass() {
+        return metaClass;
+    }
+
+    public void setMetaClass(MetaClass metaClass) {
+        this.metaClass = metaClass;
+    }
+
+    public Object invokeMethod(String name, Object arguments) {
+        return metaClass.invokeMethod(this, name, arguments);
+    }
+}
diff --git a/groovy-core/src/test/groovy/lang/GStringTest.java b/groovy-core/src/test/groovy/lang/GStringTest.java
new file mode 100644
index 0000000..0d2855f
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/GStringTest.java
@@ -0,0 +1,122 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+
+package groovy.lang;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import groovy.util.GroovyTestCase;
+
+/**
+ * Tests the use of the structured Attribute type
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class GStringTest extends GroovyTestCase {
+
+    public void testIterateOverText() {
+        DummyGString compString = new DummyGString(new Object[] { "James" });
+
+        assertArrayEquals(new String[] { "Hello ", "!" }, compString.getStrings());
+        assertArrayEquals(new Object[] { "James" }, compString.getValues());
+
+        assertEquals("Hello James!", compString.toString());
+    }
+
+    public void testAppendString() {
+        DummyGString a = new DummyGString(new Object[] { "James" });
+
+        GString result = a.plus(" how are you?");
+
+        assertEquals("Hello James! how are you?", result.toString());
+    }
+
+    public void testAppendString2() {
+        DummyGString a = new DummyGString(new Object[] { "James" }, new String[] { "Hello " });
+
+        GString result = a.plus(" how are you?");
+
+        System.out.println("Found: " + result);
+        System.out.println("Strings: " + InvokerHelper.toString(result.getStrings()));
+        System.out.println("Values: " + InvokerHelper.toString(result.getValues()));
+
+        assertEquals("Hello James how are you?", result.toString());
+    }
+
+    public void testAppendGString() {
+        DummyGString a = new DummyGString(new Object[] { "James" });
+        DummyGString b = new DummyGString(new Object[] { "Bob" });
+
+        GString result = a.plus(b);
+
+        //        System.out.println("Found: " + result);
+        //        System.out.println("Strings: " +
+		// InvokerHelper.toString(result.getStrings()));
+        //        System.out.println("Values: " +
+		// InvokerHelper.toString(result.getValues()));
+
+        assertEquals("Hello James!Hello Bob!", result.toString());
+    }
+
+    public void testAppendGString2() {
+        DummyGString a = new DummyGString(new Object[] { "James" }, new String[] { "Hello " });
+        DummyGString b = new DummyGString(new Object[] { "Bob" }, new String[] { "Hello " });
+
+        GString result = a.plus(b);
+
+        //        System.out.println("Found: " + result);
+        //        System.out.println("Strings: " +
+		// InvokerHelper.toString(result.getStrings()));
+        //        System.out.println("Values: " +
+		// InvokerHelper.toString(result.getValues()));
+
+        assertEquals("Hello JamesHello Bob", result.toString());
+    }
+
+    public void testEqualsAndHashCode() {
+        DummyGString a = new DummyGString(new Object[] { new Integer(1)});
+        DummyGString b = new DummyGString(new Object[] { new Long(1)});
+        DummyGString c = new DummyGString(new Object[] { new Double(2.3)});
+
+        assertTrue("a == b", a.equals(b));
+        assertEquals("hashcode a == b", a.hashCode(), b.hashCode());
+
+        assertFalse("a != c", a.equals(c));
+        assertTrue("hashcode a != c", a.hashCode() != c.hashCode());
+
+        assertEquals("a <=> b", 0, a.compareTo(b));
+        assertEquals("a <=> b", -1, a.compareTo(c));
+    }
+}
diff --git a/groovy-core/src/test/groovy/lang/GroovyClassLoaderTest.groovy b/groovy-core/src/test/groovy/lang/GroovyClassLoaderTest.groovy
new file mode 100644
index 0000000..929677a
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/GroovyClassLoaderTest.groovy
@@ -0,0 +1,189 @@
+/*
+ * $Id$
+ *
+ * Copyright (c) 2005 The Codehaus - http://groovy.codehaus.org
+ *
+ * Licensed 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.security.CodeSource
+import org.codehaus.groovy.control.*
+import org.codehaus.groovy.ast.*
+import org.codehaus.groovy.classgen.*
+
+
+public class GroovyClassLoaderTest extends GroovyTestCase {
+
+    private final GroovyClassLoader classLoader = new GroovyClassLoader()
+
+    private boolean contains(String[] paths, String eval) {
+        try {
+            eval = (new File(eval)).toURI().toURL().getFile();
+        } catch (MalformedURLException e) {
+            return false;
+        }
+        for (it in paths) {
+            if(eval.equals(it)) return true;
+        }
+        return false;
+    }
+    
+    public void testAddsAClasspathEntryOnlyIfItHasNotAlreadyBeenAdded() {
+        String newClasspathEntry = "/tmp"
+        int initialNumberOfClasspathEntries = classLoader.getClassPath().length
+
+        classLoader.addClasspath(newClasspathEntry)
+        assert initialNumberOfClasspathEntries + 1 == classLoader.getClassPath().length
+        assert contains(classLoader.getClassPath(),newClasspathEntry)
+
+        classLoader.addClasspath(newClasspathEntry);
+        assert initialNumberOfClasspathEntries + 1 == classLoader.getClassPath().length
+        assert contains(classLoader.getClassPath(),newClasspathEntry)
+    }
+    
+    def getPaths(URLClassLoader ucl) {
+        def urls = ucl.getURLs()
+        return urls.findAll {!it.file.endsWith(".jar")}
+    }
+
+    def getPaths(String path) {
+        int start = 0, end=0
+        String sep = File.pathSeparator
+        def ret = []
+        while (end<path.length()) {
+          start = end
+          end = path.indexOf(sep,end)
+          if (end==-1) break
+          def sub = path.substring(start,end)
+          if (!sub.endsWith(".jar")) {
+            ret << ((new File(sub)).toURL())
+          }
+          end++
+        }
+      return ret 
+    }
+
+    
+    public void testClassNotFoundIsNotHidden() {
+      def paths=[]
+      def loader = this.class.classLoader
+      while (loader!=null) {
+        if (loader instanceof URLClassLoader) { 
+          paths += getPaths(loader)
+        }
+        loader = loader.parent
+      }
+      paths += getPaths(System.getProperty("java.class.path"))
+      paths=paths.unique()
+
+      def file = File.createTempFile("Foo",".groovy")
+      def name = file.name-".groovy"
+      def script = """
+        class $name extends GroovyTestCase{}
+      """
+      file << script
+      paths << file.parentFile.toURL()
+      def cl = new URLClassLoader(paths as URL[],null)
+      def gcl = new GroovyClassLoader(cl)
+      try {
+        gcl.loadClass(name)
+        assert false
+      } catch (NoClassDefFoundError ncdfe) {
+        assert ncdfe.message.indexOf("TestCase")>0
+      }    
+    }
+    
+    public void testClassPathNotDerived() {
+      def config = new CompilerConfiguration()
+      def loader1 = new GroovyClassLoader(null,config)
+      config = new CompilerConfiguration()
+      config.setClasspath("foo")
+      def loader2 = new GroovyClassLoader(loader1,config)
+      config = new CompilerConfiguration()
+      def loader3 = new GroovyClassLoader(loader2,config)
+      def urls = loader1.URLs
+      assert urls.length == 0
+      urls = loader2.URLs
+      assert urls.length == 1
+      assert urls[0].toString().endsWith("foo")
+      urls = loader3.URLs
+      assert urls.length == 0    
+    }
+    
+    public void testMultithreading() {
+      def config = new CompilerConfiguration()
+      config.recompileGroovySource = true;
+
+      def loader = new GroovyClassLoaderTestCustomGCL(config)
+
+      def ts = new Thread[100]
+      for (i in 0..<100) {
+        ts[i] = Thread.start {
+          if (i%2==1) sleep(100)
+          assert GroovyClassLoaderTestFoo1==loader.loadClass("Foox")
+        } 
+      }
+      sleep(100)
+      for (i in 0..<100) {ts[i].join()}
+
+      assert GroovyClassLoaderTestFoo2==loader.loadClass("Foox")
+   }
+   
+   public void testAdditionalPhaseOperation(){
+      def loader = new GroovyClassLoaderTestCustomPhaseOperation()
+      def ret = loader.parseClass("""class Foo{}""")
+      def field = ret.declaredFields.find {it.name=="id" && it.type==Long.TYPE}
+      assert  field != null
+  }
+}
+
+class GroovyClassLoaderTestFoo1{}
+class GroovyClassLoaderTestFoo2{}
+
+class GroovyClassLoaderTestCustomGCL extends GroovyClassLoader{
+    def GroovyClassLoaderTestCustomGCL(config) {
+      super(null,config);
+    }
+    def counter = 0
+    protected Class recompile(URL source, String name, Class oldClass) {
+        if (name=="Foox") {
+    		if (counter<100) {
+    		  counter++
+    		  return GroovyClassLoaderTestFoo1
+    		} else {
+    		  return GroovyClassLoaderTestFoo2
+    		}
+    	}
+    	return super.recompile(source,name,oldClass)
+    }
+
+    protected boolean isSourceNewer(URL source, Class cls) {
+      return true
+    }
+}
+
+class GroovyClassLoaderTestPropertyAdder extends CompilationUnit.PrimaryClassNodeOperation {
+  void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
+     classNode.addProperty("id", ClassNode.ACC_PUBLIC, ClassHelper.long_TYPE,null,null,null);
+  }
+} 
+
+class GroovyClassLoaderTestCustomPhaseOperation extends GroovyClassLoader {
+  CompilationUnit createCompilationUnit(CompilerConfiguration config, CodeSource source) {
+      def cu = super.createCompilationUnit(config,source)
+      cu.addPhaseOperation(new GroovyClassLoaderTestPropertyAdder(),Phases.CONVERSION) 
+      return cu
+  }    
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/lang/GroovyLogTestCaseTest.groovy b/groovy-core/src/test/groovy/lang/GroovyLogTestCaseTest.groovy
new file mode 100644
index 0000000..7e11ed7
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/GroovyLogTestCaseTest.groovy
@@ -0,0 +1,33 @@
+package groovy.lang
+
+import java.util.logging.*
+
+/**
+Showing usage of the GroovyLogTestCase
+@author Dierk Koenig
+**/
+
+class GroovyLogTestCaseTest extends GroovyLogTestCase {
+
+    static final LOG = Logger.getLogger('groovy.lang.GroovyLogTestCaseTest')
+
+    void loggedMethod() {
+        LOG.finer 'some log entry'
+    }
+
+    void testStringLog(){
+        def result = stringLog(Level.FINER, 'groovy.lang.GroovyLogTestCaseTest') {
+            loggedMethod()
+        }
+        assertTrue result, result.contains('some log entry')
+    }
+
+    void testCombinedUsageForMetaClass(){
+        def result = withLevel(Level.FINER, 'groovy.lang.MetaClass') {
+            stringLog(Level.FINER, 'methodCalls'){
+                'hi'.toString()
+            }
+        }
+        assertTrue result, result.contains('java.lang.String toString()')
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/lang/GroovyShellTest.java b/groovy-core/src/test/groovy/lang/GroovyShellTest.java
new file mode 100644
index 0000000..ae212fb
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/GroovyShellTest.java
@@ -0,0 +1,112 @@
+/*
+ * $Id$version
+ * Nov 23, 2003 9:02:55 PM $user Exp $
+ * 
+ * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package groovy.lang;
+
+import groovy.util.GroovyTestCase;
+
+import java.io.ByteArrayInputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.codehaus.groovy.control.CompilerConfiguration;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+/**
+ * @author sam
+ * 
+ * To change the template for this generated type comment go to Window -
+ * Preferences - Java - Code Generation - Code and Comments
+ */
+public class GroovyShellTest extends GroovyTestCase {
+
+    private String script1 = "test = 1";
+
+    public static void main(String[] args) {
+        TestRunner.run(suite());
+    }
+    
+    public static Test suite() {
+        return new TestSuite(GroovyShellTest.class);
+    }
+
+    public void testExecuteScript() {
+        GroovyShell shell = new GroovyShell();
+        try {
+            Object result = shell.evaluate(new ByteArrayInputStream(script1.getBytes()), "Test.groovy");
+            assertEquals(new Integer(1), result);
+        }
+        catch (Exception e) {
+            fail(e.toString());
+        }
+    }
+
+    private static class PropertyHolder {
+        private Map map = new HashMap();
+        public void set(String key, Object value) {
+            map.put(key, value);
+        }
+        public Object get(String key) {
+            return map.get(key);
+        }
+    }
+
+    private String script2 = "test.prop = 2\nreturn test.prop";
+
+    public void testExecuteScriptWithContext() {
+        Binding context = new Binding();
+        context.setVariable("test", new PropertyHolder());
+        GroovyShell shell = new GroovyShell(context);
+        try {
+            Object result = shell.evaluate(new ByteArrayInputStream(script2.getBytes()), "Test.groovy");
+            assertEquals(new Integer(2), result);
+        }
+        catch (Exception e) {
+            fail(e.toString());
+        }
+    }
+    
+    public void testScriptWithDerivedBaseClass() throws Exception {
+        Binding context = new Binding();
+        CompilerConfiguration config = new CompilerConfiguration();
+        config.setScriptBaseClass(DerivedScript.class.getName());
+        GroovyShell shell = new GroovyShell(context, config);
+        Object result = shell.evaluate("x = 'abc'; doSomething(cheese)");
+        assertEquals("I like Cheddar", result);
+        assertEquals("abc", context.getVariable("x"));
+    }
+}
diff --git a/groovy-core/src/test/groovy/lang/IntRangeTest.java b/groovy-core/src/test/groovy/lang/IntRangeTest.java
new file mode 100644
index 0000000..01d7474
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/IntRangeTest.java
@@ -0,0 +1,150 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+/**
+ * @author James Strachan
+ * @version $Revision$
+ */
+public class IntRangeTest extends TestCase {
+
+    public void testSize() {
+        IntRange r = createRange(0, 10);
+        assertEquals("Size of " + r, 11, r.size());
+        r = createRange(0, 1);
+        assertEquals("Size of " + r, 2, r.size());
+        r = createRange(0, 0);
+        assertEquals("Size of " + r, 1, r.size());
+    }
+
+    public void testProperties() {
+        IntRange r = createRange(0, 10);
+        assertEquals("from", 0, r.getFromInt());
+        assertEquals("to", 10, r.getToInt());
+    }
+
+    public void testGet() {
+        IntRange r = createRange(10, 20);
+        for (int i = 0; i <= 10; i++) {
+            Integer value = (Integer) r.get(i);
+            assertEquals("Item at index: " + i, i + 10, value.intValue());
+        }
+    }
+
+    public void testGetOutOfRange() {
+        IntRange r = createRange(10, 20);
+
+        try {
+            r.get(-1);
+            fail("Should have thrown IndexOut");
+        }
+        catch (IndexOutOfBoundsException e) {
+            // worked
+        }
+        try {
+            r.get(11);
+            fail("Should have thrown IndexOut");
+        }
+        catch (IndexOutOfBoundsException e) {
+            // worked
+        }
+
+    }
+
+    public void testContains() {
+        IntRange r = createRange(10, 20);
+
+        assertTrue("contains 11", r.contains(new Integer(11)));
+        assertTrue("contains 10", r.contains(new Integer(10)));
+        assertTrue("contains 19", r.contains(new Integer(19)));
+        assertTrue("contains 20", r.contains(new Integer(20)));
+        assertFalse("contains 9", r.contains(new Integer(9)));
+        assertFalse("contains 21", r.contains(new Integer(21)));
+        assertFalse("contains 100", r.contains(new Integer(100)));
+        assertFalse("contains -1", r.contains(new Integer(-1)));
+    }
+
+    public void testSubList() {
+        IntRange r = createRange(10, 20);
+
+        List s = r.subList(2, 4);
+
+        IntRange sr = (IntRange) s;
+
+        assertEquals("from", 12, sr.getFromInt());
+        assertEquals("to", 13, sr.getToInt());
+        assertEquals("size", 2, sr.size());
+    }
+
+    public void testHashCodeAndEquals() {
+        IntRange a = createRange(1, 11);
+        IntRange b = createRange(1, 11);
+        IntRange c = createRange(2, 11);
+
+        assertEquals("hashcode", a.hashCode(), b.hashCode());
+        assertTrue("hashcode", a.hashCode() != c.hashCode());
+
+        assertEquals("a and b", a, b);
+        assertFalse("a != c", a.equals(c));
+    }
+
+    public void testIterator() {
+    }
+
+    protected IntRange createRange(int from, int to) {
+        return new IntRange(from, to);
+    }
+    
+    protected void assertEquals(String msg, int expected, Object value) {
+        assertEquals(msg, new Integer(expected), value);
+    }
+
+
+}
diff --git a/groovy-core/src/test/groovy/lang/InterceptorTest.groovy b/groovy-core/src/test/groovy/lang/InterceptorTest.groovy
new file mode 100644
index 0000000..572f045
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/InterceptorTest.groovy
@@ -0,0 +1,92 @@
+package groovy.lang
+
+import org.codehaus.groovy.runtime.InvokerHelper
+import org.codehaus.groovy.runtime.StringBufferWriter
+
+/**
+* Test for the Interceptor Interface usage as implemented by the
+* TracingInterceptor. Makes also use of the ProxyMetaClass and
+* shows the collaboration.
+* As a side Effect, the ProxyMetaClass is also partly tested.
+* @author Dierk Koenig
+**/
+class InterceptorTest extends GroovyTestCase{
+
+    def Interceptor logInterceptor
+    def StringBuffer log
+    def interceptable   // the object to intercept method calls on
+    def proxy
+
+    void setUp() {
+        logInterceptor = new TracingInterceptor()
+        log = new StringBuffer("\n")
+        logInterceptor.writer = new StringBufferWriter(log)
+        // we intercept calls from Groovy to the java.lang.String object
+        interceptable = 'Interceptable String'
+        proxy = ProxyMetaClass.getInstance(interceptable.class)
+        proxy.setInterceptor(logInterceptor)
+    }
+
+    void testSimpleInterception() {
+        proxy.use {
+            assertEquals 20, interceptable.size()
+            assertEquals 20, interceptable.length()
+            assertTrue interceptable.startsWith('I',0)
+        }
+        assertEquals(
+"""
+before java.lang.String.size()
+after  java.lang.String.size()
+before java.lang.String.length()
+after  java.lang.String.length()
+before java.lang.String.startsWith(java.lang.String, java.lang.Integer)
+after  java.lang.String.startsWith(java.lang.String, java.lang.Integer)
+""", log.toString())
+    }
+
+    void testNoInterceptionWithNullInterceptor() {
+        proxy.setInterceptor(null)
+        proxy.use {
+            interceptable.size()
+        }
+    }
+
+    void testConstructorInterception() {
+        proxy.use {
+            new String('some string')
+        }
+        assertEquals(
+"""
+before java.lang.String.ctor(java.lang.String)
+after  java.lang.String.ctor(java.lang.String)
+""", log.toString())
+    }
+
+    void testStaticMethodInterception() {
+        proxy.use {
+            assertEquals 'true', String.valueOf(true)
+        }
+        assertEquals(
+"""
+before java.lang.String.valueOf(java.lang.Boolean)
+after  java.lang.String.valueOf(java.lang.Boolean)
+""", log.toString())
+    }
+
+    void testInterceptionOfGroovyClasses(){
+        def slicer = new groovy.mock.example.CheeseSlicer()
+        def proxy = ProxyMetaClass.getInstance(slicer.class)
+        proxy.setInterceptor(logInterceptor)
+        proxy.use(slicer) {
+            slicer.coffeeBreak('')
+        }
+        assertEquals(
+"""
+before groovy.mock.example.CheeseSlicer.coffeeBreak(java.lang.String)
+after  groovy.mock.example.CheeseSlicer.coffeeBreak(java.lang.String)
+""", log.toString())
+    }
+}
+
+
+
diff --git a/groovy-core/src/test/groovy/lang/MetaClassTest.java b/groovy-core/src/test/groovy/lang/MetaClassTest.java
new file mode 100644
index 0000000..9b44c6d
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/MetaClassTest.java
@@ -0,0 +1,237 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+
+package groovy.lang;
+
+import groovy.util.GroovyTestCase;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Iterator;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MetaClassTest extends GroovyTestCase {
+
+    public void testMetaClass() {
+        Class foo = String[].class;
+        System.out.println(foo + " name: " + foo.getName());
+
+        MetaClass metaClass = InvokerHelper.getMetaClass(this);
+
+        assertTrue("got metaclass", metaClass != null);
+
+        metaClass.invokeMethod(this, "doSomething", new Object[0]);
+    }
+
+    public void testArray() {
+        String[] value = new String[] { "hello" };
+
+        MetaClass metaClass = InvokerHelper.getMetaClass(value);
+
+        assertTrue("got metaclass", metaClass != null);
+
+        metaClass.invokeMethod(value, "toString", new Object[0]);
+    }
+
+    public void testString() {
+        String value = "hello";
+
+        MetaClass metaClass = InvokerHelper.getMetaClass(value);
+
+        assertTrue("got metaclass", metaClass != null);
+
+        Object answer = metaClass.invokeMethod(value, "toString", new Object[0]);
+
+        assertEquals("hello", answer);
+    }
+
+    public void testObject() {
+        Object value = new Object();
+
+        MetaClass metaClass = InvokerHelper.getMetaClass(value);
+
+        assertTrue("got metaclass", metaClass != null);
+
+        metaClass.invokeMethod(value, "toString", new Object[0]);
+    }
+
+    public void testPublicField() {
+        DymmyClass dymmyClass = new DymmyClass();
+        
+        MetaClass metaClass = InvokerHelper.getMetaClass(dymmyClass);
+        
+        assertEquals(metaClass.getProperty(dymmyClass, "x"), new Integer(0));
+        assertEquals(metaClass.getProperty(dymmyClass, "y"), "none");
+        
+        metaClass.setProperty(dymmyClass, "x", new Integer(25));
+        assertEquals(dymmyClass.x, 25);
+
+        metaClass.setProperty(dymmyClass, "y", "newvalue");
+        assertEquals(dymmyClass.y, "newvalue");
+    }
+    
+    public void testSetPropertyWithInt() {
+        DymmyClass dymmyClass = new DymmyClass();
+        MetaClass metaClass = InvokerHelper.getMetaClass(dymmyClass);
+        metaClass.setProperty(dymmyClass, "anInt", new Integer(10));
+    }
+
+    public void testSetPropertyWithDoubleArray() {
+        DymmyClass dymmyClass = new DymmyClass();
+        MetaClass metaClass = InvokerHelper.getMetaClass(dymmyClass);
+        Double[][] matrix2 =
+        {
+                {
+                        new Double(35), new Double(50), new Double(120)
+                }, 
+                {
+                        new Double(75), new Double(80), new Double(150)
+                }
+        };
+        metaClass.setProperty(dymmyClass, "matrix", matrix2);
+        metaClass.setProperty(dymmyClass, "matrix2", matrix2);
+    }
+
+    public void testSetPropertyWithArray() {
+        DymmyClass dymmyClass = new DymmyClass();
+        MetaClass metaClass = InvokerHelper.getMetaClass(dymmyClass);
+
+        // test int[]
+        int[] ints = new int[]{
+                0, 1, 2, 3
+        };
+        metaClass.setProperty(dymmyClass, "ints", ints);
+        assertEquals(ints, metaClass.getProperty(dymmyClass, "ints"));
+
+        // test Integer[]
+        Integer[] integers = new Integer[]{
+                new Integer(0), new Integer(1), new Integer(2), new Integer(3)
+        };
+        metaClass.setProperty(dymmyClass, "integers", integers);
+        assertEquals(integers, metaClass.getProperty(dymmyClass, "integers"));
+    }
+
+    public void testSetPropertyWithList() {
+        DymmyClass dymmyClass = new DymmyClass();
+        MetaClass metaClass = InvokerHelper.getMetaClass(dymmyClass);
+
+        // test list
+        ArrayList list = new ArrayList();
+        list.add(new Integer(120));
+        list.add(new Integer(150));
+
+        // test int[]
+        metaClass.setProperty(dymmyClass, "ints", list);
+
+        // test Integer[]
+        metaClass.setProperty(dymmyClass, "integers", list);
+    }
+
+    public void testMetaMethodsOnlyAddedOnce() {
+        MetaClass metaClass = InvokerHelper.getMetaClass("some String");
+
+        List methods = metaClass.getMetaMethods();
+        for (Iterator iter = methods.iterator(); iter.hasNext();) {
+            MetaMethod method = (MetaMethod) iter.next();
+            int count = 0;
+            for (Iterator inner = methods.iterator(); inner.hasNext(); ) {
+                MetaMethod runner = (MetaMethod) inner.next();
+                if (method.equals(runner)) {
+                    System.out.println("runner = " + runner);
+                    System.out.println("method = " + method);
+                    count++;
+                }
+            }
+            assertEquals("count of Method "+method.getName(), 1, count);
+        }
+
+    }
+
+
+    
+    public void doSomething() {
+        System.out.println("Called doSomething()");
+    }
+}
+
+
+class DymmyClass {
+    public int x = 0;
+    public String y = "none";
+    
+    private int anInt;
+    private int[] ints;
+    private Integer[] integers;
+    double[][] matrix2;
+    Double[][] matrix;
+
+    public Integer[] getIntegers() {
+        return integers;
+    }
+
+    public void setIntegers(Integer[] integers) {
+        this.integers = integers;
+    }
+
+    public int[] getInts() {
+        return ints;
+    }
+
+    public void setInts(int[] ints) {
+        this.ints = ints;
+    }
+
+    public int getAnInt() {
+        return anInt;
+    }
+
+    public void setAnInt(int anInt) {
+        this.anInt = anInt;
+    }
+
+    public void setMatrix(Double[][] matrix) {
+        this.matrix = matrix;
+    }
+
+    public void setMatrix2(double[][] matrixReloaded) {
+        this.matrix2 = matrixReloaded;
+    }
+
+}
+
diff --git a/groovy-core/src/test/groovy/lang/MockWriter.java b/groovy-core/src/test/groovy/lang/MockWriter.java
new file mode 100644
index 0000000..77c1561
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/MockWriter.java
@@ -0,0 +1,81 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.lang;
+
+
+/**
+ * A mock class for testing writer based code
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MockWriter {
+
+    private String output;
+    
+    public String getOutput() {
+        String answer = output;
+        output = null;
+        return answer;
+    }
+
+    public void setOutput(String output) {
+        this.output = output;
+    }
+
+    public void println() {
+        setOutput("println()");
+    }
+    
+    public void println(Object object) {
+        setOutput("println(" + object + ")");
+    }
+
+    public void print(Object object) {
+        setOutput("print(" + object + ")");
+    }
+}
diff --git a/groovy-core/src/test/groovy/lang/RangeTest.java b/groovy-core/src/test/groovy/lang/RangeTest.java
new file mode 100644
index 0000000..76e0a93
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/RangeTest.java
@@ -0,0 +1,214 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import java.util.List;
+import java.util.Iterator;
+import java.math.BigDecimal;
+
+import junit.framework.TestCase;
+
+/**
+ * @author James Strachan
+ * @version $Revision$
+ */
+public class RangeTest extends TestCase {
+
+    public void testSize() {
+        Range r = createRange(0, 10);
+        assertEquals("Size of " + r, 11, r.size());
+        r = createRange(0, 1);
+        assertEquals("Size of " + r, 2, r.size());
+        r = createRange(0, 0);
+        assertEquals("Size of " + r, 1, r.size());
+
+        r = createRange(new BigDecimal("2.1"), new BigDecimal("10.0"));
+        assertEquals("Size of " + r, 8, r.size());
+    }
+
+    public void testProperties() {
+        Range r = createRange(0, 10);
+        assertEquals("from", 0, r.getFrom());
+        assertEquals("to", 10, r.getTo());
+    }
+
+    public void testGet() {
+        Range r = createRange(10, 20);
+        for (int i = 0; i < 10; i++) {
+            Integer value = (Integer) r.get(i);
+            assertEquals("Item at index: " + i, i + 10, value.intValue());
+        }
+
+        r = createRange(new BigDecimal("3.2"), new BigDecimal("9.9"));
+        for (int i = 0; i < r.size(); i++) {
+            BigDecimal value = (BigDecimal) r.get(i);
+            assertEquals("Item at index: " + i, new BigDecimal("3.2").add(new BigDecimal("" + i)), value);
+        }
+    }
+
+    public void testGetOutOfRange() {
+        Range r = createRange(10, 20);
+
+        try {
+            r.get(-1);
+            fail("Should have thrown IndexOut");
+        }
+        catch (IndexOutOfBoundsException e) {
+            // worked
+        }
+        try {
+            r.get(11);
+            fail("Should have thrown IndexOut");
+        }
+        catch (IndexOutOfBoundsException e) {
+            // worked
+        }
+
+        r = createRange(new BigDecimal("-4.3"), new BigDecimal("1.4"));
+
+        try {
+            r.get(-1);
+            fail("Should have thrown IndexOut");
+        }
+        catch (IndexOutOfBoundsException e) {
+            // worked
+        }
+        try {
+            r.get(7);
+            fail("Should have thrown IndexOut");
+        }
+        catch (IndexOutOfBoundsException e) {
+            // worked
+        }
+
+    }
+
+    public void testContains() {
+        Range r = createRange(10, 20);
+
+        assertTrue("contains 11", r.contains(new Integer(11)));
+        assertTrue("contains 10", r.contains(new Integer(10)));
+        assertTrue("contains 19", r.contains(new Integer(19)));
+        assertFalse("contains 9", r.contains(new Integer(9)));
+        assertFalse("contains 21", r.contains(new Integer(21)));
+        assertFalse("contains 100", r.contains(new Integer(100)));
+        assertFalse("contains -1", r.contains(new Integer(-1)));
+
+        r = createRange(new BigDecimal("2.1"), new BigDecimal("10.0"));
+
+        assertTrue("contains 9.1", r.contains(new BigDecimal("9.1")));
+        assertTrue("contains 8.0", r.contains(new BigDecimal("8.0")));
+    }
+
+    public void testSubList() {
+        Range r = createRange(10, 20);
+
+        List s = r.subList(2, 4);
+
+        Range sr = (Range) s;
+
+        assertEquals("from", 12, sr.getFrom());
+        assertEquals("to", 13, sr.getTo());
+        assertEquals("size", 2, sr.size());
+
+        r = createRange(new BigDecimal("0.5"), new BigDecimal("8.5"));
+        assertEquals("size", 9, r.size());
+        s = r.subList(2, 5);
+        sr = (Range) s;
+
+        assertEquals("from", new BigDecimal("2.5"), sr.getFrom());
+        assertEquals("to", new BigDecimal("4.5"), sr.getTo());
+        assertTrue("contains 4.5", sr.contains(new BigDecimal("4.5")));
+        assertFalse("contains 5.5", sr.contains(new BigDecimal("5.5")));
+        assertEquals("size", 3, sr.size());
+
+    }
+
+    public void testHashCodeAndEquals() {
+        Range a = createRange(1, 11);
+        Range b = createRange(1, 11);
+        Range c = createRange(2, 11);
+
+        assertEquals("hashcode", a.hashCode(), b.hashCode());
+        assertTrue("hashcode", a.hashCode() != c.hashCode());
+
+        assertEquals("a and b", a, b);
+        assertFalse("a != c", a.equals(c));
+    }
+
+    public void testIterator() {
+        Range r = createRange(5, 11);
+
+        int i = 5;
+        for (Iterator it = r.iterator(); it.hasNext(); ) {
+            assertEquals("equals to " + i, new Integer(i), (Integer) (it.next()));
+            i++;
+        }
+
+        r = createRange(new BigDecimal("5.0"), new BigDecimal("11.0"));
+        BigDecimal one = new BigDecimal("1.0");
+
+        BigDecimal val = new BigDecimal("5.0");
+        for (Iterator it = r.iterator(); it.hasNext(); ) {
+            assertEquals("equals to " + val, val, (BigDecimal) (it.next()));
+            val = val.add(one);
+        }
+    }
+
+    protected Range createRange(int from, int to) {
+        return new ObjectRange(new Integer(from), new Integer(to));
+    }
+    
+    protected Range createRange(BigDecimal from, BigDecimal to) {
+        return new ObjectRange(from, to);
+    }
+    
+    protected void assertEquals(String msg, int expected, Object value) {
+        assertEquals(msg, new Integer(expected), value);
+    }
+
+
+}
diff --git a/groovy-core/src/test/groovy/lang/ScriptIntegerDivideTest.java b/groovy-core/src/test/groovy/lang/ScriptIntegerDivideTest.java
new file mode 100644
index 0000000..eeb65a2
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/ScriptIntegerDivideTest.java
@@ -0,0 +1,18 @@
+package groovy.lang;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+
+/**
+ * @author Steve Goetze
+ * @author Jeremy Rayner
+ */
+public class ScriptIntegerDivideTest extends TestSupport {
+
+	/**
+	 * Check integer division which is now a method call rather than the symbol "\".
+	 */
+	public void testIntegerDivide() throws Exception {
+   		assertScript( "assert 4.intdiv(3) == 1" );
+    }
+}
diff --git a/groovy-core/src/test/groovy/lang/ScriptPrintTest.java b/groovy-core/src/test/groovy/lang/ScriptPrintTest.java
new file mode 100644
index 0000000..0de8c5c
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/ScriptPrintTest.java
@@ -0,0 +1,64 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.lang;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+/**
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ScriptPrintTest extends TestSupport {
+
+    public void testScriptWithCustomPrintln() throws Exception {
+        assertScript(
+            "out = new MockWriter(); println(); assert out.output == 'println()', 'value of output is: ' + out.output\n"
+                + "print('hey'); assert out.output == 'print(hey)' , 'value is: ' + out.output\n"
+                + "println('hey'); assert out.output == 'println(hey)', 'value is: ' + out.output\n");
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/lang/ScriptTest.java b/groovy-core/src/test/groovy/lang/ScriptTest.java
new file mode 100644
index 0000000..e0e6380
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/ScriptTest.java
@@ -0,0 +1,91 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) Guillaume Laforge. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.lang;
+
+import org.codehaus.groovy.classgen.TestSupport;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.runtime.MethodClosure;
+
+import java.io.IOException;
+
+/**
+ * Tests some particular script features.
+ *
+ * @author Guillaume Laforge
+ */
+public class ScriptTest extends TestSupport
+{
+    /**
+     * When a method is not found in the current script, checks that it's possible to call a method closure from the binding.
+     *
+     * @throws IOException
+     * @throws CompilationFailedException
+     * @throws IllegalAccessException
+     * @throws InstantiationException
+     */
+    public void testInvokeMethodFallsThroughToMethodClosureInBinding() throws IOException, CompilationFailedException, IllegalAccessException, InstantiationException
+    {
+        String text = "if (method() == 3) { println 'succeeded' }";
+
+        GroovyCodeSource codeSource = new GroovyCodeSource(text, "groovy.script", "groovy.script");
+        GroovyClassLoader loader = new GroovyClassLoader(Thread.currentThread().getContextClassLoader());
+        Class clazz = loader.parseClass(codeSource);
+        Script script = ((Script) clazz.newInstance());
+
+        Binding binding = new Binding();
+        binding.setVariable("method", new MethodClosure(new Dummy(), "method"));
+        script.setBinding(binding);
+
+        script.run();
+    }
+
+    public static class Dummy {
+        public Integer method() {
+            return new Integer(3);
+        }
+    }
+}
diff --git a/groovy-core/src/test/groovy/lang/SequenceTest.java b/groovy-core/src/test/groovy/lang/SequenceTest.java
new file mode 100644
index 0000000..6faca2c
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/SequenceTest.java
@@ -0,0 +1,104 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.lang;
+
+import java.util.List;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import groovy.util.GroovyTestCase;
+
+/**
+ * Tests the use of the structured Attribute type
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class SequenceTest extends GroovyTestCase {
+
+    public void testConstruction() {
+        Sequence sequence = new Sequence(String.class);
+        sequence.add("James");
+        sequence.add("Bob");
+
+        assertEquals("Size", 2, sequence.size());
+        assertEquals("Element", "James", sequence.get(0));
+        assertEquals("Element", "Bob", sequence.get(1));
+
+        // now lets try some methods on each item in the list
+        List answer = (List) InvokerHelper.invokeMethod(sequence, "startsWith", new Object[] { "Ja" });
+        assertArrayEquals(new Object[] { Boolean.TRUE, Boolean.FALSE }, answer.toArray());
+
+        answer = (List) InvokerHelper.invokeMethod(sequence, "length", null);
+        assertArrayEquals(new Object[] { new Integer(5), new Integer(3)}, answer.toArray());
+    }
+
+    public void testAddingWrongTypeFails() {
+        try {
+            Sequence sequence = new Sequence(String.class);
+            sequence.add(new Integer(5));
+
+            fail("Should have thrown exception");
+        }
+        catch (IllegalArgumentException e) {
+            System.out.println("Caught: " + e);
+        }
+    }
+
+    public void testAddingNullFails() {
+        try {
+            Sequence sequence = new Sequence(String.class);
+            sequence.add(null);
+
+            fail("Should have thrown exception");
+        }
+        catch (NullPointerException e) {
+            System.out.println("Caught: " + e);
+        }
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/lang/TupleTest.java b/groovy-core/src/test/groovy/lang/TupleTest.java
new file mode 100644
index 0000000..3f70afb
--- /dev/null
+++ b/groovy-core/src/test/groovy/lang/TupleTest.java
@@ -0,0 +1,114 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.lang;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+/**
+ * @author James Strachan
+ * @version $Revision$
+ */
+public class TupleTest extends TestCase {
+
+    Object[] data = { "a", "b", "c" };
+    Tuple t = new Tuple(data);
+
+    public void testSize() {
+        assertEquals("Size of " + t, 3, t.size());
+
+        assertEquals("get(0)", "a", t.get(0));
+        assertEquals("get(1)", "b", t.get(1));
+    }
+
+    public void testGetOutOfTuple() {
+        try {
+            t.get(-1);
+            fail("Should have thrown IndexOut");
+        }
+        catch (IndexOutOfBoundsException e) {
+            // worked
+        }
+        try {
+            t.get(10);
+            fail("Should have thrown IndexOut");
+        }
+        catch (IndexOutOfBoundsException e) {
+            // worked
+        }
+
+    }
+
+    public void testContains() {
+        assertTrue("contains a", t.contains("a"));
+        assertTrue("contains b", t.contains("b"));
+    }
+
+    public void testSubList() {
+        List s = t.subList(1, 2);
+
+        assertTrue("is a Tuple", s instanceof Tuple);
+
+        assertEquals("size", 1, s.size());
+    }
+
+    public void testHashCodeAndEquals() {
+        Tuple a = new Tuple(new Object[] { "a", "b", "c" });
+        Tuple b = new Tuple(new Object[] { "a", "b", "c" });
+        Tuple c = new Tuple(new Object[] { "d", "b", "c" });
+
+        assertEquals("hashcode", a.hashCode(), b.hashCode());
+        assertTrue("hashcode", a.hashCode() != c.hashCode());
+
+        assertEquals("a and b", a, b);
+        assertFalse("a != c", a.equals(c));
+    }
+
+    public void testIterator() {
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/mock/MockTest.groovy b/groovy-core/src/test/groovy/mock/MockTest.groovy
new file mode 100644
index 0000000..59b8d8a
--- /dev/null
+++ b/groovy-core/src/test/groovy/mock/MockTest.groovy
@@ -0,0 +1,95 @@
+package groovy.mock
+
+import groovy.mock.GroovyMock
+import junit.framework.AssertionFailedError
+
+class MockTest extends GroovyTestCase {
+
+    def mock
+
+    void setUp() {
+        mock = GroovyMock.newInstance()
+    }
+
+    void testASimpleExpectationCanBeSetAndMet() {
+        // expectation
+        mock.doSomething("hello")
+
+        // execute
+        mock.instance.doSomething("hello")
+
+        // verify
+        mock.verify()
+    }
+
+    void testASimpleExpectationCanBeSetAndFailed() {
+        // expectation
+        mock.doSomething("hello")
+
+        // execute
+        try {
+            mock.instance.doSomething("goodbye")
+            fail("expected exception")
+        }
+        catch (RuntimeException goodException) {
+        }
+
+    }
+
+    void testASimpleExpectationCanBeSetButNeverCalledSoVerifyFails() {
+        // expectation
+        mock.doSomething("hello")
+
+        // execute
+        // don't call it
+
+        // verify
+        try {
+            mock.verify()
+            fail("should not have verified")
+        }
+        catch (AssertionFailedError goodException) {
+        }
+    }
+
+    void testAnExpectationWithAClosureGivesErrorIFCalledAndClosureFails() {
+        mock.doSomething( {arg -> assert arg=="poo" } )
+
+        // verify
+        try {
+            mock.instance.doSomething("hello")
+            fail("Expected verify to fail");
+        }
+        catch (RuntimeException ex) {
+            //expected
+        }
+    }
+
+    /*
+     * was GROOVY-76
+     */
+    void testAnExpectationwithAClosurePassesIfClosurePasses() {
+        mock.doSomething {arg -> assert arg=="hello" }
+
+        // execute
+        mock.instance.doSomething("hello")
+
+        //verify
+        mock.verify()
+    }
+
+    void testAnExpectationWithAClosureGivesErrorIFNotCalled() {
+        mock.doSomething( {arg -> assert arg=="poo" } )
+        // verify
+        try {
+            mock.verify()
+            fail("Expected verify to fail");
+        }
+        catch (AssertionFailedError ex) {
+            //expected
+        }
+    }
+
+}
+
+
diff --git a/groovy-core/src/test/groovy/mock/example/CheeseSlicer.groovy b/groovy-core/src/test/groovy/mock/example/CheeseSlicer.groovy
new file mode 100644
index 0000000..528e348
--- /dev/null
+++ b/groovy-core/src/test/groovy/mock/example/CheeseSlicer.groovy
@@ -0,0 +1,13 @@
+package groovy.mock.example
+
+class CheeseSlicer {
+
+    void slice(String name) {
+        throw new RuntimeException('whatever nasty behavior that needs to be mocked...')
+    }
+
+    void coffeeBreak(String name) {
+        // dum didum didum *slurp*, *spill*
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/mock/example/SandwichMaker.groovy b/groovy-core/src/test/groovy/mock/example/SandwichMaker.groovy
new file mode 100644
index 0000000..1ce5c93
--- /dev/null
+++ b/groovy-core/src/test/groovy/mock/example/SandwichMaker.groovy
@@ -0,0 +1,11 @@
+package groovy.mock.example
+
+class SandwichMaker {
+
+    def cheeseSlicer = new CheeseSlicer()
+
+    void makeFattySandwich() {
+        cheeseSlicer.slice("cheddar")
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/mock/example/SandwichMakerTest.groovy b/groovy-core/src/test/groovy/mock/example/SandwichMakerTest.groovy
new file mode 100644
index 0000000..79d5dcf
--- /dev/null
+++ b/groovy-core/src/test/groovy/mock/example/SandwichMakerTest.groovy
@@ -0,0 +1,21 @@
+package groovy.mock.example
+
+import groovy.mock.interceptor.MockFor
+
+class SandwichMakerTest extends GroovyTestCase {
+
+    void testStuff(){
+
+        def mocker = new MockFor(CheeseSlicer.class)
+
+        mocker.demand.slice { name -> assert name.startsWith("ch") }
+
+        def sandwichMaker = new SandwichMaker()
+
+        mocker.use(sandwichMaker.cheeseSlicer) { // todo: should also work without giving the object!
+            sandwichMaker.makeFattySandwich()
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/mock/interceptor/Caller.groovy b/groovy-core/src/test/groovy/mock/interceptor/Caller.groovy
new file mode 100644
index 0000000..0132794
--- /dev/null
+++ b/groovy-core/src/test/groovy/mock/interceptor/Caller.groovy
@@ -0,0 +1,25 @@
+package groovy.mock.interceptor
+
+/**
+    Helper class for testing.
+    @author Dierk Koenig
+*/
+
+class Caller {
+    int collaborateOne() {
+        return new Collaborator().one()
+    }
+    int collaborateOne(int arg) {
+        return new Collaborator().one( arg )
+    }
+    int collaborateOne(int one, two) {
+        return new Collaborator().one( one, two )
+    }
+    int collaborateTwo() {
+        return new Collaborator().two()
+    }
+    String collaborateJava() {
+        return 'whatever'.toString()
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/mock/interceptor/Collaborator.groovy b/groovy-core/src/test/groovy/mock/interceptor/Collaborator.groovy
new file mode 100644
index 0000000..5fccf13
--- /dev/null
+++ b/groovy-core/src/test/groovy/mock/interceptor/Collaborator.groovy
@@ -0,0 +1,21 @@
+package groovy.mock.interceptor
+
+/**
+    Helper class for testing.
+    @author Dierk Koenig
+*/
+
+class Collaborator {
+    def one() {
+        throw new RuntimeException('Never reach here. Should have been mocked.')
+    }
+    def one(int arg) {
+        throw new RuntimeException('Never reach here. Should have been mocked.')
+    }
+    def one(int one, int two) {
+        throw new RuntimeException('Never reach here. Should have been mocked.')
+    }
+    def two() {
+        throw new RuntimeException('Never reach here. Should have been mocked.')
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/mock/interceptor/MockCallSequenceTest.groovy b/groovy-core/src/test/groovy/mock/interceptor/MockCallSequenceTest.groovy
new file mode 100644
index 0000000..8a3d97c
--- /dev/null
+++ b/groovy-core/src/test/groovy/mock/interceptor/MockCallSequenceTest.groovy
@@ -0,0 +1,173 @@
+package groovy.mock.interceptor
+
+import junit.framework.AssertionFailedError
+
+/*
+    Testing Groovy Mock support for multiple calls to the Collaborator with
+    demanding one or two methods multiple and and various ranges.
+    @author Dierk Koenig
+*/
+
+class MockCallSequenceTest extends GroovyTestCase {
+
+    MockFor mocker
+
+    void setUp() {
+        mocker = new MockFor(Collaborator.class)
+    }
+
+    void testUndemandedCallFailsEarly() {
+        // no demand here
+        mocker.use {
+            def caller = new Caller()
+            shouldFail(AssertionFailedError.class) { caller.collaborateOne() }
+        }
+    }
+
+    void testOneDemandedTwoCalledFailsEarly() {
+        mocker.demand.one { 1 }
+        mocker.use {
+            def caller = new Caller()
+            caller.collaborateOne()
+            shouldFail(AssertionFailedError.class) { caller.collaborateOne() }
+        }
+    }
+    void testOneDemandedDefaultRange() {
+        mocker.demand.one(1..1) { 1 }
+        mocker.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+        }
+    }
+    void testOneDemandedExactRange() {
+        mocker.demand.one(2..2) { 1 }
+        mocker.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 1, caller.collaborateOne()
+            shouldFail(AssertionFailedError.class) { caller.collaborateOne() }
+        }
+    }
+    void testOneDemandedRealRange() {
+        mocker.demand.one(1..2) { 1 }
+        mocker.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 1, caller.collaborateOne()
+            shouldFail(AssertionFailedError.class) { caller.collaborateOne() }
+        }
+    }
+    void testOneDemandedOptionalRange() {
+        mocker.demand.one(0..2) { 1 }
+        mocker.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 1, caller.collaborateOne()
+            shouldFail(AssertionFailedError.class) { caller.collaborateOne() }
+        }
+    }
+    void testTwoDemandedNoRange() {
+        mocker.demand.one() { 1 }
+        mocker.demand.two() { 2 }
+        mocker.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 2, caller.collaborateTwo()
+            shouldFail(AssertionFailedError.class) { caller.collaborateTwo() }
+        }
+    }
+    void testTwoDemandedFirstRangeExploited() {
+        mocker.demand.one(1..2) { 1 }
+        mocker.demand.two() { 2 }
+        mocker.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 2, caller.collaborateTwo()
+            shouldFail(AssertionFailedError.class) { caller.collaborateTwo() }
+        }
+    }
+    void testTwoDemandedFirstRangeNotExploited() {
+        mocker.demand.one(1..2) { 1 }
+        mocker.demand.two() { 2 }
+        mocker.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 2, caller.collaborateTwo()
+            shouldFail(AssertionFailedError.class) { caller.collaborateTwo() }
+        }
+    }
+    void testTwoDemandedFirstOptionalOmitted() {
+        mocker.demand.one(0..2) { 1 }
+        mocker.demand.two() { 2 }
+        mocker.use {
+            def caller = new Caller()
+            assertEquals 2, caller.collaborateTwo()
+            shouldFail(AssertionFailedError.class) { caller.collaborateTwo() }
+        }
+    }
+    void testMixedDemandedMinimum() {
+        mocker.demand.one(0..1) { 1 }
+        mocker.demand.two() { 2 }
+        mocker.demand.one() { 1 }
+        mocker.demand.two(0..2) { 2 }
+        mocker.demand.one() { 1 }
+        mocker.use {
+            def caller = new Caller()
+            assertEquals 2, caller.collaborateTwo()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 1, caller.collaborateOne()
+            shouldFail(AssertionFailedError.class) { caller.collaborateTwo() }
+            shouldFail(AssertionFailedError.class) { caller.collaborateOne() }
+        }
+    }
+    void testMixedDemandedMaximum() {
+        mocker.demand.one(0..1) { 1 }
+        mocker.demand.two() { 2 }
+        mocker.demand.one() { 1 }
+        mocker.demand.two(0..2) { 2 }
+        mocker.demand.one() { 1 }
+        mocker.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 2, caller.collaborateTwo()
+            assertEquals 1, caller.collaborateOne()
+
+            // 2.times( assertEquals(2, caller.collaborateTwo()) ) // todo: why this not possible?
+            assertEquals 2, caller.collaborateTwo()
+            assertEquals 2, caller.collaborateTwo()
+
+            assertEquals 1, caller.collaborateOne()
+            shouldFail(AssertionFailedError.class) { caller.collaborateTwo() }
+            shouldFail(AssertionFailedError.class) { caller.collaborateOne() }
+        }
+    }
+    void testMixedDemandedOutOfSequenceFailsEarly() {
+        mocker.demand.one(0..1) { 1 }
+        mocker.demand.two() { 2 }
+        mocker.demand.one() { 1 }
+        mocker.demand.two(0..2) { 2 }
+        mocker.demand.one() { 1 }
+        shouldFail(AssertionFailedError.class) { // fails on verify
+            mocker.use {
+                def caller = new Caller()
+                assertEquals 1, caller.collaborateOne()
+                assertEquals 2, caller.collaborateTwo()
+                shouldFail(AssertionFailedError.class) { caller.collaborateTwo() }
+            }
+        }
+    }
+    void testRangeDemandedButNotExploitedFailsOnVerify() {
+        mocker.demand.one(2..4) { 1 }
+        shouldFail(AssertionFailedError.class) { // fails on verify
+            mocker.use {
+                def caller = new Caller()
+                assertEquals 1, caller.collaborateOne()
+            }
+        }
+    }
+    void testReversedRangesNotAllowed() {
+        shouldFail(IllegalArgumentException.class) { mocker.demand.one(1..0) { 1 } }
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/mock/interceptor/MockSingleCallTest.groovy b/groovy-core/src/test/groovy/mock/interceptor/MockSingleCallTest.groovy
new file mode 100644
index 0000000..4e0e71c
--- /dev/null
+++ b/groovy-core/src/test/groovy/mock/interceptor/MockSingleCallTest.groovy
@@ -0,0 +1,92 @@
+package groovy.mock.interceptor
+
+import junit.framework.AssertionFailedError
+
+/**
+    Testing Groovy Mock support for single calls to the Collaborator with
+    no, one, multiple, or arbitrary arguments, exceptions and failures.
+    @author Dierk Koenig
+*/
+
+class MockSingleCallTest extends GroovyTestCase {
+
+    MockFor mocker
+
+    void setUp() {
+        mocker = new MockFor(Collaborator.class)
+    }
+
+    void testSingleCallNoArgs() {
+        mocker.demand.one { 1 }
+        mocker.use {
+            assertEquals 1, new Caller().collaborateOne()
+        }
+    }
+    void testSingleCallOneArg() {
+        mocker.demand.one { arg -> return arg }
+        mocker.use {
+            assertEquals 2, new Caller().collaborateOne(2)
+        }
+    }
+    void testSingleCallTwoArgs() {
+        mocker.demand.one { one, two -> return one + two }
+        mocker.use {
+            assertEquals 2, new Caller().collaborateOne(1, 1)
+        }
+    }
+    void testNoSingleCallTwoArgsWhenNoArgDemanded() {
+        mocker.demand.one { 2 }
+        mocker.use {
+            shouldFail {
+                assertEquals 2, new Caller().collaborateOne(1, 1)
+            }
+        }
+    }
+    void testSingleCallTwoArgsWhenArbitraryArgsDemanded() {
+        mocker.demand.one { Object[] arg ->  2 }
+        mocker.use {
+            assertEquals 2, new Caller().collaborateOne(1, 1)
+        }
+    }
+    void testSingleCallTwoArgsWhenDefaultArgsDemanded() {
+        mocker.demand.one { one=null, two=null ->  2 }
+        mocker.use {
+            assertEquals 2, new Caller().collaborateOne(1, 1)
+        }
+    }
+    void testVerifyFailsIfOneDemandedButNoneExcecuted() {
+        mocker.demand.one { 1 }
+        def msg = shouldFail(AssertionFailedError.class) {
+            mocker.use {
+                // no call
+            }
+        }
+        assert msg =~ /0.*1..1.*never called/
+    }
+    void testSingleCallExceptionDemanded() {
+        mocker.demand.one { throw new IllegalArgumentException() }
+        mocker.use {
+            //shouldFail(IllegalArgumentException.class) {
+            shouldFail { // todo: should fail with IllegalArgumentException instead of GroovyRuntimeException
+                new Caller().collaborateOne()
+            }
+        }
+    }
+    void testSingleCallFailDemanded() {
+        mocker.demand.one { fail 'just kidding' }
+        mocker.use {
+            shouldFail() { new Caller().collaborateOne() }
+        }
+    }
+    void testJavaCall() {
+        mocker = new MockFor(String.class)
+        mocker.demand.toString { 'groovy' }
+        mocker.use {
+            assertEquals 'groovy', new Caller().collaborateJava()
+        }
+    }
+
+}
+
+
+
diff --git a/groovy-core/src/test/groovy/mock/interceptor/StubCallSequenceTest.groovy b/groovy-core/src/test/groovy/mock/interceptor/StubCallSequenceTest.groovy
new file mode 100644
index 0000000..1f71fcf
--- /dev/null
+++ b/groovy-core/src/test/groovy/mock/interceptor/StubCallSequenceTest.groovy
@@ -0,0 +1,198 @@
+package groovy.mock.interceptor
+
+import junit.framework.AssertionFailedError
+
+/**
+    Testing Groovy Stub support for multiple calls to the Collaborator with
+    demanding one or two methods multiple and and various ranges.
+    @author Dierk Koenig
+*/
+class StubCallSequenceTest extends GroovyTestCase {
+
+    StubFor stub
+
+    void setUp() {
+        stub = new StubFor(Collaborator.class)
+    }
+
+    void testUndemandedCallFailsEarly() {
+        // no demand here
+        stub.use {
+            def caller = new Caller()
+            shouldFail(AssertionFailedError.class) { caller.collaborateOne() }
+        }
+    }
+
+    void testOneDemandedTwoCalledFailsEarly() {
+        stub.demand.one { 1 }
+        stub.use {
+            def caller = new Caller()
+            caller.collaborateOne()
+            shouldFail(AssertionFailedError.class) { caller.collaborateOne() }
+        }
+    }
+    void testOneDemandedDefaultRange() {
+        stub.demand.one(1..1) { 1 }
+        stub.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+        }
+    }
+    void testOneDemandedExactRange() {
+        stub.demand.one(2..2) { 1 }
+        stub.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 1, caller.collaborateOne()
+            shouldFail(AssertionFailedError.class) { caller.collaborateOne() }
+        }
+    }
+    void testOneDemandedRealRange() {
+        stub.demand.one(1..2) { 1 }
+        stub.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 1, caller.collaborateOne()
+            shouldFail(AssertionFailedError.class) { caller.collaborateOne() }
+        }
+    }
+    void testOneDemandedOptionalRange() {
+        stub.demand.one(0..2) { 1 }
+        stub.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 1, caller.collaborateOne()
+            shouldFail(AssertionFailedError.class) { caller.collaborateOne() }
+        }
+    }
+    void testTwoDemandedNoRange() {
+        stub.demand.one() { 1 }
+        stub.demand.two() { 2 }
+        stub.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 2, caller.collaborateTwo()
+            shouldFail(AssertionFailedError.class) { caller.collaborateTwo() }
+        }
+    }
+    void testTwoDemandedFirstRangeExploited() {
+        stub.demand.one(1..2) { 1 }
+        stub.demand.two() { 2 }
+        stub.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 2, caller.collaborateTwo()
+            shouldFail(AssertionFailedError.class) { caller.collaborateTwo() }
+        }
+    }
+    void testTwoDemandedFirstRangeNotExploited() {
+        stub.demand.one(1..2) { 1 }
+        stub.demand.two() { 2 }
+        stub.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 2, caller.collaborateTwo()
+            shouldFail(AssertionFailedError.class) { caller.collaborateTwo() }
+        }
+    }
+    void testTwoDemandedFirstOptionalOmitted() {
+        stub.demand.one(0..2) { 1 }
+        stub.demand.two() { 2 }
+        stub.use {
+            def caller = new Caller()
+            assertEquals 2, caller.collaborateTwo()
+            shouldFail(AssertionFailedError.class) { caller.collaborateTwo() }
+        }
+    }
+    void testMixedDemandedMinimumOutOfSequence() {
+        stub.demand.one(0..1) { 1 }
+        stub.demand.two() { 2 }
+        stub.demand.one() { 1 }
+        stub.demand.two(0..2) { 2 }
+        stub.demand.one() { 1 }
+        stub.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 1, caller.collaborateOne()
+
+            assertEquals 2, caller.collaborateTwo()
+            assertEquals 2, caller.collaborateTwo()
+        }
+        stub.expect.verify()
+    }
+    void testMixedDemandedMaximum() {
+        stub.demand.one(0..1) { 1 }
+        stub.demand.two() { 2 }
+        stub.demand.one() { 1 }
+        stub.demand.two(0..2) { 2 }
+        stub.demand.one() { 1 }
+        stub.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 2, caller.collaborateTwo()
+            assertEquals 1, caller.collaborateOne()
+
+            // 2.times( assertEquals(2, caller.collaborateTwo()) ) // todo: why this not possible?
+            assertEquals 2, caller.collaborateTwo()
+            assertEquals 2, caller.collaborateTwo()
+
+            assertEquals 1, caller.collaborateOne()
+            shouldFail(AssertionFailedError.class) { caller.collaborateTwo() }
+            shouldFail(AssertionFailedError.class) { caller.collaborateOne() }
+        }
+    }
+    void testMixedDemandedOutOfSequenceFailsEarly() {
+        stub.demand.one(0..1) { 1 }
+        stub.demand.two() { 2 }
+        stub.demand.one() { 1 }
+        stub.demand.two(0..2) { 2 }
+        stub.demand.one() { 1 }
+        shouldFail(AssertionFailedError.class) { // fails on verify
+            stub.use {
+                def caller = new Caller()
+                assertEquals 1, caller.collaborateOne()
+                assertEquals 2, caller.collaborateTwo()
+                shouldFail(AssertionFailedError.class) { caller.collaborateTwo() }
+            }
+        }
+    }
+    void testRangeDemandedOutOfSequenceCalls() {
+        stub.demand.one(0..3) { 1 }
+        stub.demand.two(0..3) { 2 }
+        stub.use {
+            def caller = new Caller()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 2, caller.collaborateTwo()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 2, caller.collaborateTwo()
+            assertEquals 1, caller.collaborateOne()
+            assertEquals 2, caller.collaborateTwo()
+            shouldFail(AssertionFailedError.class) { caller.collaborateOne() }
+        }
+        stub.expect.verify()
+    }
+
+    void testUnreachedDemandFailsOnVerify() {
+        stub.demand.one { 1 }
+        // nothing used
+        shouldFail(AssertionFailedError.class) { stub.expect.verify() }
+    }
+
+
+    void testRangeDemandedButNotExploitedFailsOnVerify() {
+        stub.demand.one(2..4) { 1 }
+        shouldFail(AssertionFailedError.class) { // fails on verify
+            stub.use {
+                def caller = new Caller()
+                assertEquals 1, caller.collaborateOne()
+            }
+            stub.expect.verify()
+        }
+    }
+    void testReversedRangesNotAllowed() {
+        shouldFail(IllegalArgumentException.class) { stub.demand.one(1..0) { 1 } }
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/model/MvcDemo.groovy b/groovy-core/src/test/groovy/model/MvcDemo.groovy
new file mode 100644
index 0000000..b8bbe57
--- /dev/null
+++ b/groovy-core/src/test/groovy/model/MvcDemo.groovy
@@ -0,0 +1,44 @@
+package groovy.model
+
+import java.awt.BorderLayout
+import javax.swing.BorderFactory
+import groovy.swing.SwingBuilder
+/**
+ * 
+ */
+class MvcDemo {
+    
+    def frame
+    def swing
+    
+    void run() {
+        def swing = new SwingBuilder()
+        
+        def frame = swing.frame(title:'MVC Demo', location:[200,200], size:[300,200]) {
+            menuBar {
+		        menu(text:'Help') {
+		            menuItem() {
+		                action(name:'About', closure:{ showAbout() })
+		            }
+		        }
+		    }
+		    panel(layout:new BorderLayout()) {
+    	        scrollPane(constraints:BorderLayout.CENTER) {
+    	            table() {
+    	                tableModel(list:[ ['name':'James', 'location':'London'], ['name':'Bob', 'location':'Atlanta'] ]) {
+                            propertyColumn(header:'Name', propertyName:'name')
+                            propertyColumn(header:'Location', propertyName:'location')
+    	                }
+    	            }
+    	        }
+		    }
+		}        
+		frame.show()
+    }
+ 
+    void showAbout() {
+ 		def pane = swing.optionPane(message:'This demo shows how you can create UI models from simple MVC models')
+ 		def dialog = pane.createDialog(frame, 'About MVC Demo')
+ 		dialog.show()
+    }
+}
diff --git a/groovy-core/src/test/groovy/model/TableModelTest.groovy b/groovy-core/src/test/groovy/model/TableModelTest.groovy
new file mode 100644
index 0000000..5fec1b0
--- /dev/null
+++ b/groovy-core/src/test/groovy/model/TableModelTest.groovy
@@ -0,0 +1,38 @@
+package groovy.model
+
+class TableModelTest extends GroovyTestCase {
+    
+    void testTableModel() {
+        def list = [ ['name':'James', 'location':'London'], ['name':'Bob', 'location':'Atlanta']]
+        
+        def listModel = new ValueHolder(list)
+        
+        def model = new DefaultTableModel(listModel)
+        def rowModel = model.getRowModel()
+        model.addColumn(new DefaultTableColumn("Name", new PropertyModel(rowModel, "name")))
+        model.addColumn(new DefaultTableColumn("Location", new PropertyModel(rowModel, "location")))
+        
+        assert model.getRowCount() == 2
+        assert model.getColumnCount() == 2
+        assertValueAt(model, 0, 0, 'James')
+        assertValueAt(model, 0, 1, 'London')
+        assertValueAt(model, 1, 0, 'Bob')
+        assertValueAt(model, 1, 1, 'Atlanta')
+        
+        assert model.getColumnName(0) == 'Name'
+        assert model.getColumnName(1) == 'Location'
+        
+        // lets set some values
+        model.setValueAt('Antigua', 0, 1)
+        assertValueAt(model, 0, 1, 'Antigua')
+        
+        // lets check the real model changed too
+        def james = list.get(0)
+        assert james.location == 'Antigua'
+    }
+    
+    protected void assertValueAt(model, row, col, expected) {
+        def value = model.getValueAt(row, col)
+        assert value == expected , "for row " + row + " col " + col
+    }
+}
diff --git a/groovy-core/src/test/groovy/script/AtomTestScript.groovy b/groovy-core/src/test/groovy/script/AtomTestScript.groovy
new file mode 100644
index 0000000..38af581
--- /dev/null
+++ b/groovy-core/src/test/groovy/script/AtomTestScript.groovy
@@ -0,0 +1,71 @@
+package groovy.script
+
+import groovy.xml.MarkupBuilder;
+
+/** note you could use Expando classes if you don't mind being dynamically typed 
+f = new Expando()
+
+f.author = new Expando(name:'Ted Leung',url:'http://www.sauria.com/blog', email:'twl@sauria.com')
+
+f.entries = [ new Expando(title:'one',summary:'first post'), new Expando(title:'two',summary:'the second post'), new Expando(title:'three', summary:'post the third'), new Expando(title:'four',summary:'the ponderous fourth post') ]
+*/
+
+f = new Feed()
+
+f.author = new Person(name:'Ted Leung',url:'http://www.sauria.com/blog', email:'twl@sauria.com')
+
+f.entries = [ new Entry(title:'one',summary:'first post'), new Entry(title:'two',summary:'the second post'), new Entry(title:'three', summary:'post the third'), new Entry(title:'four',summary:'the ponderous fourth post') ]
+
+f.entries.each { println it.title }
+println f.author.name
+
+xml = new MarkupBuilder()
+
+atom = xml.atom() {
+  title("Ted Leung off the air")
+  link("http://www.sauria.com/noblog")
+  author() {
+    person() {
+      name(f.author.name)
+      url(f.author.url)
+      email(f.author.email)
+    }
+  }
+
+  for (e in f.entries) {
+    entry() {
+      title(e.title)
+      summary(e.summary)
+    }
+  }
+}
+
+
+class Feed {
+    String title
+    String link
+    Person author
+    String tagline
+    String generator
+    String copyright
+    String modified
+    List entries
+}
+
+class Entry {
+    String title
+    String link
+    String id
+    String summary
+    String content
+    Person author
+    String created
+    String issued
+    String modified
+}
+
+class Person {
+    String name
+    String url
+    String email
+}
diff --git a/groovy-core/src/test/groovy/script/CallAnotherScript.groovy b/groovy-core/src/test/groovy/script/CallAnotherScript.groovy
new file mode 100644
index 0000000..b7d9317
--- /dev/null
+++ b/groovy-core/src/test/groovy/script/CallAnotherScript.groovy
@@ -0,0 +1,8 @@
+import java.io.File
+
+println("About to call another script")
+
+script = new GroovyShell()
+script.run(new File("src/test/groovy/script/HelloWorld.groovy"), [])
+
+println("Done")
diff --git a/groovy-core/src/test/groovy/script/ClassWithScript.groovy b/groovy-core/src/test/groovy/script/ClassWithScript.groovy
new file mode 100644
index 0000000..60798ba
--- /dev/null
+++ b/groovy-core/src/test/groovy/script/ClassWithScript.groovy
@@ -0,0 +1,3 @@
+class X {}
+x = new X()
+println(x)
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/script/EvalInScript.groovy b/groovy-core/src/test/groovy/script/EvalInScript.groovy
new file mode 100644
index 0000000..4dd3940
--- /dev/null
+++ b/groovy-core/src/test/groovy/script/EvalInScript.groovy
@@ -0,0 +1,14 @@
+import java.io.File
+
+a = 1
+evaluate("a = 3")
+assert a == 3
+
+println("Done and now set a to ${a}")
+
+
+println("About to call another script")
+
+evaluate(new File("src/test/groovy/script/HelloWorld.groovy"))
+
+println("Done")
diff --git a/groovy-core/src/test/groovy/script/HelloWorld.groovy b/groovy-core/src/test/groovy/script/HelloWorld.groovy
new file mode 100644
index 0000000..4f813ab
--- /dev/null
+++ b/groovy-core/src/test/groovy/script/HelloWorld.groovy
@@ -0,0 +1,4 @@
+
+println "Hello world"
+
+
diff --git a/groovy-core/src/test/groovy/script/HelloWorld2.groovy b/groovy-core/src/test/groovy/script/HelloWorld2.groovy
new file mode 100644
index 0000000..9056ef0
--- /dev/null
+++ b/groovy-core/src/test/groovy/script/HelloWorld2.groovy
@@ -0,0 +1,4 @@
+
+x = ['James', 'Bob', 'Brian']
+x.each { println("hello " + it) }
+
diff --git a/groovy-core/src/test/groovy/script/MapFromList.groovy b/groovy-core/src/test/groovy/script/MapFromList.groovy
new file mode 100644
index 0000000..ef24492
--- /dev/null
+++ b/groovy-core/src/test/groovy/script/MapFromList.groovy
@@ -0,0 +1,23 @@
+class MapFromList {
+    void talk(a) {
+        println("hello "+a)
+    }
+
+    void doit(args) {
+        def i = 1
+        def l = [:]
+        args.each { 
+	    talk(it)
+	    l.put(it,i++)
+	    }
+        l.each {
+           println(it)
+        }
+    }
+
+    static void main(args) {
+        def a = ['tom','dick','harry']
+        def t = new MapFromList()
+        t.doit(a)
+    }
+}
diff --git a/groovy-core/src/test/groovy/script/MarkupTestScript.groovy b/groovy-core/src/test/groovy/script/MarkupTestScript.groovy
new file mode 100644
index 0000000..8b45448
--- /dev/null
+++ b/groovy-core/src/test/groovy/script/MarkupTestScript.groovy
@@ -0,0 +1,22 @@
+import groovy.xml.MarkupBuilder;
+
+class Bean {
+	String b
+};
+
+t = new Bean()
+t.b = "hello"
+println t.b
+println "test: ${t.b}"
+
+xml = new MarkupBuilder()
+root = xml.foo {
+	bar {
+		// works
+		baz("test")
+		// fails
+		baz(t.b)
+		// fails
+		baz("${t.b}")
+	}
+} 
diff --git a/groovy-core/src/test/groovy/script/MethodTestScript.groovy b/groovy-core/src/test/groovy/script/MethodTestScript.groovy
new file mode 100644
index 0000000..2bdf017
--- /dev/null
+++ b/groovy-core/src/test/groovy/script/MethodTestScript.groovy
@@ -0,0 +1 @@
+GString.methods.each { println it.name }
diff --git a/groovy-core/src/test/groovy/script/PackageScript.groovy b/groovy-core/src/test/groovy/script/PackageScript.groovy
new file mode 100644
index 0000000..1e57436
--- /dev/null
+++ b/groovy-core/src/test/groovy/script/PackageScript.groovy
@@ -0,0 +1,3 @@
+package groovy.script
+
+println("Hello world")
diff --git a/groovy-core/src/test/groovy/script/ScriptTest.groovy b/groovy-core/src/test/groovy/script/ScriptTest.groovy
new file mode 100644
index 0000000..4f0021b
--- /dev/null
+++ b/groovy-core/src/test/groovy/script/ScriptTest.groovy
@@ -0,0 +1,36 @@
+import java.io.File
+
+class ScriptTest extends GroovyTestCase {
+    void testScripts() {
+        def file = new File("src/test/groovy/script")
+        file.eachFile {
+            def name = it.name
+            if (name.endsWith('.groovy')) {
+                if (name.startsWith('ScriptTest')) {
+                    //
+                }
+				else {                        
+                	runScript(it) 
+				}
+            } 
+        }
+    }
+    
+    protected def runScript(file) {
+        println("Running script: " + file)
+        
+        def shell = new GroovyShell()
+        def args = ['a', 'b', 'c']
+        
+        shell.run(file, args)
+
+        /** @todo this doesn't work when ran in an IDE?
+        try {
+	        shell.run(file, args)
+        } 
+        catch (Exception e) {
+            println("Caught: " + e)
+        }
+         */
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/script/ScriptWithFunctions.groovy b/groovy-core/src/test/groovy/script/ScriptWithFunctions.groovy
new file mode 100644
index 0000000..bb04b78
--- /dev/null
+++ b/groovy-core/src/test/groovy/script/ScriptWithFunctions.groovy
@@ -0,0 +1,11 @@
+def foo(list, value) {
+    println "Calling function foo() with param ${value}"
+    list << value
+}
+
+x = []
+foo(x, 1)
+foo(x, 2)
+assert x == [1, 2]
+
+println "Creating list ${x}"
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/script/ShowArgs.groovy b/groovy-core/src/test/groovy/script/ShowArgs.groovy
new file mode 100644
index 0000000..b3d0578
--- /dev/null
+++ b/groovy-core/src/test/groovy/script/ShowArgs.groovy
@@ -0,0 +1,5 @@
+
+for (a in args) {
+    println("Argument: " + a)
+}
+
diff --git a/groovy-core/src/test/groovy/script/UseClosureInScript.groovy b/groovy-core/src/test/groovy/script/UseClosureInScript.groovy
new file mode 100644
index 0000000..9769195
--- /dev/null
+++ b/groovy-core/src/test/groovy/script/UseClosureInScript.groovy
@@ -0,0 +1,4 @@
+a = 1
+[1].each { 
+    a = it 
+}
diff --git a/groovy-core/src/test/groovy/security/RunAllGroovyScriptsSuite.java b/groovy-core/src/test/groovy/security/RunAllGroovyScriptsSuite.java
new file mode 100644
index 0000000..849b9c5
--- /dev/null
+++ b/groovy-core/src/test/groovy/security/RunAllGroovyScriptsSuite.java
@@ -0,0 +1,67 @@
+/*
+ * Created on Apr 7, 2004
+ *
+ * To change the template for this generated file go to
+ * Window - Preferences - Java - Code Generation - Code and Comments
+ */
+package groovy.security;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+/**
+ * Run all the .groovy scripts found under the src/test tree with a security manager active.
+ * Not currently part of the build because it adds about 4 minutes to the build process.
+ * 
+ * @author Steve Goetze
+ */
+public class RunAllGroovyScriptsSuite extends SecurityTestSupport {
+
+    /**
+     * Find all Groovy script test cases in the source tree and execute them with a security policy in effect.
+     * The complete filename of the groovy source file is used as the codebase so that the proper grants can be
+     * made for each script.
+     */
+    protected void executeTests(File dir, TestResult result) throws Exception {
+        File[] files = dir.listFiles();
+        List traverseList = new ArrayList();
+        for (int i = 0; i < files.length; i++) {
+            File file = files[i];
+            if (file.isDirectory()) {
+                traverseList.add(file);
+            }
+            else {
+                String name = file.getName();
+                if (name.endsWith("Test.groovy") || name.endsWith("Bug.groovy")) {
+                //if (name.endsWith("IanMaceysBug.groovy")) {
+                	Class clazz = parseClass(file);
+            		if (TestCase.class.isAssignableFrom(clazz)) {
+            			TestSuite suite = new TestSuite(clazz);
+            			suite.run(result);
+            		}
+                }
+            }
+        }
+        for (Iterator iter = traverseList.iterator(); iter.hasNext();) {
+            executeTests((File) iter.next(), result);
+        }
+    }
+
+	public void testGroovyScripts() throws Exception {
+    	if (!isSecurityAvailable()) {
+    		return;
+    	}
+   		TestResult result = new TestResult();
+   		executeTests(new File("src/test"), result);
+   		if (!result.wasSuccessful()) {
+   			new SecurityTestResultPrinter(System.out).print(result);
+   			fail("At least one groovy testcase did not run under the secure groovy environment.  Results in the testcase output");
+   		}
+    }
+}
diff --git a/groovy-core/src/test/groovy/security/RunOneGroovyScript.java b/groovy-core/src/test/groovy/security/RunOneGroovyScript.java
new file mode 100644
index 0000000..2de6290
--- /dev/null
+++ b/groovy-core/src/test/groovy/security/RunOneGroovyScript.java
@@ -0,0 +1,34 @@
+package groovy.security;
+
+import java.io.File;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+/**
+ * Test case for running a single groovy script parsed from a .groovy file.
+ */
+public class RunOneGroovyScript extends SecurityTestSupport {
+
+	protected static String file;
+	
+    public static void main(String[] args) {
+        if (args.length > 0) {
+            file = args[0];
+        }
+        TestRunner.run( suite() );
+    }
+    
+    public static Test suite() {
+    	return new TestSuite(RunOneGroovyScript.class);
+    }
+
+	public void testScript() {
+        String fileName = System.getProperty("script", file);
+        if (fileName == null) {
+            throw new RuntimeException("No filename given in the 'script' system property so cannot run a Groovy script");
+        }
+		assertExecute(new File(fileName), null);
+	}
+}
diff --git a/groovy-core/src/test/groovy/security/SecurityTest.java b/groovy-core/src/test/groovy/security/SecurityTest.java
new file mode 100644
index 0000000..aa00e47
--- /dev/null
+++ b/groovy-core/src/test/groovy/security/SecurityTest.java
@@ -0,0 +1,115 @@
+package groovy.security;
+
+import groovy.lang.GroovyCodeSource;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.security.Security;
+import java.util.PropertyPermission;
+
+import org.codehaus.groovy.control.CompilationFailedException;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+/**
+ * Test the effects of enabling security in Groovy.  Some tests below check for proper framework
+ * behavior (e.g. ensuring that GroovyCodeSources may only be created for which proper permissions exist).
+ * Other tests run .groovy scripts under a secure environment and ensure that the proper permissions
+ * are required for success.
+ *
+ * Todo: find out why the marked tests are environment specific and why security tests are not
+ * running on the build server.
+ * 
+ * @author Steve Goetze
+ */
+public class SecurityTest extends SecurityTestSupport {
+
+	public static void main(String[] args) {
+        TestRunner.run( suite() );
+    }
+   
+    public static Test suite() {
+    	return new TestSuite(SecurityTest.class);
+    }
+
+    public void testForbiddenProperty() {
+		String script = "System.getProperty(\"user.home\")";
+		assertExecute(script, null, new PropertyPermission("user.home", "read"));
+	}
+
+	public void testForbiddenPackage() {
+		String script = "import sun.net.*; s = new NetworkClient()";
+		assertExecute(script, "/groovy/security/testForbiddenPackage", new RuntimePermission("accessClassInPackage.sun.*"));
+	}
+
+    public void testForbiddenCodebase() { 
+		assertExecute(new File("src/test/groovy/security/forbiddenCodeBase.gvy"), new GroovyCodeSourcePermission("/groovy/security/forbiddenCodeBase"));
+	}
+	
+	//Check that the Security package.access control works.
+	public void testPackageAccess() {
+		String script = "new javax.print.PrintException();";
+        Security.setProperty("package.access", "javax.print");
+        //This should throw an ACE because its codeBase does not allow access to javax.print
+		assertExecute(script, "/groovy/security/javax/print/deny", new RuntimePermission("accessClassInPackage.javax.print"));
+		//This should not throw an ACE because groovy.policy grants the codeBase access to javax.print
+		assertExecute(script, "/groovy/security/javax/print/allow", null);
+	}
+
+    public void testBadScriptNameBug() { 
+		assertExecute(new File("src/test/groovy/bugs/BadScriptNameBug.groovy"), null);
+	}
+
+    public void testClosureListenerTest() {
+        //if (System.getProperty("java.version").startsWith("1.5") && notYetImplemented()) return;
+        if (System.getProperty("java.version").startsWith("1.5")) return;
+        assertExecute(new File("src/test/groovy/ClosureListenerTest.groovy"), null);
+	}
+
+	public void testClosureMethodTest() {
+		assertExecute(new File("src/test/groovy/ClosureMethodTest.groovy"), null);
+	}
+
+	public void testGroovyMethodsTest_FAILS() {
+		if (notYetImplemented()) return;
+		assertExecute(new File("src/test/groovy/GroovyMethodsTest.groovy"), null);
+	}
+
+	public void testClosureWithDefaultParamTest() {
+		assertExecute(new File("src/test/groovy/ClosureWithDefaultParamTest.groovy"), null);
+	}
+
+	public void testGroovy303_Bug() {
+		assertExecute(new File("src/test/groovy/bugs/Groovy303_Bug.groovy"), null);
+	}
+
+    public void testScriptTest() {
+		assertExecute(new File("src/test/groovy/script/ScriptTest.groovy"), null);
+	}
+	
+	//In addition to requiring several permissions, this test is an example of the case
+	//where the groovy class loader is required at script invocation time as well as
+	//during compilation.
+	public void testSqlCompleteWithoutDataSourceTest() {
+		assertExecute(new File("src/test/groovy/sql/SqlCompleteWithoutDataSourceTest.groovy"), null);
+	}
+	
+	//Test to prevent scripts from invoking the groovy compiler.  This is done by restricting access
+	//to the org.codehaus.groovy packages.
+	public void testMetaClassTest() {
+        Security.setProperty("package.access", "org.codehaus.groovy");
+		assertExecute(new File("src/test/org/codehaus/groovy/classgen/MetaClassTest.groovy"), new RuntimePermission("accessClassInPackage.org.codehaus.groovy"));
+	}
+	
+	//Mailing list post by Richard Hensley reporting a CodeSource bug.  A GroovyCodeSource created
+	//with a URL was causing an NPE.
+	public void testCodeSource() throws IOException, CompilationFailedException {
+		URL script = loader.getResource("groovy/ArrayTest.groovy");
+		GroovyCodeSource gcs = new GroovyCodeSource(script);
+		Class result = loader.parseClass(gcs);
+	}
+	
+}
diff --git a/groovy-core/src/test/groovy/security/SecurityTestSupport.java b/groovy-core/src/test/groovy/security/SecurityTestSupport.java
new file mode 100644
index 0000000..ade5900
--- /dev/null
+++ b/groovy-core/src/test/groovy/security/SecurityTestSupport.java
@@ -0,0 +1,285 @@
+package groovy.security;
+
+import groovy.lang.Binding;
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyCodeSource;
+import groovy.lang.Script;
+import groovy.util.GroovyTestCase;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.Policy;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
+
+import junit.framework.TestCase;
+import junit.framework.TestFailure;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+import junit.textui.ResultPrinter;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * @author Steve Goetze
+ */
+public class SecurityTestSupport extends GroovyTestCase {
+
+	private static int counter = 0;
+	private static boolean securityDisabled; 
+	private static boolean securityAvailable;
+	private static boolean securityChecked = false;
+
+	static {
+		if (System.getProperty("groovy.security.disabled") != null) {
+			securityAvailable = false;
+			securityDisabled = true;
+		} else {
+			securityDisabled = false;
+			String groovyLibDir = System.getProperty("groovy.lib");
+			if (groovyLibDir == null) {
+				//Try to find maven repository in the default user.home location
+				groovyLibDir = System.getProperty("user.home") + "/" + ".maven/repository";
+			}
+			if (groovyLibDir == null) {
+				//Try at user.dir/lib
+				groovyLibDir = "lib";
+			}
+			if (new File(groovyLibDir).exists()) {
+				securityAvailable = true;
+				System.setProperty("groovy.lib", groovyLibDir);
+				System.setProperty("java.security.policy", "=security/groovy.policy");
+			} else {
+				securityAvailable = false;
+			}
+		}
+	}
+
+	public static boolean isSecurityAvailable() {
+		return securityAvailable;
+	}
+
+	public static boolean isSecurityDisabled() {
+		return securityDisabled;
+	}
+
+	public static void resetSecurityPolicy(String policyFileURL) {
+		System.setProperty("java.security.policy", policyFileURL);
+		Policy.getPolicy().refresh();
+	}
+	
+	protected class SecurityTestResultPrinter extends ResultPrinter {
+		
+		public SecurityTestResultPrinter(PrintStream stream) {
+			super(stream);
+		}
+		public void print(TestResult result) {
+			getWriter().println("Security testing on a groovy test failed:");
+		    printErrors(result);
+		    printFailures(result);
+		    printFooter(result);
+		}
+	}
+
+    protected GroovyClassLoader loader = (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
+		public Object run() {
+			return new GroovyClassLoader(SecurityTestSupport.class.getClassLoader()); 
+		}
+	});
+    
+	private SecurityManager securityManager;
+    private ClassLoader currentClassLoader;
+
+	public SecurityTestSupport() {
+	}
+	
+	/*
+	 * Check SecuritySupport to see if security is properly configured.  If not, fail the first
+	 * test that runs.  All remaining tests will run, but not do any security checking.
+	 */
+	private boolean checkSecurity() {
+		if (!securityChecked) {
+			securityChecked = true;
+			if (!isSecurityAvailable()) {
+				fail("Security is not available - skipping security tests.  Ensure that groovy.lib is set and points to the groovy dependency jars.");
+			}
+		}
+		return isSecurityAvailable();
+	}
+
+	//Prepare for each security test.  First, check to see if groovy.lib can be determined via
+	//a call to checkSecurity().  If not, fail() the first test.  Establish a security manager
+	//and make the GroovyClassLoader the initiating class loader (ala GroovyShell) to compile AND
+	//invoke the test scripts.  This handles cases where multiple .groovy scripts are involved in a
+	//test case: a.groovy depends on b.groovy; a.groovy is parsed (and in the process the gcl
+	//loads b.groovy via findClass).  Note that b.groovy is only available in the groovy class loader.
+	//See 
+	protected void setUp() {
+		if (checkSecurity()) {
+			securityManager = System.getSecurityManager();
+			if (securityManager == null) {
+	    		System.setSecurityManager(new SecurityManager());
+			}
+		}
+		currentClassLoader = Thread.currentThread().getContextClassLoader();
+		AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                Thread.currentThread().setContextClassLoader(loader);
+                return null;
+            }
+        });
+    }
+
+	protected void tearDown() {
+        AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                System.setSecurityManager(securityManager);
+                Thread.currentThread().setContextClassLoader(currentClassLoader);
+                return null;
+            }
+        });
+	}
+
+    protected synchronized String generateClassName() {
+        return "testSecurity" + (++counter);
+    }
+
+	/*
+	 * Execute the groovy script contained in file.  If missingPermission
+	 * is non-null, then this invocation expects an AccessControlException with missingPermission
+	 * as the reason.  If missingPermission is null, the script is expected to execute successfully.
+	 */
+	protected Class parseClass(File file) {
+		GroovyCodeSource gcs = null;
+		try {
+			gcs = new GroovyCodeSource(file);
+		} catch (FileNotFoundException fnfe) {
+			fail(fnfe.toString());
+		}
+		return parseClass(gcs);
+	}
+
+    /*
+	 * Parse the Groovy code contained in the GroovyCodeSource as a privileged operation (i.e. do not
+	 * require the code source to have specific compile time permissions) and return the resulting class.
+	 */
+	protected Class parseClass(final GroovyCodeSource gcs) {
+		Class clazz = null;
+		try {
+			clazz = loader.parseClass(gcs);
+		} catch (Exception e) {
+			fail(e.toString());
+		}
+		return clazz;
+	}
+    
+    /*
+	 * Parse the script contained in the GroovyCodeSource as a privileged operation (i.e. do not
+	 * require the code source to have specific compile time permissions).  If the class produced is a
+	 * TestCase, run the test in a suite and evaluate against the missingPermission.
+	 * Otherwise, run the class as a groovy script and evaluate against the missingPermission.
+	 */
+	private void parseAndExecute(final GroovyCodeSource gcs, Permission missingPermission) {
+		Class clazz = null;
+		try {
+			clazz = loader.parseClass(gcs);
+		} catch (Exception e) {
+			fail(e.toString());
+		}
+		if (TestCase.class.isAssignableFrom(clazz)) {
+			executeTest(clazz, missingPermission);
+		} else {
+			executeScript(clazz, missingPermission);
+		}
+	}
+
+	protected void executeTest(Class test, Permission missingPermission) {
+		TestSuite suite = new TestSuite();
+		suite.addTestSuite(test);
+        TestResult result = new TestResult();
+        suite.run(result);
+        if (result.wasSuccessful()) {
+        	if (missingPermission == null) {
+        		return;
+        	} else {
+        		fail("Security test expected an AccessControlException on " + missingPermission + ", but did not receive one");
+        	}
+        } else {
+        	if (missingPermission == null) {
+        		new SecurityTestResultPrinter(System.out).print(result);
+        		fail("Security test was expected to run successfully, but failed (results on System.out)");
+        	} else {
+        		//There may be more than 1 failure:  iterate to ensure that they all match the missingPermission.
+        		boolean otherFailure = false;
+        		for (Enumeration e = result.errors(); e.hasMoreElements(); ) {
+        			TestFailure failure = (TestFailure) e.nextElement();
+        			if (failure.thrownException() instanceof AccessControlException) {
+        				AccessControlException ace = (AccessControlException) failure.thrownException();
+        				if (missingPermission.implies(ace.getPermission())) {
+        					continue;
+        				}
+        			}
+        			otherFailure = true;        			
+        		}
+        		if (otherFailure) {
+        			new SecurityTestResultPrinter(System.out).print(result);
+        			fail("Security test expected an AccessControlException on " + missingPermission + ", but  failed for other reasons (results on System.out)");
+        		}
+        	}
+        }
+    }
+
+	protected void executeScript(Class scriptClass, Permission missingPermission) {
+		try {
+			Script script = InvokerHelper.createScript(scriptClass, new Binding());
+			script.run();
+			//InvokerHelper.runScript(scriptClass, null);
+		} catch (AccessControlException ace) {
+			if (missingPermission != null && missingPermission.implies(ace.getPermission())) {
+				return;
+			} else {
+				fail(ace.toString());
+			}
+		}
+		if (missingPermission != null) {
+			fail("Should catch an AccessControlException");
+		}
+	}
+	
+	/*
+	 * Execute the groovy script contained in file.  If missingPermission
+	 * is non-null, then this invocation expects an AccessControlException with missingPermission
+	 * as the reason.  If missingPermission is null, the script is expected to execute successfully.
+	 */
+	protected void assertExecute(File file, Permission missingPermission) {
+		if (!isSecurityAvailable()) {
+			return;
+		}
+		GroovyCodeSource gcs = null;
+		try {
+			gcs = new GroovyCodeSource(file);
+		} catch (FileNotFoundException fnfe) {
+			fail(fnfe.toString());
+		}
+		parseAndExecute(gcs, missingPermission);
+	}
+	
+	/*
+	 * Execute the script represented by scriptStr using the supplied codebase.  If missingPermission
+	 * is non-null, then this invocation expects an AccessControlException with missingPermission
+	 * as the reason.  If missingPermission is null, the script is expected to execute successfully.
+	 */
+	protected void assertExecute(String scriptStr, String codeBase, Permission missingPermission) {
+		if (!isSecurityAvailable()) {
+			return;
+		}
+		if (codeBase == null) {
+			codeBase = "/groovy/security/test";
+		}
+		parseAndExecute(new GroovyCodeSource(scriptStr, generateClassName(), codeBase), missingPermission);
+	}
+}
diff --git a/groovy-core/src/test/groovy/security/SignedJarTest.java b/groovy-core/src/test/groovy/security/SignedJarTest.java
new file mode 100644
index 0000000..d5687d7
--- /dev/null
+++ b/groovy-core/src/test/groovy/security/SignedJarTest.java
@@ -0,0 +1,46 @@
+package groovy.security;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+
+/**
+ * Read a .groovy file from a signed jar and verify that a policy file grant with a signedBy field
+ * works.  The following steps were used to create and manage the keys used to sign and read the jar:
+ * <ol>
+ * <li>keytool -genkey -alias groovy -keypass keypass -keystore groovystore -storepass storepass -validity 7000
+ * <li>keytool -export -keystore groovystore -alias groovy -file GroovyDev.cer
+ * <li>keytool -import -alias groovy -file GroovyDev.cer -keystore groovykeys
+ * </ol>
+ * Once the keys are constructed, creat the jar and sign:
+ * <ol>
+ * <li>jar -cvf Groovy.jar groovy
+ * <li>jarsigner -keystore groovystore -signedjar GroovyJarTest.jar Groovy.jar groovy
+ * </ol>
+ * Add the keystore to the policy file and write the grant:
+ * <ol>
+ * <li>keystore "file:${user.dir}/src/test/groovy/security/groovykeys";
+ * </ol>
+ */
+public class SignedJarTest extends SecurityTestSupport {
+
+	public static void main(String[] args) {
+        TestRunner.run( suite() );
+    }
+   
+    public static Test suite() {
+    	return new TestSuite(SignedJarTest.class);
+    }
+
+    public void testReadSignedJar() throws Exception {
+    	if (!isSecurityAvailable() || (notYetImplemented())) return;
+
+    	//spg 2006-02-09 The GroovyClassLoader code that checked jar files
+    	//for source files was removed last July.  This test will not function
+    	//without that capability.
+        Class c = loader.loadClass("groovy.security.JarTest");  // ClassNotFoundException !
+    	executeTest(c, null);
+
+    }
+}
diff --git a/groovy-core/src/test/groovy/security/forbiddenCodeBase.gvy b/groovy-core/src/test/groovy/security/forbiddenCodeBase.gvy
new file mode 100644
index 0000000..d5e0141
--- /dev/null
+++ b/groovy-core/src/test/groovy/security/forbiddenCodeBase.gvy
@@ -0,0 +1,6 @@
+/*
+ * Groovy script to be read as a file to test the file based codesource features of groovy security.
+ * The file extension of .gvy is used to prevent this script from being treated as a groovy script by maven.
+ */
+ 
+new GroovyShell().evaluate("1+2", "forbiddenCodeBaseTest", "/groovy/security/forbiddenCodeBase");
diff --git a/groovy-core/src/test/groovy/servlet/GroovyServletTest.java b/groovy-core/src/test/groovy/servlet/GroovyServletTest.java
new file mode 100644
index 0000000..f2255d9
--- /dev/null
+++ b/groovy-core/src/test/groovy/servlet/GroovyServletTest.java
@@ -0,0 +1,50 @@
+package groovy.servlet;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+
+import org.jmock.Mock;
+import org.jmock.MockObjectTestCase;
+
+public class GroovyServletTest extends MockObjectTestCase {
+
+    private ServletConfig config;
+    private ServletContext context;
+    private GroovyServlet servlet;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        //this.config = (ServletConfig) mock(ServletConfig.class).proxy();
+        //this.context = (ServletContext) mock(ServletContext.class).proxy();
+        this.servlet = new GroovyServlet();
+        //servlet.init(config);
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testRequestGetCommandOK() {
+        Mock requestMock = mock(HttpServletRequest.class);
+        requestMock.expects(once()).method("getParameter").with(eq("command")).will(returnValue("SELECT..."));
+        HttpServletRequest request = (HttpServletRequest) requestMock.proxy();
+        String command = request.getParameter("command");
+        assertEquals("SELECT...", command);
+    }
+
+    //    public void testService() {
+    //        Mock requestMock = mock(HttpServletRequest.class);
+    //        Mock responseMock = mock(HttpServletResponse.class);
+    //        
+    //        HttpServletRequest request = (HttpServletRequest) requestMock.proxy();
+    //        HttpServletResponse response = (HttpServletResponse) responseMock.proxy();
+    //        try {
+    //            servlet.service(request, response);
+    //        } catch (Throwable t) {
+    //            t.printStackTrace();
+    //            fail(t.getMessage());
+    //        }
+    //    }
+
+}
diff --git a/groovy-core/src/test/groovy/sql/GroovyRowResultTest.groovy b/groovy-core/src/test/groovy/sql/GroovyRowResultTest.groovy
new file mode 100644
index 0000000..1f27a9d
--- /dev/null
+++ b/groovy-core/src/test/groovy/sql/GroovyRowResultTest.groovy
@@ -0,0 +1,116 @@
+package groovy.sql

+

+import java.util.LinkedHashMap

+

+class GroovyRowResultTest extends GroovyTestCase {

+

+    void testMap() {

+        def row = createRow();

+        def row2 = createRow();

+        

+        /**

+         * Test for implementing Map

+         */ 

+        assert row instanceof Map, "GroovyRowResult doesn't implement Map interface"

+        

+        /**

+         * Test for put and accessing the new property

+         */ 

+        row.put("john","Doe")

+        assert row.john=="Doe"

+        assert row["john"]=="Doe"

+        assert row['john']=='Doe'

+        assert row.containsKey("john")

+        assert !row2.containsKey("john")

+        assert row.containsValue("Doe")

+        assert !row2.containsKey("Doe")

+

+        /**

+         * Test for equality (1) and size

+         */ 

+        assert row!=row2, "rows unexpectedly equal"

+        assert row.size()==7

+        assert row2.size()==6

+        

+        /**

+         * Test for remove, equality (2) and isEmpty (1)

+         */ 

+        row.remove("john")        

+        assert row==row2, "rows different after remove"

+        assert !row.isEmpty(), "row empty after remove"

+        

+        /**

+         * Test for clear, equality (3) and isEmpty (2)

+         */ 

+        row.clear()

+        row2.clear()

+        assert row==row2, "rows different after clear"

+        assert row.isEmpty(), "row not empty after clear"

+    }

+    

+    void testProperties() {

+        def row = createRow()

+        assert row.miXed == "quick"

+        assert row.lower == "brown"

+        assert row.upper == "fox"

+        assert row.UPPER == "fox"

+        

+        try {

+            assert row.LOWER == "brown"

+            assert false

+        } catch (MissingPropertyException mpe) {

+        } catch (Exception e) {

+            assert false

+        }

+

+        try {

+            println row.foo

+            assert false

+        } catch (MissingPropertyException mpe) {

+        } catch (Exception e) {

+            assert false

+        }

+

+        /**

+         * This is for GROOVY-1296

+         */

+        assert row.nullMixed==null

+        assert row[1]==null

+        assert row.nulllower==null

+        assert row[3]==null

+        assert row.NULLUPPER==null

+        assert row[5]==null

+        

+    } 

+    

+    void testOrder() {

+        def row = createRow()

+        assert row[0] == "quick" 

+        assert row[1] == null 

+        assert row[2] == "brown" 

+        assert row[3] == null 

+        assert row[4] == "fox" 

+        assert row[5] == null 

+        assert row[27] == null 

+        assert row[-1] == null 

+        assert row[-2] == "fox" 

+    }

+

+    protected def createRow() {

+        def map = new LinkedHashMap()

+        assert map != null , "failed to load LinkedHashMap class"

+

+        map.put("miXed", "quick")

+        map.put("nullMixed", null)

+        map.put("lower", "brown")

+        map.put("nulllower", null)

+        map.put("UPPER", "fox")

+        map.put("NULLUPPER", null)

+

+        def row = new GroovyRowResult(map)

+        assert row != null , "failed to load GroovyRowResult class"

+

+        return row

+    }

+    

+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/sql/Person.groovy b/groovy-core/src/test/groovy/sql/Person.groovy
new file mode 100644
index 0000000..ddcff90
--- /dev/null
+++ b/groovy-core/src/test/groovy/sql/Person.groovy
@@ -0,0 +1,8 @@
+package groovy.sql
+
+class Person {
+
+    def firstName
+    def lastName
+    def age
+}
diff --git a/groovy-core/src/test/groovy/sql/PersonTest.groovy b/groovy-core/src/test/groovy/sql/PersonTest.groovy
new file mode 100644
index 0000000..81c50aa
--- /dev/null
+++ b/groovy-core/src/test/groovy/sql/PersonTest.groovy
@@ -0,0 +1,64 @@
+package groovy.sql
+
+import javax.sql.DataSource
+
+import org.axiondb.jdbc.AxionDataSource
+
+class PersonTest extends GroovyTestCase {
+
+    def type
+    
+    void testFoo() {
+        def persons = createDataSet()
+		
+        def blogs = persons.findAll { it.lastName == "Bloggs" }
+		
+        assertSql(blogs, "select * from person where lastName = ?", ['Bloggs'])
+    }
+
+    void testWhereWithAndClause() {
+        def persons = createDataSet()
+		
+        def blogs = persons.findAll { it.lastName == "Bloggs" }
+        
+        def bigBlogs = blogs.findAll { it.size > 100 }
+		
+        assertSql(bigBlogs, "select * from person where lastName = ? and size > ?", ['Bloggs', 100])
+    }
+
+    void testWhereClosureWithAnd() {
+        def persons = createDataSet()
+		
+        def blogs = persons.findAll { it.size < 10 && it.lastName == "Bloggs" }
+		
+        assertSql(blogs, "select * from person where size < ? and lastName = ?", [10, 'Bloggs'])
+    }
+ 
+    protected def compareFn(value) {
+        value > 1 && value < 10
+    }
+    
+    protected def assertSql(dataSet, expectedSql, expectedParams) {
+        def sql = dataSet.sql
+        def params = dataSet.parameters
+        assert sql == expectedSql
+        assert params == expectedParams
+    }
+    
+    protected DataSource createDataSource() {
+        return new AxionDataSource("jdbc:axiondb:foo" + getMethodName())
+    }
+    
+    protected def createDataSet() {
+        def type = Person
+
+        assert type != null , "failed to load Person class"
+
+        def dataSource = createDataSource()
+        def sql = new Sql(dataSource)
+
+        return sql.dataSet(type)
+    }
+
+
+}
diff --git a/groovy-core/src/test/groovy/sql/SqlCompleteTest.groovy b/groovy-core/src/test/groovy/sql/SqlCompleteTest.groovy
new file mode 100644
index 0000000..abc3b78
--- /dev/null
+++ b/groovy-core/src/test/groovy/sql/SqlCompleteTest.groovy
@@ -0,0 +1,133 @@
+package groovy.sql
+
+class SqlCompleteTest extends TestHelper {
+
+    void testSqlQuery() {
+        def sql = createSql()
+        
+        def results = [:]
+        sql.eachRow("select * from PERSON") { results.put(it.firstname, it.lastname) }
+        
+        def expected = ["James":"Strachan", "Bob":"Mcwhirter", "Sam":"Pullara"]
+					
+        assert results == expected
+    }
+    
+    void testSqlQueryWithWhereClause() {
+        def sql = createSql()
+        
+        def foo = "drink"
+        def results = []
+        sql.eachRow("select * from FOOD where type=${foo}") { results.add(it.name) }
+        
+        def expected = ["beer", "coffee"]
+        assert results == expected
+    }
+    
+    void testSqlQueryWithWhereClauseWith2Arguments() {
+        def sql = createSql()
+        
+        def foo = "cheese"
+        def bar = "edam"
+        def results = []
+        sql.eachRow("select * from FOOD where type=${foo} and name != ${bar}") { results.add(it.name) }
+        
+        def expected = ["brie", "cheddar"]
+        assert results == expected
+    }
+
+    void testSqlQueryWith2ParametersUsingQuestionMarkNotation() {
+        def sql = createSql()
+        
+        def results = []
+        sql.eachRow("select * from FOOD where type=? and name != ?", ["cheese", "edam"]) { results.add(it.name) }
+        
+        def expected = ["brie", "cheddar"]
+        assert results == expected
+    }
+
+    void testDataSet() {
+        def sql = createSql()
+        
+        def results = []
+        def people = sql.dataSet("PERSON")
+        people.each { results.add(it.firstname) }
+        
+        def expected = ["James", "Bob", "Sam"]
+        assert results == expected
+    }
+    
+    void testDataSetWithClosurePredicate() {
+        def sql = createSql()
+        
+        def results = []
+        def food = sql.dataSet("FOOD")
+        food.findAll { it.type == "cheese" }.each { results.add(it.name) }
+        
+        def expected = ["edam", "brie", "cheddar"]
+        assert results == expected
+    }
+    
+    void testUpdatingDataSet() {
+        def sql = createSql()
+        
+        def results = []
+        def features = sql.dataSet("FEATURE")
+        features.each { 
+            /** @todo Axion doesn't yet support ResultSet updating
+            if (it.id == 1) {
+                it.name = it.name + " Rocks!"
+                println("Changing name to ${it.name}")
+            }
+            */
+            results.add(it.name) 
+        }
+        
+        def expected = ["GDO", "GPath", "GroovyMarkup"]
+        assert results == expected
+    }
+    
+    void testGStringToSqlConversion(){
+       def foo = 'loincloth'
+       def bar = 'wasteband'
+       def sql = createSql()
+       def expected = "A narrow ? supported by a ?!!"
+       def gstring = "A narrow ${foo} supported by a ${bar}!!"
+       def result = sql.asSql(gstring, gstring.values.toList())
+       assert result == expected
+    }
+    
+    void testExecuteUpdate(){
+        def foo='food-drink'
+        def food = 'food'
+        def drink = 'drink'
+        def bar='guinness'
+        def sql = createSql();
+        def expected = 0
+        def result = sql.executeUpdate("update FOOD set type=? where name=?",[foo,bar]);
+        assert result == expected
+        expected  = 1
+        result = sql.executeUpdate("insert into FOOD (type,name) values (${food},${bar})");
+    	assert result == expected
+        result = sql.executeUpdate("insert into FOOD (type,name) values (${drink},${bar})");
+    	assert result == expected
+        result = sql.executeUpdate("insert into FOOD (type,name) values ('drink','guinness')");
+    	assert result == expected
+        expected = 3
+        result = sql.executeUpdate("update FOOD set type=? where name=?",[foo,bar]);
+        assert result == expected
+    }
+    
+    void testFirstRow() {
+      def sql = createSql();
+      def row = sql.firstRow("select * from FOOD where type=? and name=?", ["cheese", "edam"])
+      assert row.type == "cheese"
+    }
+    
+    /** When no results, firstRow should return null */
+    void testFirstRowNoResults() {
+      def sql = createSql();
+      def row = sql.firstRow("select * from FOOD where type=?", ["nothing"])
+      assert row == null
+    }
+}
diff --git a/groovy-core/src/test/groovy/sql/SqlCompleteWithoutDataSourceTest.groovy b/groovy-core/src/test/groovy/sql/SqlCompleteWithoutDataSourceTest.groovy
new file mode 100644
index 0000000..1c84d48
--- /dev/null
+++ b/groovy-core/src/test/groovy/sql/SqlCompleteWithoutDataSourceTest.groovy
@@ -0,0 +1,17 @@
+package groovy.sql
+
+import org.axiondb.jdbc.AxionDriver
+import java.sql.DriverManager
+
+/**
+ * Tests the use of the Sql class using just a Connection 
+ * rather than a DataSource
+ */
+class SqlCompleteWithoutDataSourceTest extends SqlCompleteTest {
+    
+    protected def newSql(String uri) {
+        def driver = AxionDriver
+        println("Loading driver ${driver}")
+        return new Sql(DriverManager.getConnection(uri))
+    }
+}
diff --git a/groovy-core/src/test/groovy/sql/SqlRowsTest.groovy b/groovy-core/src/test/groovy/sql/SqlRowsTest.groovy
new file mode 100644
index 0000000..0bb1244
--- /dev/null
+++ b/groovy-core/src/test/groovy/sql/SqlRowsTest.groovy
@@ -0,0 +1,79 @@
+package groovy.sql
+
+import org.axiondb.jdbc.AxionDriver
+
+class SqlRowsTest extends TestHelper {
+
+    void testFirstRowWithPropertyName() {
+        def sql = createSql()
+
+        def results = sql.firstRow("select firstname, lastname from PERSON where id=1").firstname
+        def expected = "James"
+        assert results == expected
+    }
+
+    void testFirstRowWithPropertyNameAndParams() {
+        def sql = createSql()
+
+        def results = sql.firstRow("select firstname, lastname from PERSON where id=?", [1]).lastname
+        def expected = "Strachan"
+        assert results == expected
+    }
+
+    void testFirstRowWithPropertyNumber() {
+        def sql = createSql()
+
+        def results = sql.firstRow("select firstname, lastname from PERSON where id=1")[0]
+        def expected = "James"
+        assert results == expected
+    }
+    
+    void testFirstRowWithPropertyNumberAndParams() {
+        def sql = createSql()
+
+        def results = sql.firstRow("select firstname, lastname from PERSON where id=?", [1])[0]
+        def expected = "James"
+        assert results == expected
+    }
+    
+    void testAllRowsWithPropertyNumber() {
+        def sql = createSql()
+
+        def results = sql.rows("select firstname, lastname from PERSON where id=1 or id=2 order by id")
+        assert results[0][0] == "James"
+        assert results[0][1] == "Strachan"
+        assert results[1][0] == "Bob"
+        assert results[1][1] == "Mcwhirter"
+    }
+
+    void testAllRowsWithPropertyNumberAndParams() {
+        def sql = createSql()
+
+        def results = sql.rows("select firstname, lastname from PERSON where id=? or id=? order by id", [1,2])
+        assert results[0][0] == "James"
+        assert results[0][1] == "Strachan"
+        assert results[1][0] == "Bob"
+        assert results[1][1] == "Mcwhirter"
+    }
+
+    void testAllRowsWithPropertyName() {
+        def sql = createSql()
+
+        def results = sql.rows("select firstname, lastname from PERSON where id=1 or id=2 order by id")
+        assert results[0].firstname == "James"
+        assert results[0].lastname == "Strachan"
+        assert results[1].firstname == "Bob"
+        assert results[1].lastname == "Mcwhirter"
+    }
+
+    void testAllRowsWithPropertyNameAndParams() {
+        def sql = createSql()
+
+        def results = sql.rows("select firstname, lastname from PERSON where id=? or id=? order by id", [1,2])
+        assert results[0].firstname == "James"
+        assert results[0].lastname == "Strachan"
+        assert results[1].firstname == "Bob"
+        assert results[1].lastname == "Mcwhirter"
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/sql/SqlTest.groovy b/groovy-core/src/test/groovy/sql/SqlTest.groovy
new file mode 100644
index 0000000..910cb6f
--- /dev/null
+++ b/groovy-core/src/test/groovy/sql/SqlTest.groovy
@@ -0,0 +1,115 @@
+package groovy.sql
+
+import org.axiondb.jdbc.AxionDataSource
+
+/**
+ * This is more of a sample program than a unit test and is here as an easy
+ * to read demo of GDO. The actual full unit test case is in SqlCompleteTest
+ */
+class SqlTest extends GroovyTestCase {
+
+    void testSqlQuery() {
+        def sql = createSql()
+        
+        sql.eachRow("select * from PERSON") { println("Hello ${it.firstname} ${it.lastname}") }
+    }
+    
+    void testQueryUsingColumnIndex() {
+            def sql = createSql()
+
+            def answer = null
+
+            sql.eachRow("select count(*) from PERSON") { answer = it[0] }
+
+            println "Found the count of ${answer}"
+
+            assert answer == 3
+        }
+    
+    void testQueryUsingNegativeColumnIndex() {
+            def sql = createSql()
+
+        def first = null
+        def last = null
+
+            sql.eachRow("select firstname, lastname from PERSON where firstname='James'") { row ->
+                first = row[-2]
+                last = row[-1]
+            }
+
+            println "Found name ${first} ${last}"
+
+            assert first == "James"
+            assert last == "Strachan"
+    }
+    
+    void testSqlQueryWithWhereClause() {
+        def sql = createSql()
+        
+        def foo = "drink"
+        sql.eachRow("select * from FOOD where type=${foo}") { println("Drink ${it.name}") }
+    }
+    
+    void testSqlQueryWithWhereClauseWith2Arguments() {
+        def sql = createSql()
+        
+        def foo = "cheese"
+        def bar = "edam"
+        sql.eachRow("select * from FOOD where type=${foo} and name != ${bar}") { println("Found cheese ${it.name}") }
+    }
+    
+    void testSqlQueryWithIncorrectlyQuotedDynamicExpressions() {
+        def sql = createSql()
+        
+        def foo = "cheese"
+        def bar = "edam"
+        sql.eachRow("select * from FOOD where type='${foo}' and name != '${bar}'") { println("Found cheese ${it.name}") }
+    }
+    
+    void testDataSet() {
+        def sql = createSql()
+        
+        def people = sql.dataSet("PERSON")
+        people.each { println("Hey ${it.firstname}") }
+    }
+    
+    void testDataSetWithClosurePredicate() {
+        def sql = createSql()
+        
+        def food = sql.dataSet("FOOD")
+        food.findAll { it.type == "cheese" }.each { println("Cheese ${it.name}") }
+    }
+    
+    void testExecuteUpdate(){
+        def foo='food-drink'
+        def bar='guinness'
+        def sql = createSql();
+        def nRows = sql.executeUpdate("update FOOD set type=? where name=?",[foo,bar]);
+        if(nRows == 0){
+            sql.executeUpdate("insert into FOOD (type,name) values (${foo},${bar})");
+            }
+    }
+    
+    protected def createSql() {
+        def dataSource = new AxionDataSource("jdbc:axiondb:foo" + getMethodName())
+        def sql = new Sql(dataSource)
+        
+        sql.execute("create table PERSON ( firstname varchar, lastname varchar )")     
+        sql.execute("create table FOOD ( type varchar, name varchar)")
+        
+        // now lets populate the datasets
+        def people = sql.dataSet("PERSON")
+        people.add( firstname:"James", lastname:"Strachan" )
+        people.add( firstname:"Bob", lastname:"Mcwhirter" )
+        people.add( firstname:"Sam", lastname:"Pullara" )
+        
+        def food = sql.dataSet("FOOD")
+        food.add( type:"cheese", name:"edam" )
+        food.add( type:"cheese", name:"brie" )
+        food.add( type:"cheese", name:"cheddar" )
+        food.add( type:"drink", name:"beer" )
+        food.add( type:"drink", name:"coffee" )
+        
+        return sql
+    }
+}
diff --git a/groovy-core/src/test/groovy/sql/SqlWithBuilderTest.groovy b/groovy-core/src/test/groovy/sql/SqlWithBuilderTest.groovy
new file mode 100644
index 0000000..07175c4
--- /dev/null
+++ b/groovy-core/src/test/groovy/sql/SqlWithBuilderTest.groovy
@@ -0,0 +1,26 @@
+package groovy.sql
+
+import groovy.xml.MarkupBuilder 
+
+/**
+ * @author Brian McCallister
+ * @version $Revision$
+ */
+class SqlWithBuilderTest extends TestHelper {
+
+    void testSqlQuery() {
+         def sql = createSql()
+         println "Created ${sql}"
+        
+         def doc = new MarkupBuilder()
+        
+         doc.people {
+             sql.eachRow("select * from PERSON") {
+                 doc.person(first: it.firstname, last: it.lastname, location: it.location_name)
+             }
+         }
+        
+         sql.close()
+    }
+}
+
diff --git a/groovy-core/src/test/groovy/sql/SqlWithTypedResultsTest.groovy b/groovy-core/src/test/groovy/sql/SqlWithTypedResultsTest.groovy
new file mode 100644
index 0000000..1724416
--- /dev/null
+++ b/groovy-core/src/test/groovy/sql/SqlWithTypedResultsTest.groovy
@@ -0,0 +1,37 @@
+package groovy.sql
+
+import groovy.xml.MarkupBuilder 
+
+/**
+ * @author Thomas Heller
+ * @version $Revision$
+ */
+class SqlWithTypedResultsTest extends TestHelper {
+
+    void testSqlQuery() {
+         def sql = createEmptySql()
+         
+         sql.execute("create table groovytest ( anint integer, astring varchar )");
+
+         def groovytest = sql.dataSet("groovytest")
+         groovytest.add( anint:1, astring:"Groovy" )
+         groovytest.add( anint:2, astring:"rocks" )
+
+         // this line messes up things:
+         /** @todo this fails
+         Integer id
+		 */
+         Integer id = 0
+		 
+         sql.eachRow("SELECT * FROM groovytest ORDER BY anint") { 
+         	println "found ${it.astring} for id ${it.anint}"
+         	
+         	id = it.anint 
+         }
+
+         assert id == 2
+        
+         sql.close()
+    }
+}
+
diff --git a/groovy-core/src/test/groovy/sql/TestHelper.groovy b/groovy-core/src/test/groovy/sql/TestHelper.groovy
new file mode 100644
index 0000000..09ee741
--- /dev/null
+++ b/groovy-core/src/test/groovy/sql/TestHelper.groovy
@@ -0,0 +1,64 @@
+package groovy.sql
+
+import org.axiondb.jdbc.AxionDataSource
+
+class TestHelper extends GroovyTestCase {
+
+    static def counter = 1
+    
+    static Sql makeSql() {
+        def foo = new TestHelper()
+        return foo.createSql()
+    }
+    
+    
+    protected def createEmptySql() {
+        return newSql(getURI())
+    }
+    
+    protected def createSql() {
+        def sql = newSql(getURI())
+        
+        try {
+           sql.execute("drop table PERSON")
+           sql.execute("drop table FOOD")
+           sql.execute("drop table FEATURE")
+        } catch(Exception e){}
+        
+        sql.execute("create table PERSON ( firstname varchar, lastname varchar, id integer, location_id integer, location_name varchar )")     
+        sql.execute("create table FOOD ( type varchar, name varchar)")
+        sql.execute("create table FEATURE ( id integer, name varchar)")
+        
+        // now lets populate the datasets
+        def people = sql.dataSet("PERSON")
+        people.add( firstname:"James", lastname:"Strachan", id:1, location_id:10, location_name:'London' )
+        people.add( firstname:"Bob", lastname:"Mcwhirter", id:2, location_id:20, location_name:'Atlanta' )
+        people.add( firstname:"Sam", lastname:"Pullara", id:3, location_id:30, location_name:'California' )
+        
+        def food = sql.dataSet("FOOD")
+        food.add( type:"cheese", name:"edam" )
+        food.add( type:"cheese", name:"brie" )
+        food.add( type:"cheese", name:"cheddar" )
+        food.add( type:"drink", name:"beer" )
+        food.add( type:"drink", name:"coffee" )
+        
+        def features = sql.dataSet("FEATURE")
+        features.add( id:1, name:'GDO' )
+        features.add( id:2, name:'GPath' )
+        features.add( id:3, name:'GroovyMarkup' )
+        return sql
+    }
+    
+    protected def getURI() {
+		def answer = "jdbc:axiondb:foo"
+		def name = getMethodName()
+		if (name == null) {name = ""}
+		name += counter++
+		return answer + name
+    }
+    
+    protected def newSql(String uri) {
+	    def dataSource = new AxionDataSource(uri)
+	    return new Sql(dataSource)
+    }
+}
diff --git a/groovy-core/src/test/groovy/swing/Demo.java b/groovy-core/src/test/groovy/swing/Demo.java
new file mode 100644
index 0000000..c30c93d
--- /dev/null
+++ b/groovy-core/src/test/groovy/swing/Demo.java
@@ -0,0 +1,65 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.swing;
+
+import groovy.lang.GroovyObject;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+/**
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class Demo extends TestSupport {
+
+    public static void main(String[] args) throws Exception {
+        Demo demo = new Demo();
+        GroovyObject object = demo.compile("src/test/groovy/swing/SwingDemo.groovy");
+        object.invokeMethod("run", null);
+    }
+}
diff --git a/groovy-core/src/test/groovy/swing/MyTableModel.java b/groovy-core/src/test/groovy/swing/MyTableModel.java
new file mode 100644
index 0000000..c4ae050
--- /dev/null
+++ b/groovy-core/src/test/groovy/swing/MyTableModel.java
@@ -0,0 +1,106 @@
+package groovy.swing;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.swing.table.AbstractTableModel;
+
+/** 
+ * A sample table model
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MyTableModel extends AbstractTableModel {
+
+    private static final Logger log = Logger.getLogger(MyTableModel.class.getName());
+
+    public MyTableModel() {
+    }
+
+    final String[] columnNames = { "First Name", "Last Name", "Sport", "# of Years", "Vegetarian" };
+    final Object[][] data = { { "Mary", "Campione", "Snowboarding", new Integer(5), new Boolean(false)}, {
+            "Alison", "Huml", "Rowing", new Integer(3), new Boolean(true)
+            }, {
+            "Kathy", "Walrath", "Chasing toddlers", new Integer(2), new Boolean(false)
+            }, {
+            "Mark", "Andrews", "Speed reading", new Integer(20), new Boolean(true)
+            }, {
+            "Angela", "Lih", "Teaching high school", new Integer(4), new Boolean(false)
+            }
+    };
+
+    public int getColumnCount() {
+        return columnNames.length;
+    }
+
+    public int getRowCount() {
+        return data.length;
+    }
+
+    public String getColumnName(int col) {
+        return columnNames[col];
+    }
+
+    public Object getValueAt(int row, int col) {
+        return data[row][col];
+    }
+
+    /*
+     * JTable uses this method to determine the default renderer/
+     * editor for each cell.  If we didn't implement this method,
+     * then the last column would contain text ("true"/"false"),
+     * rather than a check box.
+     */
+    public Class getColumnClass(int c) {
+        return getValueAt(0, c).getClass();
+    }
+
+    /*
+     * Don't need to implement this method unless your table's
+     * editable.
+     */
+    public boolean isCellEditable(int row, int col) {
+        //Note that the data/cell address is constant,
+        //no matter where the cell appears onscreen.
+        if (col < 2) {
+            return false;
+        }
+        else {
+            return true;
+        }
+    }
+
+    /*
+     * Don't need to implement this method unless your table's
+     * data can change.
+     */
+    public void setValueAt(Object value, int row, int col) {
+        if (log.isLoggable(Level.FINE)) {
+            log.fine(
+                "Setting value at " + row + "," + col + " to " + value + " (an instance of " + value.getClass() + ")");
+        }
+
+        if (data[0][col] instanceof Integer && !(value instanceof Integer)) {
+            //With JFC/Swing 1.1 and JDK 1.2, we need to create    
+            //an Integer from the value; otherwise, the column     
+            //switches to contain Strings.  Starting with v 1.3,   
+            //the table automatically converts value to an Integer,
+            //so you only need the code in the 'else' part of this 
+            //'if' block.                                          
+            //XXX: See TableEditDemo.java for a better solution!!!
+            try {
+                data[row][col] = new Integer(value.toString());
+                fireTableCellUpdated(row, col);
+            }
+            catch (NumberFormatException e) {
+                log.log(Level.SEVERE, "The \"" + getColumnName(col) + "\" column accepts only integer values.");
+            }
+        }
+        else {
+            data[row][col] = value;
+            fireTableCellUpdated(row, col);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/swing/SwingDemo.groovy b/groovy-core/src/test/groovy/swing/SwingDemo.groovy
new file mode 100644
index 0000000..e895539
--- /dev/null
+++ b/groovy-core/src/test/groovy/swing/SwingDemo.groovy
@@ -0,0 +1,105 @@
+package groovy.swing
+
+import java.awt.BorderLayout
+import javax.swing.BorderFactory
+import groovy.model.MvcDemo
+
+class SwingDemo {
+
+    def swing = new SwingBuilder()
+    def frame
+    
+    static void main(args) {
+        def demo = new SwingDemo()
+        demo.run()
+    }
+
+    void run() {
+        def frame = swing.frame(
+            title:'This is a Frame',
+            location:[100,100],
+            size:[800,400],
+            defaultCloseOperation:javax.swing.WindowConstants.EXIT_ON_CLOSE) {
+
+            menuBar {
+                menu(text:'File') {
+                    menuItem() {
+                        action(name:'New', closure:{ println("clicked on the new menu item!") })
+                    }
+                    menuItem() {
+                        action(name:'Open', closure:{ println("clicked on the open menu item!") })
+                    }
+                    separator()
+                    menuItem() {
+                        action(name:'Save', enabled:false, closure:{ println("clicked on the Save menu item!") })
+                    }
+                }
+                menu(text:'Demos') {
+                    menuItem() {
+                        action(name:'Simple TableModel Demo', closure:{ showGroovyTableDemo() })
+                    }
+                    menuItem() {
+                        action(name:'MVC Demo', closure:{ showMVCDemo() })
+                    }
+                    menuItem() {
+                        action(name:'TableLayout Demo', closure:{ showTableLayoutDemo() })
+                    }
+                }
+                menu(text:'Help') {
+                    menuItem() {
+                        action(name:'About', closure:{ showAbout() })
+                    }
+                }
+            }
+            splitPane {
+                panel(layout:new BorderLayout(), border:BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), 'titled border')) {
+                    vbox(constraints:BorderLayout.NORTH) {
+                        panel(layout:new BorderLayout()) {
+                            label(text:'Name', constraints:BorderLayout.WEST, toolTipText:'This is the name field')
+                            textField(text:'James', constraints:BorderLayout.CENTER, toolTipText:'Enter the name into this field')
+                        }
+                        panel(layout:new BorderLayout()) {
+                            label(text:'Location', constraints:BorderLayout.WEST, toolTipText:'This is the location field')
+                            comboBox(items:['Atlanta', 'London', 'New York'], constraints:BorderLayout.CENTER, toolTipText:'Choose the location into this field')
+                        }
+                        button(text:'Click Me', actionPerformed:{event -> println("closure fired with event: " + event) })
+                    }
+                    scrollPane(constraints:BorderLayout.CENTER, border:BorderFactory.createRaisedBevelBorder()) {
+                        textArea(text:'Some text goes here', toolTipText:'This is a large text area to type in text')
+                    }
+                }
+                scrollPane {
+                    table(model:new MyTableModel())
+                }
+            }
+        }
+        frame.show()
+    }
+    
+    void showAbout() {
+        // this version doesn't auto-size & position the dialog
+        /*
+        def dialog = swing.dialog(owner:frame, title:'About GroovySwing') {
+            optionPane(message:'Welcome to the wonderful world of GroovySwing')
+        }
+        */
+         def pane = swing.optionPane(message:'Welcome to the wonderful world of GroovySwing')
+         def dialog = pane.createDialog(frame, 'About GroovySwing')
+         dialog.show()
+    }
+    
+    void showGroovyTableDemo() {
+        def demo = new TableDemo()
+        demo.run()
+    }
+
+    void showMVCDemo() {
+        def demo = new MvcDemo()
+        demo.run()
+    }
+
+    void showTableLayoutDemo() {
+        def demo = new TableLayoutDemo()
+        demo.run()
+    }
+}
diff --git a/groovy-core/src/test/groovy/swing/TableDemo.groovy b/groovy-core/src/test/groovy/swing/TableDemo.groovy
new file mode 100644
index 0000000..a41f683
--- /dev/null
+++ b/groovy-core/src/test/groovy/swing/TableDemo.groovy
@@ -0,0 +1,52 @@
+package groovy.swing
+
+import java.awt.BorderLayout
+import javax.swing.BorderFactory
+
+/**
+ * Demonstrates the use of the Groovy TableModels for viewing tables of any List of objects
+ */
+class TableDemo {
+    
+    // properties
+    def frame
+    def swing
+    
+    static void main(args) {
+        def demo = new TableDemo()
+        demo.run()
+    }
+    
+    void run() {
+        swing = new SwingBuilder()
+        
+        frame = swing.frame(title:'Groovy TableModel Demo', location:[200,200], size:[300,200]) {
+            menuBar {
+                menu(text:'Help') {
+                    menuItem() {
+                        action(name:'About', closure:{ showAbout() })
+                    }
+                }
+            }
+            panel(layout:new BorderLayout()) {
+                scrollPane(constraints:BorderLayout.CENTER) {
+                    table() {
+                        def model = [['name':'James', 'location':'London'], ['name':'Bob', 'location':'Atlanta'], ['name':'Geir', 'location':'New York']]
+
+                        tableModel(list:model) {
+                            closureColumn(header:'Name', read:{row -> return row.name})
+                            closureColumn(header:'Location', read:{row -> return row.location})
+                        }
+                    }
+                }
+            }
+        }
+        frame.show()
+    }
+    
+    void showAbout() {
+         def pane = swing.optionPane(message:'This demo shows how GroovySwing can use Groovy closures to create simple table models')
+         def dialog = pane.createDialog(frame, 'About GroovySwing')
+         dialog.show()
+    }
+}
diff --git a/groovy-core/src/test/groovy/swing/TableLayoutDemo.groovy b/groovy-core/src/test/groovy/swing/TableLayoutDemo.groovy
new file mode 100644
index 0000000..f63ccf6
--- /dev/null
+++ b/groovy-core/src/test/groovy/swing/TableLayoutDemo.groovy
@@ -0,0 +1,57 @@
+package groovy.swing
+
+import java.awt.BorderLayout
+import javax.swing.BorderFactory
+
+/**
+ * Demonstrates the use of the table layout
+ */
+class TableLayoutDemo {
+    
+    def frame
+    def swing
+    
+    void run() {
+        swing = new SwingBuilder()
+        
+        frame = swing.frame(title:'TableLayout Demo', location:[200,200], size:[300,200]) {
+            menuBar {
+                menu(text:'Help') {
+                    menuItem() {
+                        action(name:'About', closure:{ showAbout() })
+                    }
+                }
+            }
+            tableLayout {
+                tr {
+                    td {
+                        label(text:'name')
+                    }
+                    td(colfill:true) {
+                        textField(text:'James')
+                    }
+                }
+                tr {
+                    td {
+                        label(text:'location')
+                    }
+                    td(colfill:true) {
+                        textField(text:'London')
+                    }
+                }
+                tr {
+                    td(colspan:2, align:'center') {
+                        button(text:'OK')
+                    }
+                }
+            }
+        }
+        frame.show()
+    }
+    
+    void showAbout() {
+         def pane = swing.optionPane(message:'This demo shows how you can use HTML style table layouts with Swing components')
+         def dialog = pane.createDialog(frame, 'About TableLayout Demo')
+         dialog.show()
+    }
+}
diff --git a/groovy-core/src/test/groovy/text/SimpleTemplateTest.groovy b/groovy-core/src/test/groovy/text/SimpleTemplateTest.groovy
new file mode 100644
index 0000000..207828a
--- /dev/null
+++ b/groovy-core/src/test/groovy/text/SimpleTemplateTest.groovy
@@ -0,0 +1,58 @@
+package groovy.text
+
+class SimpleTemplateTest extends GroovyTestCase {
+
+    void testSimpleCallFromGroovyEmpty() {
+        assertEquals('', simpleCall(''))
+    }
+
+    void testSimpleCallFromGroovyStatic() {
+        def input = 'some static text'
+        assertEquals(input, simpleCall(input))
+    }
+
+    void testExpressionAssign() {
+        assertEquals('1',   simpleCall('<%=1%>'))
+        assertEquals(' 1',  simpleCall(' <%=1%>'))
+        assertEquals(' 1 ', simpleCall(' <%=1%> '))
+        assertEquals(' 1 ', simpleCall(' <%= 1%> '))
+        assertEquals(' 1 ', simpleCall(' <%= 1 %> '))
+        assertEquals(' 1 ', simpleCall(" <%=\n 1 \n%> "))
+        assertEquals(' 1', bindingCall([a:1],' <%=a%>'))
+    }
+
+    void testExpressionEval() {
+        assertEquals('1', simpleCall('<%print(1)%>'))
+        assertEquals('01', simpleCall('<%for(i in 0..1){print(i)}%>'))
+    }
+
+    void testWithMarkupBuilder(){
+    def text = '''<%
+        builder = new groovy.xml.MarkupBuilder(out)
+        [1,2,3].each{ count ->
+            out.print(1)
+        }
+    %>'''
+    assertEquals('111', simpleCall(text))
+    }
+
+    void testWithMarkupBuilderWithSemicolons(){
+    def text = '''<%
+        builder = new groovy.xml.MarkupBuilder(out);
+        [1,2,3].each{ count ->
+            out.print(1);
+        }
+    %>'''
+    assertEquals('111', simpleCall(text))
+    }
+
+    String simpleCall(input){
+        bindingCall([:], input)
+    }
+
+    String bindingCall(binding, input){
+        def template = new SimpleTemplateEngine(true).createTemplate(input)
+        return template.make(binding).toString()
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/text/TemplateTest.java b/groovy-core/src/test/groovy/text/TemplateTest.java
new file mode 100644
index 0000000..a067424
--- /dev/null
+++ b/groovy-core/src/test/groovy/text/TemplateTest.java
@@ -0,0 +1,70 @@
+/*
+ * $Id$version Mar 8, 2004 1:36:31 AM $user Exp $
+ * 
+ * Copyright 2003 (C) Sam Pullara. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package groovy.text;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+import org.codehaus.groovy.control.CompilationFailedException;
+
+/**
+ * @author sam
+ */
+public class TemplateTest extends TestCase {
+
+    public void testMixedTemplateText() throws CompilationFailedException, ClassNotFoundException, IOException {
+        Template template1 = new SimpleTemplateEngine().createTemplate("<%= \"test\" %> of expr and <% test = 1 %>${test} script.");
+        assertEquals("test of expr and 1 script.", template1.make().toString());
+
+        Template template2 = new GStringTemplateEngine().createTemplate("<%= \"test\" %> of expr and <% test = 1 %>${test} script.");
+        assertEquals("test of expr and 1 script.", template2.make().toString());
+
+    }
+
+    public void testBinding() throws CompilationFailedException, ClassNotFoundException, IOException {
+        Map binding = new HashMap();
+        binding.put("sam", "pullara");
+
+        Template template1 = new SimpleTemplateEngine().createTemplate("<%= sam %><% print sam %>");
+        assertEquals("pullarapullara", template1.make(binding).toString());
+
+        Template template2 = new GStringTemplateEngine().createTemplate("<%= sam %><% out << sam %>");
+        assertEquals("pullarapullara", template2.make(binding).toString());
+
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/text/XmlTemplateEngineTest.java b/groovy-core/src/test/groovy/text/XmlTemplateEngineTest.java
new file mode 100644
index 0000000..51bcb04
--- /dev/null
+++ b/groovy-core/src/test/groovy/text/XmlTemplateEngineTest.java
@@ -0,0 +1,30 @@
+package groovy.text;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import junit.framework.TestCase;
+
+public class XmlTemplateEngineTest extends TestCase {
+
+    public void testBinding() throws Exception {
+        Map binding = new HashMap();
+        binding.put("Christian", "Stein");
+
+        XmlTemplateEngine xmlTemplateEngine = new XmlTemplateEngine();
+        String xmlScript = "<!-- Just a comment. -->\n" //
+                + "<xml xmlns:gsp=\"http://groovy.codehaus.org/2005/gsp\">" //
+                + "  ${Christian}" //
+                + "  <gsp:expression>Christian</gsp:expression>" //
+                + "  <gsp:scriptlet>println Christian</gsp:scriptlet>" //
+                + "</xml>";
+        String xmlResult = "<xml>\n" //
+                + "  Stein\n" //
+                + xmlTemplateEngine.getIndention() + "Stein\n" //
+                + "Stein" + System.getProperty("line.separator") //
+                + "</xml>\n";
+        Template template = xmlTemplateEngine.createTemplate(xmlScript);
+        assertEquals(xmlResult, template.make(binding).toString());
+    }
+    
+}
diff --git a/groovy-core/src/test/groovy/tree/ClosureClassLoaderBug.groovy b/groovy-core/src/test/groovy/tree/ClosureClassLoaderBug.groovy
new file mode 100644
index 0000000..5f12ee2
--- /dev/null
+++ b/groovy-core/src/test/groovy/tree/ClosureClassLoaderBug.groovy
@@ -0,0 +1,14 @@
+class ClosureClassLoaderBug extends GroovyTestCase {
+    def b
+    def EXPECTED = 'root1[attributes={}; value=[elem1[attributes={}; value=hello1]]]'
+
+    void testTree() {
+        b = NodeBuilder.newInstance()
+        
+        def root = b.root1( {
+            b.elem1('hello1')
+        })
+        
+        assert EXPECTED == root.toString()
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/tree/NavigationTest.groovy b/groovy-core/src/test/groovy/tree/NavigationTest.groovy
new file mode 100644
index 0000000..33bd007
--- /dev/null
+++ b/groovy-core/src/test/groovy/tree/NavigationTest.groovy
@@ -0,0 +1,49 @@
+
+
+/**
+ * Simple test of tree walking
+ */
+class NavigationTest extends GroovyTestCase {
+    
+    void testDepthFirst() {
+        def tree = createTree()
+        
+        def names = tree.depthFirst().collect { it.name() }
+        def expected = ['a', 'b1', 'b2', 'c1', 'c2', 'b3', 'b4', 'c3', 'c4', 'b5']
+        
+        assert names == expected
+    }
+    
+    void testBredthFirst() {
+        def tree = createTree()
+        
+        def names = tree.breadthFirst().collect { it.name() }
+        def expected = ['a', 'b1', 'b2', 'b3', 'b4', 'b5', 'c1', 'c2', 'c3', 'c4']
+        
+        assert names == expected
+    }
+    
+    protected def createTree() {       
+        def b = NodeBuilder.newInstance()
+        
+        def root = b.a(a:5, b:7) {
+            b1()
+            b2 {
+                c1()
+                c2()
+            }
+            b3()
+            b4 {
+                c3()
+                c4()
+            }
+            b5()
+        }
+        
+        assert root != null
+        
+        println(root)
+        
+        return root
+    }
+}
diff --git a/groovy-core/src/test/groovy/tree/NestedClosureBugTest.groovy b/groovy-core/src/test/groovy/tree/NestedClosureBugTest.groovy
new file mode 100644
index 0000000..6bed414
--- /dev/null
+++ b/groovy-core/src/test/groovy/tree/NestedClosureBugTest.groovy
@@ -0,0 +1,19 @@
+/**
+ * Test case for a bug with nested closures
+ */
+class NestedClosureBugTest extends GroovyTestCase {
+    def b
+    def EXPECTED = 'root[attributes={a=xyz}; value=[child[attributes={}; value=[grandChild[attributes={}; value=[]]]]]]'
+
+    void testNestedClosureBug() {
+        b = NodeBuilder.newInstance()
+        
+        def root = b.root(['a':'xyz'], {
+            b.child({
+                b.grandChild()  
+            })
+        })
+
+        assert EXPECTED == root.toString()
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/tree/NodePrinterTest.java b/groovy-core/src/test/groovy/tree/NodePrinterTest.java
new file mode 100644
index 0000000..bff218e
--- /dev/null
+++ b/groovy-core/src/test/groovy/tree/NodePrinterTest.java
@@ -0,0 +1,96 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.tree;
+
+import java.util.logging.Logger;
+
+import groovy.lang.GroovyObject;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+/**
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class NodePrinterTest extends TestSupport {
+
+    public void testTree() throws Exception {
+        GroovyObject object = compile("src/test/groovy/tree/TreeTest.groovy");
+        object.invokeMethod("testTree", null);
+    }
+
+    public void testVerboseTree() throws Exception {
+        GroovyObject object = compile("src/test/groovy/tree/VerboseTreeTest.groovy");
+        object.invokeMethod("testTree", null);
+    }
+
+    public void testSmallTree() throws Exception {
+        GroovyObject object = compile("src/test/groovy/tree/SmallTreeTest.groovy");
+        object.invokeMethod("testTree", null);
+    }
+
+    public void testLittleClosure() throws Exception {
+        GroovyObject object = compile("src/test/groovy/LittleClosureTest.groovy");
+        object.invokeMethod("testClosure", null);
+    }
+    
+    public void testNestedClosureBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/tree/NestedClosureBugTest.groovy");
+        object.invokeMethod("testNestedClosureBug", null);
+    }
+    
+    public void testClosureClassLoaderBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/tree/ClosureClassLoaderBug.groovy");
+        object.invokeMethod("testTree", null);
+    }
+    
+    public void testLogging() {
+        Logger log = Logger.getLogger(getClass().getName());
+        log.info("Logging using JDK 1.4 logging");
+    }
+}
diff --git a/groovy-core/src/test/groovy/tree/SmallTreeTest.groovy b/groovy-core/src/test/groovy/tree/SmallTreeTest.groovy
new file mode 100644
index 0000000..56c3652
--- /dev/null
+++ b/groovy-core/src/test/groovy/tree/SmallTreeTest.groovy
@@ -0,0 +1,16 @@
+class SmallTreeTest extends GroovyTestCase {
+    def b
+    def EXPECTED = 'root1[attributes={}; value=[elem1[attributes={}; value=hello1]]]'
+
+    void testTree() {
+        b = NodeBuilder.newInstance()
+        
+        def root = b.root1( {
+            elem1('hello1')
+        })
+        
+        assert root != null
+        
+        assert EXPECTED == root.toString()
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/tree/TreeTest.groovy b/groovy-core/src/test/groovy/tree/TreeTest.groovy
new file mode 100644
index 0000000..037c32e
--- /dev/null
+++ b/groovy-core/src/test/groovy/tree/TreeTest.groovy
@@ -0,0 +1,77 @@
+/**
+ * This test uses the concise GroovyMarkup syntax to test the building of trees
+ */
+class TreeTest extends GroovyTestCase {
+    
+    void testSmallTree() {
+        def b = NodeBuilder.newInstance()
+        
+        def root = b.root1(a:5, b:7) {
+            elem1('hello1')
+            elem2('hello2')
+            elem3(x:7)
+        }
+        
+        assert root != null
+        
+        print(root)
+    }
+    
+    void testTree() {
+        def b = NodeBuilder.newInstance()
+        
+        def root = b.root2(a:5, b:7) {
+            elem1('hello1')
+            elem2('hello2')
+            nestedElem(x:'abc', y:'def') {
+                child(z:'def')
+                child2()  
+            }
+            
+            nestedElem2(z:'zzz') {
+                child(z:'def')
+                child2("hello")  
+            }
+        }
+        
+        assert root != null
+        
+        print(root)
+
+        def e1 = root.elem1.get(0)
+        assert e1.value() == 'hello1'
+        
+        def e2 = root.elem2.get(0)
+        assert e2.value() == 'hello2'
+
+        assert root.elem1.get(0).value() == 'hello1'
+        assert root.elem2.get(0).value() == 'hello2'
+
+        assert root.nestedElem.get(0).attributes() == ['x':'abc', 'y':'def']        
+        assert root.nestedElem.child.get(0).attributes() == ['z':'def']
+        
+        assert root.nestedElem.child2.get(0).value() == []
+        assert root.nestedElem.child2.get(0).text() == ''
+
+        assert root.nestedElem2.get(0).attributes() == ['z':'zzz']      
+        assert root.nestedElem2.child.get(0).attributes() == ['z':'def']
+        assert root.nestedElem2.child2.get(0).value() == 'hello'
+        assert root.nestedElem2.child2.get(0).text() == 'hello'
+        
+        def list = root.value()
+        assert list.size() == 4
+
+        assert root.attributes().a == 5
+        assert root.attributes().b == 7
+        
+        assert root.nestedElem.get(0).attributes().x == 'abc'
+        assert root.nestedElem.get(0).attributes().y == 'def'
+        assert root.nestedElem2.get(0).attributes().z == 'zzz'
+        assert root.nestedElem2.child.get(0).attributes().z == 'def'
+        
+        /** @todo parser add .@ as an operation
+                assert root.@a == 5
+                assert root.@b == 7
+        */        
+    }
+}
diff --git a/groovy-core/src/test/groovy/tree/VerboseTreeTest.groovy b/groovy-core/src/test/groovy/tree/VerboseTreeTest.groovy
new file mode 100644
index 0000000..b5049e8
--- /dev/null
+++ b/groovy-core/src/test/groovy/tree/VerboseTreeTest.groovy
@@ -0,0 +1,80 @@
+/**
+ * This test uses the verbose syntax to test the building of trees
+ * using GroovyMarkup
+ */
+class VerboseTreeTest extends GroovyTestCase {
+    
+    def b
+
+    void testSmallTree() {
+        b = NodeBuilder.newInstance()
+        
+        def root = b.root1(['a':5, 'b':7], {
+            elem1('hello1')
+            elem2('hello2')
+            elem3(['x':7])
+        })
+        
+        assert root != null
+        
+        print(root)
+    }
+    
+    void testTree() {
+        b = NodeBuilder.newInstance()
+        
+        def root = b.root2(['a':5, 'b':7], {
+            elem1('hello1')
+            elem2('hello2')
+            nestedElem(['x':'abc', 'y':'def'], {
+                child(['z':'def'])
+                child2()  
+            })
+            
+            nestedElem2(['z':'zzz'], {
+                child(['z':'def'])
+                child2("hello")  
+            })
+        })
+        
+        assert root != null
+        
+        print(root)
+
+        def e1 = root.elem1.get(0)
+        assert e1.value() == 'hello1'
+        
+        def e2 = root.elem2.get(0)
+        assert e2.value() == 'hello2'
+
+        assert root.elem1.get(0).value() == 'hello1'
+        assert root.elem2.get(0).value() == 'hello2'
+
+        assert root.nestedElem.get(0).attributes() == ['x':'abc', 'y':'def']        
+        assert root.nestedElem.child.get(0).attributes() == ['z':'def']
+        
+        assert root.nestedElem.child2.get(0).value() == []
+        assert root.nestedElem.child2.get(0).text() == ''
+
+        assert root.nestedElem2.get(0).attributes() == ['z':'zzz']      
+        assert root.nestedElem2.child.get(0).attributes() == ['z':'def']
+        assert root.nestedElem2.child2.get(0).value() == 'hello'
+        assert root.nestedElem2.child2.get(0).text() == 'hello'
+        
+        def list = root.value()
+        assert list.size() == 4
+
+        assert root.attributes().a == 5
+        assert root.attributes().b == 7
+        
+        assert root.nestedElem.get(0).attributes().x == 'abc'
+        assert root.nestedElem.get(0).attributes().y == 'def'
+        assert root.nestedElem2.get(0).attributes().z == 'zzz'
+        assert root.nestedElem2.child.get(0).attributes().z == 'def'
+        
+        /** @todo parser add .@ as an operation
+                assert root.@a == 5
+                assert root.@b == 7
+        */        
+    }
+}
diff --git a/groovy-core/src/test/groovy/txn/TransactionBean.java b/groovy-core/src/test/groovy/txn/TransactionBean.java
new file mode 100644
index 0000000..c06fc79
--- /dev/null
+++ b/groovy-core/src/test/groovy/txn/TransactionBean.java
@@ -0,0 +1,37 @@
+package groovy.txn;
+
+import groovy.lang.Closure;
+
+/**
+ * @author James Strachan
+ * @version $Revision$
+ */
+public class TransactionBean {
+    private Closure run;
+    private Closure onError;
+    private Closure onSuccess;
+    
+    public Closure run() {
+        return run;
+    }
+    
+    public Closure onError() {
+        return onError;
+    }
+    
+    public Closure onSuccess() {
+        return onSuccess;
+    }
+    
+    public void run(Closure run) {
+        this.run = run;
+    }
+    
+    public void onError(Closure onError) {
+        this.onError = onError;
+    }
+    
+    public void onSuccess(Closure onSuccess) {
+        this.onSuccess = onSuccess;
+    }
+}
diff --git a/groovy-core/src/test/groovy/txn/TransactionBuilder.java b/groovy-core/src/test/groovy/txn/TransactionBuilder.java
new file mode 100644
index 0000000..c85406c
--- /dev/null
+++ b/groovy-core/src/test/groovy/txn/TransactionBuilder.java
@@ -0,0 +1,24 @@
+package groovy.txn;
+
+import groovy.lang.Closure;
+
+/**
+ * @author James Strachan
+ * @version $Revision$
+ */
+public class TransactionBuilder {
+    public void transaction(Closure closure) {
+        TransactionBean bean = new TransactionBean();
+        closure.setDelegate(bean);
+        closure.call(this);
+        
+        // lets call the closures now
+        System.out.println("Performing normal transaction");
+        bean.run().call(this);
+        bean.onSuccess().call(this);
+        
+        System.out.println("Performing error transaction");
+        bean.run().call(this);
+        bean.onError().call(this);
+    }
+}
diff --git a/groovy-core/src/test/groovy/txn/TransactionTest.groovy b/groovy-core/src/test/groovy/txn/TransactionTest.groovy
new file mode 100644
index 0000000..3e5b9b7
--- /dev/null
+++ b/groovy-core/src/test/groovy/txn/TransactionTest.groovy
@@ -0,0 +1,20 @@
+package groovy.txn
+
+class TransactionTest extends GroovyTestCase {
+
+    void testTxn() {
+		def builder = new TransactionBuilder()
+		builder.transaction {
+		    run {
+		        println("run code!")
+		    }
+		    onError {
+                println("on error!")
+		    }
+		    onSuccess {
+                println("on success!")
+		    }
+		}
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/util/AllTestSuiteTest.groovy b/groovy-core/src/test/groovy/util/AllTestSuiteTest.groovy
new file mode 100644
index 0000000..62f6fb1
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/AllTestSuiteTest.groovy
@@ -0,0 +1,53 @@
+package groovy.util
+
+import java.util.logging.Level
+import junit.framework.Test
+
+/**
+    Testing groovy.util.AllTestSuite.
+    The suite() method must properly collect Test files under the given dir and pattern,
+    add found files to the log,
+    produce a proper TestSuite,
+    and wrap Scripts into TestCases.
+    @author Dierk Koenig
+*/
+class AllTestSuiteTest extends GroovyLogTestCase {
+
+    def suite
+
+    void setUp() {
+        suite = null
+    }
+
+    void testSuiteForThisFileOnly() {
+        def result = stringLog(Level.FINEST, 'groovy.util.AllTestSuite') {
+            withProps('src/test/groovy/util','AllTestSuiteTest.groovy') {
+                suite = AllTestSuite.suite()
+            }
+        }
+        assertTrue result, result.contains('AllTestSuiteTest.groovy')
+        assertEquals 1+1, result.count("\n")   // only one entry in the log
+        assert suite, 'Resulting suite should not be null'
+        assertEquals 2, suite.countTestCases() // the 2 test methods in this file
+    }
+
+    void testAddingScriptsThatDoNotInheritFromTestCase() {
+        withProps('src/test/groovy/util','suite/*.groovy') {
+            suite = AllTestSuite.suite()
+        }
+        assert suite
+        assertEquals 1, suite.countTestCases()
+        suite.testAt(0) // call the contained Script to makes sure it is testable
+    }
+
+    /** store old System property values for not overriding them accidentally */
+    void withProps(dir, pattern, yield) {
+        String olddir = System.properties.'groovy.test.dir'
+        String oldpat = System.properties.'groovy.test.pattern'
+        System.properties.'groovy.test.dir' = dir
+        System.properties.'groovy.test.pattern' = pattern
+        yield()
+        if (olddir) System.properties.'groovy.test.dir' = olddir
+        if (oldpat) System.properties.'groovy.test.pattern' = oldpat
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/util/AntTest.groovy b/groovy-core/src/test/groovy/util/AntTest.groovy
new file mode 100644
index 0000000..d929b2a
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/AntTest.groovy
@@ -0,0 +1,171 @@
+package groovy.util
+
+import java.io.File
+import org.apache.tools.ant.Project
+import org.apache.tools.ant.ProjectHelper
+import groovy.xml.NamespaceBuilder
+
+
+class AntTest extends GroovyTestCase {
+    
+    void testAnt() {
+        def ant = new AntBuilder()
+
+        // lets just call one task
+        ant.echo("hello")
+        
+        // here"s an example of a block of Ant inside GroovyMarkup
+        ant.sequential {
+            echo("inside sequential")
+            
+            def myDir = "target/AntTest/"
+            
+            mkdir(dir:myDir) 
+            copy(todir:myDir) {
+                fileset(dir:"src/test") {
+                    include(name:"**/*.groovy")
+                }
+            }
+            
+            echo("done")
+        }
+        
+        // now lets do some normal Groovy again
+        def file = new File("target/AntTest/groovy/util/AntTest.groovy")
+        assert file.exists()
+    }
+    
+    void testFileIteration() {
+        def ant = new AntBuilder()
+        
+        // lets create a scanner of filesets
+        def scanner = ant.fileScanner {
+            fileset(dir:"src/test") {
+                include(name:"**/Ant*.groovy")
+            }
+        }
+        
+        // now lets iterate over 
+        def found = false
+        for (f in scanner) {
+            println("Found file ${f}")
+            
+            found = true
+            
+            assert f instanceof File
+            assert f.name.endsWith(".groovy")
+        }
+        assert found
+    }
+    
+    void testJunitTask() {
+        def ant = new AntBuilder()
+        
+        ant.junit {
+            test(name:'groovy.util.SomethingThatDoesNotExist')
+        }
+    }
+    
+    void testPathBuilding() {
+        def ant = new AntBuilder()
+        
+        def value = ant.path {
+            fileset(dir:"xdocs") {
+                include(name:"*.wiki")
+            }
+        }
+
+        assert value != null
+        assertEquals org.apache.tools.ant.types.Path, value.getClass()
+    }
+
+    void testTaskContainerExecutionSequence() {
+        SpoofTaskContainer.getSpoof().length = 0
+
+        def antFile = new File("src/test/groovy/util/AntTest.xml")
+        assertTrue "Couldn't find ant test script", antFile.exists()
+
+		// run it with ant, to be sure that our assumptions are correct
+		def project = new Project()
+		project.init()
+		ProjectHelper.projectHelper.parse(project, antFile)
+		project.executeTarget(project.defaultTarget);
+		
+        def expectedSpoof =
+"""SpoofTaskContainer ctor
+in addTask
+configuring UnknownElement
+SpoofTask ctor
+begin SpoofTaskContainer execute
+begin SpoofTask execute
+tag name from wrapper: spoof
+attributes map from wrapper: ["foo":"123"]
+param foo: 123
+end SpoofTask execute
+end SpoofTaskContainer execute
+"""
+		println SpoofTaskContainer.getSpoof().toString()
+        assertEquals expectedSpoof, SpoofTaskContainer.getSpoof().toString()
+        SpoofTaskContainer.spoof.length = 0
+
+        def ant = new AntBuilder()
+        def PATH = 'task.path'
+
+		// and now run it with the AntBuilder        
+        ant.path(id:PATH) {ant.pathelement(location:'classes')}
+        ['spoofcontainer': SpoofTaskContainer, 'spoof': SpoofTask].each{ pair ->
+            ant.taskdef(name:pair.key, classname: pair.value.name, classpathref: PATH)
+        }
+        ant.spoofcontainer(){
+            ant.spoof(foo: 123)
+        }
+        assertEquals expectedSpoof, SpoofTaskContainer.getSpoof().toString()
+        
+        // now run it with AntBuilder using Namespaces (test for GROOVY-1070)
+        def antNS = new AntBuilder()
+        SpoofTaskContainer.resetSpoof()
+
+		// and now run it with the AntBuilder        
+        antNS.path(id:PATH) {antNS.pathelement(location:'classes')}
+        ['spoofcontainer': SpoofTaskContainer, 'spoof': SpoofTask].each{ pair ->
+            antNS.taskdef(name:pair.key, classname: pair.value.name, classpathref: PATH, 
+                          uri: 'testNS')
+        }
+		def testNS = NamespaceBuilder.newInstance(antNS,"testNS","testNSprefix");
+        testNS.spoofcontainer(){
+            testNS.spoof(foo: 123)
+        }
+        assertEquals expectedSpoof, SpoofTaskContainer.getSpoof().toString()
+    }
+
+    /** Checks that we can access dynamically (through Ant's property task) defined properties in Groovy scriptlets */
+    void testDynamicProperties() {
+        def antBuilder = new AntBuilder()
+
+        antBuilder.property(name: "testProp1", value: "TEST 1")
+        antBuilder.taskdef(name:"groovy", classname:"org.codehaus.groovy.ant.Groovy")
+        antBuilder.groovy("""
+            ant.property(name: "testProp2", value: "TEST 2")
+
+            assert properties.testProp1 == project.properties.testProp1
+            assert properties.testProp2 == project.properties.testProp2
+        """)
+    }
+    
+    /**
+    * Tests that the AntBuilder can handle conditions (conditions aren't tasks)
+    * (test for GROOVY-824)
+    */
+    void testCondition() {
+        def ant = new AntBuilder()
+        ant.condition(property: "containsHi") {
+        	contains([string: "hi", substring: "hi"])
+        }
+        assertEquals "true", ant.project.properties["containsHi"]
+
+        ant.condition(property: "equalsHi", else: "false") {
+        	Equals([arg1: "hi", arg2: "bye"])
+        }
+        assertEquals "false", ant.project.properties["equalsHi"]
+    }
+}
diff --git a/groovy-core/src/test/groovy/util/AntTest.xml b/groovy-core/src/test/groovy/util/AntTest.xml
new file mode 100755
index 0000000..9f917e2
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/AntTest.xml
@@ -0,0 +1,18 @@
+<!-- 
+does exactly the same as the AntBuilder in AntTest... just to be sure that ant behaves the same
+as what we expect from the AntBuilder
+ -->
+<project name="test" default="full">
+
+  <target name="full">
+    <path id="task.path">
+      <pathelement location="classes"/>
+    </path>
+  	<taskdef name="spoofcontainer" classname="groovy.util.SpoofTaskContainer" classpathref="task.path"/>
+  	<taskdef name="spoof" classname="groovy.util.SpoofTask" classpathref="task.path"/>
+
+    <spoofcontainer>
+      <spoof foo="123"/>
+    </spoofcontainer>
+  </target>
+</project>
diff --git a/groovy-core/src/test/groovy/util/BuilderSupportTest.groovy b/groovy-core/src/test/groovy/util/BuilderSupportTest.groovy
new file mode 100644
index 0000000..48319da
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/BuilderSupportTest.groovy
@@ -0,0 +1,149 @@
+package groovy.util
+
+import groovy.lang.MissingMethodException
+
+/**
+     Testing BuilderSupport and reveal how calling
+    methods on it result in implementation callbacks.
+    Using the SpoofBuilder (see below) to call it in various ways
+    and analyze the "spoofed" logs.
+    This is especially useful when designing subclasses of BuilderSupport.
+     @author Dierk Koenig
+**/
+
+
+class BuilderSupportTest extends GroovyTestCase{
+    void testSimpleNode() {
+        def b = new SpoofBuilder()
+        assert b.log == []
+        def node = b.foo()
+        assert b.log == ['create_with_name','foo','node_completed',null, node]
+    }
+
+    void testSimpleNodeWithValue() {
+        def b = new SpoofBuilder()
+        def node = b.foo('value')
+        assert b.log == ['create_with_name_and_value','foo','value', 'node_completed',null,node]
+    }
+
+    void testSimpleNodeWithOneAttribute() {
+        def b = new SpoofBuilder()
+        def node = b.foo(name:'value')
+        assert b.log == [
+            'create_with_name_and_map','foo', 'name','value', 'node_completed',null,'x']
+    }
+
+    void testSimpleNodeWithClosure() {
+        def b = new SpoofBuilder()
+        b.foo(){
+            b.bar()
+        }
+        assert b.log == [
+            'create_with_name','foo',
+                'create_with_name','bar',
+            'set_parent', 'x', 'x',
+                'node_completed','x','x',
+            'node_completed',null,'x']
+    }
+
+    void testSimpleNodeWithOneAttributeAndValue() {
+        def b = new SpoofBuilder()
+        def node = b.foo(bar:'baz', 'value')
+        assert b.log == ['create_with_name_map_and_value', 'foo', 'bar', 'baz','value', 'node_completed',null,node]
+    }
+
+    void testSimpleNodeWithValueAndOneAttribute() {
+        def b = new SpoofBuilder()
+        def node = b.foo('value', bar:'baz')
+        assert b.log == ['create_with_name_map_and_value', 'foo', 'bar', 'baz','value', 'node_completed',null,node]
+    }
+
+    void testSimpleNodeWithOneAttributeAndValueAndClosure() {
+        def b = new SpoofBuilder()
+        def node = b.foo(bar:'baz', 'value') { 1 }
+        assert b.log == ['create_with_name_map_and_value', 'foo', 'bar', 'baz','value', 'node_completed',null,node]
+    }
+
+    void testSimpleNodeWithValueAndOneAttributeAndClosure() {
+        def b = new SpoofBuilder()
+        def node = b.foo('value', bar:'baz') { 1 }
+        assert b.log == ['create_with_name_map_and_value', 'foo', 'bar', 'baz','value', 'node_completed',null,node]
+    }
+
+    void testSimpleNodeTwoValues() {
+        def b = new SpoofBuilder()
+        shouldFail(MissingMethodException, {def node = b.foo('arg1', 'arg2')})
+    }
+
+    void testSimpleNodeTwoValuesClosure() {
+        def b = new SpoofBuilder()
+        shouldFail(MissingMethodException, {def node = b.foo('arg1', 'arg2') { 1 } })
+    }
+
+    void testSimpleNodeThreeValues() {
+        def b = new SpoofBuilder()
+        shouldFail(MissingMethodException, {def node = b.foo('arg1', 'arg2', 'arg3') })
+    }
+
+    void testSimpleNodeFourValues() {
+        def b = new SpoofBuilder()
+        shouldFail(MissingMethodException, {def node = b.foo('arg1', 'arg2', 'arg3', 'arg4') })
+    }
+
+    void testNestedMethodCallsResolution() {
+        def b = new SpoofBuilder()
+        b.outest {
+            b.outer {
+                nestedBuilderCall(b)
+            }
+        }
+        assert b.log.contains('inner') 
+    }
+
+    void nestedBuilderCall(builder) {
+        builder.inner()
+    }
+}
+
+/**
+    The SpoofBuilder is a sample instance of the abstract BuilderSupport class
+    that does nothing but logging how it was called, returning 'x' for each node.
+**/
+class SpoofBuilder extends BuilderSupport{
+    def log = []
+    
+    protected void setParent(Object parent, Object child){
+        log << "set_parent"
+        log << parent
+        log << child
+    }
+    protected Object createNode(Object name){
+        log << 'create_with_name'
+        log <<  name
+        return 'x'
+    }
+    protected Object createNode(Object name, Object value){
+        log << 'create_with_name_and_value'
+        log << name
+        log << value
+        return 'x'
+    }
+    protected Object createNode(Object name, Map attributes){
+        log << 'create_with_name_and_map'
+        log << name
+        attributes.each{entry -> log << entry.key; log << entry.value}
+        return 'x'
+    }
+    protected Object createNode(Object name, Map attributes, Object value){
+        log << 'create_with_name_map_and_value'
+        log << name
+        attributes.each{entry -> log << entry.key; log << entry.value}
+        log << value
+        return 'x'
+    }
+    protected void nodeCompleted(Object parent, Object node) {
+        log << 'node_completed'
+        log << parent
+        log << node
+    }
+}
diff --git a/groovy-core/src/test/groovy/util/CliBuilderTest.groovy b/groovy-core/src/test/groovy/util/CliBuilderTest.groovy
new file mode 100644
index 0000000..1e50d2f
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/CliBuilderTest.groovy
@@ -0,0 +1,70 @@
+class CliBuilderTest extends GroovyTestCase {
+
+    void testSample() {
+        def writer = new StringWriter()
+        def cli = new CliBuilder(usage:'groovy [option]* filename', writer: new PrintWriter(writer))
+        cli.h(longOpt: 'help', 'usage information')
+        cli.c(argName: 'charset', args:1, longOpt: 'encoding', 'character encoding')
+        cli.i(argName: 'extension', optionalArg: true,
+             "modify files in place, create backup if extension is given (e.g. \'.bak\')")
+
+        def stringified = cli.options.toString()
+        assert stringified =~ /i=. option: i  :: modify files in place, create backup if extension is given/
+        assert stringified =~ /c=. option: c encoding  :: character encoding/
+        assert stringified =~ /h=. option: h help  :: usage information/
+        assert stringified =~ /encoding=. option: c encoding  :: character encoding/
+        assert stringified =~ /help=. option: h help  :: usage information/
+
+        def options = cli.parse(['-h','-c','ASCII'])
+
+        assert options.hasOption('h')
+        assert options.h
+        if (options.h) cli.usage()
+        assert writer.toString().tokenize("\r\n").join("\n") ==
+'''usage: groovy [option]* filename
+ -c,--encoding <charset>   character encoding
+ -h,--help                 usage information
+ -i                        modify files in place, create backup if
+                           extension is given (e.g. '.bak')'''
+
+        assert options.hasOption('c')
+        assert options.c
+        assertEquals 'ASCII', options.getOptionValue('c')
+        assertEquals 'ASCII', options.c
+        assertEquals false, options.encoding
+
+        assertEquals false, options.noSuchOptionGiven
+        assertEquals false, options.x
+    }
+
+    void testMultipleArgs() {
+        def cli = new CliBuilder()
+        cli.a(longOpt:'arg', args:2, valueSeparator:',' as char, 'arguments')
+        def options = cli.parse(['-a','1,2'])
+        assertEquals '1', options.a
+        assertEquals(['1','2'], options.as)
+        assertEquals false, options.arg
+        assertEquals(false, options.args)
+    }
+
+    void testArgs() {
+        def cli = new CliBuilder()
+        cli.a([:],'')
+        def options = cli.parse(['-a','1','2'])
+        assertEquals(['1','2'], options.arguments())
+    }
+
+    void testFailedParsePrintsUsage() {
+        def writer = new StringWriter()
+        def cli = new CliBuilder(writer: new PrintWriter(writer))
+        cli.x(required:true, 'message')
+
+        def options = cli.parse([])
+
+        assert writer.toString().tokenize("\r\n").join("\n") ==
+'''error: -x
+usage: groovy
+ -x   message'''
+
+    }
+}
diff --git a/groovy-core/src/test/groovy/util/Dummy.java b/groovy-core/src/test/groovy/util/Dummy.java
new file mode 100644
index 0000000..91e451c
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/Dummy.java
@@ -0,0 +1,94 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+public class Dummy implements DummyMBean {
+
+    private String name = "James";
+    private String location = "London";
+    private int size = 12;
+
+    public Dummy() {
+    }
+    
+    public Dummy(String name, String location) {
+        this.name = name;
+        this.location = location;
+    }
+    
+    public void start() {
+        System.out.println("Started!");
+    }
+    
+    public void stop() {
+        System.out.println("Stopped!");
+    }
+    
+    public String getLocation() {
+        return location;
+    }
+
+    public void setLocation(String location) {
+        this.location = location;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public int getSize() {
+        return size;
+    }
+
+    public void setSize(int size) {
+        this.size = size;
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/util/DummyMBean.java b/groovy-core/src/test/groovy/util/DummyMBean.java
new file mode 100644
index 0000000..f691285
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/DummyMBean.java
@@ -0,0 +1,57 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package groovy.util;
+
+public interface DummyMBean {
+    public void start();
+    public void stop();
+    public String getLocation();
+    public void setLocation(String location);
+    public String getName();
+    public void setName(String name);
+    public int getSize();
+    public void setSize(int size);
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/util/EmptyScriptTest.groovy b/groovy-core/src/test/groovy/util/EmptyScriptTest.groovy
new file mode 100644
index 0000000..5a92ca0
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/EmptyScriptTest.groovy
@@ -0,0 +1,54 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.util;
+
+public class EmptyScriptTest extends GroovyTestCase {
+
+    public void testEmptyScript() throws Exception {
+        assertScript("");
+    }
+}
diff --git a/groovy-core/src/test/groovy/util/EvalTest.java b/groovy-core/src/test/groovy/util/EvalTest.java
new file mode 100644
index 0000000..7b1a19d
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/EvalTest.java
@@ -0,0 +1,38 @@
+package groovy.util;
+
+import junit.framework.TestCase;
+import org.codehaus.groovy.control.CompilationFailedException;
+
+/**
+ * Testing the simple Groovy integration with Eval.
+ *
+ * @author Dierk Koenig
+ */
+public class EvalTest extends TestCase {
+    public void testMeSimple() throws CompilationFailedException {
+        Object result = Eval.me("10");
+        assertEquals("10", result.toString());
+    }
+
+    public void testMeWithSymbolAndObject() throws CompilationFailedException {
+        Object result = Eval.me("x", new Integer(10), "x");
+        assertEquals("10", result.toString());
+    }
+
+    public void testX() throws CompilationFailedException {
+        Object result = Eval.x(new Integer(10), "x");
+        assertEquals("10", result.toString());
+    }
+
+    public void testXY() throws CompilationFailedException {
+        Integer ten = new Integer(10);
+        Object result = Eval.xy(ten,ten, "x+y");
+        assertEquals("20", result.toString());
+    }
+
+     public void testXYZ() throws CompilationFailedException {
+        Integer ten = new Integer(10);
+        Object result = Eval.xyz(ten,ten,ten, "x+y+z");
+        assertEquals("30", result.toString());
+    }
+}
diff --git a/groovy-core/src/test/groovy/util/FileNameFinderTest.groovy b/groovy-core/src/test/groovy/util/FileNameFinderTest.groovy
new file mode 100644
index 0000000..cf11fca
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/FileNameFinderTest.groovy
@@ -0,0 +1,14 @@
+package groovy.util
+
+/**
+    Make sure FilenNameFinder uses Ant filesets correctly.
+    @author Dierk Koenig
+*/
+class fileNameFinderTest extends GroovyLogTestCase {
+
+    void testFilesInTestDirArePickedUp() {
+        def finder = new FileNameFinder()
+        def files = finder.getFileNames('src/test','*')
+        assert files, 'There should be files in the src/test'
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/util/GroovyTestCaseTest.groovy b/groovy-core/src/test/groovy/util/GroovyTestCaseTest.groovy
new file mode 100644
index 0000000..e0bfe2a
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/GroovyTestCaseTest.groovy
@@ -0,0 +1,41 @@
+/**
+    Testing the notYetImplemented feature of GroovyTestCase.
+    Todo: testing all other features.
+    @author Dierk Koenig
+*/
+
+class GroovyTestCaseTest extends GroovyTestCase {
+
+    void testNotYetImplementedSubclassUse () {
+        if (notYetImplemented()) return
+        fail 'here the code that is expected to fail'
+    }
+    void testNotYetImplementedStaticUse () {
+        if (GroovyTestCase.notYetImplemented(this)) return
+        fail 'here the code that is expected to fail'
+    }
+
+    // we cannot test this automatically...
+    // remove the leading x, run the test and see it failing
+    void xtestSubclassFailing() {
+        if (notYetImplemented()) return
+        assert true // passes unexpectedly
+    }
+    void xtestStaticFailing() {
+        if (GroovyTestCase.notYetImplemented(this)) return
+        assert true // passes unexpectedly
+    }
+
+// ----------------
+
+    void testShouldFailWithMessage() {
+        def msg = shouldFail { throw new RuntimeException('x') }
+        assertEquals 'java.lang.RuntimeException: x', msg
+    }
+    void testShouldFailWithMessageForClass() {
+        def msg = shouldFail(RuntimeException.class) { throw new RuntimeException('x') }
+        println msg
+        assertEquals 'x', msg
+    }
+
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/util/MBeanTest.java b/groovy-core/src/test/groovy/util/MBeanTest.java
new file mode 100644
index 0000000..d18381d
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/MBeanTest.java
@@ -0,0 +1,84 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.util;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+import javax.management.ObjectName;
+
+import groovy.lang.GroovyObject;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+/**
+ * Tests using the GroovyObject API from Java to access MBeans via 
+ * the normal properties API (to simulate normal Groovy property access)
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MBeanTest extends TestSupport {
+
+    public void testGetProperty() throws Exception {
+        MBeanServer mbeanServer = MBeanServerFactory.createMBeanServer();
+        ObjectName name = new ObjectName("groovy.test:role=TestMBean,type=Dummy");
+        mbeanServer.registerMBean(new Dummy(), name);
+
+        assertEquals("JMX value of Name", "James", mbeanServer.getAttribute(name, "Name"));
+
+        GroovyObject object = new GroovyMBean(mbeanServer, name);
+        
+        Object value = object.getProperty("Name");
+        assertEquals("Name property", "James", value);
+
+        object.setProperty("Name", "Bob");
+        assertEquals("Name property", "Bob", object.getProperty("Name"));
+        
+        // now lets look up the name via JMX to checki
+        assertEquals("JMX value of Name", "Bob", mbeanServer.getAttribute(name, "Name"));
+    }
+}
diff --git a/groovy-core/src/test/groovy/util/NavToWiki.groovy b/groovy-core/src/test/groovy/util/NavToWiki.groovy
new file mode 100644
index 0000000..8538580
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/NavToWiki.groovy
@@ -0,0 +1,41 @@
+import groovy.util.XmlParser
+
+if (args.size() < 1) {
+    println "Usage: NavToWiki fileName"
+}
+else {
+    file = args[0]
+    println "About to parse ${file}"
+    doc = new XmlParser().parse(file)
+
+    println """
+QuickLinks page
+-------------------------------
+
+
+"""
+    links = doc.body.links.item
+    println links.collect {
+        return "{link:" + it['@name'] + "|" + it['@href'] + "}"
+    }.join(" | ")
+
+    println """
+
+
+
+Navigation page
+-------------------------------
+
+
+"""
+    menus = doc.body.menu
+    menus.each {
+        println "h3:${it['@name']}"
+
+        it.item.each {
+            println "- {link:" + it['@name'] + "|" + it['@href'] + "}"
+        }
+        println ""
+    }
+}
+
diff --git a/groovy-core/src/test/groovy/util/NodeTest.groovy b/groovy-core/src/test/groovy/util/NodeTest.groovy
new file mode 100644
index 0000000..ef5d618
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/NodeTest.groovy
@@ -0,0 +1,188 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.util;
+
+
+import groovy.util.GroovyTestCase;
+import groovy.util.Node;
+import groovy.xml.QName;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Tests the use of the structured Attribute type
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class NodeTest extends GroovyTestCase {
+
+    public void testSimpleAttribute() {
+        Node attribute = new Node(null, "transactional");
+        assertEquals("name", "transactional", attribute.name());
+        assertEquals("attributes", 0, attribute.attributes().size());
+        assertEquals("value", 0, attribute.children().size());
+        assertEquals("text", "", attribute.text());
+
+        dump(attribute);
+    }
+
+    public void testAttributeWithAttributes() {
+        Map attributes = new HashMap();
+        attributes.put("a", "xyz");
+        
+        Node attribute = new Node(null, "foo", attributes);
+        assertEquals("name", "foo", attribute.name());
+        assertEquals("attributes", 1, attribute.attributes().size());
+        assertEquals("value", 0, attribute.children().size());
+        assertEquals("text", "", attribute.text());
+
+        dump(attribute);
+    }
+
+    public void testAttributeWithText() {
+        Node attribute = new Node(null, "foo", "the text");
+        assertEquals("name", "foo", attribute.name());
+        assertEquals("attributes", 0, attribute.attributes().size());
+        assertEquals("value", 1, attribute.children().size());
+        assertEquals("text", "the text", attribute.text());
+
+        dump(attribute);
+    }
+
+    public void testAttributeWithAttributesAndChildren() {
+        Map attributes = new HashMap();
+        attributes.put("a", "xyz");
+        
+        List children = new ArrayList();
+        children.add(new Node(null, "person", "James"));
+        children.add(new Node(null, "person", "Bob"));
+        children.add("someText");
+        
+        Node attribute = new Node(null, "foo", attributes, children);
+        assertEquals("name", "foo", attribute.name());
+        assertEquals("attributes", 1, attribute.attributes().size());
+        assertEquals("value", 3, attribute.children().size());
+        assertEquals("text", "someText", attribute.text());
+
+        dump(attribute);
+    }
+
+    public void testAttributeWithAttributesAndChildrenWithMixedText() {
+        Map attributes = new HashMap();
+        attributes.put("a", "xyz");
+        
+        List children = new ArrayList();
+        children.add("someText");
+        Node node1 = new Node(null, "person", "James");
+        children.add(node1);
+        children.add("moreText");
+        Node node2 = new Node(null, "person", "Bob");
+        children.add(node2);
+        children.add("moreText");
+        
+        Node attribute = new Node(null, "foo", attributes, children);
+        assertEquals("name", "foo", attribute.name());
+        assertEquals("attributes", 1, attribute.attributes().size());
+        assertEquals("value", 5, attribute.children().size());
+        assertEquals("text", "someTextmoreTextmoreText", attribute.text());
+        
+        
+        // lets test get
+        List list = (List) attribute.get("person");
+        assertEquals("Expected list size: " + list, 2, list.size());
+        
+        assertEquals("Node1", node1, list.get(0));
+        assertEquals("Node2", node2, list.get(1));
+
+        dump(attribute);
+    }
+    
+    public void testNavigationUsingQNames() throws Exception {
+        QName name1 = new QName("http://something", "foo", "f");
+        
+        Node node = new Node(null, null, new ArrayList());
+        Node child = new Node(null, new QName("http://something", "foo", "f"), new HashMap(), new ArrayList());
+        child.attributes().put("cheese", "Edam");
+        Node grandChild = new Node(null, new QName("http://something", "bar", "f"), new HashMap(), new ArrayList());
+        grandChild.attributes().put("drink", "Beer");
+        grandChild.children().add("I am a youngling");
+        child.children().add(grandChild);
+        
+        node.children().add(child);
+
+        // lets look up by QName
+        Object value = node.getAt(name1);
+        assertTrue("Should return a list: " + value, value instanceof NodeList);
+        NodeList list = (NodeList) value;
+        assertEquals("Size", 1, list.size());
+        
+        Node answer = (Node) list.get(0);
+        assertNotNull("Node is null!", answer);
+        
+        System.out.println("Found node: " + answer);
+        
+        // now lets navigate the list
+        NodeList gc = list.getAt(new QName("http://something", "bar"));
+        assertEquals("grand children size", 1, gc.size());
+        
+        System.out.println("Found grandChild: " + gc);
+        
+        String text= gc.text();
+        assertEquals("text of grandchild", "I am a youngling", text);
+    }
+
+    protected void dump(Node node) {
+        NodePrinter printer = new NodePrinter();
+        printer.print(node);
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/util/OrderByTest.groovy b/groovy-core/src/test/groovy/util/OrderByTest.groovy
new file mode 100644
index 0000000..efea682
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/OrderByTest.groovy
@@ -0,0 +1,54 @@
+class OrderByTest extends GroovyTestCase {
+
+    void testSortByOneField() {
+        def builder = new NodeBuilder()
+        def tree = builder.people {
+            person(name:'James', cheese:'Edam', location:'London')
+            person(name:'Bob', cheese:'Cheddar', location:'Atlanta')
+            person(name:'Chris', cheese:'Red Leicester', location:'London')
+            person(name:'Joe', cheese:'Brie', location:'London')
+        }
+        
+        def people = tree.children()
+        
+        /** @todo parser should allow this syntax sugar
+        def order = new OrderBy { it.get('@cheese') }
+        */
+        def order = new OrderBy( { it.get('@cheese') } )
+        def sorted = people.sort(order)
+        
+        assert sorted.get(0).get('@name') == 'Joe'
+        assert sorted.get(1).get('@name') == 'Bob'
+        assert sorted.get(2).get('@name') == 'James'
+        assert sorted.get(3).get('@name') == 'Chris'
+        
+        order = new OrderBy( { it.get('@name') } )
+        sorted = people.sort(order)
+        
+        assert sorted.get(0).get('@name') == 'Bob'
+        assert sorted.get(1).get('@name') == 'Chris'
+        assert sorted.get(2).get('@name') == 'James'
+        assert sorted.get(3).get('@name') == 'Joe'
+    }
+
+
+    void testSortByMultipleFields() {
+        def builder = new NodeBuilder()
+        def tree = builder.people {
+            person(name:'James', cheese:'Edam', location:'London')
+            person(name:'Bob', cheese:'Cheddar', location:'Atlanta')
+            person(name:'Chris', cheese:'Red Leicester', location:'London')
+            person(name:'Joe', cheese:'Brie', location:'London')
+        }
+        
+        def people = tree.children()
+
+        def order = new OrderBy([ { it.get('@location') }, { it.get('@cheese') } ])
+        def sorted = people.sort(order)
+        
+        assert sorted.get(0).get('@name') == 'Bob'
+        assert sorted.get(1).get('@name') == 'Joe'
+        assert sorted.get(2).get('@name') == 'James'
+        assert sorted.get(3).get('@name') == 'Chris'
+    }
+}
diff --git a/groovy-core/src/test/groovy/util/ProxyTest.groovy b/groovy-core/src/test/groovy/util/ProxyTest.groovy
new file mode 100644
index 0000000..46920d8
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/ProxyTest.groovy
@@ -0,0 +1,64 @@
+package groovy.util
+
+/**
+* @author Dierk Koenig
+**/
+class ProxyTest extends GroovyTestCase {
+
+    void testStringDecoration(){
+        def original = 'decorated String'
+        def proxy = new StringDecorator().wrap(original)
+        // method, that is only known on proxy
+        assertSame original, proxy.adaptee
+        // method, that is only known on adaptee is relayed through the proxy
+        assertEquals original.size(), proxy.size()
+        // method, that is availabe in both objects should come from proxy
+        assertEquals 0, proxy.length()
+        // method, that is availabe in both objects
+        // but should come from adaptee needs explicit relay
+        assertEquals original, proxy.toString()
+        // method from decorator, that is not in adaptee
+        assertEquals 'new Method reached', proxy.someNewMethod()
+    }
+
+  /*
+   *  Some test cases to probe perceived problems with each and collect on Proxy objects.
+   *  cf. GROOVY-1461.  Jonathan Carlson <Jonathan.Carlson@katun.com> made a proposal for a test
+   *  as a single method, Russel Winder <russel@russel.org.uk> split things up when entering
+   *  them so that there is only a single assert per method to try and maximize the benefit of
+   *  the tests.
+   */
+
+  void testProxyCollect ( ) {
+    def collection = [ 1 , 2 , 3 ]
+    def proxy = ( new Proxy ( ) ).wrap ( collection ) 
+    assertEquals ( [ 2 , 3 , 4 ] , proxy.collect { it + 1 } )
+  }
+
+  void testProxyAny ( ) {
+    def collection = [ 1 , 2 , 3 ]
+    def proxy = ( new Proxy ( ) ).wrap ( collection ) 
+    assertEquals ( true , proxy.any { it == 2 } )
+  }
+
+  void testProxyFind ( ) {
+    def collection = [ 1 , 2 , 3 ]
+    def proxy = ( new Proxy ( ) ).wrap ( collection ) 
+    assertEquals ( 2 , proxy.find { it == 2 } )
+  }
+
+  void testProxyEach ( ) {
+    def collection = [ 1 , 2 , 3 ]
+    def proxy = ( new Proxy ( ) ).wrap ( collection ) 
+    def testString = ''
+    proxy.each { testString += it }
+    assertEquals ( '123' , testString )
+  }
+
+}
+
+class StringDecorator extends Proxy{
+    int length()          { 0 }
+    String toString()     { adaptee.toString()}
+    String someNewMethod(){ 'new Method reached' }
+}
diff --git a/groovy-core/src/test/groovy/util/SpoofTask.java b/groovy-core/src/test/groovy/util/SpoofTask.java
new file mode 100644
index 0000000..13020dd
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/SpoofTask.java
@@ -0,0 +1,31 @@
+package groovy.util;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+public class SpoofTask extends Task {
+	private int foo;
+
+    public SpoofTask() {
+        super();
+        SpoofTaskContainer.spoof("SpoofTask ctor");
+    }
+    
+    public void setFoo(final int i) {
+    	foo = i;
+    }
+    
+
+    public void execute() throws BuildException {
+        SpoofTaskContainer.spoof("begin SpoofTask execute");
+        SpoofTaskContainer.spoof("tag name from wrapper: " + getWrapper().getElementTag());
+        // don't rely on Map.toString(), behaviour is not documented
+        SpoofTaskContainer.spoof("attributes map from wrapper: " 
+        		+ InvokerHelper.toMapString(getWrapper().getAttributeMap()));
+        SpoofTaskContainer.spoof("param foo: " + foo);
+        
+        SpoofTaskContainer.spoof("end SpoofTask execute");
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/util/SpoofTaskContainer.java b/groovy-core/src/test/groovy/util/SpoofTaskContainer.java
new file mode 100644
index 0000000..65ab7f5
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/SpoofTaskContainer.java
@@ -0,0 +1,54 @@
+package groovy.util;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TaskContainer;
+import org.apache.tools.ant.UnknownElement;
+import org.apache.tools.ant.BuildException;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+public class SpoofTaskContainer extends Task implements TaskContainer {
+    private List tasks = new ArrayList();
+    static StringBuffer spoof = new StringBuffer();
+
+    public SpoofTaskContainer() {
+        super();
+        spoof("SpoofTaskContainer ctor");
+    }
+
+    static StringBuffer getSpoof(){
+        return spoof;
+    }
+
+    static void resetSpoof() {
+    	spoof = new StringBuffer();
+    }
+    
+    static void spoof(String message){
+        spoof.append(message);
+        spoof.append("\n");
+    }
+
+    public void addTask(Task task) {
+    	// to work with ant 1.6
+        spoof("in addTask");
+        if (task instanceof UnknownElement) {
+            spoof("configuring UnknownElement");
+            task.maybeConfigure();
+            task = ((UnknownElement) task).getTask();
+        }
+        tasks.add(task);
+    }
+
+    public void execute() throws BuildException {
+        spoof("begin SpoofTaskContainer execute");
+        for (Iterator iter = tasks.iterator(); iter.hasNext();) {
+            Task task = (Task) iter.next();
+            task.perform();
+        }
+        spoof("end SpoofTaskContainer execute");
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/util/StringTestUtil.groovy b/groovy-core/src/test/groovy/util/StringTestUtil.groovy
new file mode 100644
index 0000000..34f7bb1
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/StringTestUtil.groovy
@@ -0,0 +1,14 @@
+package groovy.util

+

+import junit.framework.Assert

+

+class StringTestUtil {

+    static void assertMultilineStringsEqual(String a, String b) {

+        def aLines = a.trim().replaceAll('\r','').split('\n')

+        def bLines = b.trim().replaceAll('\r','').split('\n')

+        assert aLines.size() == bLines.size()

+        for (i in 0..<aLines.size()) {

+            Assert.assertEquals(aLines[i].trim(), bLines[i].trim())

+        }

+    }

+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/util/XmlParserTest.groovy b/groovy-core/src/test/groovy/util/XmlParserTest.groovy
new file mode 100644
index 0000000..a38f8fc
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/XmlParserTest.groovy
@@ -0,0 +1,44 @@
+package groovy.util
+
+import groovy.xml.TraversalTestSupport
+import groovy.xml.GpathSyntaxTestSupport
+import groovy.xml.MixedMarkupTestSupport
+
+class XmlParserTest extends GroovyTestCase {
+
+    def getRoot = { xml -> new XmlParser().parseText(xml) }
+    
+    void testNodePrinter() {
+        def text = """
+<p>Please read the <a href="index.html">Home</a> page</p>
+"""
+        def node = new XmlParser().parseText(text)
+        new NodePrinter().print(node)
+    }
+
+    void testElement() {
+        GpathSyntaxTestSupport.checkElement(getRoot)
+        GpathSyntaxTestSupport.checkFindElement(getRoot)
+        GpathSyntaxTestSupport.checkElementTypes(getRoot)
+        GpathSyntaxTestSupport.checkElementClosureInteraction(getRoot)
+    }
+
+    void testAttribute() {
+        GpathSyntaxTestSupport.checkAttribute(getRoot)
+        GpathSyntaxTestSupport.checkAttributes(getRoot)
+    }
+
+    void testNavigation() {
+        GpathSyntaxTestSupport.checkChildren(getRoot)
+        GpathSyntaxTestSupport.checkParent(getRoot)
+    }
+
+    void testTraversal() {
+        TraversalTestSupport.checkDepthFirst(getRoot)
+        TraversalTestSupport.checkBreadthFirst(getRoot)
+    }
+
+    void testMixedMarkup() {
+        MixedMarkupTestSupport.checkMixedMarkup(getRoot)
+    }
+}
diff --git a/groovy-core/src/test/groovy/util/XmlSlurperTest.groovy b/groovy-core/src/test/groovy/util/XmlSlurperTest.groovy
new file mode 100644
index 0000000..f1e5315
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/XmlSlurperTest.groovy
@@ -0,0 +1,64 @@
+package groovy.util
+
+import groovy.xml.TraversalTestSupport
+import groovy.xml.GpathSyntaxTestSupport
+import groovy.xml.MixedMarkupTestSupport
+
+class XmlSlurperTest extends GroovyTestCase {
+
+    def getRoot = { xml -> new XmlSlurper().parseText(xml) }
+
+    void testWsdl() {
+        def wsdl = '''
+            <definitions name="AgencyManagementService"
+                         xmlns:ns1="http://www.example.org/NS1"
+                         xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+                         xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
+                         xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
+                         xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
+                         xmlns="http://schemas.xmlsoap.org/wsdl/">                                              
+                <message name="SomeRequest">                                                          
+                    <part name="parameters" element="ns1:SomeReq" />                                  
+                </message>                                                                            
+                <message name="SomeResponse">                                                         
+                    <part name="result" element="ns1:SomeRsp" />                                      
+                </message>                                                                            
+            </definitions>                                                                            
+            '''
+        def xml = new XmlSlurper().parseText(wsdl)
+        assert xml.message.part.@element.findAll {it =~ /.Req$/}.size() == 1
+        assert xml.message.part.findAll { true }.size() == 2
+        assert xml.message.part.find { it.name() == 'part' }.name() == 'part'
+        assert xml.message.findAll { true }.size() == 2
+        assert xml.message.part.lookupNamespace("ns1") == "http://www.example.org/NS1"
+        assert xml.message.part.lookupNamespace("") == "http://schemas.xmlsoap.org/wsdl/"
+        assert xml.message.part.lookupNamespace("undefinedPrefix") == null
+        xml.message.findAll { true }.each { assert it.name() == "message"}
+    }
+
+    void testElement() {
+        GpathSyntaxTestSupport.checkElement(getRoot)
+        GpathSyntaxTestSupport.checkFindElement(getRoot)
+        GpathSyntaxTestSupport.checkElementTypes(getRoot)
+        GpathSyntaxTestSupport.checkElementClosureInteraction(getRoot)
+    }
+
+    void testAttribute() {
+        GpathSyntaxTestSupport.checkAttribute(getRoot)
+        GpathSyntaxTestSupport.checkAttributes(getRoot)
+    }
+
+    void testNavigation() {
+        GpathSyntaxTestSupport.checkChildren(getRoot)
+        GpathSyntaxTestSupport.checkParent(getRoot)
+    }
+
+    void testTraversal() {
+        TraversalTestSupport.checkDepthFirst(getRoot)
+        TraversalTestSupport.checkBreadthFirst(getRoot)
+    }
+
+    void testMixedMarkup() {
+        MixedMarkupTestSupport.checkMixedMarkup(getRoot)
+    }
+}
diff --git a/groovy-core/src/test/groovy/util/suite/ATestScriptThatsNoTestCase.groovy b/groovy-core/src/test/groovy/util/suite/ATestScriptThatsNoTestCase.groovy
new file mode 100644
index 0000000..35de296
--- /dev/null
+++ b/groovy-core/src/test/groovy/util/suite/ATestScriptThatsNoTestCase.groovy
@@ -0,0 +1,2 @@
+// used for testing ScriptTestCaseAdapter usage with AllTestSuite
+assert true
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/xml/DOMTest.groovy b/groovy-core/src/test/groovy/xml/DOMTest.groovy
new file mode 100644
index 0000000..09749d2
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/DOMTest.groovy
@@ -0,0 +1,81 @@
+package groovy.xml
+
+/**
+ * This test uses the concise syntax to test the building of 
+ * W3C DOM trees using GroovyMarkup
+ */
+class DOMTest extends TestXmlSupport {
+    
+    void testSmallTree() {
+        def b = DOMBuilder.newInstance()
+        
+        def root = b.root1(a:5, b:7) {
+            elem1('hello1')
+            elem2('hello2')
+            elem3(x:7)
+        }
+        
+        assert root != null
+        
+        dump(root)
+    }
+    
+    void testTree() {
+        def b = DOMBuilder.newInstance()
+        
+        def root = b.root2(a:5, b:7) {
+            elem1('hello1')
+            elem2('hello2')
+            nestedElem(x:'abc', y:'def') {
+                child(z:'def')
+                child2()  
+            }
+            
+            nestedElem2(z:'zzz') {
+                child(z:'def')
+                child2("hello")  
+            }
+        }
+        
+        assert root != null
+        
+        dump(root)
+
+/*
+        def elem1 = root.elem1
+        assert elem1.value() := 'hello1'
+        
+        def elem2 = root.elem2
+        assert elem2.value() := 'hello2'
+
+        assert root.elem1.value() := 'hello1'
+        assert root.elem2.value() := 'hello2'
+
+        assert root.nestedElem.attributes() := ['x':'abc', 'y':'def']        
+        assert root.nestedElem.child.attributes() := ['z':'def']
+        assert root.nestedElem.child2.value() := []
+        assert root.nestedElem.child2.text() := ''
+
+        assert root.nestedElem2.attributes() := ['z':'zzz']      
+        assert root.nestedElem2.child.attributes() := ['z':'def']
+        assert root.nestedElem2.child2.value() := 'hello'
+        assert root.nestedElem2.child2.text() := 'hello'
+        
+        def list = root.value()
+        assert list.size() := 4
+        
+        assert root.attributes().a := 5
+        assert root.attributes().b := 7
+
+        assert root.nestedElem.attributes().x := 'abc'
+        assert root.nestedElem.attributes().y := 'def'
+        assert root.nestedElem2.attributes().z := 'zzz'
+        assert root.nestedElem2.child.attributes().z := 'def'
+*/        
+        /** @todo parser add .@ as an operation
+                assert root.@a := 5
+                assert root.@b := 7
+        */        
+    }
+    
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/xml/FactorySupportTest.java b/groovy-core/src/test/groovy/xml/FactorySupportTest.java
new file mode 100644
index 0000000..a70891e
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/FactorySupportTest.java
@@ -0,0 +1,45 @@
+package groovy.xml;
+
+import junit.framework.TestCase;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
+
+public class FactorySupportTest extends TestCase {
+    private static final PrivilegedActionException PRIVILEGED_ACTION_EXCEPTION = new PrivilegedActionException(new IllegalStateException());
+    private static final ParserConfigurationException PARSER_CONFIGURATION_EXCEPTION = new ParserConfigurationException();
+
+    public void testCreatesFactories() throws Exception {
+        assertNotNull(FactorySupport.createDocumentBuilderFactory());
+        assertNotNull(FactorySupport.createSaxParserFactory());
+    }
+
+    public void testParserConfigurationExceptionNotWrapped() throws ParserConfigurationException {
+        try {
+            FactorySupport.createFactory(new PrivilegedExceptionAction(){
+                public Object run() throws Exception {
+                    throw PARSER_CONFIGURATION_EXCEPTION;
+                }
+            });
+            fail("Exception was not caught");
+        } catch (Throwable t) {
+            assertSame(PARSER_CONFIGURATION_EXCEPTION, t);
+        }
+    }
+
+    public void testOtherExceptionsWrappedAsUnchecked() throws ParserConfigurationException {
+        try {
+            FactorySupport.createFactory(new PrivilegedExceptionAction(){
+                public Object run() throws Exception {
+                    throw PRIVILEGED_ACTION_EXCEPTION;
+                }
+            });
+            fail("Exception was not caught");
+        } catch (RuntimeException re) {
+            assertSame(PRIVILEGED_ACTION_EXCEPTION, re.getCause());
+        } catch (Throwable t) {
+            fail("Exception was not wrapped as runtime");
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/xml/GpathSyntaxTestSupport.groovy b/groovy-core/src/test/groovy/xml/GpathSyntaxTestSupport.groovy
new file mode 100644
index 0000000..43a48376
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/GpathSyntaxTestSupport.groovy
@@ -0,0 +1,202 @@
+package groovy.xml
+
+class GpathSyntaxTestSupport {
+    private static def sampleXml = '''
+<characters>
+    <character id="1" name="Wallace">
+    	<likes>cheese</likes>
+    </character>
+    <character id="2" name="Gromit">
+	    <likes>sleep</likes>
+    </character>
+    <numericValue>1</numericValue>
+    <booleanValue>y</booleanValue>
+    <uriValue>http://example.org/</uriValue>
+    <urlValue>http://example.org/</urlValue>
+    <empty/>
+</characters>
+'''
+
+    static void checkElement(Closure getRoot) {
+        def root = getRoot(sampleXml)
+        assert root != null
+        def characters = root.character
+        assert 2 == characters.size()
+        assert 2 == root.'character'.size()
+        assert 2 == root['character'].size()
+        def wallace = characters[0]
+        assert wallace.name() == 'character'
+        def likes = characters.likes
+        assert 2 == likes.size()
+        def wallaceLikes = likes[0]
+        assert wallaceLikes.name() == 'likes'
+        assert wallaceLikes.text() == 'cheese'
+        checkEmptyMissingCases(root)
+        if (isDom(root)) {
+            // additional DOM long-hand syntax
+            // for illustrative purposes only
+            assert likes.item(0).nodeName == 'likes'
+            assert wallaceLikes.firstChild.nodeValue == 'cheese'
+            if (wallaceLikes.class.name.contains('xerces')) {
+                assert 'cheese' == wallaceLikes.textContent
+            }
+        }
+    }
+
+    private static void checkEmptyMissingCases(root) {
+        def unknownChild = root.xxx
+        assert unknownChild.isEmpty()
+        def unknownAttr = root.'@xxx'
+        assert isSlurper(root) || !unknownAttr
+        assert !isSlurper(root) || unknownAttr.isEmpty()
+        assert root.'empty'.text() == ''
+    }
+
+    static void checkFindElement(Closure getRoot) {
+        def root = getRoot(sampleXml)
+        // lets find Gromit
+        def gromit = root.character.find { it.'@id' == '2' }
+        assert gromit != null, "Should have found Gromit!"
+        assert gromit['@name'] == "Gromit"
+        // lets find what Wallace likes in 1 query
+        def answer = root.character.find { it['@id'] == '1' }.likes[0].text()
+        assert answer == "cheese"
+    }
+
+    static void checkElementTypes(Closure getRoot) {
+        def root = getRoot(sampleXml)
+        def numericValue = root.numericValue[0]
+        def booleanValue = root.booleanValue[0]
+        def uriValue     = root.uriValue[0]
+        def urlValue     = root.urlValue[0]
+        assert numericValue.text().toInteger() == 1
+        assert numericValue.text().toLong() == 1
+        assert numericValue.text().toFloat() == 1
+        assert numericValue.text().toDouble() == 1
+        assert numericValue.text().toBigInteger() == 1
+        assert numericValue.text().toBigDecimal() == 1
+        assert booleanValue.text().toBoolean() == true
+        assert uriValue.text().toURI() == "http://example.org/".toURI()
+        assert urlValue.text().toURL() == "http://example.org/".toURL()
+        if (isSlurper(root)) {
+            // slurper shorthand - are these really pulling their weight?
+            assert numericValue.toInteger() == 1
+            assert numericValue.toLong() == 1
+            assert numericValue.toFloat() == 1
+            assert numericValue.toDouble() == 1
+            assert numericValue.toBigInteger() == 1
+            assert numericValue.toBigDecimal() == 1
+            assert booleanValue.toBoolean() == true
+            assert uriValue.toURI() == "http://example.org/".toURI()
+            assert urlValue.toURL() == "http://example.org/".toURL()
+        }
+    }
+
+    static void checkElementClosureInteraction(Closure getRoot) {
+        def root = getRoot(sampleXml)
+        def sLikes = root.character.likes.findAll{ it.text().startsWith('s') }
+        assert sLikes.size() == 1
+        assert root.likes.size() == 0
+        if (isDom(root)) {
+            // addtitional DOMCategory long-hand notation gets nested nodes from root
+            assert root.getElementsByTagName('likes').size() == 2
+        }
+        assert 'sleep' == sLikes[0].text()
+        assert 'cheesesleep' == root.character.likes.collect{ it.text() }.join()
+        assert root.character.likes.every{ it.text().contains('ee') }
+        def groupLikesByFirstLetter
+        def likes = root.character.likes.collect{ it }
+        if (isSlurper(root)) {
+            groupLikesByFirstLetter = likes.groupBy{ like ->
+                root.character.find{ it.likes[0].text() == like.text() }.@name.toString()[0]
+            }
+            // TODO: Broken? Why doesn't below work?
+            //groupLikesByFirstLetter = likes.groupBy{ it.parent().@name.toString()[0] }
+        } else {
+            groupLikesByFirstLetter = likes.groupBy{ it.parent().'@name'[0] }
+        }
+        groupLikesByFirstLetter.keySet().each{
+            groupLikesByFirstLetter[it] = groupLikesByFirstLetter[it][0].text()
+        }
+        assert groupLikesByFirstLetter == [W:'cheese', G:'sleep']
+    }
+
+    static void checkAttribute(Closure getRoot) {
+        def root = getRoot(sampleXml)
+        if (isSlurper(root)) {
+            assert 'Wallace' == root.character[0].'@name'.text()
+            assert 'Wallace' == root.character[0]['@name'].text()
+            assert 'Wallace' == (root.character.'@name')[0].text()
+            assert ['Wallace', 'Gromit'] == root.character.'@name'.list()*.text()
+            assert 'WallaceGromit' == root.character.'@name'.text()
+        } else {
+            assert 'Wallace' == root.character[0].'@name'
+            assert 'Wallace' == root.character[0]['@name']
+            assert 'Wallace' == (root.character.'@name')[0]
+            assert ['Wallace', 'Gromit'] == root.character.collect{ it.'@name' }
+            assert 'WallaceGromit' == root.character.'@name'.join()
+        }
+        if (isSlurper(root)) {
+            // additional slurper shorthand
+            assert 'Wallace' == root.character[0].@name.text()
+            def gromit = root.character.find{ it.@id == '2' }
+            assert gromit.@name.name() == "name"
+        }
+    }
+
+    static void checkAttributes(Closure getRoot) {
+        def root = getRoot(sampleXml)
+        def attributes = root.character[0].attributes()
+        assert         2 == attributes.size()
+        assert 'Wallace' == attributes['name']
+        assert 'Wallace' == attributes.name
+        assert       '1' == attributes.'id'
+    }
+
+    static void checkChildren(Closure getRoot) {
+        def root = getRoot(sampleXml)
+        def children = root.children()
+        // count direct children
+        assert children.size() == 7, "Children ${children.size()}"
+        assert root.'*'.size() == 7
+        // illustrative purposes only
+        if (isDom(root)) {
+            // count whitespace and nested children
+            assert root.childNodes.size() == 15
+            // count nested children
+            assert root.getElementsByTagName('*').size() == 9
+        }
+    }
+
+    static void checkParent(Closure getRoot) {
+        def root = getRoot(sampleXml)
+        def gromit = root.character.find { it['@id'] == '2' }
+        assert gromit.likes[0].parent() == gromit
+        assert gromit.likes[0].'..' == gromit
+        assert gromit.likes[0].parent().parent() == root
+        assert gromit.parent() == root
+        if (isSlurper(root)) {
+            // additional slurper shorthand
+            assert gromit.likes.parent() == gromit
+        }
+        if (isSlurper(root)) {
+            assert root.parent() == root
+        } else if (isParser(root)) {
+            assert root.parent() == null
+        } else if (isDom(root)) {
+            assert (root.parent() instanceof org.w3c.dom.Document)
+        }
+    }
+
+    private static boolean isSlurper(node) {
+        return node.getClass().name.contains('slurper')
+    }
+
+    private static boolean isParser(node) {
+        return (node instanceof groovy.util.Node)
+    }
+
+    private static boolean isDom(node) {
+        return node.getClass().name.contains('Element')
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/xml/MarkupBuilderTest.groovy b/groovy-core/src/test/groovy/xml/MarkupBuilderTest.groovy
new file mode 100644
index 0000000..9e3eae8
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/MarkupBuilderTest.groovy
@@ -0,0 +1,150 @@
+package groovy.xml;
+
+import groovy.util.GroovyTestCase
+
+/** 
+ * Tests that special XML chars are entitized by MarkupBuilder.
+ *
+ * @author <a href="mailto:scottstirling@rcn.com">Scott Stirling</a>
+ *
+ * @version $Revision: 1.4 $
+ *
+ *   Fix the cr lf handling of multiline stringon both of linux and Windows XP.
+ *   This test should success on Windows XP.
+ *
+ *   @author Pilho Kim
+ */
+class MarkupBuilderTest extends GroovyTestCase {
+    private StringWriter writer
+    private MarkupBuilder xml
+
+    protected void setUp() {
+        writer = new StringWriter()
+        xml = new MarkupBuilder(writer)
+    }
+
+    /**
+     * Main test method. Checks that well-formed XML is generated
+     * and that the appropriate characters are escaped with the
+     * correct entities.
+     */
+    void testBuilder() {
+        String expectedXml = '''<chars>
+  <ampersand a='&amp;'>&amp;</ampersand>
+  <quote attr='"'>"</quote>
+  <apostrophe attr='&apos;'>'</apostrophe>
+  <lessthan attr='value'>chars: &amp; &lt; &gt; '</lessthan>
+  <element attr='value 1 &amp; 2'>chars: &amp; &lt; &gt; " in middle</element>
+  <greaterthan>&gt;</greaterthan>
+  <emptyElement />
+</chars>'''
+
+        // Generate the markup.
+        xml.chars {
+            ampersand(a: "&", "&")
+            quote(attr: "\"", "\"")
+            apostrophe(attr: "'", "'")
+            lessthan(attr: "value", "chars: & < > '")
+            element(attr: "value 1 & 2", "chars: & < > \" in middle")
+            greaterthan(">")
+            emptyElement()
+        }
+
+        // Compare the MarkupBuilder generated XML with the 'expectedXml'
+        // string.
+        assertEquals(expectedXml, fixEOLs(writer.toString()))
+    }
+
+    /**
+     * Tests the builder with double quotes for attribute values.
+     */
+    void testBuilderWithDoubleQuotes() {
+        String expectedXml = '''<chars>
+  <ampersand a="&amp;">&amp;</ampersand>
+  <quote attr="&quot;">"</quote>
+  <apostrophe attr="'">'</apostrophe>
+  <lessthan attr="value">chars: &amp; &lt; &gt; '</lessthan>
+  <element attr="value 1 &amp; 2">chars: &amp; &lt; &gt; " in middle</element>
+  <greaterthan>&gt;</greaterthan>
+  <emptyElement />
+</chars>'''
+
+        // Generate the markup.
+        xml.doubleQuotes = true
+        xml.chars {
+            ampersand(a: "&", "&")
+            quote(attr: "\"", "\"")
+            apostrophe(attr: "'", "'")
+            lessthan(attr: "value", "chars: & < > '")
+            element(attr: "value 1 & 2", "chars: & < > \" in middle")
+            greaterthan(">")
+            emptyElement()
+        }
+
+        // Compare the MarkupBuilder generated XML with the 'expectedXml'
+        // string.
+        assertEquals(expectedXml, fixEOLs(writer.toString()))
+    }
+
+    /**
+     * Tests that MarkupBuilder escapes element content correctly, even
+     * when the content contains line-endings.
+     */
+    void testEscapingMultiLineContent() {
+        def expectedXml = 
+'''<element>This is multi-line content with characters, such as &lt;, that
+require escaping. The other characters consist of:
+
+    * &gt; - greater than
+    * &amp; - ampersand
+</element>'''
+
+        // Generate the markup.
+        xml.element('''This is multi-line content with characters, such as <, that
+require escaping. The other characters consist of:
+
+    * > - greater than
+    * & - ampersand
+''')
+
+        // Compare the generated markup with the 'expectedXml' string.
+        assertEquals(expectedXml, fixEOLs(writer.toString()))
+    }
+
+    /**
+     * Checks against a regression bug whereby some empty elements were
+     * not closed.
+     */
+    void testMarkupForClosingTags() {
+        def expectedXml =
+'''<ELEM1>
+  <ELEM2 type='2' id='first'>
+    <ELEM3A id='first' />
+    <ELEM3B type='3'>text</ELEM3B>
+  </ELEM2>
+  <ELEM2 type='2' id='second'>
+    <ELEM3A id='second' />
+    <ELEM3B type='3'>text</ELEM3B>
+  </ELEM2>
+  <ELEM2 type='2' id='third'>
+    <ELEM3A id='third' />
+    <ELEM3B type='3'>text</ELEM3B>
+  </ELEM2>
+</ELEM1>'''
+
+        // Generate the XML.
+        def list = ['first', 'second', 'third']
+
+        xml.ELEM1() {
+            list.each(){ r ->
+                xml.ELEM2(id:r, type:'2') {
+                    xml.ELEM3A(id:r)
+                    xml.ELEM3B(type:'3', 'text')
+                }
+            }
+        }
+
+        // Check that the MarkupBuilder has generated the expected XML.
+        assertEquals(expectedXml, fixEOLs(writer.toString()))
+    }  
+}
diff --git a/groovy-core/src/test/groovy/xml/MarkupTest.groovy b/groovy-core/src/test/groovy/xml/MarkupTest.groovy
new file mode 100644
index 0000000..89f0b77
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/MarkupTest.groovy
@@ -0,0 +1,66 @@
+package groovy.xml
+
+/**
+ * This test uses the concise syntax to test the building of 
+ * textual markup (XML or HTML) using GroovyMarkup
+ */
+class MarkupTest extends TestXmlSupport {
+    
+    void testSmallTree() {
+        def b = new MarkupBuilder()
+        
+        b.root1(a:5, b:7) {
+            elem1('hello1')
+            elem2('hello2')
+            elem3(x:7)
+        }
+    }
+    
+    void testTree() {
+        def b = new MarkupBuilder()
+        
+        b.root2(a:5, b:7) {
+            elem1('hello1')
+            elem2('hello2')
+            nestedElem(x:'abc', y:'def') {
+                child(z:'def')
+                child2()  
+            }
+            
+            nestedElem2(z:'zzz') {
+                child(z:'def')
+                child2("hello")  
+            }
+        }
+    }
+
+    void testContentAndDataInMarkup() {
+        def b = new MarkupBuilder()
+
+        b.a(href:"http://groovy.codehaus.org", "groovy")
+    }
+
+    void testMarkupWithColonsAndNamespaces() {
+        def mkp = new groovy.xml.MarkupBuilder()
+
+        mkp."ns1:customer-description"{
+            "last-name"("Laforge")
+            "first-name"{
+                first("Guillaume")
+                "initial-letters"("A.J.")
+            }
+        }
+    }
+    
+    void testObjectOperationsInMarkup() {
+        def doc = new StreamingMarkupBuilder().bind {
+          root {
+            (1..3).each {
+             item() 
+            }
+          }
+        }
+        
+        assert doc.toString() == "<root><item/><item/><item/></root>"    
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/xml/MarkupWithWriterTest.groovy b/groovy-core/src/test/groovy/xml/MarkupWithWriterTest.groovy
new file mode 100644
index 0000000..190d39f
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/MarkupWithWriterTest.groovy
@@ -0,0 +1,28 @@
+package groovy.xml
+
+/**
+ * This test uses GroovyMarkup with writers other than System.out
+ */
+class MarkupWithWriterTest extends TestXmlSupport {
+
+    void testSmallTreeWithStringWriter() {
+        def writer = new java.io.StringWriter()
+        def b = new MarkupBuilder(writer)
+
+        b.root1(a:5, b:7) {
+            elem1('hello1')
+            elem2('hello2')
+            elem3(x:7)
+        }
+        println writer.toString()
+//        assertEquals "<root1 a='5' b='7'>\n" +
+//                "  <elem1>hello1</elem1>\n" +
+//                "  <elem2>hello2</elem2>\n" +
+//                "  <elem3 x='7' />\n" +
+//                "</root1>", writer.toString()
+    }
+
+    void testWriterUseInScriptFile() {
+        assertScriptFile 'src/test/groovy/xml/UseMarkupWithWriterScript.groovy'
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/xml/MixedMarkupTestSupport.groovy b/groovy-core/src/test/groovy/xml/MixedMarkupTestSupport.groovy
new file mode 100644
index 0000000..67da2d1
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/MixedMarkupTestSupport.groovy
@@ -0,0 +1,33 @@
+package groovy.xml
+
+class MixedMarkupTestSupport {
+
+    private static def mixedXml = '''
+<p>Please read the <a href="index.html">Home</a> page</p>
+'''
+    static void checkMixedMarkup(Closure getRoot) {
+        def root = getRoot(mixedXml)
+        assert root != null
+        def children = root.children()
+        if (isSlurper(root)) {
+            assert children.size() == 1
+            assert children[0].name() == 'a'
+        } else {
+            assert children.size() == 3
+            assert children[1].name() == 'a'
+            assert children[2].toString() == 'page'
+        }
+    }
+
+    private static boolean isSlurper(node) {
+        return node.getClass().name.contains('slurper')
+    }
+
+    private static boolean isParser(node) {
+        return (node instanceof groovy.util.Node)
+    }
+
+    private static boolean isDom(node) {
+        return node.getClass().name.contains('Element')
+    }
+}
diff --git a/groovy-core/src/test/groovy/xml/NamespaceDOMTest.groovy b/groovy-core/src/test/groovy/xml/NamespaceDOMTest.groovy
new file mode 100644
index 0000000..e30f2f5
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/NamespaceDOMTest.groovy
@@ -0,0 +1,73 @@
+package groovy.xml
+
+/**
+ * Test the building of namespaced XML using GroovyMarkup
+ */
+class NamespaceDOMTest extends TestXmlSupport {
+    
+    void testTree() {
+        def builder = DOMBuilder.newInstance()
+        def xmlns = new NamespaceBuilder(builder)
+        
+        def xsd = xmlns.namespace('http://www.w3.org/2001/XMLSchema', 'xsd')
+        
+        def root = xsd.schema(xmlns:['foo':'http://someOtherNamespace']) {
+          annotation {
+              documentation("Purchase order schema for Example.com.")
+              //documentation(xmlns=[xml.lang:'en']) ["Purchase order schema for Example.com."]
+          }
+          element(name:'purchaseOrder', type:'PurchaseOrderType')
+          element(name:'comment', type:'xsd:string')
+          complexType(name:'PurchaseOrderType') {
+            sequence {
+              element(name:'shipTo', type:'USAddress')
+              element(name:'billTo', type:'USAddress')
+              element(minOccurs:'0', ref:'comment')
+              element(name:'items', type:'Items')
+            }
+            attribute(name:'orderDate', type:'xsd:date')
+          }
+          complexType(name:'USAddress') {
+            sequence {
+              element(name:'name', type:'xsd:string')
+              element(name:'street', type:'xsd:string')
+              element(name:'city', type:'xsd:string')
+              element(name:'state', type:'xsd:string')
+              element(name:'zip', type:'xsd:decimal')
+            }
+            attribute(fixed:'US', name:'country', type:'xsd:NMTOKEN')
+          }
+          complexType(name:'Items') {
+            sequence {
+              element(maxOccurs:'unbounded', minOccurs:'0', name:'item') {
+                complexType {
+                  sequence {
+                    element(name:'productName', type:'xsd:string')
+                    element(name:'quantity') {
+                      simpleType {
+                        restriction(base:'xsd:positiveInteger') {
+                          maxExclusive(value:'100')
+                        }
+                      }
+                    }
+                    element(name:'USPrice', type:'xsd:decimal')
+                    element(minOccurs:'0', ref:'comment')
+                    element(minOccurs:'0', name:'shipDate', type:'xsd:date')
+                  }
+                  attribute(name:'partNum', type:'SKU', use:'required')
+                }
+              }
+            }
+          }
+          /* Stock Keeping Unit, a code for identifying products */
+          simpleType(name:'SKU') {
+            restriction(base:'xsd:string') {
+              pattern(value:'\\d{3}-[A-Z]{2}')
+            }
+          }
+        }        
+        assert root != null
+        
+        dump(root)
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/xml/NamespaceNodeGPathTest.groovy b/groovy-core/src/test/groovy/xml/NamespaceNodeGPathTest.groovy
new file mode 100644
index 0000000..3fa18f1
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/NamespaceNodeGPathTest.groovy
@@ -0,0 +1,56 @@
+package groovy.xml
+
+/**
+ * Test the use of GPath navigation with namespaces
+ */
+class NamespaceNodeGPathTest extends TestXmlSupport {
+    
+    void testTree() {
+		Node root = new XmlParser().parseText("""
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+  <xsd:annotation xsd:cheese="Edam">
+     <xsd:documentation>Purchase order schema for Example.com.</xsd:documentation>
+  </xsd:annotation>
+</xsd:schema>
+""")
+
+    		Namespace xsd = new Namespace('http://www.w3.org/2001/XMLSchema', 'xsd')
+
+	    def children = root.children()
+	    println "has children $children"
+	        		
+    		def name = root.name()
+    		println "name is of type ${name.getClass()} with value $name"
+
+		root.children().each { println "has a child with name ${it.name()} and content $it" }
+		    		
+    		def foo = xsd.annotation
+    		println "qname is $foo"
+    		println "qname url is $foo.namespaceURI"
+    		println "qname prefix is $foo.prefix"
+    		println "qname localPart is $foo.localPart"
+    		
+    		def a = root[xsd.annotation]
+    		println "Found results $a"
+    		
+	    assert a.size() == 1 : " size is $a.size()"
+
+   		def aNode = a[0]
+   		def cheese = aNode.attributes()[xsd.cheese]
+		assert cheese == "Edam"   		
+   		println "Found namespaced attribute $cheese"
+
+   		cheese = aNode.attribute(xsd.cheese)
+		assert cheese == "Edam"   		
+   		println "Found namespaced attribute $cheese"
+   		    		
+    		def e = root[xsd.annotation][xsd.documentation]
+    		//def e = a[xsd.documentation]
+
+	    assert e.size() == 1: " size is $e.size()"
+		
+    		String text = e.text()
+    		println "Found element: $e with text: $text"
+    		assert text == "Purchase order schema for Example.com."
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/xml/NamespaceNodeTest.groovy b/groovy-core/src/test/groovy/xml/NamespaceNodeTest.groovy
new file mode 100644
index 0000000..40b2a76
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/NamespaceNodeTest.groovy
@@ -0,0 +1,101 @@
+package groovy.xml
+
+/**
+ * Test the building of namespaced XML using GroovyMarkup
+ */
+class NamespaceNodeTest extends TestXmlSupport {
+    
+    void testTree_FAILS() { if (notYetImplemented()) return
+        def builder = NodeBuilder.newInstance()
+        def xmlns = new NamespaceBuilder(builder)
+        
+        def xsd = xmlns.namespace('http://www.w3.org/2001/XMLSchema', 'xsd')
+        
+        def root = xsd.schema(xmlns:['foo':'http://someOtherNamespace']) {
+          annotation {
+              documentation("Purchase order schema for Example.com.")
+              //documentation(xmlns=[xml.lang:'en']) ["Purchase order schema for Example.com."]
+          }
+          element(name:'purchaseOrder', type:'PurchaseOrderType')
+          element(name:'comment', type:'xsd:string')
+          complexType(name:'PurchaseOrderType') {
+            sequence {
+              element(name:'shipTo', type:'USAddress')
+              element(name:'billTo', type:'USAddress')
+              element(minOccurs:'0', ref:'comment')
+              element(name:'items', type:'Items')
+            }
+            attribute(name:'orderDate', type:'xsd:date')
+          }
+          complexType(name:'USAddress') {
+            sequence {
+              element(name:'name', type:'xsd:string')
+              element(name:'street', type:'xsd:string')
+              element(name:'city', type:'xsd:string')
+              element(name:'state', type:'xsd:string')
+              element(name:'zip', type:'xsd:decimal')
+            }
+            attribute(fixed:'US', name:'country', type:'xsd:NMTOKEN')
+          }
+          complexType(name:'Items') {
+            sequence {
+              element(maxOccurs:'unbounded', minOccurs:'0', name:'item') {
+                complexType {
+                  sequence {
+                    element(name:'productName', type:'xsd:string')
+                    element(name:'quantity') {
+                      simpleType {
+                        restriction(base:'xsd:positiveInteger') {
+                          maxExclusive(value:'100')
+                        }
+                      }
+                    }
+                    element(name:'USPrice', type:'xsd:decimal')
+                    element(minOccurs:'0', ref:'comment')
+                    element(minOccurs:'0', name:'shipDate', type:'xsd:date')
+                  }
+                  attribute(name:'partNum', type:'SKU', use:'required')
+                }
+              }
+            }
+          }
+          /* Stock Keeping Unit, a code for identifying products */
+          simpleType(name:'SKU') {
+            restriction(base:'xsd:string') {
+              pattern(value:'\\d{3}-[A-Z]{2}')
+            }
+          }
+        }        
+        assert root != null
+        
+        assertGPaths(root)
+    }
+    
+    void assertGPaths(Node root) {
+    		Namespace xsd = new Namespace('http://www.w3.org/2001/XMLSchema', 'xsd')
+
+	    def children = root.children()
+	    println "has children $children"
+	        		
+    		def name = root.name()
+    		println "name is of type ${name.getClass()} with value $name"
+
+		root.children().each { println "has a child with name ${it.name()} and content $it" }
+		    		
+    		def foo = xsd.annotation
+    		println "qname is $foo"
+    		println "qname url is $foo.namespaceURI"
+    		println "qname prefix is $foo.prefix"
+    		println "qname localPart is $foo.localPart"
+    		
+    		def a = root[xsd.annotation]
+    		println "Found results $a"
+    		
+    		
+    		def e = root[xsd.annotation][xsd.documentation]
+    		
+    		String text = e.text()
+    		println "Found element: $e with text: $text"
+    		assert text == "Purchase order schema for Example.com."
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/xml/SAXTest.groovy b/groovy-core/src/test/groovy/xml/SAXTest.groovy
new file mode 100644
index 0000000..3bb642a
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/SAXTest.groovy
@@ -0,0 +1,36 @@
+package groovy.xml
+
+/**
+ * This test uses the concise syntax to test the generation
+ * of SAX events using GroovyMarkup
+ */
+class SAXTest extends TestXmlSupport {
+    
+    void testSmallTree() {
+        def b = createSAXBuilder()
+        
+        def root = b.root1(a:5, b:7) {
+            elem1('hello1')
+            elem2('hello2')
+            elem3(x:7)
+        }
+    }
+    
+    void testTree() {
+        def b = createSAXBuilder()
+        
+        def root = b.root2(a:5, b:7) {
+            elem1('hello1')
+            elem2('hello2')
+            nestedElem(x:'abc', y:'def') {
+                child(z:'def')
+                child2()  
+            }
+            
+            nestedElem2(z:'zzz') {
+                child(z:'def')
+                child2("hello")  
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/xml/SmallNamespaceDOMTest.groovy b/groovy-core/src/test/groovy/xml/SmallNamespaceDOMTest.groovy
new file mode 100644
index 0000000..09d7555
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/SmallNamespaceDOMTest.groovy
@@ -0,0 +1,26 @@
+package groovy.xml
+
+class SmallNamespaceDOMTest extends TestXmlSupport {
+    
+    void testTree() {
+        def builder = DOMBuilder.newInstance()
+        def xsd = NamespaceBuilder.newInstance(builder, 'http://www.w3.org/2001/XMLSchema', 'xsd')
+        
+        def root = xsd.schema() {
+          element(name:'purchaseOrder', type:'PurchaseOrderType')
+          element(name:'comment', type:'xsd:string')
+          complexType(name:'PurchaseOrderType') {
+            sequence {
+              element(name:'shipTo', type:'USAddress')
+              element(name:'billTo', type:'USAddress')
+              element(minOccurs:'0', ref:'comment')
+              element(name:'items', type:'Items')
+            }
+            attribute(name:'orderDate', type:'xsd:date')
+          }
+        }        
+        assert root != null
+        
+        dump(root)
+    }
+}
diff --git a/groovy-core/src/test/groovy/xml/StreamingMarkupTest.groovy b/groovy-core/src/test/groovy/xml/StreamingMarkupTest.groovy
new file mode 100644
index 0000000..7e1289e
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/StreamingMarkupTest.groovy
@@ -0,0 +1,45 @@
+package groovy.xml
+
+/**
+ * This test uses the concise syntax to test the building of 
+ * textual markup (XML or HTML) using GroovyMarkup
+ */
+class StreamingMarkupTest extends groovy.xml.TestXmlSupport {
+    
+    void testSmallTree() {
+        def b = new StreamingMarkupBuilder()
+        
+        def m = {
+            delegate.mkp.pi("xml-stylesheet":[href:"mystyle.css", type:"text/css"])
+            root1(a:5, b:7) {
+                elem1('hello1')
+                elem2('hello2')
+                elem3(x:7)
+            }
+        }
+
+        System.out << b.bind(m)
+    }
+    
+    void testTree() {
+        def b = new StreamingMarkupBuilder()
+        
+        def m = {
+            root2(a:5, b:7) {
+                elem1('hello1')
+                elem2('hello2')
+                nestedElem(x:'abc', y:'def') {
+                    child(z:'def')
+                    child2()
+                }
+
+                nestedElem2(z:'zzz') {
+                    child(z:'def')
+                    child2("hello")
+                }
+            }
+        }
+
+        System.out << b.bind(m)
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/xml/TestXmlSupport.java b/groovy-core/src/test/groovy/xml/TestXmlSupport.java
new file mode 100644
index 0000000..cfb771f
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/TestXmlSupport.java
@@ -0,0 +1,84 @@
+/*
+$Id$
+
+Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions of source code must retain copyright
+statements and notices.  Redistributions must also contain a
+copy of this document.
+
+2. Redistributions in binary form must reproduce the
+above copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+3. The name "groovy" must not be used to endorse or promote
+products derived from this Software without prior written
+permission of The Codehaus.  For written permission,
+please contact info@codehaus.org.
+
+4. Products derived from this Software may not be called "groovy"
+nor may "groovy" appear in their names without prior written
+permission of The Codehaus. "groovy" is a registered
+trademark of The Codehaus.
+
+5. Due credit should be given to The Codehaus -
+http://groovy.codehaus.org/
+
+THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+package groovy.xml;
+
+import org.apache.xml.serialize.XMLSerializer;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import java.io.IOException;
+
+/**
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public abstract class TestXmlSupport extends TestSupport {
+
+    protected void dump(Node node) throws IOException {
+        XMLSerializer printer = createSerializer();
+        if (node instanceof Document) {
+            printer.serialize((Document) node);
+        }
+        else {
+            printer.serialize((Element) node);
+        }
+        System.out.println();
+    }
+
+    protected XMLSerializer createSerializer() {
+        return new XMLSerializer(System.out, null);
+    }
+
+    protected SAXBuilder createSAXBuilder() throws IOException {
+        return new SAXBuilder(createSerializer().asContentHandler());
+    }
+}
diff --git a/groovy-core/src/test/groovy/xml/TraversalTestSupport.groovy b/groovy-core/src/test/groovy/xml/TraversalTestSupport.groovy
new file mode 100644
index 0000000..81fac56
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/TraversalTestSupport.groovy
@@ -0,0 +1,35 @@
+package groovy.xml
+
+class TraversalTestSupport {
+    private static def nestedXml = '''
+    <_1>
+        <_1_1>
+            <_1_1_1/>
+            <_1_1_2>
+                <_1_1_2_1/>
+            </_1_1_2>
+        </_1_1>
+        <_1_2>
+            <_1_2_1/>
+        </_1_2>
+    </_1>
+    '''
+
+    static void checkDepthFirst(Closure getRoot) {
+        def root = getRoot(nestedXml)
+        def trace = ''
+        root.depthFirst().each{ trace += it.name() + ' ' }
+        assert trace == '_1 _1_1 _1_1_1 _1_1_2 _1_1_2_1 _1_2 _1_2_1 '
+        // test shorthand
+        trace = ''
+        root.'_1_2'.'**'.each{ trace += it.name() + ' ' }
+        assert trace == '_1_2 _1_2_1 '
+    }
+
+    static void checkBreadthFirst(Closure getRoot) {
+        def root = getRoot(nestedXml)
+        def trace = ''
+        root.breadthFirst().each{ trace += it.name() + ' ' }
+        assert trace == '_1 _1_1 _1_2 _1_1_1 _1_1_2 _1_2_1 _1_1_2_1 '
+    }
+}
diff --git a/groovy-core/src/test/groovy/xml/UseMarkupWithWriterScript.groovy b/groovy-core/src/test/groovy/xml/UseMarkupWithWriterScript.groovy
new file mode 100644
index 0000000..5d01a94
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/UseMarkupWithWriterScript.groovy
@@ -0,0 +1,8 @@
+// used by MarkupWithWriterTest.testWriterUseInScriptFile
+
+writer = new java.io.StringWriter()
+b = new groovy.xml.MarkupBuilder(writer)
+
+b.root1(a:5)
+println writer.toString()
+assert "<root1 a='5' />" == writer.toString()
\ No newline at end of file
diff --git a/groovy-core/src/test/groovy/xml/VerboseDOMTest.groovy b/groovy-core/src/test/groovy/xml/VerboseDOMTest.groovy
new file mode 100644
index 0000000..83b99b9
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/VerboseDOMTest.groovy
@@ -0,0 +1,81 @@
+package groovy.xml
+
+/**
+ * This test uses the verbose syntax to test the building of 
+ * W3C DOM trees using GroovyMarkup
+ */
+class VerboseDOMTest extends TestXmlSupport {
+    
+    void testSmallTree() {
+        def b = DOMBuilder.newInstance()
+        
+        def root = b.root1(['a':5, 'b':7], {->
+            elem1('hello1')
+            elem2('hello2')
+            elem3(['x':7])
+        })
+        
+        assert root != null
+        
+        dump(root)
+    }
+    
+    void testTree() {
+        def b = DOMBuilder.newInstance()
+        
+        def root = b.root2(['a':5, 'b':7], {
+            elem1('hello1')
+            elem2('hello2')
+            nestedElem(['x':'abc', 'y':'def'], {->
+                child(['z':'def'])
+                child2()
+            })
+
+            nestedElem2(['z':'zzz'], {->
+                child(['z':'def'])
+                child2("hello")  
+            })
+        })
+        
+        assert root != null
+        
+        dump(root)
+
+/*
+		def elem1 = root.elem1
+        assert elem1.value() := 'hello1'
+        
+        def elem2 = root.elem2
+        assert elem2.value() := 'hello2'
+
+        assert root.elem1.value() := 'hello1'
+        assert root.elem2.value() := 'hello2'
+
+        assert root.nestedElem.attributes() := ['x':'abc', 'y':'def']        
+        assert root.nestedElem.child.attributes() := ['z':'def']
+        assert root.nestedElem.child2.value() := []
+        assert root.nestedElem.child2.text() := ''
+
+        assert root.nestedElem2.attributes() := ['z':'zzz']      
+        assert root.nestedElem2.child.attributes() := ['z':'def']
+        assert root.nestedElem2.child2.value() := 'hello'
+        assert root.nestedElem2.child2.text() := 'hello'
+        
+        def list = root.value()
+        assert list.size() := 4
+        
+        assert root.attributes().a := 5
+        assert root.attributes().b := 7
+
+        assert root.nestedElem.attributes().x := 'abc'
+        assert root.nestedElem.attributes().y := 'def'
+        assert root.nestedElem2.attributes().z := 'zzz'
+        assert root.nestedElem2.child.attributes().z := 'def'
+*/        
+        /** @todo parser add .@ as an operation
+                assert root.@a := 5
+                assert root.@b := 7
+        */        
+    }
+    
+}
diff --git a/groovy-core/src/test/groovy/xml/XmlTest.java b/groovy-core/src/test/groovy/xml/XmlTest.java
new file mode 100644
index 0000000..edd5135
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/XmlTest.java
@@ -0,0 +1,80 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package groovy.xml;
+
+import groovy.lang.GroovyObject;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+/**
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class XmlTest extends TestSupport {
+
+    public void testTree() throws Exception {
+        GroovyObject object = compile("src/test/groovy/xml/SmallNamespaceDOMTest.groovy");
+        object.invokeMethod("testTree", null);
+    }
+
+    public void testQName() throws Exception {
+        QName qname = new QName("urn:mynamespace","localPart","x");
+
+        assertTrue(qname.equals(new QName("urn:mynamespace","localPart")));
+        assertTrue(qname.equals("urn:mynamespace:localPart"));
+        assertTrue(qname.equals("x:localPart"));
+
+        assertTrue(!qname.equals(null));
+        assertTrue(!qname.equals(""));
+        assertTrue(!qname.equals(" "));
+        assertTrue(!qname.equals("localPart"));
+        assertTrue(!qname.equals("x:"));
+        assertTrue(!qname.equals(":"));
+        assertTrue(!qname.equals(":localPart"));
+    }
+}
diff --git a/groovy-core/src/test/groovy/xml/dom/DOMCategoryTest.groovy b/groovy-core/src/test/groovy/xml/dom/DOMCategoryTest.groovy
new file mode 100644
index 0000000..56d56a7
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/dom/DOMCategoryTest.groovy
@@ -0,0 +1,52 @@
+package groovy.xml.dom
+
+import groovy.xml.DOMBuilder
+import groovy.xml.GpathSyntaxTestSupport
+import groovy.xml.TraversalTestSupport
+import groovy.xml.MixedMarkupTestSupport
+
+class DOMCategoryTest extends GroovyTestCase {
+
+    def getRoot = { xml ->
+        def reader = new StringReader(xml)
+        def doc    = DOMBuilder.parse(reader)
+        def root   = doc.documentElement
+    }
+
+    void testMixedMarkup() {
+        use(DOMCategory) {
+            MixedMarkupTestSupport.checkMixedMarkup(getRoot)
+        }
+    }
+
+    void testElement() {
+        use(DOMCategory) {
+            GpathSyntaxTestSupport.checkElement(getRoot)
+            GpathSyntaxTestSupport.checkFindElement(getRoot)
+            GpathSyntaxTestSupport.checkElementTypes(getRoot)
+            GpathSyntaxTestSupport.checkElementClosureInteraction(getRoot)
+        }
+    }
+
+    void testAttribute() {
+        use(DOMCategory) {
+            GpathSyntaxTestSupport.checkAttribute(getRoot)
+            GpathSyntaxTestSupport.checkAttributes(getRoot)
+        }
+    }
+
+    void testNavigation() {
+        use(DOMCategory) {
+            GpathSyntaxTestSupport.checkChildren(getRoot)
+            GpathSyntaxTestSupport.checkParent(getRoot)
+        }
+    }
+
+    void testTraversal() {
+        use(DOMCategory) {
+            TraversalTestSupport.checkDepthFirst(getRoot)
+            TraversalTestSupport.checkBreadthFirst(getRoot)
+        }
+    }
+
+}
diff --git a/groovy-core/src/test/groovy/xml/dom/DOMTest.groovy b/groovy-core/src/test/groovy/xml/dom/DOMTest.groovy
new file mode 100644
index 0000000..467b63d
--- /dev/null
+++ b/groovy-core/src/test/groovy/xml/dom/DOMTest.groovy
@@ -0,0 +1,87 @@
+package groovy.xml.dom
+
+import groovy.xml.*
+import org.codehaus.groovy.sandbox.markup.*
+import org.codehaus.groovy.tools.xml.*
+
+class DOMTest extends GroovyTestCase {
+    def benchmark = false
+
+    void testDOMParser() {
+        def xml = new StringReader("<html><head><title class='mytitle'>Test</title></head><body><p class='mystyle'>This is a test.</p></body></html>")
+        def doc = DOMBuilder.parse(xml)
+        def html = doc.documentElement
+        if (!benchmark) assertCorrect html
+    }
+
+    void testDOMBuilder() {
+        def html = DOMBuilder.newInstance().
+        html {
+          head {
+            title (class:"mytitle", "Test")
+          }
+          body {
+            p (class:"mystyle", "This is a test.")
+          }
+        }
+        if (!benchmark) assertCorrect html
+    }
+
+  void testStreamingDOMBuilder_FAILS() { if (notYetImplemented()) return
+
+        def doc = new StreamingDOMBuilder().bind{
+          html {
+            head {
+              title (class:"mytitle", "Test")
+            }
+            body {
+              p (class:"mystyle", "This is a test.")
+            }
+          }
+        }()
+        if (!benchmark) { assertCorrect doc.documentElement }
+    }
+
+    private def assertCorrect(html) {
+        use (DOMCategory) {
+          assert html.head.title.collect{ it.text() } == ['Test']
+          assert html.head.title[0].text() == 'Test'
+          assert html.body.p[0].text() == 'This is a test.'
+          assert html.find { it.tagName == 'body' }.tagName == 'body'
+          assert html.getElementsByTagName('*').findAll{ it.'@class' != '' }.size() == 2
+        }
+        // should fail outside category
+        shouldFail (MissingPropertyException) { html.head }
+    }
+  
+    static void main(args) {
+        // Relative results:
+        // Test       05 May 2004  14 Oct 2006
+        // Parser:    1.0          1.0
+        // Builder:   1.05         2.90
+        // Streaming: 0.77         0.20
+        def x = args.size() == 0 ? 1000 : Integer.parseInt(args[0])
+        def mydomtest = new DOMTest()
+        def standard = 0
+        mydomtest.benchmark = true
+        [{ mydomtest.testDOMParser() },
+         { mydomtest.testDOMBuilder() },
+         { mydomtest.testStreamingDOMBuilder_FAILS() }].eachWithIndex { testMethod, index ->
+            // Run the method once to fill any caches and to load classes
+            testMethod()
+            def start = System.currentTimeMillis()
+            def lastIndex
+            for (i in 1..x) {
+                testMethod()
+                lastIndex = i
+            }
+            def elapsed = System.currentTimeMillis() - start
+            def result = lastIndex * 1000 / elapsed
+
+            standard = (standard == 0 ? result : standard)
+            def factor = result/standard
+            def relative = 1/factor
+            println "${index}: ${factor}x relative=${relative} (${result} trees/s)"
+        }
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/ant/GroovyTest.java b/groovy-core/src/test/org/codehaus/groovy/ant/GroovyTest.java
new file mode 100644
index 0000000..574efa4
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/ant/GroovyTest.java
@@ -0,0 +1,80 @@
+package org.codehaus.groovy.ant;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+
+import groovy.util.GroovyTestCase;
+
+/**
+ * Unit tests for the {@link Groovy} ant task.
+ * Caution: the *.groovy files used by this test should not get compiled with the rest of the
+ * test classes compilation process otherwiser they would be available in the classpath
+ * and the tests here would be meaningless (tested by testClasspath_missing).
+ * @author Marc Guillemot
+ */
+public class GroovyTest extends GroovyTestCase {
+	public static String FLAG = null;
+    private final File antFile = new File("src/test/org/codehaus/groovy/ant/GroovyTest.xml");
+	private Project project;
+
+	protected void setUp() throws Exception
+	{
+		super.setUp();
+		project = new Project();
+		project.init();
+		ProjectHelper.getProjectHelper().parse(project, antFile);
+		FLAG = null;
+	}
+
+	public void testGroovyCodeWithinTag() {
+		assertNull(FLAG);
+		project.executeTarget("groovyCodeWithinTask");
+		assertEquals("from groovy inlined in ant", FLAG);
+	}
+
+	public void testGroovyCodeExternalFile() {
+		assertNull(FLAG);
+		project.executeTarget("groovyCodeInExternalFile");
+		assertEquals("from groovy file called from ant", FLAG);
+	}
+
+	public void testGroovyCodeInExternalFileWithOtherClass() {
+		assertNull(FLAG);
+		project.executeTarget("groovyCodeInExternalFileWithOtherClass");
+		assertEquals("from GroovyTest2Class.doSomething()", FLAG);
+	}
+
+	public void testClasspath_missing() {
+		try
+		{
+			project.executeTarget("groovyClasspath_missing");
+			fail();
+		}
+		catch (final Exception e)
+		{
+			assertEquals(BuildException.class, e.getClass());
+		}
+		
+	}
+
+	public void testClasspath_classpathAttribute() {
+		assertNull(FLAG);
+		project.executeTarget("groovyClasspath_classpathAttribute");
+		assertEquals("from groovytest3.GroovyTest3Class.doSomething()", FLAG);
+	}
+
+	public void testClasspath_classpathrefAttribute() {
+		assertNull(FLAG);
+		project.executeTarget("groovyClasspath_classpathrefAttribute");
+		assertEquals("from groovytest3.GroovyTest3Class.doSomething()", FLAG);
+	}
+
+	public void testClasspath_nestedclasspath() {
+		assertNull(FLAG);
+		project.executeTarget("groovyClasspath_nestedClasspath");
+		assertEquals("from groovytest3.GroovyTest3Class.doSomething()", FLAG);
+	}
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/ant/GroovyTest.xml b/groovy-core/src/test/org/codehaus/groovy/ant/GroovyTest.xml
new file mode 100644
index 0000000..057b88b
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/ant/GroovyTest.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+
+<project name="test-groovy-task" default="groovyCodeWithinTask" basedir=".">
+
+	<target name="groovyCodeWithinTask" depends="defineTask">
+		<groovy>
+			org.codehaus.groovy.ant.GroovyTest.FLAG = "from groovy inlined in ant"
+		</groovy>
+	</target>
+
+	<target name="groovyCodeInExternalFile" depends="defineTask">
+		<groovy src="GroovyTest1.groovy"/>
+	</target>
+
+	<target name="groovyCodeInExternalFileWithOtherClass" depends="defineTask">
+		<groovy src="GroovyTest2.groovy"/>
+	</target>
+
+	<target name="groovyClasspath_missing" depends="defineTask" description="should fail!">
+		<groovy>
+def foo = new GroovyTest3Class()
+foo.doSomething()
+		</groovy>
+	</target>
+
+	<target name="groovyClasspath_classpathAttribute" depends="defineTask">
+		<groovy classpath="groovytest3">
+def foo = new GroovyTest3Class()
+foo.doSomething()
+		</groovy>
+	</target>
+
+	<target name="groovyClasspath_classpathrefAttribute" depends="defineTask">
+		<path id="myClasspathRef">
+			<pathelement location="groovytest3"/>
+		</path>
+
+		<groovy classpathref="myClasspathRef">
+def foo = new GroovyTest3Class()
+foo.doSomething()
+		</groovy>
+	</target>
+
+	<target name="groovyClasspath_nestedClasspath" depends="defineTask">
+		<groovy classpathref="myClasspathRef">
+			<classpath>
+				<pathelement location="groovytest3"/>
+			</classpath>
+def foo = new GroovyTest3Class()
+foo.doSomething()
+		</groovy>
+	</target>
+
+	<target name="defineTask">
+		<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
+	</target>
+</project>
\ No newline at end of file
diff --git a/groovy-core/src/test/org/codehaus/groovy/ant/GroovyTest1.groovy b/groovy-core/src/test/org/codehaus/groovy/ant/GroovyTest1.groovy
new file mode 100644
index 0000000..869cdeb
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/ant/GroovyTest1.groovy
@@ -0,0 +1,2 @@
+
+org.codehaus.groovy.ant.GroovyTest.FLAG = "from groovy file called from ant"
diff --git a/groovy-core/src/test/org/codehaus/groovy/ant/GroovyTest2.groovy b/groovy-core/src/test/org/codehaus/groovy/ant/GroovyTest2.groovy
new file mode 100644
index 0000000..b058150
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/ant/GroovyTest2.groovy
@@ -0,0 +1,3 @@
+
+def foo = new GroovyTest2Class()
+foo.doSomething()
diff --git a/groovy-core/src/test/org/codehaus/groovy/ant/GroovyTest2Class.groovy b/groovy-core/src/test/org/codehaus/groovy/ant/GroovyTest2Class.groovy
new file mode 100644
index 0000000..3ed9537
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/ant/GroovyTest2Class.groovy
@@ -0,0 +1,9 @@
+
+class GroovyTest2Class
+{
+
+	void doSomething()
+	{
+		org.codehaus.groovy.ant.GroovyTest.FLAG = "from GroovyTest2Class.doSomething()"
+	}
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/ant/groovytest3/GroovyTest3Class.groovy b/groovy-core/src/test/org/codehaus/groovy/ant/groovytest3/GroovyTest3Class.groovy
new file mode 100644
index 0000000..f345eb5
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/ant/groovytest3/GroovyTest3Class.groovy
@@ -0,0 +1,9 @@
+
+class GroovyTest3Class
+{
+
+	void doSomething()
+	{
+		org.codehaus.groovy.ant.GroovyTest.FLAG = "from groovytest3.GroovyTest3Class.doSomething()"
+	}
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/antlr/GroovySourceASTTest.java b/groovy-core/src/test/org/codehaus/groovy/antlr/GroovySourceASTTest.java
new file mode 100644
index 0000000..cf88fb7
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/antlr/GroovySourceASTTest.java
@@ -0,0 +1,28 @@
+package org.codehaus.groovy.antlr;
+
+import groovy.util.GroovyTestCase;
+
+public class GroovySourceASTTest extends GroovyTestCase {
+    GroovySourceAST a;
+    GroovySourceAST b;
+
+    protected void setUp() throws Exception {
+        a = new GroovySourceAST();
+        a.setLine(3);
+        a.setColumn(3);
+
+        b = new GroovySourceAST();
+        b.setLine(4);
+        b.setColumn(2);
+    }
+    public void testLessThan() throws Exception {
+        assertTrue(a.compareTo(b) < 0);
+    }
+    public void testEquality() throws Exception {
+        assertTrue(a.equals(a));
+        assertTrue(a.compareTo(a) == 0);
+    }
+    public void testGreaterThan() throws Exception {
+        assertTrue(b.compareTo(a) > 0);
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/antlr/SourceBufferTest.java b/groovy-core/src/test/org/codehaus/groovy/antlr/SourceBufferTest.java
new file mode 100644
index 0000000..e2a71da
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/antlr/SourceBufferTest.java
@@ -0,0 +1,120 @@
+/*
+ $Id$
+
+ Copyright 2005 (C) Jeremy Rayner. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.antlr;
+
+import groovy.util.GroovyTestCase;
+
+import java.io.Reader;
+import java.io.StringReader;
+
+/**
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+public class SourceBufferTest extends GroovyTestCase {
+
+    public void testEmptyBuffer() throws Exception {
+        SourceBuffer buffer = getSourceBuffer("");
+        assertNull(buffer.getSnippet(new LineColumn(1,1),new LineColumn(1,1)));
+    }
+
+    public void testSimpleUsage() throws Exception {
+        SourceBuffer buffer = getSourceBuffer("println 'hello world'");
+        assertEquals("hello",buffer.getSnippet(new LineColumn(1,10),new LineColumn(1,15)));
+    }
+
+    public void testUnixLineUsage() throws Exception {
+        String endOfLine = "\n";
+        StringBuffer src = new StringBuffer();
+        src.append("println 'hello world'").append(endOfLine);
+        src.append("println 'oh not, not that again'").append(endOfLine);
+        SourceBuffer buffer = getSourceBuffer(src.toString());
+        assertEquals("hello",buffer.getSnippet(new LineColumn(1,10),new LineColumn(1,15)));
+        assertEquals("world'" + endOfLine + "print",buffer.getSnippet(new LineColumn(1,16),new LineColumn(2,6)));
+        assertEquals(endOfLine,buffer.getSnippet(new LineColumn(1,22),new LineColumn(1,23)));
+        assertEquals(endOfLine,buffer.getSnippet(new LineColumn(2,33),new LineColumn(2,34)));
+    }
+
+    public void testDOSLineUsage() throws Exception {
+        String endOfLine = "\r\n";
+        StringBuffer src = new StringBuffer();
+        src.append("println 'hello world'").append(endOfLine);
+        src.append("println 'oh not, not that again'").append(endOfLine);
+        SourceBuffer buffer = getSourceBuffer(src.toString());
+        assertEquals("hello",buffer.getSnippet(new LineColumn(1,10),new LineColumn(1,15)));
+        assertEquals("oh not",buffer.getSnippet(new LineColumn(2,10),new LineColumn(2,16)));
+        assertEquals("world'" + endOfLine + "print",buffer.getSnippet(new LineColumn(1,16),new LineColumn(2,6)));
+        assertEquals(endOfLine,buffer.getSnippet(new LineColumn(1,22),new LineColumn(1,24)));
+        assertEquals(endOfLine,buffer.getSnippet(new LineColumn(2,33),new LineColumn(2,35)));
+    }
+
+    public void testOutOfBounds() throws Exception {
+        String endOfLine = "\n";
+        StringBuffer src = new StringBuffer();
+        src.append("println 'hello world'").append(endOfLine);
+        src.append("println 'oh not, not that again'").append(endOfLine);
+        SourceBuffer buffer = getSourceBuffer(src.toString());
+        assertEquals("println",buffer.getSnippet(new LineColumn(0,0),new LineColumn(1,8)));
+        assertEquals("println",buffer.getSnippet(new LineColumn(-10,-1),new LineColumn(1,8)));
+        assertEquals(endOfLine,buffer.getSnippet(new LineColumn(2,33),new LineColumn(2,40)));
+        assertEquals("",buffer.getSnippet(new LineColumn(3,33),new LineColumn(6,40)));
+    }
+
+    private SourceBuffer getSourceBuffer(String text) throws Exception {
+        SourceBuffer buffer = new SourceBuffer();
+        Reader reader = new UnicodeEscapingReader(new StringReader(text),buffer);
+
+        while (reader.read() != -1) {
+            // empty loop
+            // - read all characters till the end of the reader
+            // UnicodeEscapingReader has side effects of
+            // filling the buffer
+        }
+        return buffer;
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/antlr/treewalker/Java2GroovyTest.java b/groovy-core/src/test/org/codehaus/groovy/antlr/treewalker/Java2GroovyTest.java
new file mode 100644
index 0000000..5f8090a
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/antlr/treewalker/Java2GroovyTest.java
@@ -0,0 +1,65 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr.treewalker;
+
+import groovy.util.GroovyTestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.PrintStream;
+import java.io.StringReader;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.PosixParser;
+import org.codehaus.groovy.antlr.AntlrASTProcessor;
+import org.codehaus.groovy.antlr.SourceBuffer;
+import org.codehaus.groovy.antlr.UnicodeEscapingReader;
+import org.codehaus.groovy.antlr.java.Java2GroovyConverter;
+import org.codehaus.groovy.antlr.java.Java2GroovyMain;
+import org.codehaus.groovy.antlr.java.JavaLexer;
+import org.codehaus.groovy.antlr.java.JavaRecognizer;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+
+import antlr.collections.AST;
+
+public class Java2GroovyTest extends GroovyTestCase {
+
+	public void testSimpleClass() throws Exception {
+		assertEquals("private class Foo {int x = 1}", convert("private class Foo{int x=1;}"));
+	}
+
+	public void testStringLiteral() throws Exception {
+        assertEquals("class Foo {String x = \"mooky\"}", convert("public class Foo{String x = \"mooky\";}"));
+        assertEquals("class C {void m(String s) {File f = new File(\"sl\" + s)}}", convert("public class C{void m(String s) {File f=new File(\"sl\" + s);}}"));
+	}
+	
+	private String convert(String input) throws Exception {
+		return Java2GroovyMain.convert(input);
+	}
+	private String mindmap(String input) throws Exception {
+		return Java2GroovyMain.mindmap(input);
+	}
+	private String nodePrinter(String input) throws Exception {
+		return Java2GroovyMain.nodePrinter(input);
+	}
+}
+
diff --git a/groovy-core/src/test/org/codehaus/groovy/antlr/treewalker/SourcePrinterTest.java b/groovy-core/src/test/org/codehaus/groovy/antlr/treewalker/SourcePrinterTest.java
new file mode 100644
index 0000000..0675594
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/antlr/treewalker/SourcePrinterTest.java
@@ -0,0 +1,869 @@
+/**
+ *
+ * Copyright 2005 Jeremy Rayner
+ *
+ * Licensed 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.antlr.treewalker;
+
+import groovy.util.GroovyTestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.StringReader;
+
+import org.codehaus.groovy.antlr.AntlrASTProcessor;
+import org.codehaus.groovy.antlr.SourceBuffer;
+import org.codehaus.groovy.antlr.UnicodeEscapingReader;
+import org.codehaus.groovy.antlr.parser.GroovyLexer;
+import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
+
+import antlr.collections.AST;
+
+/**
+ * Testcases for the antlr AST visitor that prints groovy source code.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ * @version $Revision$
+ */
+public class SourcePrinterTest extends GroovyTestCase {
+
+	public void testAbstract() throws Exception {
+		assertEquals("public abstract class Foo {}", pretty("public abstract class Foo{}"));
+	}
+	
+    public void testAnnotation() throws Exception{
+        assertEquals("@Crimson foo", pretty("@Crimson foo"));
+        assertEquals("@Override int hashCode() {return 0}", pretty("@Override int hashCode() {return 0}"));
+    }
+    
+    public void testAnnotations() throws Exception{
+    	assertEquals("@Important @Blue package foo.bar",pretty("@Important @Blue package foo.bar"));
+    }
+
+    public void testAnnotationArrayInit() throws Exception{
+    	// obsolete java syntax
+    }
+    
+    public void testAnnotationDef() throws Exception{
+    	// todo - 17 July 2006 - test fine, however this parses but causes error in AntlrParserPlugin
+        assertEquals("public @interface Foo{}", pretty("public @interface Foo{}"));
+    }
+    
+    public void testAnnotationFieldDef() throws Exception{
+    	assertEquals("public @interface Foo{int bar() default 123}", pretty("public @interface Foo{int bar() default 123}"));
+    }
+    
+    public void testAnnotationMemberValuePair() throws Exception{
+    	assertEquals("@Prime(value = 17) int foo",pretty("@Prime(value=17) int foo"));
+    	assertEquals("@Blue(v = 3, v = 5) int bar",pretty("@Blue(v = 3, v = 5) int bar"));
+    }
+    
+    public void testArrayDeclarator() throws Exception {
+    	assertEquals("int[] primes = new int[5]", pretty("int[] primes = new int[5]"));
+    }
+    
+    public void testAssign() throws Exception {
+        assertEquals("a = 12", pretty("a=12"));
+    }
+    
+    public void testBand() throws Exception {
+    	assertEquals("def x = 1 & 2", pretty("def x=1&2"));
+    }
+
+    public void testBandAssign() throws Exception {
+    	assertEquals("x &= 2", pretty("x&=2"));
+    }
+    
+    public void testBnot() throws Exception {
+    	assertEquals("def z = ~123", pretty("def z = ~123"));
+    }
+    
+    public void testBor() throws Exception {
+    	assertEquals("def y = 1 | 2", pretty("def y = 1 | 2"));
+    }
+    
+    public void testBorAssign() throws Exception {
+    	assertEquals("y |= 2", pretty("y|=2"));
+    }
+
+    public void testBsr() throws Exception {
+    	// unsigned right shift
+    	assertEquals("def q = 1 >>> 2", pretty("def q = 1 >>> 2"));
+    }
+
+    public void testBsrAssign() throws Exception {
+    	assertEquals("y >>>= 2", pretty("y>>>=2"));
+    }
+    
+    public void testBxor() throws Exception {
+    	assertEquals("def y = true ^ false", pretty("def y = true ^ false"));
+    }
+    
+    public void testBxorAssign() throws Exception {
+    	assertEquals("y ^= false", pretty("y^=false"));
+    }
+
+    public void testCaseGroup() throws Exception {
+        assertEquals("switch (foo) {case bar:x = 1}", pretty("switch(foo){case bar:x=1}"));
+    }
+    
+    public void testClassDef() throws Exception {
+        assertEquals("class Foo {def bar}", pretty("class Foo{def bar}"));
+    }
+
+    public void testClosedBlock() throws Exception{
+        assertEquals("[1, 2, 3].each {println it}", pretty("[1,2,3].each{println it}"));
+        assertEquals("def x = foo.bar(mooky){ x, y -> wibble(y, x)}", pretty("def x = foo.bar(mooky) {x,y-> wibble(y,x)}"));
+        // todo: above is not quite the spacing I would expect, but good enough for now...
+    }
+    
+    public void testCompareTo() throws Exception{
+    	assertEquals("1 <=> 2", pretty("1<=>2"));
+    }
+    
+    public void testCtorCall() throws Exception{
+    	assertEquals("class Foo {Foo(int x) {this()}}",pretty("class Foo{Foo(int x) {this()}}"));
+    	assertEquals("class Foo {Foo( x) {this()}}",pretty("class Foo{Foo(x) {this()}}"));
+        // todo: above is not quite the spacing I would expect, but good enough for now...
+    }
+    
+    public void testCtorIdent() throws Exception {
+        assertEquals("class Foo {private Foo() {}}", pretty("class Foo {private Foo() {}}"));
+    }
+    
+    public void testDec() throws Exception {
+    	assertEquals("--b", pretty("--b"));
+    }
+
+    public void testDiv() throws Exception {
+    	assertEquals("1 / 2", pretty("1/2"));
+    }
+    
+    public void testDivAssign() throws Exception {
+    	assertEquals("x /= 2", pretty("x/=2"));
+    }
+    
+    public void testDot() throws Exception {
+    	assertEquals("java.util.Date d = new java.util.Date()", pretty("java.util.Date d = new java.util.Date()"));
+    	assertEquals("class Foo extends java.util.Date {}", pretty("class Foo extends java.util.Date {}"));
+    	assertEquals("foo.bar.mooky()", pretty("foo.bar.mooky()"));
+    	assertEquals("package foo.bar", pretty("package foo.bar"));
+    	assertEquals("import java.util.Date", pretty("import java.util.Date"));
+    	assertEquals("import java.io.*", pretty("import java.io.*"));
+    	assertEquals("@foo.Bar mooky", pretty("@foo.Bar mooky"));
+    	assertEquals("def foo() throws bar.MookyException{}", pretty("def foo() throws bar.MookyException{}"));
+    	assertEquals("def x = \"${foo.bar}\"", pretty("def x = \"${foo.bar}\""));
+    }
+    
+    public void testDynamicMember() throws Exception{
+    	assertEquals("foo.(bar)", pretty("foo.(bar)"));
+    	assertEquals("foo.\"${bar}\"", pretty("foo.\"${bar}\""));
+    }
+    
+    public void testElist() throws Exception {
+    	assertEquals("println 2 + 2", pretty("println 2 + 2"));
+    	assertEquals("for (i = 0, j = 2 ; i < 10 ; i++, j--){print i}", pretty("for (i = 0,j = 2;i < 10; i++, j--) {print i}"));
+    	assertEquals("foo()", pretty("foo()")); // empty ELIST
+    	assertEquals("foo(bar, mooky)", pretty("foo( bar , mooky )"));
+    }
+
+    public void testEnumConstantDef() throws Exception {
+    	assertEquals("enum Coin {PENNY(1), DIME(10), QUARTER(25)}", pretty("enum Coin {PENNY(1), DIME(10), QUARTER(25)}"));
+    }
+
+    public void testEnumDef() throws Exception {
+    	assertEquals("enum Season {WINTER, SPRING, SUMMER, AUTUMN}", pretty("enum Season{WINTER,SPRING,SUMMER,AUTUMN}"));
+    	//todo: more strange spacing in following line
+    	assertEquals("enum Operation {ADDITION{double eval( x,  y) {return x + y}}}",pretty("enum Operation {ADDITION {double eval(x,y) {return x + y}}}"));    	
+    }
+    
+    public void testEqual() throws Exception {
+        assertEquals("a == b", pretty("a==b"));
+    }
+
+    public void testEsc_FAILS() throws Exception { if (notYetImplemented()) return;
+    	// dquote-tab-dquote
+    	assertEquals("println \"\\\"\t\\\"\"", pretty("println \"\\\"\t\\\"\""));
+    }
+    
+    public void testExponent() throws Exception {
+    	assertEquals("println 1.2e-10", pretty("println 1.2e-10"));
+    }
+    
+    public void testExpr_FAILS() throws Exception { if (notYetImplemented()) return;
+    	assertEquals("System.out.println(x)", pretty("System.out.println(x)"));
+    	assertEquals("return f", pretty("return f"));
+        assertEquals("foo(bar);mooky(bar)", pretty("foo(bar);mooky(bar)"));
+    }
+
+    public void testExtendsClause() throws Exception {
+        assertEquals("class Foo extends Bar {}", pretty("class Foo extends Bar {}"));
+        assertEquals("interface Wibble extends Mooky{}", pretty("interface Wibble extends Mooky {}"));
+        //todo spacing is odd, c.f. last space in class vs interface above
+    }
+    
+    public void testFinal() throws Exception {
+    	assertEquals("public final int getX() {return 0}", pretty("public final int getX() {return 0}"));
+    }
+    public void testForCondition() throws Exception {
+    	assertEquals("for (i = 0 ; i < 10 ; i++){println i}", pretty("for (i=0;i<10;i++) {println i}"));
+    }
+    
+    // testForInit() covered by testForCondition()
+    
+    public void testForInIterable() throws Exception {
+        assertEquals("for (i in [1, 2]) {}", pretty("for (i in [1,2]) {}"));
+    }
+
+    // testForIterator() covered by testForCondition()
+    
+    public void testGe() throws Exception {
+    	assertEquals("if (60 >= 70) {}", pretty("if (60>=70) {}"));
+    }
+    
+    public void testGt() throws Exception {
+        assertEquals("if (2070 > 354) {}", pretty("if (2070 > 354) {}"));
+    }
+
+    public void testHexDigit() throws Exception {
+        assertEquals("def bar = 0xCaFe", pretty("def bar = 0xCaFe"));    	
+    }
+    public void testHexDigitInUnicodeEscape_FAILS() throws Exception { if (notYetImplemented()) return;
+      assertEquals("def foo = '\\ubabe'", pretty("def foo = '\\ubabe'"));
+    }
+    
+    public void testIdent() throws Exception {
+    	// used _everywhere_ , lets assume that the other specific 
+    	// testcases include enough ident usage for now.
+        assertEquals("foo.bar", pretty("foo.bar"));
+    }
+
+    public void testImplementsClause() throws Exception {
+        assertEquals("class Foo implements Bar {}", pretty("class Foo implements Bar {}"));
+    }
+
+    public void testImplicitParameters() throws Exception {
+    	assertEquals("[1, 2, 3].each {println it}", pretty("[1,2,3].each{println it}"));
+    }
+    
+    public void testImport() throws Exception {
+        assertEquals("import foo.bar.Wibble", pretty("import foo.bar.Wibble"));
+    }
+    
+    public void testInc() throws Exception {
+    	assertEquals("++x",pretty("++x"));
+    }
+
+    public void testIndexOp() throws Exception {
+        assertEquals("foo.bar()[fred.wilma()]", pretty("foo.bar()[fred.wilma()]"));
+    }
+    
+    public void testInterfaceDef() throws Exception {
+    	//todo, the spacing here is... unusual
+    	assertEquals("interface Foo{void blah() }", pretty("interface Foo{void blah()}"));
+    }
+
+    public void testInstanceInit() throws Exception {
+    	assertEquals("class Foo {{x = 1}}", pretty("class Foo {{x=1}}"));
+    }
+
+    public void testLabeledArg() throws Exception {
+        assertEquals("myMethod(argOne:123, argTwo:123)", pretty("myMethod(argOne:123,argTwo:123)"));
+        assertEquals("myMap = [keyOne:123, keyTwo:234]", pretty("myMap = [keyOne:123,keyTwo:234]"));
+    }
+
+    public void testLabeledStat() throws Exception {
+     	assertEquals("foo:x = 1", pretty("foo:x = 1"));
+    }
+    
+    public void testLand() throws Exception {
+        assertEquals("true && false", pretty("true && false"));
+    }
+    
+    public void testLe() throws Exception {
+    	assertEquals("if (60 <= 70) {}", pretty("if (60<=70) {}"));
+    }    
+
+    public void testListConstructor() throws Exception {
+        assertEquals("[a, b]", pretty("[a,b]"));
+    }
+
+    public void testLiteralAny() throws Exception {
+        assertEquals("any x = 2", pretty("any x = 2"));
+    }
+
+    public void testLiteralAs() throws Exception {
+        assertEquals("import java.util.Date as MyDate", pretty("import java.util.Date as MyDate"));
+        // todo suspicious spacing in the following assertion
+        assertEquals("x = 12 as Long ", pretty("x = 12 as Long"));
+    }
+
+    public void testLiteralAssert() throws Exception {
+        assertEquals("assert a == true", pretty("assert a== true"));
+        assertEquals("assert b == true : 99", pretty("assert b==true:99"));
+        // todo is ',' deprecated now?
+        //assertEquals("assert b == true , 99", pretty("assert b==true,99"));
+    }
+
+    public void testLiteralBoolean() throws Exception {
+        assertEquals("boolean b = true", pretty("boolean b =true"));
+    }
+    
+    public void testLiteralBreak() throws Exception {
+    	assertEquals("for (i in 1..100) {break }", pretty("for (i in 1..100) {break}"));
+        assertEquals("switch (foo) {default:break }", pretty("switch(foo){default:break}"));
+        assertEquals("def myMethod() {break }", pretty("def myMethod(){break}"));
+    	assertEquals("for (i in 1..100) {break 2}", pretty("for (i in 1..100) {break 2}"));
+    	//todo should the colon be postfixed to the label?
+    	assertEquals("for (i in 1..100) {break label1:}", pretty("for (i in 1..100) {break label1:}"));
+    }
+
+    public void testLiteralByte() throws Exception {
+        assertEquals("byte b = 1", pretty("byte b=1"));
+    }
+
+    public void testLiteralCase() throws Exception {
+        assertEquals("switch (foo) {case 1:x = 3}", pretty("switch(foo){case 1:x=3}"));
+    }
+    
+    public void testLiteralCatch() throws Exception {
+        assertEquals("try {} catch (Exception e) {}", pretty("try {} catch (Exception e) {}"));
+        assertEquals("try {} catch (Exception e1) {} catch (Exception2 e2) {}", pretty("try {} catch (Exception e1) {} catch (Exception2 e2) {}"));
+    }
+
+    public void testLiteralChar() throws Exception {
+        assertEquals("char c = \"a\"", pretty("char c = \"a\""));
+    }
+
+    public void testLiteralClass() throws Exception {
+    	assertEquals("public class Foo {int bar}", pretty("public class Foo{int bar}"));
+    }
+    
+    public void testLiteralContinue() throws Exception {
+    	assertEquals("for (i in 1..100) {continue }", pretty("for (i in 1..100) {continue}"));
+    	assertEquals("for (i in 1..100) {continue 2}", pretty("for (i in 1..100) {continue 2}"));
+    	//todo should the colon be postfixed to the label?
+    	assertEquals("for (i in 1..100) {continue label1:}", pretty("for (i in 1..100) {continue label1:}"));
+    	assertEquals("[1, 2, 3].each {continue }", pretty("[1,2,3].each{continue}"));
+    }
+
+    public void testLiteralDef() throws Exception {
+    	assertEquals("def x = 123", pretty("def x=123"));
+    	assertEquals("def myMethod() {return 0}", pretty("def myMethod(){return 0}"));
+    	// note: def not needed in parameter declarations, but it is valid
+    	//todo: is it ok to strip out 'def' from parameter declarations?
+    	assertEquals("def foo( bar) {}", pretty("def foo(def bar){}"));
+    }
+    
+    public void testLiteralDefault() throws Exception {
+        assertEquals("switch (foo) {default:x = 2}", pretty("switch(foo){default:x=2}"));
+    	assertEquals("public @interface Foo{int bar() default 123}", pretty("public @interface Foo{int bar() default 123}"));
+    }
+    
+    public void testLiteralDouble() throws Exception {
+    	assertEquals("double d = 1.0", pretty("double d = 1.0"));
+    }
+    
+    public void testLiteralElse() throws Exception {
+    	assertEquals("if (false) {a = 1} else {a = 2}", pretty("if (false) {a=1} else {a=2}"));
+    }
+
+    public void testLiteralEnum() throws Exception {
+    	assertEquals("enum Season {WINTER, SPRING, SUMMER, AUTUMN}", pretty("enum Season{WINTER,SPRING,SUMMER,AUTUMN}"));
+    }
+    
+    public void testLiteralExtends() throws Exception {
+    	assertEquals("class Foo extends java.util.Date {}", pretty("class Foo extends java.util.Date {}"));
+        assertEquals("class Foo extends Bar {}", pretty("class Foo extends Bar {}"));
+        assertEquals("interface Wibble extends Mooky{}", pretty("interface Wibble extends Mooky {}"));
+        //todo spacing is odd, c.f. last space in class vs interface above
+    	assertEquals("public boolean process(Set<? extends TypeElement> annotations) {println annotations}", pretty("public boolean process(Set<? extends TypeElement> annotations) {println annotations}"));
+    }
+    
+    public void testLiteralFalse() throws Exception {
+        assertEquals("if (false) {}", pretty("if (false) {}"));
+    }
+
+    public void testLiteralFinally() throws Exception {
+        assertEquals("try {}finally {}", pretty("try {}finally {}"));
+    }
+
+    public void testLiteralFloat() throws Exception {
+        assertEquals("float x", pretty("float x"));
+    }
+
+    public void testLiteralFor() throws Exception {
+        assertEquals("for (i in [1, 2, 3]) {}", pretty("for (i in [1,2,3]) {}"));
+        // check non-braced single statement
+        assertEquals("for (i in 1..100) rotateAntiClockwise()", pretty("for (i in 1..100) rotateAntiClockwise()"));
+    }
+
+    public void testLiteralIf() throws Exception {
+        assertEquals("if (a == b) return false", pretty("if (a==b) return false"));
+        assertEquals("if (a == b) {}", pretty("if (a==b) {}"));
+    }
+
+    public void testLiteralImplements() throws Exception {
+        assertEquals("class Foo implements Bar {}", pretty("class Foo implements Bar {}"));
+        //todo the following is legal Java, but pretty strange...?
+        assertEquals("enum EarthSeason implements Season {SPRING}", pretty("enum EarthSeason implements Season{SPRING}"));
+    }
+    
+    public void testLiteralImport() throws Exception {
+    	assertEquals("import foo.Bar", pretty("import foo.Bar"));
+    	assertEquals("import mooky.*", pretty("import mooky.*"));
+    }
+    
+    public void testLiteralIn() throws Exception {
+    	assertEquals("for (i in 1..10) {}", pretty("for (i in 1..10) {}"));
+    	assertEquals("if (i in myList) {}", pretty("if (i in myList) {}"));
+    }
+
+    public void testLiteralInstanceOf() throws Exception {
+        assertEquals("if (a instanceof String) {}", pretty("if (a instanceof String) {}"));
+    }
+    public void testLiteralInt() throws Exception {
+        assertEquals("int a", pretty("int a"));
+    }
+    
+    public void testLiteralInterface() throws Exception {
+    	assertEquals("interface Foo{}", pretty("interface Foo{}"));
+    }
+    public void testLiteralLong() throws Exception {
+        assertEquals("long a = 1", pretty("long a = 1"));
+    }
+    public void testLiteralNative() throws Exception {
+        assertEquals("public class R {public native void seek(long pos) }", pretty("public class R{public native void seek(long pos)}"));
+        assertEquals("native foo() ", pretty("native foo()"));
+    }
+    public void testLiteralNew() throws Exception {
+        assertEquals("new Foo()", pretty("new Foo()"));
+        assertEquals("def x = new int[5]", pretty("def x = new int[5]"));
+    }
+
+    public void testLiteralNull() throws Exception {
+        assertEquals("def foo = null", pretty("def foo=null"));
+    }
+
+    public void testLiteralPackage() throws Exception {
+    	assertEquals("package foo.bar", pretty("package foo.bar"));
+    }
+    public void testLiteralPrivate() throws Exception{
+        assertEquals("private bar", pretty("private bar"));
+    }
+
+    public void testLiteralProtected() throws Exception{
+        assertEquals("protected mooky", pretty("protected mooky"));
+    }
+
+    public void testLiteralPublic() throws Exception{
+        assertEquals("public foo", pretty("public foo"));
+    }
+
+    public void testLiteralReturn() throws Exception {
+        assertEquals("def foo() {return false}", pretty("def  foo() { return false }"));
+        assertEquals("void bar() {return }", pretty("void bar() {return}"));
+    }
+
+    public void testLiteralShort() throws Exception {
+        assertEquals("short a = 1", pretty("short a = 1"));
+    }
+
+    public void testLiteralStatic() throws Exception {
+        assertEquals("static void foo() {}", pretty("static void foo() {}"));
+        //classes, interfaces, class/instance vars and methods
+        assertEquals("static int bar = 1", pretty("static int bar = 1"));
+        //todo: this should parse... assertEquals("private static <T> void foo(List<T> list){}", pretty("private static <T> void foo(List<T> list){}"));
+        assertEquals("class Foo {static {bar = 1}}", pretty("class Foo{static {bar=1}}"));
+    }
+
+    public void testLiteralSuper() throws Exception {
+    	assertEquals("class Foo {public Foo() {super()}}", pretty("class Foo{public Foo(){super()}}"));
+    	// todo will 'super' be allowed in non-parentheses method call styles?
+    	assertEquals("class Bar {public Bar() {super 99}}", pretty("class Bar{public Bar(){super 99}}"));
+    	assertEquals("class Bar {public Bar() {super(1, 2, 3)}}", pretty("class Bar{public Bar(){super(1,2,3)}}"));
+    	assertEquals("println(super.toString())", pretty("println(super.toString())"));
+    	//todo: doesn't parse correctly...   assertEquals("class Foo<T super C> {T t}",pretty("class Foo<T super C> {T t}"));
+    }
+    public void testLiteralSwitch() throws Exception {
+        assertEquals("switch (foo) {case bar:x = 2}", pretty("switch(foo){case bar:x=2}"));
+    }
+        
+    public void testLiteralSynchronized() throws Exception {
+    	assertEquals("synchronized foo() {}", pretty("synchronized foo(){}"));
+    	assertEquals("synchronized (t) {doStuff(t)}", pretty("synchronized (t) {doStuff(t)}"));
+    }
+
+    public void testLiteralThis() throws Exception {
+    	assertEquals("this",pretty("this"));
+    	assertEquals("this 2",pretty("this 2"));
+    	assertEquals("this()",pretty("this()"));
+    	assertEquals("this(1, 2, 3)",pretty("this(1,2,3)"));
+        assertEquals("this.x = this.y", pretty("this.x=this.y"));
+    }
+    
+    public void testLiteralThreadsafe() throws Exception {
+    	assertEquals("threadsafe foo() {}", pretty("threadsafe foo() {}"));
+    }
+    
+    public void testLiteralThrow() throws Exception {
+        assertEquals("def foo() {if (false) throw new RuntimeException()}", pretty("def foo() {if (false) throw new RuntimeException()}"));
+    }
+    public void testLiteralThrows() throws Exception {
+    	//todo AntlrParserPlugin: Unexpected node type: '.' found when expecting type: an identifier
+    	assertEquals("def foo() throws java.io.IOException{}", pretty("def foo() throws java.io.IOException{}"));
+    }
+    public void testLiteralTransient() throws Exception {
+    	assertEquals("transient bar", pretty("transient bar"));
+    }
+    
+    public void testLiteralTrue() throws Exception {
+        assertEquals("foo = true", pretty("foo = true"));
+    }
+
+    public void testLiteralTry() throws Exception {
+        assertEquals("try {} catch (Exception e) {}", pretty("try {} catch (Exception e) {}"));
+    }
+
+    public void testLiteralVoid() throws Exception {
+        assertEquals("void foo() {}", pretty("void foo(){}"));
+    }
+    public void testLiteralVolatile() throws Exception {
+    	assertEquals("volatile mooky", pretty("volatile mooky"));
+    }
+
+    public void testLiteralWhile() throws Exception {
+        assertEquals("while (true) {}", pretty("while(true){}"));
+    }
+
+    public void testLiteralWith() throws Exception {
+        assertEquals("with (myObject) {x = 1}", pretty("with(myObject) {x = 1}"));
+    }
+    public void testLnot() throws Exception {
+        assertEquals("if (!isRaining) {}", pretty("if (!isRaining) {}"));
+    }
+
+    public void testLor() throws Exception {
+        assertEquals("true || false", pretty("true || false"));
+    }
+    public void testLparen_FAILS() throws Exception { if (notYetImplemented()) return;
+    	assertEquals("for (i in (history.size() - 1)..0) {}", pretty("for (i in (history.size() - 1)..0) {}"));
+    }
+    public void testLt() throws Exception {
+        assertEquals("if (3.4f < 12f) {}", pretty("if (3.4f < 12f) {}"));
+    }
+    public void testMapConstructor() throws Exception{
+        assertEquals("Map foo = [:]", pretty("Map foo = [:]"));
+        assertEquals("[a:1, b:2]", pretty("[a:1,b:2]"));
+    }
+
+    public void testMemberPointer() throws Exception {
+        assertEquals("def x = foo.&bar()", pretty("def x=foo.&bar()"));
+    }
+    public void testMethodCall() throws Exception {
+        assertEquals("foo(bar)", pretty("foo(bar)"));
+        assertEquals("[1, 2, 3].each {println it}", pretty("[1,2,3].each{println it}"));
+        assertEquals("foo(bar){mooky()}", pretty("foo(bar){mooky()}"));
+    }
+
+    public void testMethodDef() throws Exception{
+        assertEquals("def foo(int bar, boolean boo) {}", pretty("def foo(int bar,boolean boo) {}"));
+    }
+
+    public void testMinus() throws Exception {
+        assertEquals("def bar = 4 - foo", pretty("def bar=4-foo"));
+    }
+
+    public void testMinusAssign() throws Exception {
+        assertEquals("x -= 23", pretty("x -= 23"));
+    }
+
+    public void testMod() throws Exception {
+        assertEquals("x = 4 % 3", pretty("x = 4 % 3"));
+    }
+
+    public void testModifiers() throws Exception {
+    	assertEquals("public static transient final native threadsafe synchronized volatile strictfp foo() {}", pretty("public static transient final native threadsafe synchronized volatile strictfp foo() {}"));
+    }
+    
+    public void testModAssign() throws Exception {
+        assertEquals("x %= 23", pretty("x %= 23"));
+    }
+
+    public void testNotEqual() throws Exception {
+        assertEquals("a != b", pretty("a!=b"));
+    }
+
+    public void testNumBigDecimal() throws Exception {
+    	assertEquals("a = 9.8g", pretty("a  =9.8g"));
+    }
+    public void testNumBigInt() throws Exception {
+    	assertEquals("a = 12g", pretty("a=   12g"));
+    }
+    
+    public void testNumDouble() throws Exception {
+        assertEquals("b = 34.4d", pretty("b=34.4d"));
+        assertEquals("b = 34.4D", pretty("b=34.4D"));
+    }
+    public void testNumFloat() throws Exception {
+        assertEquals("b = 34.4f", pretty("b=34.4f"));
+        assertEquals("b = 34.4F", pretty("b=34.4F"));
+    }
+    public void testNumInt() throws Exception {
+        assertEquals("a = 12", pretty("a=12"));
+    }
+
+    public void testNumLong() throws Exception {
+    	assertEquals("a = 12l", pretty("a=12l"));    	
+    }
+    public void testObjblock() throws Exception {
+        assertEquals("class Foo {def bar}", pretty("class Foo {def bar}"));
+    }
+    public void testOptionalDot() throws Exception {
+        assertEquals("foo = england.london.kings?.head", pretty("foo = england.london.kings?.head"));
+    }
+
+    public void testPackageDef() throws Exception {
+        assertEquals("package foo.bar", pretty("package foo.bar"));
+    }
+
+    public void testParameterDef() throws Exception {
+    	//todo spacing slightly suspect with "foo( bar)"
+    	assertEquals("def foo( bar) {}", pretty("def foo(bar){}"));
+        assertEquals("def foo(String bar, String mooky) {}", pretty("def foo(String bar, String mooky){}"));
+        assertEquals("def c = { x -> println x}", pretty("def c = {x->println x}"));
+        assertEquals("def c = { x, y -> println(x + y)}", pretty("def c={x,y->println(x+y)}"));
+        assertEquals("def c = {int x,int y -> println(x + y)}", pretty("def c={int x, int y->println(x+y)}"));
+    }
+
+    public void testParameters() throws Exception {
+        assertEquals("def foo(String bar, String mooky) {}", pretty("def foo(String bar, String mooky){}"));
+    }
+    public void testPlus() throws Exception {
+        assertEquals("a + b", pretty("a+b"));
+    }
+    
+    public void testPlusAssign() throws Exception {
+        assertEquals("x += 23", pretty("x += 23"));
+    }
+
+    public void testPostDec() throws Exception {
+    	assertEquals("a--", pretty("a--"));
+    }
+    public void testPostInc() throws Exception {
+    	assertEquals("a++", pretty("a++"));
+    }
+    public void testQuestion() throws Exception {
+        assertEquals("foo == bar?10:20", pretty("foo==bar?10:20"));
+    	assertEquals("public boolean process(Set<? extends B> a) {println a}", pretty("public boolean process(Set<? extends B> a) {println a}"));
+    	assertEquals("public boolean process(Set<? extends B, ? super C> a) {println a}", pretty("public boolean process(Set<? extends B, ? super C> a) {println a}"));
+    }
+    public void testRangeExclusive() throws Exception {
+        assertEquals("foo[45..<89]", pretty("foo[45 ..< 89]"));
+    }
+    public void testRangeInclusive() throws Exception {
+        assertEquals("foo[bar..12]", pretty("foo[bar .. 12]"));
+    }
+    public void testRegexpLiteral() throws Exception {
+    	assertEquals("println", pretty("println //")); // empty regexp_literal should be treated as single line comment
+    }
+
+    public void testRegexpLiteral_FAILS() throws Exception { if (notYetImplemented()) return;
+		//todo: these fail because regexp_literals are converted into string_literals on the antlr AST
+		assertEquals("def x = /./", pretty("def x = /./"));
+		assertEquals("def z = /blah\\s/", pretty("def z = /blah\\s/")); // actually: def z = /blah\s/
+    }
+    
+    public void testRegexFind() throws Exception {
+    	assertEquals("def m = foo =~ \"bar\"", pretty("def m = foo =~ \"bar\""));
+    	assertEquals("if (foo =~ \"bar\") {}", pretty("if (foo=~\"bar\"){}"));
+    }
+    
+    public void testRegexMatch() throws Exception {
+    	assertEquals("if (foo ==~ \"bar\") {}", pretty("if (foo==~\"bar\"){}"));
+    }
+    
+    public void testScopeEscape() throws Exception {
+    	// todo - 31 July + 14 Dec 2006 - test fine, however this parses but causes error in AntlrParserPlugin
+    	assertEquals("println([$x, x, y])", pretty("println([$x, x, y])"));
+    }
+    
+    public void testSelectSlot() throws Exception {
+    	assertEquals("def x = foo.@bar", pretty("def x = foo . @ bar"));
+    }
+    
+    public void testSl() throws Exception {
+    	assertEquals("foo << 123", pretty("foo << 123"));
+    }
+    
+    public void testSlAssign() throws Exception {
+    	assertEquals("foo <<= 123", pretty("foo <<= 123")); // does this operator make any sense?
+    }
+
+    public void testSlist() throws Exception {
+    	assertEquals("class Foo {private Foo() {println bar}}",pretty("class Foo {private Foo() {println bar}}"));
+    	assertEquals("if (true) {foo}", pretty("if (true) {foo}"));
+    	assertEquals("def x = foo.{bar}", pretty("def x = foo.{bar}")); // todo - inline open block is great, but it doesn't work as one would expect (yet). (c.f. with)
+    	assertEquals("def foo() {l:{x = 2}}", pretty("def foo(){l:{x=2}}")); // slist inside a method body (needed label to distinguish from a closure)
+    	assertEquals("switch (f) {case 1:break }", pretty("switch(f){case 1:break}")); // slist inside each case body...
+    } 
+    
+    public void testSpreadArg() throws Exception {
+    	assertEquals("myList {*name}", pretty("myList{*name}"));
+        assertEquals("\"foo$*bar\"", pretty("\"foo$*bar\"")); // this doesn't work beyond parser (AntlrParserPlugin)
+        assertEquals("\"foo${*bar}\"", pretty("\"foo${*bar}\"")); // this doesn't work beyond parser (AntlrParserPlugin)
+        assertEquals("f(*[a, b, c])", pretty("f(*[a,b,c])"));
+        assertEquals("f(*null)", pretty("f(*null)")); // equiv to f()
+    }
+    public void testSpreadMapArg() throws Exception {
+    	assertEquals("f(*:myMap)", pretty("f(*:myMap)"));
+    }
+    public void testSr() throws Exception {
+    	assertEquals("foo >> 123", pretty("foo >> 123"));
+    }
+    
+    public void testSrAssign() throws Exception {
+    	assertEquals("foo >>= 123", pretty("foo >>= 123")); // does this operator make any sense?
+    }
+
+    public void testStar() throws Exception {
+        assertEquals("import foo.*", pretty("import foo.*"));
+        assertEquals("a*b", pretty("a*b"));
+    }
+    
+    public void testStarAssign() throws Exception {
+    	assertEquals("foo *= 123", pretty("foo *= 123"));
+    }
+
+    public void testStarStar() throws Exception {
+        assertEquals("def square = +5**2", pretty("def square=+5**2"));
+        assertEquals("def cube = 5**3", pretty("def cube = 5**3"));
+    } 
+    
+    public void testStarStarAssign() throws Exception {
+    	assertEquals("cubeMe **= 3", pretty("cubeMe **= 3"));
+    }
+
+    public void testStaticImport() throws Exception {
+    	assertEquals("import static foo.Bar.mooky", pretty("import static foo.Bar.mooky"));
+    	assertEquals("import static foo.Bar.*", pretty("import static foo.Bar.*"));
+    }
+
+    public void testStaticInit() throws Exception {
+    	assertEquals("class Foo {static {println(1 + 1)}}", pretty("class Foo{static{println(1+1)}}"));
+    }
+    
+    public void testStrictFp() throws Exception {
+    	assertEquals("private strictfp flibble = 1.2", pretty("private strictfp flibble = 1.2"));
+    }
+    
+    public void testStringConstructor() throws Exception{
+        assertEquals("def x = \"foo$bar\"", pretty("def x=\"foo$bar\""));
+        assertEquals("def y = \"foo${mooky}\"", pretty("def y = \"foo${mooky}\""));
+    }
+
+    public void testStringLiteral_FAILS() throws Exception{ if (notYetImplemented()) return;
+        assertEquals("\"mooky\"", pretty("\"mooky\""));
+        assertEquals("'mooky'", pretty("'mooky'"));
+    	assertEquals("def x = '''can go over newline'''", pretty("def x = '''can go over newline'''"));
+    	assertEquals("def x = \"\"\"can go over newline\"\"\"", pretty("def x = \"\"\"can go over newline\"\"\""));
+    	//todo test newlines inside strings somehow...
+    }
+
+    public void testSuperCtorCall() throws Exception{
+    	assertEquals("class Foo {Foo(int x) {super(12, 3)}}",pretty("class Foo{Foo(int x) {super(12, 3)}}"));
+    	assertEquals("class Foo {Foo( x) {super()}}",pretty("class Foo{Foo(x) {super()}}"));
+        // todo: above is not quite the spacing I would expect, but good enough for now...
+    	// todo not yet implemented in parser: assertEquals("(new Outer()).super()", pretty("(new Outer()).super()"));
+    }
+    
+    public void testType() throws Exception {
+    	assertEquals("def bar", pretty("def bar"));
+        assertEquals("public bar", pretty("public bar"));
+        assertEquals("public String bar", pretty("public String bar"));
+        assertEquals("String bar", pretty("String bar"));
+    }
+
+    public void testTypecast() throws Exception {
+        assertEquals("foo = (int)bar", pretty("foo = (int)bar"));
+        assertEquals("foo = (int[])bar", pretty("foo = (int[])bar"));
+        assertEquals("foo = (String)bar", pretty("foo = (String)bar"));
+        assertEquals("foo = (String[])bar", pretty("foo = (String[])bar"));
+    }
+
+    public void testTypeArguments() throws Exception {
+    	assertEquals("void printCollection(Collection<?> c) {}", pretty("void printCollection(Collection<?> c) {}"));
+    }
+    public void testTypeLowerBounds() throws Exception {
+    	assertEquals("void printCollection(Collection<? super X> c) {}", pretty("void printCollection(Collection<? super X> c) {}"));
+    }
+    public void testTypeUpperBounds() throws Exception {
+    	assertEquals("void printCollection(Collection<? extends X> c) {}", pretty("void printCollection(Collection<? extends X> c) {}"));
+    }
+
+    public void testTypeParameters() throws Exception {
+    	assertEquals("class Foo<T extends C & I> {T t}",pretty("class Foo<T extends C & I> {T t}"));
+    }
+    public void testUnaryMinus() throws Exception {
+        assertEquals("def x = -3", pretty("def x= -3"));
+    }
+    public void testUnaryPlus() throws Exception {
+        assertEquals("def x = +2", pretty("def x= +2"));
+    }
+
+    public void testVariableDef() throws Exception {
+        assertEquals("def x = 1", pretty("def x = 1"));
+        assertEquals("int y = 2", pretty("int y = 2"));
+        assertEquals("String y", pretty("String y"));
+        assertEquals("def foo() {int b = 9}", pretty("def foo(){int b = 9}"));
+    }
+    public void testVariableDef_FAILS() throws Exception { if (notYetImplemented()) return;
+    	assertEquals("boolean x, y, z = false", pretty("boolean x,y,z = false"));       
+    }
+    
+    public void testVaribleParameterDef() throws Exception {
+    	assertEquals("void myMethod(String param1, String ... others) {}", pretty("void myMethod(String param1, String ... others) {}"));
+    	assertEquals("void myMethod(final int ... others) {}", pretty("void myMethod(final int ... others) {}"));
+    	assertEquals("void myMethod(def ... others) {}", pretty("void myMethod(def ... others) {}"));
+    }
+    
+    public void testWildcardType() throws Exception {
+    	assertEquals("public boolean process(Set<? extends TypeElement> annotations) {println annotations}", pretty("public boolean process(Set<? extends TypeElement> annotations) {println annotations}"));
+    }
+
+    public String pretty(String input) throws Exception{
+        GroovyRecognizer parser = null;
+        SourceBuffer sourceBuffer = new SourceBuffer();
+        UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(new StringReader(input),sourceBuffer);
+        GroovyLexer lexer = new GroovyLexer(unicodeReader);
+        unicodeReader.setLexer(lexer);
+        parser = GroovyRecognizer.make(lexer);
+        parser.setSourceBuffer(sourceBuffer);
+
+        String[] tokenNames;
+        tokenNames = parser.getTokenNames();
+        parser.compilationUnit();
+        AST ast = parser.getAST();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Visitor visitor = new SourcePrinter(new PrintStream(baos),tokenNames,false);
+        AntlrASTProcessor traverser = new SourceCodeTraversal(visitor);
+
+        traverser.process(ast);
+
+        return new String(baos.toByteArray());
+    }
+
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/ast/ClassNodeTest.java b/groovy-core/src/test/org/codehaus/groovy/ast/ClassNodeTest.java
new file mode 100644
index 0000000..1e62daa
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/ast/ClassNodeTest.java
@@ -0,0 +1,83 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+import org.objectweb.asm.Opcodes;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests the ClassNode
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ClassNodeTest extends TestCase implements Opcodes {
+
+    ClassNode classNode = new ClassNode("Foo", ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
+    ClassNode innerClassNode = new InnerClassNode(classNode, "Foo$1", ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
+
+    protected void setUp() throws Exception {
+        classNode.addField("field", ACC_PUBLIC, ClassHelper.STRING_TYPE, null);
+    }
+
+    public void testOuterClass() {
+        assertNull(classNode.getOuterClass());
+        assertNotNull(innerClassNode.getOuterClass());
+    }
+
+    public void testOuterField() {
+        assertNull(classNode.getOuterField("field"));
+        assertNotNull(innerClassNode.getOuterField("field"));
+    }
+    
+    public void testPackageName() {
+        assertEquals("Package", null, classNode.getPackageName());
+        
+        ClassNode packageNode = new ClassNode("com.acme.Foo", ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
+        assertEquals("Package", "com.acme", packageNode.getPackageName());
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/ast/ModuleNodeTest.java b/groovy-core/src/test/org/codehaus/groovy/ast/ModuleNodeTest.java
new file mode 100644
index 0000000..2da8a47
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/ast/ModuleNodeTest.java
@@ -0,0 +1,73 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.ast;
+
+import java.util.List;
+
+import org.codehaus.groovy.syntax.parser.TestParserSupport;
+
+/**
+ * Tests the ClassNode
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ModuleNodeTest extends TestParserSupport {
+
+    public void testStatementClass_FAILS() throws Exception { if (notYetImplemented()) return;
+        
+        ModuleNode module = parse("x = [1, 2, 3]; println(x)", "Cheese.groovy");
+        
+        assertTrue("Should have statements", ! module.getStatementBlock().isEmpty());
+        
+        List classes = module.getClasses();
+        assertEquals("Number of classes", 1, classes.size());
+        
+        ClassNode classNode = (ClassNode) classes.get(0);
+        
+        assertEquals("Class name", "Cheese", classNode.getName());
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/bsf/BSFTest.java b/groovy-core/src/test/org/codehaus/groovy/bsf/BSFTest.java
new file mode 100644
index 0000000..b2e55af
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/bsf/BSFTest.java
@@ -0,0 +1,212 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.bsf;
+
+import java.io.File;
+import java.util.List;
+import java.util.Vector;
+
+import junit.framework.TestCase;
+
+import org.apache.bsf.BSFManager;
+import org.apache.bsf.BSFException;
+import org.apache.bsf.BSFEngine;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+
+/**
+ * Tests the BSF integration
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Paul King
+ * @version $Revision$
+ */
+public class BSFTest extends TestCase {
+
+    protected BSFManager manager;
+
+    protected void setUp() throws Exception {
+        manager = new BSFManager();
+    }
+
+    public void testInvalidName() throws Exception {
+        manager.exec("groovy", null, 0, 0, "assert bsf != null");
+        manager.exec("groovy", "", 0, 0, "assert bsf != null");
+        manager.exec("groovy", "-", 0, 0, "assert bsf != null");
+    }
+
+    public void testCompileErrorWithExec() throws Exception {
+        try {
+            manager.exec("groovy", "dummy", 0, 0, "assert assert");
+            fail("Should have caught compile exception");
+        } catch (BSFException e) {
+            assertTrue("e.getMessage() should contain CompilationError: " + e.getMessage(),
+                    e.getMessage().indexOf("CompilationError") != -1);
+        }
+    }
+
+    public void testCompileErrorWithEval() throws Exception {
+        try {
+            manager.eval("groovy", "dummy", 0, 0, "assert assert");
+            fail("Should have caught compile exception");
+        } catch (BSFException e) {
+            assertTrue("e.getMessage() should contain CompilationError: " + e.getMessage(),
+                    e.getMessage().indexOf("CompilationError") != -1);
+        }
+    }
+
+    public void testExec() throws Exception {
+        manager.exec("groovy", "Test1.groovy", 0, 0, "assert bsf != null , 'should have a bsf variable'");
+    }
+
+    public void testApplyWithClosure() throws Exception {
+        Vector ignoreParamNames = null;
+        Vector ignoreArgs = null;
+        Integer actual = (Integer) manager.apply("groovy", "applyTest", 0, 0,
+                "251", ignoreParamNames, ignoreArgs);
+        assertEquals(251, actual.intValue());
+    }
+
+    public void testApply() throws Exception {
+        Vector ignoreParamNames = null;
+        Vector args = new Vector();
+        args.add(new Integer(2));
+        args.add(new Integer(5));
+        args.add(new Integer(1));
+        Integer actual = (Integer) manager.apply("groovy", "applyTest", 0, 0,
+                "def summer = { a, b, c -> a * 100 + b * 10 + c }", ignoreParamNames, args);
+        assertEquals(251, actual.intValue());
+    }
+
+    public void testBracketName() throws Exception {
+        manager.exec("groovy", "Test1<groovy>", 0, 0, "assert bsf != null , 'should have a bsf variable'");
+    }
+
+    public void testEval() throws Exception {
+        Object answer = manager.eval("groovy", "Test1.groovy", 0, 0, "return [1, 2, 3]");
+        assertTrue("Should return a list: " + answer, answer instanceof List);
+        List list = (List) answer;
+        assertEquals("List should be of right size", 3, list.size());
+    }
+
+    public void testTwoEvalsWithSameName() throws Exception {
+        Object answer = manager.eval("groovy", "Test1.groovy", 0, 0, "return 'cheese'");
+        assertEquals("cheese", answer);
+        answer = manager.eval("groovy", "Test1.groovy", 0, 0, "return 'gromit'");
+        assertEquals("gromit", answer);
+    }
+
+    public void testExecBug() throws Exception {
+        for (int i = 0; i < 10; i++) {
+            manager.exec("groovy", "Test1.groovy", 0, 0, "assert true");
+            manager.exec("groovy", "Test1.groovy", 0, 0, "assert true");
+        }
+    }
+
+    public void testBsfVariables() throws Exception {
+        Object answer = manager.eval("groovy", "Test1.groovy", 0, 0,
+                "assert this.bsf != null\n  return this.bsf");
+        assertTrue("Should have an answer", answer != null);
+    }
+
+    public void testNotFoundVariables() throws Exception {
+        manager.registerBean("x", new Integer(4));
+        Object answer = manager.eval("groovy", "Test1.groovy", 0, 0,
+                "def valueOfX = this.bsf.lookupBean('y'); assert valueOfX == null");
+        assertNull("Undeclared beans should yield null", answer);
+    }
+
+    public void testRegisteredVariables() throws Exception {
+        manager.registerBean("x", new Integer(4));
+        Object answer = manager.eval("groovy", "Test1.groovy", 0, 0,
+                "def valueOfX = this.bsf.lookupBean('x'); assert valueOfX == 4; valueOfX + 1");
+        assertEquals("Incorrect return", new Integer(5), answer);
+    }
+
+    public void testUnregisteredVariables() throws Exception {
+        manager.registerBean("x", new Integer(4));
+        Object answer = manager.eval("groovy", "Test1.groovy", 0, 0,
+                "def valueOfX = this.bsf.lookupBean('x'); assert valueOfX == 4; valueOfX + 1");
+        assertEquals("Incorrect return", new Integer(5), answer);
+        manager.unregisterBean("x");
+        // have to lookup registered beans
+        answer = manager.eval("groovy", "Test1.groovy", 0, 0,
+                "def valueOfX = this.bsf.lookupBean('x'); assert valueOfX == null");
+        assertNull("Unregistered beans should yield null", answer);
+    }
+
+    public void testDeclaredVariables() throws Exception {
+        manager.declareBean("xyz", new Integer(4), Integer.class);
+        Object answer = manager.eval("groovy", "Test1.groovy", 0, 0, "xyz + 1");
+        assertEquals("Incorrect return", new Integer(5), answer);
+    }
+
+    public void testUndeclaredVariables() throws Exception {
+        manager.declareBean("abc", new Integer(4), Integer.class);
+        // declared beans should just be available
+        Object answer = manager.eval("groovy", "Test1.groovy", 0, 0, "abc + 1");
+        assertEquals("Incorrect return", new Integer(5), answer);
+        manager.undeclareBean("abc");
+        answer = manager.eval("groovy", "Test1.groovy", 0, 0, "abc");
+        assertNull("Undeclared beans should yield null", answer);
+    }
+
+    public void testCall() throws Exception {
+        BSFEngine bsfEngine = manager.loadScriptingEngine("groovy");
+        manager.declareBean("myvar", "hello", String.class);
+        Object myvar = manager.lookupBean("myvar");
+        String result = (String) bsfEngine.call(myvar, "reverse", new Object[]{});
+        assertEquals("olleh", result);
+    }
+
+    public void testExecFile() throws Exception {
+        execScript("src/test/groovy/script/MapFromList.groovy");
+        execScript("src/test/groovy/script/AtomTestScript.groovy");
+    }
+
+    protected void execScript(String fileName) throws Exception {
+        manager.exec("groovy", fileName, 0, 0, DefaultGroovyMethods.getText(new File(fileName)));
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/bsf/CacheBSFTest.java b/groovy-core/src/test/org/codehaus/groovy/bsf/CacheBSFTest.java
new file mode 100644
index 0000000..32833cd
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/bsf/CacheBSFTest.java
@@ -0,0 +1,139 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package org.codehaus.groovy.bsf;
+
+import java.util.List;
+import java.util.Vector;
+
+import junit.framework.TestCase;
+
+import org.apache.bsf.BSFManager;
+import org.apache.bsf.BSFEngine;
+import org.apache.bsf.BSFException;
+import groovy.lang.GroovyShell;
+
+/**
+ * Tests the Caching BSF integration
+ *
+ * @author James Birchfield
+ * @version $Revision$
+ */
+public class CacheBSFTest extends TestCase {
+
+    protected BSFManager manager;
+    private static final Class CACHING_ENGINE = CachingGroovyEngine.class;
+
+    protected void setUp() throws Exception {
+        // override standard engine with caching one
+        BSFManager.registerScriptingEngine("groovy", CACHING_ENGINE.getName(), new String[] { "groovy", "gy" });
+        manager = new BSFManager();
+    }
+
+    public void testVersion() throws Exception {
+        //System.out.println("BSFManager.getVersion() = " + BSFManager.getVersion());
+        BSFEngine bsfEngine = manager.loadScriptingEngine("groovy");
+        assertEquals(CACHING_ENGINE, bsfEngine.getClass());
+    }
+
+    public void testExec() throws Exception {
+        manager.exec("groovy", "Test1.groovy", 0, 0, "println('testing Exec')");
+        //nothing to really test here...just looking for debug that says it
+        // used cache version
+        manager.exec("groovy", "Test1.groovy", 0, 0, "println('testing Exec')");
+    }
+
+    public void testCompileErrorWithExec() throws Exception {
+        try {
+            manager.exec("groovy", "dummy", 0, 0, "assert assert");
+            fail("Should have caught compile exception");
+        } catch (BSFException e) {
+            assertTrue("e.getMessage() should contain CompilationError: " + e.getMessage(),
+                    e.getMessage().indexOf("CompilationError") != -1);
+        }
+    }
+
+    public void testEval() throws Exception {
+        Object dontcare = manager.eval("groovy", "Test1.groovy", 0, 0, "return [1, 2, 3]");
+        // nothing to really test here...just looking for debug that says it
+        // used cache version
+        Object answer = manager.eval("groovy", "Test.groovy", 0, 0, "return [1, 2, 3]");
+        assertTrue("Should return a list: " + answer, answer instanceof List);
+        List list = (List) answer;
+        assertEquals("List should be of right size", 3, list.size());
+    }
+
+    public void testCompileErrorWithEval() throws Exception {
+        try {
+            manager.eval("groovy", "dummy", 0, 0, "assert assert");
+            fail("Should have caught compile exception");
+        } catch (BSFException e) {
+            assertTrue("e.getMessage() should contain CompilationError: " + e.getMessage(),
+                    e.getMessage().indexOf("CompilationError") != -1);
+        }
+    }
+
+    public void testBuiltInVariable() throws Exception {
+        Object answer = manager.eval("groovy", "Test1.groovy", 0, 0,
+                "assert this.bsf != null\n  return this.bsf");
+        assertTrue("Should have an answer", answer != null);
+    }
+
+    public void testVariables() throws Exception {
+        manager.registerBean("x", new Integer(4));
+        Object dontcare = manager.eval("groovy", "Test1.groovy", 0, 0,
+                "valueOfX = this.bsf.lookupBean('x'); assert valueOfX == 4; valueOfX + 1");
+        // nothing to really test here...just looking for debug that says it
+        // used cache version
+        Object answer = manager.eval("groovy", "Test2.groovy", 0, 0,
+                "valueOfX = this.bsf.lookupBean('x'); assert valueOfX == 4; valueOfX + 1");
+        assertEquals("Incorrect return", new Integer(5), answer);
+    }
+
+    public void testClassLoaderSet() throws BSFException {
+        CachingGroovyEngine cachingGroovyEngine = new CachingGroovyEngine();
+        manager.setClassLoader(null);
+        cachingGroovyEngine.initialize(manager, "dummy", new Vector());
+        // still working implies classloader set, coverage confirms this
+        assertEquals("hi", manager.eval("groovy", "dummy", 0, 0, "'hi'"));
+    }
+
+    public void testDeclaredVariables() throws Exception {
+        manager.declareBean("foo", new Integer(5), Integer.class);
+        Object answer = manager.eval("groovy", "Test1.groovy", 0, 0, "valueOfFoo = foo; return valueOfFoo");
+        assertEquals(new Integer(5), answer);
+        manager.declareBean("foo", new Integer(6), Integer.class);
+        answer = manager.eval("groovy", "Test2.groovy", 0, 0, "valueOfFoo = foo; return valueOfFoo");
+        assertEquals(new Integer(6), answer);
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/BytecodeHelperTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/BytecodeHelperTest.java
new file mode 100644
index 0000000..6dfce65
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/BytecodeHelperTest.java
@@ -0,0 +1,74 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.ClassHelper;
+
+import groovy.util.GroovyTestCase;
+
+/**
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class BytecodeHelperTest extends GroovyTestCase {
+
+    public void testTypeName() {
+        assertEquals("[C", BytecodeHelper.getTypeDescription(ClassHelper.char_TYPE.makeArray()));
+    }
+
+    public void testMethodDescriptor() {
+        String answer = BytecodeHelper.getMethodDescriptor(char[].class, new Class[0]);
+        assertEquals("()[C", answer);
+
+        answer = BytecodeHelper.getMethodDescriptor(int.class, new Class[] { long.class });
+        assertEquals("(J)I", answer);
+
+        answer = BytecodeHelper.getMethodDescriptor(String[].class, new Class[] { String.class, int.class });
+        assertEquals("(Ljava/lang/String;I)[Ljava/lang/String;", answer);
+       }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/CallClosureFieldAsMethodTest.groovy b/groovy-core/src/test/org/codehaus/groovy/classgen/CallClosureFieldAsMethodTest.groovy
new file mode 100644
index 0000000..b8d6c77
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/CallClosureFieldAsMethodTest.groovy
@@ -0,0 +1,22 @@
+package org.codehaus.groovy.classgen
+
+import groovy.util.GroovyTestCase
+
+/**
+ * @author Guillaume Laforge
+ */
+class CallClosureFieldAsMethodTest extends GroovyTestCase {
+
+    String firstname = "Guillaume"
+    def closureMethod = { greeting-> "${greeting} ${firstname}" }
+
+    /**
+     * Check that we can call a closure defined as a field as if it were a normal method
+     */
+    void testCallToClosureAsMethod() {
+
+        def obj = new CallClosureFieldAsMethodTest()
+
+        assert obj.closureMethod("Hello") == "Hello Guillaume"
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/CapitalizeTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/CapitalizeTest.java
new file mode 100644
index 0000000..feaed42
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/CapitalizeTest.java
@@ -0,0 +1,66 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import groovy.util.GroovyTestCase;
+
+/**
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class CapitalizeTest extends GroovyTestCase {
+
+    public void testCapitalize() {
+        assertEquals("Foo", Verifier.capitalize("foo"));
+        assertEquals("Foo", Verifier.capitalize("Foo"));
+        assertEquals("FOo", Verifier.capitalize("fOo"));
+        assertEquals("FOO", Verifier.capitalize("fOO"));
+        assertEquals("F", Verifier.capitalize("f"));
+    }
+
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/ClassCompletionVerifierTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/ClassCompletionVerifierTest.java
new file mode 100644
index 0000000..586a96e
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/ClassCompletionVerifierTest.java
@@ -0,0 +1,124 @@
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.*;
+import org.codehaus.groovy.control.SourceUnit;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ *
+ * @author Paul King
+ */
+public class ClassCompletionVerifierTest extends TestSupport {
+    private SourceUnit source;
+    private ClassCompletionVerifier verifier;
+    private static final String ABSTRACT_FINAL_CLASS = "AbstractFinalClass";
+    private static final String FINAL_INTERFACE = "FinalInterface";
+    private static final String EXPECTED_CLASS_MODIFIER_ERROR_MESSAGE =
+            "The class '" + ABSTRACT_FINAL_CLASS + "' must not be both final and abstract.";
+    private static final String EXPECTED_INTERFACE_MODIFIER_ERROR_MESSAGE =
+            "The interface '" + FINAL_INTERFACE + "' must not be final. It is by definition abstract.";
+    private static final String EXPECTED_INTERFACE_FINAL_METHOD_ERROR_MESSAGE =
+            "The method 'xxx' from interface 'zzz' must not be final. It is by definition abstract.";
+    private static final String EXPECTED_INTERFACE_STATIC_METHOD_ERROR_MESSAGE =
+            "The method 'yyy' from interface 'zzz' must not be static. Only fields may be static in an interface.";
+    private static final String EXPECTED_TRANSIENT_CLASS_ERROR_MESSAGE =
+            "The class 'DodgyClass' has an incorrect modifier transient.";
+    private static final String EXPECTED_VOLATILE_CLASS_ERROR_MESSAGE =
+            "The class 'DodgyClass' has an incorrect modifier volatile.";
+    private static final String EXPECTED_DUPLICATE_METHOD_ERROR_CLASS_MESSAGE =
+            "Repetitive method name/signature for method 'xxx' in class 'zzz'.";
+    private static final String EXPECTED_DUPLICATE_METHOD_ERROR_INTERFACE_MESSAGE =
+            "Repetitive method name/signature for method 'xxx' in interface 'zzz'.";
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        source = SourceUnit.create("dummy.groovy", "");
+        verifier = new ClassCompletionVerifier(source);
+    }
+
+    public void testDetectsFinalAbstractClass() throws Exception {
+        checkVisitErrors("FinalClass", ACC_FINAL, false);
+        checkVisitErrors("AbstractClass", ACC_ABSTRACT, false);
+        checkVisitErrors(ABSTRACT_FINAL_CLASS, ACC_ABSTRACT | ACC_FINAL, true);
+        checkErrorMessage(EXPECTED_CLASS_MODIFIER_ERROR_MESSAGE);
+    }
+
+    public void testDetectsDuplicateMethodsForClassNoParams() throws Exception {
+        checkDetectsDuplicateMethods(0, EXPECTED_DUPLICATE_METHOD_ERROR_CLASS_MESSAGE, Parameter.EMPTY_ARRAY);
+    }
+
+    public void testDetectsDuplicateMethodsForInterfaceOneParam() throws Exception {
+        Parameter[] stringParam = { new Parameter(ClassHelper.STRING_TYPE, "x") };
+        checkDetectsDuplicateMethods(ACC_INTERFACE, EXPECTED_DUPLICATE_METHOD_ERROR_INTERFACE_MESSAGE, stringParam);
+    }
+
+    private void checkDetectsDuplicateMethods(int modifiers, String expectedErrorMessage, Parameter[] params) {
+        ClassNode node = new ClassNode("zzz", modifiers, ClassHelper.OBJECT_TYPE);
+        node.addMethod(new MethodNode("xxx", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, params, ClassNode.EMPTY_ARRAY, null));
+        node.addMethod(new MethodNode("xxx", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, params, ClassNode.EMPTY_ARRAY, null));
+        verifier.visitClass(node);
+        checkErrorCount(2);
+        checkErrorMessage(expectedErrorMessage);
+    }
+
+    public void testDetectsIncorrectOtherModifier() throws Exception {
+        checkVisitErrors("DodgyClass", ACC_TRANSIENT | ACC_VOLATILE, true);
+        checkErrorMessage(EXPECTED_TRANSIENT_CLASS_ERROR_MESSAGE);
+        checkErrorMessage(EXPECTED_VOLATILE_CLASS_ERROR_MESSAGE);
+    }
+
+    public void testDetectsFinalAbstractInterface() throws Exception {
+        checkVisitErrors(FINAL_INTERFACE, ACC_ABSTRACT | ACC_FINAL | ACC_INTERFACE, true);
+        checkErrorMessage(EXPECTED_INTERFACE_MODIFIER_ERROR_MESSAGE);
+    }
+
+    public void testDetectsFinalAndStaticMethodsInInterface() throws Exception {
+        ClassNode node = new ClassNode("zzz", ACC_ABSTRACT | ACC_INTERFACE, ClassHelper.OBJECT_TYPE);
+        node.addMethod(new MethodNode("xxx", ACC_PUBLIC | ACC_FINAL, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
+        node.addMethod(new MethodNode("yyy", ACC_PUBLIC | ACC_STATIC, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
+        // constructors should not be treated as errors (they have no real meaning for interfaces anyway)
+        node.addMethod(new MethodNode("<clinit>", ACC_PUBLIC | ACC_STATIC, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null));
+        verifier.visitClass(node);
+        checkErrorCount(2);
+        checkErrorMessage(EXPECTED_INTERFACE_FINAL_METHOD_ERROR_MESSAGE);
+        checkErrorMessage(EXPECTED_INTERFACE_STATIC_METHOD_ERROR_MESSAGE);
+    }
+
+    private void checkErrorCount(int count) {
+        assertEquals(buildErrorMessage(count), count, source.getErrorCollector().getErrorCount());
+    }
+
+    private String buildErrorMessage(int count) {
+        StringBuffer sb = new StringBuffer();
+        sb.append("Expected ").append(count);
+        sb.append(" error messages but found ");
+        sb.append(source.getErrorCollector().getErrorCount()).append(":\n");
+        sb.append(flattenErrorMessage());
+        return sb.toString();
+    }
+
+    private void checkVisitErrors(String name, int modifiers, boolean expectedToFail) {
+        ClassNode node = new ClassNode(name, modifiers, ClassHelper.OBJECT_TYPE);
+        verifier.visitClass(node);
+        assertTrue(source.getErrorCollector().hasErrors() == expectedToFail);
+    }
+
+    private void checkErrorMessage(String expectedErrorMessage) {
+        assertTrue("Expected an error message but none found.", source.getErrorCollector().hasErrors());
+        assertTrue("Expected message to contain <" + expectedErrorMessage +
+                "> but was <" + flattenErrorMessage() + ">.",
+                flattenErrorMessage().indexOf(expectedErrorMessage) != -1);
+    }
+
+    private String flattenErrorMessage() {
+        StringWriter stringWriter = new StringWriter();
+        PrintWriter writer = new PrintWriter(stringWriter, true);
+        for (int i = source.getErrorCollector().getErrorCount() - 1; i >= 0; i--) {
+            source.getErrorCollector().getError(i).write(writer);
+        }
+        writer.close();
+        return stringWriter.toString();
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/ConstructorIssueTest.groovy b/groovy-core/src/test/org/codehaus/groovy/classgen/ConstructorIssueTest.groovy
new file mode 100644
index 0000000..14cd789
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/ConstructorIssueTest.groovy
@@ -0,0 +1,35 @@
+package org.codehaus.groovy.classgen
+
+import groovy.bugs.TestSupport
+
+class ConstructorIssueTest extends TestSupport {
+    
+    ConstructorIssueTest() {
+        //println("Created test case!")
+    }
+
+    ConstructorIssueTest(String[] args) {
+        //println("Created test case!")
+    }
+
+    static void main(args) {
+        //println("in main() - called with ${array}")
+        
+        def foo = new ConstructorIssueTest()
+        foo.done()
+
+        //System.out.println("Done");
+    }
+    
+    void done() {
+        println("Yeah, I've been made")
+    }
+    
+    void testConstructorIssue() {
+        def array = getMockArguments()
+
+        main(array)
+
+        new ConstructorIssueTest(array).done()
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/ConstructorTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/ConstructorTest.java
new file mode 100644
index 0000000..c0d9c08
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/ConstructorTest.java
@@ -0,0 +1,64 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import groovy.lang.GroovyObject;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+/**
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ConstructorTest extends TestSupport {
+
+    public void testConstructor() throws Exception {
+        GroovyObject object = compile("src/test/groovy/NewExpressionTest.groovy");
+        object.invokeMethod("testNewInstance", null);
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/DerivedBean.java b/groovy-core/src/test/org/codehaus/groovy/classgen/DerivedBean.java
new file mode 100644
index 0000000..a203564
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/DerivedBean.java
@@ -0,0 +1,67 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+
+/**
+ * A simple bean
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class DerivedBean extends org.codehaus.groovy.runtime.DummyBean {
+
+    private String bar;
+
+    public String getBar() {
+        return bar;
+    }
+
+    public void setBar(String value) {
+        this.bar = value;
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/DummyReflector.java b/groovy-core/src/test/org/codehaus/groovy/classgen/DummyReflector.java
new file mode 100644
index 0000000..eb5eb28
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/DummyReflector.java
@@ -0,0 +1,102 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+
+package org.codehaus.groovy.classgen;
+
+import java.util.List;
+
+import groovy.lang.MetaMethod;
+
+import org.codehaus.groovy.runtime.Reflector;
+
+/**
+ * This is a scratch class used to experiment with ASM to see what kind of
+ * stuff is output for normal Java code
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class DummyReflector extends Reflector {
+
+    public DummyReflector() {
+    }
+
+    /*
+    public Object invoke(MetaMethod method, Object object, Object[] arguments) {
+        switch (method.getMethodIndex()) {
+            case 1 :
+                return InvokerHelper.toObject(object.hashCode());
+            case 2 :
+                return object.toString();
+            case 3 :
+                return InvokerHelper.toObject(object.equals(arguments[0]));
+            case 4 :
+                return new ObjectRange((Comparable) arguments[0], (Comparable) arguments[1]);
+            case 5 :
+                return ((String) object).toCharArray();
+            case 7 :
+                return new Character("hello".charAt(2));
+            case 8 :
+                return null;
+            default :
+                return noSuchMethod(method, object, arguments);
+        }
+    }
+    */
+
+    public Object invoke(MetaMethod method, Object object, Object[] arguments) {
+        switch (method.getMethodIndex()) {
+            case 1 :
+                return ((String) object).toCharArray();
+            case 2 :
+                return new Boolean(((List) object).contains(arguments[0]));
+            default :
+                return noSuchMethod(method, object, arguments);
+        }
+    }
+
+    public Object invokeConstructorAt(Object at, Object constructor, Object[] arguments) {
+        return null; // noSuchMethod(method, object, arguments);
+    }
+
+    public Object invokeConstructorOf(Object constructor, Object[] arguments) {
+        return null; // noSuchMethod(method, object, arguments);
+    }
+
+    char[] blah() {
+        return "foo".toCharArray();
+    }
+
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/DummyTestDerivation.java b/groovy-core/src/test/org/codehaus/groovy/classgen/DummyTestDerivation.java
new file mode 100644
index 0000000..d4036c2
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/DummyTestDerivation.java
@@ -0,0 +1,60 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import groovy.util.GroovyTestCase;
+
+/**
+ * A dummy test case
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class DummyTestDerivation extends GroovyTestCase {
+    public DummyTestDerivation() {
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/DumpingClassLoader.java b/groovy-core/src/test/org/codehaus/groovy/classgen/DumpingClassLoader.java
new file mode 100644
index 0000000..7a81ec7
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/DumpingClassLoader.java
@@ -0,0 +1,113 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import groovy.lang.GroovyClassLoader;
+
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.SourceUnit;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.util.CheckClassAdapter;
+import org.objectweb.asm.util.ASMifierClassVisitor;
+
+/**
+ * A class loader used for debugging the bytecode generation. 
+ * This will log all bytecode being loaded
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class DumpingClassLoader extends GroovyClassLoader implements Opcodes {
+
+    protected static boolean CHECK_CLASS = false;
+    protected static boolean DUMP_CLASS = true;
+
+    public DumpingClassLoader(ClassLoader parentLoader) {
+        super(parentLoader);
+    }
+    
+    
+    protected class DebugCollector extends ClassCollector {
+
+        DebugCollector(GroovyClassLoader cl, CompilationUnit unit, SourceUnit su) {
+            super(new GroovyClassLoader.InnerLoader(cl), unit, su);
+        }
+        
+        public void call(ClassVisitor classWriter, ClassNode classNode) {
+            // lets test out the class verifier
+            if (DUMP_CLASS) {
+                dumper.visitClass(classNode);
+            }
+
+            if (CHECK_CLASS) {
+                checker.visitClass(classNode);
+            }
+            
+            super.call(classWriter, classNode);
+        }
+    }
+    
+    protected ClassCollector createCollector(CompilationUnit unit) {
+        return new DebugCollector(this,unit, null);
+    }
+
+    protected ASMifierClassVisitor dumpVisitor = new ASMifierClassVisitor(new PrintWriter(new OutputStreamWriter(System.out)));
+    protected ASMifierClassVisitor invisibleDumpVisitor = new ASMifierClassVisitor(new PrintWriter(new StringWriter()));
+    protected CompileUnit unit = new CompileUnit(this, new CompilerConfiguration());
+    protected ClassGenerator checker =
+        new AsmClassGenerator(new GeneratorContext(unit), new CheckClassAdapter(invisibleDumpVisitor), this, null);
+    protected ClassGenerator dumper = new AsmClassGenerator(new GeneratorContext(unit), dumpVisitor, this, null);
+
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/ForTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/ForTest.java
new file mode 100644
index 0000000..9b39e70
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/ForTest.java
@@ -0,0 +1,154 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.*;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.InvokerInvocationException;
+
+/**
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Pilho Kim
+ * @version $Revision$
+ */
+public class ForTest extends TestSupport {
+
+    public void testNonLoop() throws Exception {
+        ClassNode classNode = new ClassNode("Foo", ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
+        classNode.addConstructor(new ConstructorNode(ACC_PUBLIC, null));
+
+        Parameter[] parameters = {new Parameter(ClassHelper.OBJECT_TYPE, "coll")};
+
+        Statement statement = createPrintlnStatement(new VariableExpression("coll"));
+        classNode.addMethod(new MethodNode("oneParamDemo", ACC_PUBLIC, ClassHelper.VOID_TYPE, parameters, ClassNode.EMPTY_ARRAY, statement));
+
+        Class fooClass = loadClass(classNode);
+        assertTrue("Loaded a new class", fooClass != null);
+
+        Object bean = fooClass.newInstance();
+        assertTrue("Managed to create bean", bean != null);
+
+        System.out.println("################ Now about to invoke a method without looping");
+        Object value = new Integer(10000);
+
+        try {
+            InvokerHelper.invokeMethod(bean, "oneParamDemo", new Object[] {value});
+        } catch (InvokerInvocationException e) {
+            System.out.println("Caught: " + e.getCause());
+            e.getCause().printStackTrace();
+            fail("Should not have thrown an exception");
+        }
+        System.out.println("################ Done");
+    }
+
+
+    public void testLoop() throws Exception {
+        ClassNode classNode = new ClassNode("Foo", ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
+        classNode.addConstructor(new ConstructorNode(ACC_PUBLIC, null));
+
+        Parameter[] parameters = {new Parameter(ClassHelper.OBJECT_TYPE.makeArray(), "coll")};
+
+        Statement loopStatement = createPrintlnStatement(new VariableExpression("i"));
+
+        ForStatement statement = new ForStatement(new Parameter(ClassHelper.OBJECT_TYPE,"i"), new VariableExpression("coll"), loopStatement);
+        classNode.addMethod(new MethodNode("iterateDemo", ACC_PUBLIC, ClassHelper.VOID_TYPE, parameters, ClassNode.EMPTY_ARRAY, statement));
+
+        Class fooClass = loadClass(classNode);
+        assertTrue("Loaded a new class", fooClass != null);
+
+        Object bean = fooClass.newInstance();
+        assertTrue("Managed to create bean", bean != null);
+
+        System.out.println("################ Now about to invoke a method with looping");
+        Object[] array = {new Integer(1234), "abc", "def"};
+
+        try {
+            InvokerHelper.invokeMethod(bean, "iterateDemo", new Object[]{array});
+        } catch (InvokerInvocationException e) {
+            System.out.println("Caught: " + e.getCause());
+            e.getCause().printStackTrace();
+            fail("Should not have thrown an exception");
+        }
+        System.out.println("################ Done");
+    }
+
+    public void testManyParam() throws Exception {
+        ClassNode classNode = new ClassNode("Foo", ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
+        classNode.addConstructor(new ConstructorNode(ACC_PUBLIC, null));
+
+        Parameter[] parameters = { new Parameter(ClassHelper.OBJECT_TYPE, "coll1"), new Parameter(ClassHelper.OBJECT_TYPE, "coll2"), new Parameter(ClassHelper.OBJECT_TYPE, "coll3") };
+
+        BlockStatement statement = new BlockStatement();
+        statement.addStatement(createPrintlnStatement(new VariableExpression("coll1")));
+        statement.addStatement(createPrintlnStatement(new VariableExpression("coll2")));
+        statement.addStatement(createPrintlnStatement(new VariableExpression("coll3")));
+
+        classNode.addMethod(new MethodNode("manyParamDemo", ACC_PUBLIC, ClassHelper.VOID_TYPE, parameters, ClassNode.EMPTY_ARRAY, statement));
+
+        Class fooClass = loadClass(classNode);
+        assertTrue("Loaded a new class", fooClass != null);
+
+        Object bean = fooClass.newInstance();
+        assertTrue("Managed to create bean", bean != null);
+
+        System.out.println("################ Now about to invoke a method with many parameters");
+        Object[] array = {new Integer(1000*1000), "foo-", "bar~"};
+
+        try {
+            InvokerHelper.invokeMethod(bean, "manyParamDemo", array);
+        } catch (InvokerInvocationException e) {
+            System.out.println("Caught: " + e.getCause());
+            e.getCause().printStackTrace();
+            fail("Should not have thrown an exception");
+        }
+        System.out.println("################ Done");
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/GStringTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/GStringTest.java
new file mode 100644
index 0000000..344736b
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/GStringTest.java
@@ -0,0 +1,134 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+ 
+ package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.GStringExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.AssertStatement;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.InvokerInvocationException;
+import org.codehaus.groovy.syntax.Token;
+
+/**
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class GStringTest extends TestSupport {
+
+    public void testConstructor() throws Exception {
+        ClassNode classNode = new ClassNode("Foo", ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
+
+        //Statement printStatement = createPrintlnStatement(new VariableExpression("str"));
+
+        // simulate "Hello ${user}!"
+        GStringExpression compositeStringExpr = new GStringExpression( "hello ${user}!" );
+        compositeStringExpr.addString(new ConstantExpression("Hello "));
+        compositeStringExpr.addValue(new VariableExpression("user"));
+        compositeStringExpr.addString(new ConstantExpression("!"));
+        BlockStatement block = new BlockStatement();
+        block.addStatement(
+            new ExpressionStatement(
+                new DeclarationExpression(
+                    new VariableExpression("user"),
+                    Token.newSymbol("=", -1, -1),
+                    new ConstantExpression("World"))));
+        block.addStatement(
+            new ExpressionStatement(
+                new DeclarationExpression(new VariableExpression("str"), Token.newSymbol( "=", -1, -1), compositeStringExpr)));
+        block.addStatement(
+            new ExpressionStatement(
+                new MethodCallExpression(VariableExpression.THIS_EXPRESSION, "println", new VariableExpression("str"))));
+
+        block.addStatement(
+            new ExpressionStatement(
+                new DeclarationExpression(
+                    new VariableExpression("text"),
+                    Token.newSymbol( "=", -1, -1),
+                    new MethodCallExpression(new VariableExpression("str"), "toString", MethodCallExpression.NO_ARGUMENTS))));
+
+        block.addStatement(
+            new AssertStatement(
+                new BooleanExpression(
+                    new BinaryExpression(
+                        new VariableExpression("text"),
+                        Token.newSymbol( "==", -1, -1),
+                        new ConstantExpression("Hello World!")))));
+        classNode.addMethod(new MethodNode("stringDemo", ACC_PUBLIC, ClassHelper.VOID_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, block));
+
+        Class fooClass = loadClass(classNode);
+        assertTrue("Loaded a new class", fooClass != null);
+
+        Object bean = fooClass.newInstance();
+        assertTrue("Managed to create bean", bean != null);
+
+        System.out.println("################ Now about to invoke method");
+
+        //Object[] array = { new Integer(1234), "abc", "def" };
+
+        try {
+            InvokerHelper.invokeMethod(bean, "stringDemo", null);
+        }
+        catch (InvokerInvocationException e) {
+            System.out.println("Caught: " + e.getCause());
+            e.getCause().printStackTrace();
+            fail("Should not have thrown an exception");
+        }
+        System.out.println("################ Done");
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/GetPropertyTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/GetPropertyTest.java
new file mode 100644
index 0000000..c1aa487
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/GetPropertyTest.java
@@ -0,0 +1,71 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import groovy.lang.GroovyObject;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+/**
+ * Tests using the GroovyObject API from Java on a groovy object
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class GetPropertyTest extends TestSupport {
+
+    public void testProperty() throws Exception {
+        GroovyObject object = compile("src/test/org/codehaus/groovy/classgen/MyBean.groovy");
+        System.out.println("Got object: " + object);
+
+        Object value = object.getProperty("name");
+        assertEquals("name property", "James", value);
+
+        object.setProperty("name", "Bob");
+        assertEquals("name property", "Bob", object.getProperty("name"));
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/GroovyClassLoaderTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/GroovyClassLoaderTest.java
new file mode 100644
index 0000000..4c09665
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/GroovyClassLoaderTest.java
@@ -0,0 +1,84 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import groovy.lang.GroovyObject;
+import groovy.lang.MetaClass;
+
+import java.io.File;
+
+
+/**
+ * Tests dynamically compiling a new class
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class GroovyClassLoaderTest extends TestSupport {
+
+    public void testCompile() throws Exception {
+        Class groovyClass = loader.parseClass(new File("src/test/org/codehaus/groovy/classgen/Main.groovy"));
+
+        System.out.println("Invoking main...");
+        
+        GroovyObject object = (GroovyObject) groovyClass.newInstance();
+        
+        assertTrue(object != null);
+
+        MetaClass metaClass = object.getMetaClass();
+        System.out.println("Metaclass: " + metaClass);
+        
+        Class type = object.getClass();
+        System.out.println("Type: " + type);
+        
+        // invoke via metaclass
+        metaClass.invokeMethod(object, "main", null);
+        
+        // invoke directly
+        object.invokeMethod("main", null);
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/IfElseTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/IfElseTest.java
new file mode 100644
index 0000000..72ad320
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/IfElseTest.java
@@ -0,0 +1,120 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.syntax.Token;
+
+/**
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class IfElseTest extends TestSupport {
+
+    public void testLoop() throws Exception {
+        ClassNode classNode = new ClassNode("Foo", ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
+        classNode.addConstructor(new ConstructorNode(ACC_PUBLIC, null));
+        classNode.addProperty(new PropertyNode("bar", ACC_PUBLIC, ClassHelper.STRING_TYPE, classNode, null, null, null));
+
+        classNode.addProperty(new PropertyNode("result", ACC_PUBLIC, ClassHelper.STRING_TYPE, classNode, null, null, null));
+
+        BooleanExpression expression =
+            new BooleanExpression(
+                new BinaryExpression(
+                    new FieldExpression(
+                        new FieldNode("bar", ACC_PRIVATE, ClassHelper.STRING_TYPE, classNode, ConstantExpression.NULL)),
+                    Token.newSymbol("==", 0, 0),
+                    new ConstantExpression("abc")));
+
+        Statement trueStatement =
+            new ExpressionStatement(
+                new BinaryExpression(
+                    new FieldExpression(
+                        new FieldNode("result", ACC_PRIVATE, ClassHelper.STRING_TYPE, classNode, ConstantExpression.NULL)),
+                    Token.newSymbol("=", 0, 0),
+                    new ConstantExpression("worked")));
+
+        Statement falseStatement = createPrintlnStatement(new ConstantExpression("false"));
+
+        IfStatement statement = new IfStatement(expression, trueStatement, falseStatement);
+        classNode.addMethod(new MethodNode("ifDemo", ACC_PUBLIC, ClassHelper.VOID_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, statement));
+
+        Class fooClass = loadClass(classNode);
+        assertTrue("Loaded a new class", fooClass != null);
+
+        Object bean = fooClass.newInstance();
+        assertTrue("Managed to create bean", bean != null);
+
+        assertSetProperty(bean, "bar", "abc");
+
+        System.out.println("################ Now about to invoke method");
+
+        Object[] array = {
+        };
+
+        InvokerHelper.invokeMethod(bean, "ifDemo", array);
+
+        System.out.println("################ Done");
+
+        assertGetProperty(bean, "result", "worked");
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/Main.groovy b/groovy-core/src/test/org/codehaus/groovy/classgen/Main.groovy
new file mode 100644
index 0000000..15becd1
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/Main.groovy
@@ -0,0 +1,8 @@
+package org.codehaus.groovy.classgen
+
+class Main {
+    
+    def main() {
+        println("Hello World!")
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/MainTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/MainTest.java
new file mode 100644
index 0000000..79355f3
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/MainTest.java
@@ -0,0 +1,64 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import groovy.lang.GroovyShell;
+
+import java.io.File;
+
+/**
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MainTest extends TestSupport {
+
+    public void testMainMethod() throws Exception {
+        GroovyShell shell = new GroovyShell();
+        shell.run(new File("src/test/groovy/SampleMain.groovy"), new String[] { "A", "B", "C" });
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/MetaClassTest.groovy b/groovy-core/src/test/org/codehaus/groovy/classgen/MetaClassTest.groovy
new file mode 100644
index 0000000..004835e
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/MetaClassTest.groovy
@@ -0,0 +1,34 @@
+package org.codehaus.groovy.classgen
+
+class MetaClassTest extends GroovyTestCase {
+    
+    void testMetaClass() {
+        test(this)
+        test { print(it) }
+    }
+    
+    protected def test(object) {
+        def metaClass = object.metaClass
+        assert metaClass != null
+        
+        println(metaClass)
+        
+        def classNode = metaClass.getClassNode()
+        assert classNode != null
+
+        println(classNode)
+        
+        def name = object.getClass().getName()
+        assert classNode.name == name
+    }
+    
+	void testMetClassDefinition() {
+		assertScript """
+			class Foo {
+		    	MetaClass metaClass
+			} 
+			def foo = new Foo()
+			assert foo.@metaClass != null
+			"""
+	}
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/MethodTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/MethodTest.java
new file mode 100644
index 0000000..ea95d84
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/MethodTest.java
@@ -0,0 +1,103 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MethodTest extends TestSupport {
+
+    public void testMethods() throws Exception {
+        ClassNode classNode = new ClassNode("Foo", ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
+        classNode.addConstructor(new ConstructorNode(ACC_PUBLIC, null));
+
+        Statement statementA = new ReturnStatement(new ConstantExpression("calledA"));
+        Statement statementB = new ReturnStatement(new ConstantExpression("calledB"));
+        Statement emptyStatement = new BlockStatement();
+
+        classNode.addMethod(new MethodNode("a", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, statementA));
+        classNode.addMethod(new MethodNode("b", ACC_PUBLIC, null, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, statementB));
+        
+        classNode.addMethod(new MethodNode("noReturnMethodA", ACC_PUBLIC, null, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, emptyStatement));
+        classNode.addMethod(new MethodNode("noReturnMethodB", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, emptyStatement));
+        
+        classNode.addMethod(new MethodNode("c", ACC_PUBLIC, ClassHelper.VOID_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, emptyStatement));
+
+        Class fooClass = loadClass(classNode);
+        assertTrue("Loaded a new class", fooClass != null);
+
+        Object bean = fooClass.newInstance();
+        assertTrue("Created instance of class: " + bean, bean != null);
+ 
+        assertCallMethod(bean, "a", "calledA");
+        assertCallMethod(bean, "b", "calledB");
+        assertCallMethod(bean, "noReturnMethodA", null);
+        assertCallMethod(bean, "noReturnMethodB", null);
+        assertCallMethod(bean, "c", null);
+    }
+
+    protected void assertCallMethod(Object object, String method, Object expected) {
+        Object value = InvokerHelper.invokeMethod(object, method, new Object[0]);
+        assertEquals("Result of calling method: " + method + " on: " + object + " with empty list", expected, value);
+
+        value = InvokerHelper.invokeMethod(object, method, null);
+        assertEquals("Result of calling method: " + method + " on: " + object + " with null", expected, value);
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/MyBean.groovy b/groovy-core/src/test/org/codehaus/groovy/classgen/MyBean.groovy
new file mode 100644
index 0000000..0358757
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/MyBean.groovy
@@ -0,0 +1,7 @@
+package org.codehaus.groovy.classgen
+
+class MyBean {
+
+	def name = "James"
+	def foo = 123
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/PropertyTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/PropertyTest.java
new file mode 100644
index 0000000..c831dd8
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/PropertyTest.java
@@ -0,0 +1,111 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import java.lang.reflect.Modifier;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.runtime.DummyBean;
+
+/**
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class PropertyTest extends TestSupport {
+
+    public void testFields() throws Exception {
+        ClassNode classNode = new ClassNode("Foo", ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
+        classNode.addField("x", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, null);
+        classNode.addField("y", ACC_PUBLIC, ClassHelper.Integer_TYPE, null);
+        classNode.addField("z", ACC_PRIVATE, ClassHelper.STRING_TYPE, null);
+
+        Class fooClass = loadClass(classNode);
+        assertTrue("Loaded a new class", fooClass != null);
+
+        assertField(fooClass, "x", Modifier.PUBLIC, ClassHelper.OBJECT_TYPE);
+        assertField(fooClass, "y", Modifier.PUBLIC, ClassHelper.Integer_TYPE);
+        assertField(fooClass, "z", Modifier.PRIVATE, ClassHelper.STRING_TYPE);
+    }
+
+    public void testProperties() throws Exception {
+        ClassNode classNode =new ClassNode("Foo", ACC_PUBLIC+ACC_SUPER, ClassHelper.OBJECT_TYPE);
+        classNode.addProperty(new PropertyNode("bar", ACC_PUBLIC, ClassHelper.STRING_TYPE, classNode, null, null, null));
+
+        Class fooClass = loadClass(classNode);
+        assertTrue("Loaded a new class", fooClass != null);
+
+        Object bean = fooClass.newInstance();
+        assertTrue("Managed to create bean", bean != null);
+
+        assertField(fooClass, "bar", 0, ClassHelper.STRING_TYPE);
+
+        assertGetProperty(bean, "bar", null);
+        assertSetProperty(bean, "bar", "newValue");
+    }
+
+    public void testInheritedProperties() throws Exception {
+        ClassNode classNode = new ClassNode("Foo", ACC_PUBLIC+ACC_SUPER, ClassHelper.make(DummyBean.class));
+        classNode.addProperty(new PropertyNode("bar", ACC_PUBLIC, ClassHelper.STRING_TYPE, classNode, null, null, null));
+
+        Class fooClass = loadClass(classNode);
+        assertTrue("Loaded a new class", fooClass != null);
+
+        Object bean = fooClass.newInstance();
+        assertTrue("Managed to create bean", bean != null);
+
+        assertField(fooClass, "bar", 0, ClassHelper.STRING_TYPE);
+
+        assertGetProperty(bean, "name", "James");
+        assertSetProperty(bean, "name", "Bob");
+
+        assertGetProperty(bean, "bar", null);
+        assertSetProperty(bean, "bar", "newValue");
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/ReflectorGeneratorTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/ReflectorGeneratorTest.java
new file mode 100644
index 0000000..eb33c82
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/ReflectorGeneratorTest.java
@@ -0,0 +1,114 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.util.CheckClassAdapter;
+import org.objectweb.asm.util.ASMifierClassVisitor;
+
+import groovy.lang.MetaClassRegistry;
+import groovy.lang.MetaMethod;
+import groovy.util.GroovyTestCase;
+
+/**
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class ReflectorGeneratorTest extends GroovyTestCase {
+
+    public void testGenerator() throws Exception {
+        List methods = new ArrayList();
+        methods.add(new MetaMethod("toCharArray", String.class, new Class[0], char[].class, 0));
+        //methods.add(new MetaMethod("toString", String.class, new Class[0], String.class, 0));
+        testMethods(methods);
+    }
+    
+    public void testObjectGenerator() throws Exception {
+        List methods = InvokerHelper.getMetaClass(new Object()).getMethods();
+        testMethods(methods);
+    }
+    
+    public void testDummyReflector() throws Exception {
+        DummyReflector dummy = new DummyReflector();
+        assertTrue(dummy != null);
+    }
+    
+    protected void testMethods(List methods) throws Exception {
+        ReflectorGenerator generator = new ReflectorGenerator(methods);
+        String name = getClass().getName() + "." + getMethodName();
+        ClassWriter cw = new ClassWriter(true);
+
+        
+        //ASMifierClassVisitor dumper = new ASMifierClassVisitor(new PrintWriter(new OutputStreamWriter(System.out)));
+        //generator.generate(dumper, name);
+
+        generator.generate(new CheckClassAdapter(cw), name);
+
+        byte[] bytecode = cw.toByteArray();
+
+        // lets write it to disk
+        String fileName = "target/" + name + ".class";
+        FileOutputStream out = new FileOutputStream(fileName);
+        out.write(bytecode);
+        out.close();
+
+        // now lets try dump it
+        ASMifierClassVisitor.main(new String[] { fileName });
+
+        // now lets try class load it
+        MetaClassRegistry registry = new MetaClassRegistry();
+        Object reflector = registry.loadReflector(getClass(),methods);
+         
+        System.out.println("Created new reflector: " + reflector);
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/ReflectorLoaderTest.groovy b/groovy-core/src/test/org/codehaus/groovy/classgen/ReflectorLoaderTest.groovy
new file mode 100644
index 0000000..b622be8
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/ReflectorLoaderTest.groovy
@@ -0,0 +1,14 @@
+package org.codehaus.groovy.classgen

+

+class ReflectorLoaderTest extends GroovyTestCase {

+

+    void testDuplication(){

+      def program =  '''

+		closureA = {}

+		closureB = {closureA ( ) }

+	  '''

+	  def binding  = new Binding()

+	  ( new GroovyShell ( binding ) ).evaluate ( program )

+	  binding.closureB.call( )

+  }

+}
\ No newline at end of file
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/RunBugsTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/RunBugsTest.java
new file mode 100644
index 0000000..0c9fd28
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/RunBugsTest.java
@@ -0,0 +1,152 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+
+package org.codehaus.groovy.classgen;
+
+import groovy.lang.GroovyObject;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+/**
+ * A helper class for testing bugs in code generation errors. By turning on the
+ * logging in TestSupport we can dump the ASM code generation code for inner
+ * classes etc.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class RunBugsTest extends TestSupport {
+
+    /*
+    public void testStaticMethodCall() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/StaticMethodCallBug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+
+    public void testTryCatchBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/TryCatchBug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+
+    public void testRodsBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/RodsBug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+
+    public void testCastBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/ClosureMethodCallTest.groovy");
+        object.invokeMethod("testCallingClosureWithMultipleArguments", null);
+    }
+
+    public void testGuillaumesMapBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/GuillaumesMapBug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+
+    public void testUseClosureInScript() throws Exception {
+        GroovyObject object = compile("src/test/groovy/script/UseClosureInScript.groovy");
+        object.invokeMethod("run", null);
+    }
+
+    public void testUseStaticInClosure() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/UseStaticInClosureBug.groovy");
+        object.invokeMethod("testBug2", null);
+    }
+
+    public void testPrimitiveTypeFieldTest() throws Exception {
+        GroovyObject object = compile("src/test/groovy/PrimitiveTypeFieldTest.groovy");
+        object.invokeMethod("testPrimitiveField", null);
+    }
+    
+    public void testMethodDispatchBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/MethodDispatchBug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+    public void testClosureInClosureTest() throws Exception {
+        GroovyObject object = compile("src/test/groovy/ClosureInClosureTest.groovy");
+        object.invokeMethod("testInvisibleVariable", null);
+    }
+    public void testStaticMarkupBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/StaticMarkupBug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+    public void testOverloadInvokeMethodBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/OverloadInvokeMethodBug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+    public void testClosureVariableBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/ClosureVariableBug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+    
+    public void testMarkupAndMethodBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/MarkupAndMethodBug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+    public void testClosureParameterPassingBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/ClosureParameterPassingBug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+    public void testNestedClosureBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/NestedClosure2Bug.groovy");
+        object.invokeMethod("testFieldBug", null);
+    }
+    public void testSuperMethod2Bug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/SuperMethod2Bug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+    public void testToStringBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/ToStringBug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+    public void testByteIndexBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/ByteIndexBug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+    public void testGroovy252_Bug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/Groovy252_Bug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+    
+    */
+        
+    public void testGroovy303_Bug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/Groovy303_Bug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+    
+    
+    
+   }
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/RunClosureTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/RunClosureTest.java
new file mode 100644
index 0000000..e66600d
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/RunClosureTest.java
@@ -0,0 +1,111 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import groovy.lang.GroovyObject;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+/**
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class RunClosureTest extends TestSupport {
+
+    public void testClosure() throws Exception {
+        GroovyObject object = compile("src/test/groovy/ClosureUsingOuterVariablesTest.groovy");
+        object.invokeMethod("testExampleUseOfClosureScopesUsingEach", null);
+    }
+
+    public void testStaticClosureBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/StaticClosurePropertyBug.groovy");
+        object.invokeMethod("testCallStaticClosure", null);
+    }
+
+    public void testZoharsBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/ZoharsBug.groovy");
+        object.invokeMethod("testBug", null);
+    }
+
+    public void testBytecodeBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/BytecodeBug.groovy");
+        object.invokeMethod("testTedsBytecodeBug", null);
+    }
+
+    public void testBytecode2Bug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/Bytecode2Bug.groovy");
+        object.invokeMethod("testTedsBytecodeBug", null);
+    }
+
+    public void testBytecode3Bug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/Bytecode3Bug.groovy");
+        //object.invokeMethod("testInject", null);
+        object.invokeMethod("testIncrementPropertyInclosure", null);
+    }
+
+    public void testBytecode4Bug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/Bytecode4Bug.groovy");
+        object.invokeMethod("testInject", null);
+        object.invokeMethod("testUsingProperty", null);
+    }
+
+    public void testBytecode5Bug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/Bytecode5Bug.groovy");
+        object.invokeMethod("testUsingLocalVar", null);
+    }
+
+    public void testBytecode6Bug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/bugs/Bytecode6Bug.groovy");
+        object.invokeMethod("testPreFixReturn", null);
+    }
+
+    public void testPropertyTest() throws Exception {
+        GroovyObject object = compile("src/test/groovy/PropertyTest.groovy");
+        object.invokeMethod("testNormalPropertyGettersAndSetters", null);
+    }
+
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/RunGroovyTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/RunGroovyTest.java
new file mode 100644
index 0000000..8bd97db
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/RunGroovyTest.java
@@ -0,0 +1,97 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import groovy.lang.GroovyObject;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+/**
+ * Tests dynamically compiling and running a new class
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class RunGroovyTest extends TestSupport {
+
+    public void testArrayBug() throws Exception {
+        GroovyObject object = compile("src/test/groovy/ToArrayBugTest.groovy");
+        object.invokeMethod("testToArrayBug", null);
+    }
+
+
+    public void testPostfix() throws Exception {
+        GroovyObject object = compile("src/test/groovy/PostfixTest.groovy");
+        object.invokeMethod("testIntegerPostfix", null);
+    }
+
+    public void testMap() throws Exception {
+        GroovyObject object = compile("src/test/groovy/MapTest.groovy");
+        object.invokeMethod("testMap", null);
+    }
+
+    public void testClosure() throws Exception {
+        GroovyObject object = compile("src/test/groovy/ClosureMethodTest.groovy");
+        object.invokeMethod("testListCollect", null);
+    }
+
+    public void testClosureWithDefaultParam() throws Exception {
+        GroovyObject object = compile("src/test/groovy/ClosureWithDefaultParamTest.groovy");
+        object.invokeMethod("methodWithDefaultParam", null);
+    }
+
+    public void testOptionalReturn() throws Exception {
+        GroovyObject object = compile("src/test/groovy/OptionalReturnTest.groovy");
+        object.invokeMethod("testSingleExpression", null);
+        object.invokeMethod("testLastExpressionIsSimple", null);
+    }
+
+    public void testConsole() throws Exception {
+        GroovyObject object = compile("src/main/groovy/ui/Console.groovy");
+    }
+    /*    */
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/SimpleBean.java b/groovy-core/src/test/org/codehaus/groovy/classgen/SimpleBean.java
new file mode 100644
index 0000000..ded77d9
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/SimpleBean.java
@@ -0,0 +1,79 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+
+/**
+ * A simple bean
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class SimpleBean {
+
+    private String bar;
+    private Object x;
+
+    //private static final Object INT_CONST = new Integer(123);
+
+    public String getBar() {
+        return bar;
+    }
+
+    public void setBar(String value) {
+        this.bar = value;
+    }
+    
+    
+    public void setNumber() {
+        x = new Integer(123);
+    }
+    
+    public void setFloat() {
+        x = new Double(123);
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/TestSupport.java b/groovy-core/src/test/org/codehaus/groovy/classgen/TestSupport.java
new file mode 100644
index 0000000..c073db2
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/TestSupport.java
@@ -0,0 +1,215 @@
+package org.codehaus.groovy.classgen;
+
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+import groovy.lang.Binding;
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyCodeSource;
+import groovy.lang.GroovyObject;
+import groovy.lang.Script;
+import groovy.util.GroovyTestCase;
+
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.File;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Base class for test cases
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class TestSupport extends GroovyTestCase implements Opcodes {
+
+    protected static boolean DUMP_CLASS = false;
+
+    // ClassLoader parentLoader = Thread.currentThread().getContextClassLoader();
+    ClassLoader parentLoader = getClass().getClassLoader();
+    protected GroovyClassLoader loader = 
+    	(GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
+    		public Object run() {
+    			return new GroovyClassLoader(parentLoader);
+    		}
+    	});
+    CompileUnit unit = new CompileUnit(loader, new CompilerConfiguration());
+    ModuleNode module = new ModuleNode(unit);
+    
+    protected Class loadClass(ClassNode classNode) {
+        classNode.setModule(module);
+        Class fooClass = loader.defineClass(classNode, classNode.getName() + ".groovy", "groovy.testSupport");
+        return fooClass;
+    }
+
+    protected void assertSetProperty(Object bean, String property, Object newValue) throws Exception {
+        PropertyDescriptor descriptor = getDescriptor(bean, property);
+        Method method = descriptor.getWriteMethod();
+        assertTrue("has setter method", method != null);
+
+        Object[] args = { newValue };
+        Object value = invokeMethod(bean, method, args);
+
+        assertEquals("should return null", null, value);
+
+        assertGetProperty(bean, property, newValue);
+    }
+
+    protected void assertGetProperty(Object bean, String property, Object expected) throws Exception {
+        PropertyDescriptor descriptor = getDescriptor(bean, property);
+        Method method = descriptor.getReadMethod();
+        assertTrue("has getter method", method != null);
+
+        Object[] args = {
+        };
+        Object value = invokeMethod(bean, method, args);
+
+        /*
+        System.out.println("Expected: " + expected);
+        System.out.println("Value: " + value);
+        
+        if (expected == null) { System.out.println("Expected is null"); }
+        if (value == null) { System.out.println("value is null"); }
+        */
+        
+        assertEquals("property value", expected, value);
+    }
+
+    protected Object invokeMethod(Object bean, Method method, Object[] args) throws Exception {
+        try {
+            return method.invoke(bean, args);
+        }
+        catch (InvocationTargetException e) {
+            fail("InvocationTargetException: " + e.getTargetException());
+            return null;
+        }
+    }
+
+    protected PropertyDescriptor getDescriptor(Object bean, String property) throws Exception {
+        BeanInfo info = Introspector.getBeanInfo(bean.getClass());
+        PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
+        for (int i = 0; i < descriptors.length; i++) {
+            PropertyDescriptor descriptor = descriptors[i];
+            if (descriptor.getName().equals(property)) {
+                return descriptor;
+            }
+        }
+        fail("Could not find property: " + property + " on bean: " + bean);
+        return null;
+    }
+
+    protected void assertField(Class aClass, String name, int modifiers, ClassNode type) throws Exception {
+        Field field = aClass.getDeclaredField(name);
+
+        assertTrue("Found field called: " + name, field != null);
+        assertEquals("Name", name, field.getName());
+        assertEquals("Type", type.getName(), field.getType().getName());
+        assertEquals("Modifiers", modifiers, field.getModifiers());
+    }
+
+    protected ExpressionStatement createPrintlnStatement(Expression expression) throws NoSuchFieldException {
+        return new ExpressionStatement(
+            new MethodCallExpression(
+                new FieldExpression(FieldNode.newStatic(System.class, "out")),
+                "println",
+                expression));
+    }
+
+    /**
+     * Asserts that the script runs without any exceptions
+     */
+    protected void assertScript(String text) throws Exception {
+        assertScript(text, getTestClassName());
+    }
+    
+    protected void assertScript(final String text, final String scriptName) throws Exception {
+        log.info("About to execute script");
+        log.info(text);
+    	GroovyCodeSource gcs = (GroovyCodeSource) AccessController.doPrivileged(new PrivilegedAction() {
+    		public Object run() {
+    			return new GroovyCodeSource(text, scriptName, "/groovy/testSupport");
+    		}
+    	});
+        Class groovyClass = loader.parseClass(gcs);
+        Script script = InvokerHelper.createScript(groovyClass, new Binding());
+        script.run();
+    }
+    
+    protected void assertScriptFile(String fileName) throws Exception {
+        log.info("About to execute script: " + fileName);
+        
+        Class groovyClass = loader.parseClass(new GroovyCodeSource(new File(fileName)));
+        Script script = InvokerHelper.createScript(groovyClass, new Binding());
+        script.run();
+    }
+    
+    protected GroovyObject compile(String fileName) throws Exception {
+        Class groovyClass = loader.parseClass(new GroovyCodeSource(new File(fileName)));
+
+        GroovyObject object = (GroovyObject) groovyClass.newInstance();
+
+        assertTrue(object != null);
+
+        return object;
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/TupleListTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/TupleListTest.java
new file mode 100644
index 0000000..fad2730
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/TupleListTest.java
@@ -0,0 +1,134 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.MapExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.InvokerInvocationException;
+import org.codehaus.groovy.syntax.Token;
+
+/**
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class TupleListTest extends TestSupport {
+
+    public void testIterateOverTuple() throws Exception {
+        TupleExpression listExpression = new TupleExpression();
+        listExpression.addExpression(new ConstantExpression("a"));
+        listExpression.addExpression(new ConstantExpression("b"));
+        listExpression.addExpression(new ConstantExpression("c"));
+        assertIterate("iterateOverTuple", listExpression);
+    }
+    
+    public void testIterateOverList() throws Exception {
+        ListExpression listExpression = new ListExpression();
+        listExpression.addExpression(new ConstantExpression("a"));
+        listExpression.addExpression(new ConstantExpression("b"));
+        listExpression.addExpression(new ConstantExpression("c"));
+        listExpression.addExpression(new ConstantExpression("a"));
+        listExpression.addExpression(new ConstantExpression("b"));
+        listExpression.addExpression(new ConstantExpression("c"));
+        assertIterate("iterateOverList", listExpression);
+    }
+    
+    public void testIterateOverMap() throws Exception {
+        MapExpression mapExpression = new MapExpression();
+        mapExpression.addMapEntryExpression(new ConstantExpression("a"), new ConstantExpression("x"));
+        mapExpression.addMapEntryExpression(new ConstantExpression("b"), new ConstantExpression("y"));
+        mapExpression.addMapEntryExpression(new ConstantExpression("c"), new ConstantExpression("z"));
+        assertIterate("iterateOverMap", mapExpression);
+    }
+    
+    protected void assertIterate(String methodName, Expression listExpression) throws Exception {
+        ClassNode classNode = new ClassNode("Foo", ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
+        classNode.addConstructor(new ConstructorNode(ACC_PUBLIC, null));
+        classNode.addProperty(new PropertyNode("bar", ACC_PUBLIC, ClassHelper.STRING_TYPE, classNode, null, null, null));
+
+        Statement loopStatement = createPrintlnStatement(new VariableExpression("i"));
+
+        BlockStatement block = new BlockStatement();
+        block.addStatement(new ExpressionStatement(new DeclarationExpression(new VariableExpression("list"), Token.newSymbol("=", 0, 0), listExpression)));
+        block.addStatement(new ForStatement(new Parameter(ClassHelper.DYNAMIC_TYPE,"i"), new VariableExpression("list"), loopStatement));
+        classNode.addMethod(new MethodNode(methodName, ACC_PUBLIC, ClassHelper.VOID_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, block));
+
+        Class fooClass = loadClass(classNode);
+        assertTrue("Loaded a new class", fooClass != null);
+
+        Object bean = fooClass.newInstance();
+        assertTrue("Managed to create bean", bean != null);
+
+        System.out.println("################ Now about to invoke method");
+        
+        try {
+            InvokerHelper.invokeMethod(bean, methodName, null);
+        }
+        catch (InvokerInvocationException e) {
+            System.out.println("Caught: " + e.getCause());
+            e.getCause().printStackTrace();
+            fail("Should not have thrown an exception");
+        }
+        System.out.println("################ Done");    }
+
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/classgen/VerifierCodeVisitorTest.java b/groovy-core/src/test/org/codehaus/groovy/classgen/VerifierCodeVisitorTest.java
new file mode 100644
index 0000000..f124c44
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/classgen/VerifierCodeVisitorTest.java
@@ -0,0 +1,58 @@
+/**
+ *
+ * Copyright 2004 James Strachan
+ *
+ * Licensed 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;
+
+import junit.framework.TestCase;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.syntax.RuntimeParserException;
+
+/**
+ * @version $Revision$
+ */
+public class VerifierCodeVisitorTest extends TestCase {
+    public void testValidNames() {
+        assertValidName("a");
+        assertValidName("a1234");
+        assertValidName("a_b_c");
+        assertValidName("a____1234");
+    }
+
+    public void testInvalidNames() {
+        assertInvalidName("1");
+        assertInvalidName("100");
+        assertInvalidName("1a");
+        assertInvalidName("a!");
+        assertInvalidName("a.");
+        assertInvalidName("$");
+        assertInvalidName("$foo");
+    }
+
+    protected void assertValidName(String name) {
+        VerifierCodeVisitor.assertValidIdentifier(name, "variable name", new ASTNode());
+    }
+
+    protected void assertInvalidName(String name) {
+        try {
+            VerifierCodeVisitor.assertValidIdentifier(name, "variable name", new ASTNode());
+            fail("Should have thrown exception due to invalid name: " + name);
+        }
+        catch (RuntimeParserException e) {
+            System.out.println("Caught invalid exception: " + e);
+        }
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/control/CompilationUnitTest.java b/groovy-core/src/test/org/codehaus/groovy/control/CompilationUnitTest.java
new file mode 100644
index 0000000..f1811ff
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/control/CompilationUnitTest.java
@@ -0,0 +1,44 @@
+/*
+ * $Id$
+ *
+ * Copyright (c) 2005 The Codehaus - http://groovy.codehaus.org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and limitations under the License.
+ *
+ */
+
+
+package org.codehaus.groovy.control;
+
+import java.util.Iterator;
+
+import org.jmock.Mock;
+import org.jmock.cglib.MockObjectTestCase;
+
+import groovy.lang.GroovyClassLoader;
+
+public class CompilationUnitTest extends MockObjectTestCase {
+
+    public void testAppendsTheClasspathOfTheCompilerConfigurationToCurrentClassLoaderWhenInstantiated() {
+        CompilerConfiguration configuration = new CompilerConfiguration();
+        configuration.setClasspath(System.getProperty("java.class.path"));
+        // disabled until checked with fraz
+        //new CompilationUnit(configuration, null, createGroovyClassLoaderWithExpectations(configuration));
+    }
+
+    private GroovyClassLoader createGroovyClassLoaderWithExpectations(CompilerConfiguration configuration) {
+        Mock mockGroovyClassLoader = mock(GroovyClassLoader.class);
+        for (Iterator iterator = configuration.getClasspath().iterator(); iterator.hasNext();) {
+            mockGroovyClassLoader.expects(once()).method("addClasspath").with(eq(iterator.next()));
+        }
+        return (GroovyClassLoader) mockGroovyClassLoader.proxy();
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/control/messages/SyntaxErrorMessageTest.java b/groovy-core/src/test/org/codehaus/groovy/control/messages/SyntaxErrorMessageTest.java
new file mode 100644
index 0000000..843c989
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/control/messages/SyntaxErrorMessageTest.java
@@ -0,0 +1,42 @@
+/*
+ * $Id$
+ *
+ * Copyright (c) 2005 The Codehaus - http://groovy.codehaus.org
+ *
+ * Licensed 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.messages;
+
+import junit.framework.TestCase;
+
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.syntax.SyntaxException;
+
+public class SyntaxErrorMessageTest extends TestCase {
+
+    public void testSetsTheSourceLocatorOfItsSyntaxExceptionAsTheNameOfTheCorrespondingSourceUnitWhenInstantiated() {
+        SyntaxException syntaxException = new SyntaxException(someString(), -1, -1);
+        assertEquals("source locator", null, syntaxException.getSourceLocator());
+
+        String sourceUnitName = someString();
+        SourceUnit sourceUnit = SourceUnit.create(sourceUnitName, someString());
+
+        new SyntaxErrorMessage(syntaxException, sourceUnit);
+        assertEquals("source locator", sourceUnitName, syntaxException.getSourceLocator());
+    }
+
+    private String someString() {
+        return String.valueOf(Math.random() * System.currentTimeMillis());
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/dummy/ClassWithStaticMethod.groovy b/groovy-core/src/test/org/codehaus/groovy/dummy/ClassWithStaticMethod.groovy
new file mode 100644
index 0000000..3b24e66
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/dummy/ClassWithStaticMethod.groovy
@@ -0,0 +1,9 @@
+package org.codehaus.groovy.dummy;
+
+/**
+ * Class used by groovy.bugs.StaticMethodImportBug.
+ * Bug reference: Explicit import needed to call static method, GROOVY-935
+ */
+class ClassWithStaticMethod {
+    static boolean staticMethod() { return true }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/org/codehaus/groovy/dummy/FooHandler.java b/groovy-core/src/test/org/codehaus/groovy/dummy/FooHandler.java
new file mode 100644
index 0000000..e29b0a9
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/dummy/FooHandler.java
@@ -0,0 +1,11 @@
+package org.codehaus.groovy.dummy;
+
+import java.io.Reader;
+
+/**
+ * @author Robert Fuller
+ * @version $Revision$
+ */
+public interface FooHandler {
+    public void handle(Reader reader);
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/CategoryForIteratorTest.groovy b/groovy-core/src/test/org/codehaus/groovy/runtime/CategoryForIteratorTest.groovy
new file mode 100644
index 0000000..3e46116
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/CategoryForIteratorTest.groovy
@@ -0,0 +1,61 @@
+
+import java.util.Iterator
+
+import groovy.util.GroovyTestCase
+
+/*
+ * Test whether the Invoker includes categories when 
+ * trying to find an iterator (via the method iterator())
+ */ 
+class CategoryForIteratorTest extends GroovyTestCase {
+
+	def identity = { val -> val }
+	def c
+	def countCalls = { c = c + 1 }
+
+	void setUp() {
+		c = 0
+	}
+	
+	/*
+	 * Ensure that without the iterator category a
+	 * one-element collection is returned that
+	 * results in one call to the countCalls closure
+	 */
+	void testWithoutIteratorCategory() {
+		identity.each countCalls
+		assert c == 1
+	}
+	/*
+	 * When using the IteratorCategory below we get an
+	 * iterator that does no iteration. So the count
+	 * has to be 0
+	 */
+	void testWithIteratorCategory() {
+		use(IteratorCategory) {
+			c = 0
+			identity.each countCalls
+			assert c == 0
+		}
+	}
+}
+
+/*
+ * The category simply adds an iterator()-method returning
+ * the null iterator defined below
+ */
+class IteratorCategory {
+	static Iterator iterator(Closure c) { 
+		return new TestIterator()
+	}
+}
+
+/*
+ * This iterator returns 0 elements, allowing us to distinguish
+ * from the default collection-iterator
+ */
+class TestIterator implements Iterator {
+    public boolean hasNext() { return false }
+    public Object next() { return null }
+    public void remove() {}
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.java b/groovy-core/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.java
new file mode 100644
index 0000000..c76f15f
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.java
@@ -0,0 +1,139 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.Closure;
+import groovy.util.GroovyTestCase;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Marc Guillemot
+ * @version $Revision$
+ */
+public class DefaultGroovyMethodsTest extends GroovyTestCase {
+
+    public void testPrint() throws Exception {
+        Map map = new HashMap();
+        map.put("bob", "drools");
+        map.put("james", "geronimo");
+        List list = new ArrayList();
+        list.add(map);
+
+        /** @todo fix this! */
+        //assertConsoleOutput(list, "[['bob':'drools', 'james':'geronimo']]");
+    }
+
+    public void testIncrementString() throws Exception {
+        String original = "z";
+        String answer = DefaultGroovyMethods.next(original);
+
+        System.out.println(answer);
+        assertTrue(answer.compareTo(original) > 0);
+    }
+
+    public void testDecrementString() throws Exception {
+        String original = "a";
+        String answer = DefaultGroovyMethods.previous(original);
+
+        System.out.println(answer);
+        assertTrue(ScriptBytecodeAdapter.compareLessThan(answer, original));
+    }
+
+    public void testToMethods() throws Exception {
+        Number n = new Long(7);
+
+        assertEquals(DefaultGroovyMethods.toInteger("1"), new Integer(1));
+        assertEquals(DefaultGroovyMethods.toInteger(n), new Integer(7));
+        assertEquals(DefaultGroovyMethods.toLong("1"), new Long(1));
+        assertEquals(DefaultGroovyMethods.toLong(n), new Long(7));
+        assertEquals(DefaultGroovyMethods.toFloat("1"), new Float(1));
+        assertEquals(DefaultGroovyMethods.toFloat(n), new Float(7));
+        assertEquals(DefaultGroovyMethods.toDouble("1"), new Double(1));
+        assertEquals(DefaultGroovyMethods.toDouble(n), new Double(7));
+        assertEquals(DefaultGroovyMethods.toBigInteger("1"), new BigInteger("1"));
+        assertEquals(DefaultGroovyMethods.toBigInteger(n), new BigInteger("7"));
+        assertEquals(DefaultGroovyMethods.toBigDecimal("1"), new BigDecimal("1"));
+        assertEquals(DefaultGroovyMethods.toBigDecimal(n), new BigDecimal("7"));
+        assertEquals(DefaultGroovyMethods.toURL("http://example.org/"), new URL("http://example.org/"));
+        assertEquals(DefaultGroovyMethods.toURI("http://example.org/"), new URI("http://example.org/"));
+        assertEquals(DefaultGroovyMethods.toBoolean("True"), Boolean.TRUE);
+        assertEquals(DefaultGroovyMethods.toBoolean("Y"), Boolean.TRUE);
+        assertEquals(DefaultGroovyMethods.toBoolean(" y "), Boolean.TRUE);
+        assertEquals(DefaultGroovyMethods.toBoolean("1"), Boolean.TRUE);
+        assertEquals(DefaultGroovyMethods.toBoolean("false"), Boolean.FALSE);
+        assertEquals(DefaultGroovyMethods.toBoolean("n"), Boolean.FALSE);
+        assertEquals(DefaultGroovyMethods.toBoolean("0"), Boolean.FALSE);
+    }
+
+
+    public void testDownto() {
+        final int[] count = new int[]{0};
+        final Closure closure = new Closure(null) {
+            public Object doCall(final Object params) {
+                count[0]++;
+                return null;
+            }
+        };
+
+        DefaultGroovyMethods.downto(new BigInteger("1"), new BigDecimal("0"), closure);
+        assertEquals(count[0], 2);
+
+        count[0] = 0;
+
+        DefaultGroovyMethods.downto(new BigInteger("1"), new BigDecimal("0.123"), closure);
+        assertEquals(count[0], 1);
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/DummyBean.java b/groovy-core/src/test/org/codehaus/groovy/runtime/DummyBean.java
new file mode 100644
index 0000000..f849bf7
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/DummyBean.java
@@ -0,0 +1,136 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.runtime;
+
+import java.awt.Point;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A bean used by the test cases
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class DummyBean {
+    private String name = "James";
+    private Integer i = new Integer(123);
+    private Map dynamicProperties = new HashMap();
+    private Point point;
+    private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
+    
+    public DummyBean() {
+    }
+
+    public DummyBean(String name) {
+        this.name = name;
+    }
+
+    public DummyBean(String name, Integer i) {
+        this.name = name;
+        this.i = i;
+    }
+
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        changeSupport.addPropertyChangeListener(listener);
+    }
+    
+    public Integer getI() {
+        return i;
+    }
+
+    public void setI(Integer i) {
+        this.i = i;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    // dynamic properties
+    public Object get(String property) {
+        return dynamicProperties.get(property);
+    }
+
+    public void set(String property, Object newValue) {
+        dynamicProperties.put(property, newValue);
+    }
+
+    public static String dummyStaticMethod(String text) {
+        return text.toUpperCase();
+    }
+    
+    public boolean equals(Object that) {
+        if (that instanceof DummyBean) {
+            return equals((DummyBean) that);
+        }
+        return false;
+    }
+    
+    public boolean equals(DummyBean that) {
+        return this.name.equals(that.name) && this.i.equals(that.i);
+    }
+
+    public String toString() {
+        return super.toString() + "[name=" + name + ";i=" + i + "]";
+    }
+
+    public Point getPoint() {
+        return point;
+    }
+
+    public void setPoint(Point point) {
+        this.point = point;
+    }
+
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/EachWithReaderAndInputStreamTest.groovy b/groovy-core/src/test/org/codehaus/groovy/runtime/EachWithReaderAndInputStreamTest.groovy
new file mode 100644
index 0000000..c5bc159
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/EachWithReaderAndInputStreamTest.groovy
@@ -0,0 +1,76 @@
+package org.codehaus.groovy.runtime
+
+import java.io.StringReader
+import java.io.StringBufferInputStream
+
+/** 
+ * Test .each with Reader and InputStream
+ * 
+ * @author <a href="mailto:joachim.baumann@xinaris.de">Joachim Baumann</a>
+ * @version $Revision: $
+ */
+class EachWithReaderAndInputStreamTest extends GroovyTestCase {
+	/**
+	 * The following instances are used in testing the file operations
+	 */
+
+	String multiLineVal = """
+This text
+as can be seen
+has multiple lines
+and not one punctuation mark
+"""
+
+	// Our file instance
+	def File file;
+	
+	void setUpFile() {
+		// Setup guarantees us that we use a non-existent file
+		file = File.createTempFile("unitTest", ".txt") 
+		assert file.exists() == true
+		//println file.canonicalPath
+		assert file.length() == 0L
+		file << multiLineVal
+	}
+	void tearDownFile() {
+		// we remove our temporary file
+		def deleted = false
+		while(deleted == false)
+			deleted = file.delete()
+		assert file.exists() == false
+	}
+
+	void testEachForStringBufferInputStream(){
+		def ist = new StringBufferInputStream(multiLineVal)
+		def readVal = ""
+		ist.each { readVal += (char)it }
+		assert readVal == multiLineVal
+	}
+	 		
+	void testEachForStringReader(){
+		def ir = new StringReader(multiLineVal)
+		def readVal = ""
+		ir.each { readVal += it + "\n" }
+		assert readVal == multiLineVal
+	}
+
+	void testEachForFileWithInputStream() {
+		setUpFile()
+		def readVal = ""
+		file.withInputStream{ is ->
+			is.each { readVal += (char)it }
+		}
+		tearDownFile()
+		assert readVal == multiLineVal
+	}
+
+	void testEachForFileWithReader() {
+		setUpFile()
+		def readVal = ""
+		file.withReader{ reader ->
+			reader.each { readVal += it + "\n" }
+		}
+		tearDownFile()
+		assert readVal == multiLineVal
+	}
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/FileAppendTest.groovy b/groovy-core/src/test/org/codehaus/groovy/runtime/FileAppendTest.groovy
new file mode 100644
index 0000000..e4335eb
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/FileAppendTest.groovy
@@ -0,0 +1,221 @@
+package org.codehaus.groovy.runtime;
+
+import java.io.File
+import java.io.Reader
+
+/** 
+ * Test File append and left shift methods in Groovy
+ * 
+ * @author <a href="mailto:joachim.baumann@xinaris.de">Joachim Baumann</a>
+ * @version $Revision$
+ */
+class FileAppendTest extends GroovyTestCase {
+	/**
+	 * The following instances are used in testing the file writes
+	 */
+	static text = """
+			<groovy>
+			  <things>
+			    <thing>Jelly Beans</thing>
+			  </things>
+			  <music>
+			    <tune>The 59th Street Bridge Song</tune>
+			  </music>
+			  <characters>
+			    <character name="Austin Powers">
+			       <enemy>Dr. Evil</enemy>
+			       <enemy>Mini Me</enemy>
+			    </character>
+			  </characters>
+			</groovy>
+			"""
+	static gPathResult = new XmlSlurper().parseText(text)
+	static gPathWriteTo;
+	{
+		StringWriter sw = new StringWriter()
+		gPathResult.writeTo(sw)
+		gPathWriteTo = sw.toString()
+	}
+	
+	// see below for class definition
+	def testInstance = new TestClass()
+
+	// Our file instance
+	def File file;
+	
+	void setUp() {
+		// Setup guarantees us that we use a non-existent file
+		file = File.createTempFile("unitTest", ".txt") 
+		assert file.exists() == true
+		//println file.canonicalPath
+		assert file.length() == 0L
+	}
+	void tearDown() {
+		// we remove our temporary file
+		def deleted = false
+		while(deleted == false)
+			deleted = file.delete()
+		assert file.exists() == false
+	}
+
+	void testAppendString(){
+		def expected
+		
+		// test new
+		file.append(text)
+		expected = text
+		assert hasContents(file, expected)
+		
+		// test existing
+		file.append(text)
+		expected += text
+		assert hasContents(file, expected)
+	}
+	 		
+	void testAppendObjectToString(){
+		def expected
+		
+		// test new
+		file.append(testInstance)
+		expected = testInstance.toString()
+		assert hasContents(file, expected)
+		
+		// test existing
+		file.append(testInstance)
+		expected += testInstance.toString()
+		assert hasContents(file, expected)
+	}
+
+	void testappendWritable(){
+		def expected
+		
+		// test new
+		file.append(gPathResult)
+		expected = gPathWriteTo
+		assert hasContents(file, expected)
+		
+		// test existing
+		file.append(gPathResult)
+		expected += gPathWriteTo
+		assert hasContents(file, expected)
+	}
+
+	void testappendMixed(){
+		def expected
+		
+		// test new
+		file.append(text)
+		expected = text
+		assert hasContents(file, expected)
+		
+		file.append(testInstance)
+		expected += testInstance.toString()
+		assert hasContents(file, expected)
+		
+		file.append(gPathResult)
+		expected += gPathWriteTo
+		assert hasContents(file, expected)
+		
+		// test existing
+		file.append(gPathResult)
+		expected += gPathWriteTo
+		assert hasContents(file, expected)
+
+		file.append(testInstance)
+		expected += testInstance.toString()
+		assert hasContents(file, expected)
+
+		file.append(text)
+		expected += text
+		assert hasContents(file, expected)
+	}
+
+	void testLeftShiftString(){
+		def expected
+		
+		// test new
+		file << text
+		expected = text
+		assert hasContents(file, expected)
+		
+		// test existing
+		file << text
+		expected += text
+		assert hasContents(file, expected)
+	}
+			
+	void testLeftShiftObjectToString(){
+		def expected
+		
+		// test new
+		file << testInstance
+		expected = testInstance.toString()
+		assert hasContents(file, expected)
+		
+		// test existing
+		file << testInstance
+		expected += testInstance.toString()
+		assert hasContents(file, expected)
+	}
+
+	void testLeftShiftWritable(){
+		def expected
+		
+		// test new
+		file << gPathResult
+		expected = gPathWriteTo
+		assert hasContents(file, expected)
+		
+		// test existing
+		file << gPathResult
+		expected += gPathWriteTo
+		assert hasContents(file, expected)
+	}		 
+
+	void testLeftShiftMixed(){
+		def expected
+		
+		// test new
+		file << text
+		expected = text
+		assert hasContents(file, expected)
+		
+		file << testInstance
+		expected += testInstance.toString()
+		assert hasContents(file, expected)
+		
+		file << gPathResult
+		expected += gPathWriteTo
+		assert hasContents(file, expected)
+		
+		// test existing
+		file << gPathResult
+		expected += gPathWriteTo
+		assert hasContents(file, expected)
+
+		file << testInstance
+		expected += testInstance.toString()
+		assert hasContents(file, expected)
+
+		file << text
+		expected += text
+		assert hasContents(file, expected)
+	}
+
+	boolean hasContents(File f, String expected)
+	{
+		assert file.length() == expected.length()
+		// read contents the Java way
+		char[] cbuf = new char[expected.length()];
+		def fileReader = new FileReader(file)
+		fileReader.read(cbuf)
+		return expected == String.valueOf(cbuf)
+	}
+}
+
+class TestClass {
+	def testString = "TestThis"
+	public String toString() {
+		super.toString() + ": " + testString
+	}
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/FileLeftShiftTest.groovy b/groovy-core/src/test/org/codehaus/groovy/runtime/FileLeftShiftTest.groovy
new file mode 100644
index 0000000..fa6db01
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/FileLeftShiftTest.groovy
@@ -0,0 +1,10 @@
+package org.codehaus.groovy.runtime
+
+class FileLeftShiftTest extends GroovyTestCase {
+    void testFileLeftShift() {
+        new File("target/test-classes/MyFileLeftShiftTest.txt").delete()
+        new File("target/test-classes/MyFileLeftShiftTest.txt") << "This is " << "groovy"
+        assertEquals(new File("target/test-classes/MyFileLeftShiftTest.txt").text, "This is groovy")
+        new File("target/test-classes/MyFileLeftShiftTest.txt").delete()
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/GroovyCategoryTest.groovy b/groovy-core/src/test/org/codehaus/groovy/runtime/GroovyCategoryTest.groovy
new file mode 100644
index 0000000..764c3b2
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/GroovyCategoryTest.groovy
@@ -0,0 +1,44 @@
+package org.codehaus.groovy.runtime
+
+class GroovyCategoryTest extends GroovyTestCase {
+	void testUseWithVarArg() {
+		// Make sure I didn't break use(Category, Closure)
+		use (Category1) {
+			assert "HeLlO".upper() == "HELLO"
+		}
+
+        // Make sure I didn't break use([Category, Category], Closure)
+        use ([Category1, Category2]) {
+            assert "HeLlO".upper() == "HELLO"
+            assert "HeLlO".lower() == "hello"
+        }
+	
+		// Try out the new vararg version implemented in DGM
+		use (Category1, Category2) {
+			assert "HeLlO".upper() == "HELLO"
+			assert "HeLlO".lower() == "hello"
+		}
+		
+		// This should fail
+		try {
+			use (Category1)
+			fail()
+		} catch (IllegalArgumentException e) {
+		}
+		
+		// And so should this
+		try {
+			use (Category1, Category2)
+			fail()
+		} catch (IllegalArgumentException e) {
+		}
+	}
+}
+
+class Category1 {
+	static String upper(String message) { return message.toUpperCase() }
+}
+
+class Category2 {
+	static String lower(String message) { return message.toLowerCase() }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/InheritedInterfaceMethodTest.java b/groovy-core/src/test/org/codehaus/groovy/runtime/InheritedInterfaceMethodTest.java
new file mode 100644
index 0000000..4f37799
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/InheritedInterfaceMethodTest.java
@@ -0,0 +1,66 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.runtime;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+/**
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class InheritedInterfaceMethodTest extends TestCase {
+
+    public void testInvokeNewListMethodOnArrayList() {
+        List list = new ArrayList();
+        Object answer = InvokerHelper.invokeMethod(list, "count", new Object[] { "123" });
+        assertEquals(new Integer(0), answer);
+
+        System.out.println("Found: " + answer);
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/InterfaceConversionTest.groovy b/groovy-core/src/test/org/codehaus/groovy/runtime/InterfaceConversionTest.groovy
new file mode 100644
index 0000000..fb803d1
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/InterfaceConversionTest.groovy
@@ -0,0 +1,26 @@
+class InterfaceConversionTest extends GroovyTestCase {

+ 

+  void testClosureConversion(){

+	def c1 = {Object[] args -> args?.length}

+	def c2 = c1 as InterfaceConversionTestFoo

+	assert !(c1 instanceof InterfaceConversionTestFoo)

+	assert c2 instanceof InterfaceConversionTestFoo

+	assert c2.a() == null

+	assert c2.b(null) == 1

+  }

+  

+  void testMapConversion() {  

+	def m1 = [a:{1}, b:{2}]

+	def m2 = m1 as InterfaceConversionTestFoo

+	

+	assert !(m1 instanceof InterfaceConversionTestFoo)

+	assert m2 instanceof InterfaceConversionTestFoo

+	assert m2.a() == 1

+	assert m2.b(null) == 2

+  }

+}

+ 

+interface InterfaceConversionTestFoo {

+    def a();

+    def b(Integer i);

+}
\ No newline at end of file
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/InvokeConstructorTest.java b/groovy-core/src/test/org/codehaus/groovy/runtime/InvokeConstructorTest.java
new file mode 100644
index 0000000..e432156
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/InvokeConstructorTest.java
@@ -0,0 +1,100 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.GString;
+import groovy.util.GroovyTestCase;
+
+/**
+ * Tests method invocation
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class InvokeConstructorTest extends GroovyTestCase {
+
+    protected Invoker invoker = new Invoker();
+
+    public void testInvokeConstructorNoParams() throws Throwable {
+        assertConstructor(new DummyBean(), new Object[0]);
+    }
+
+    public void testInvokeConstructorOneParam() throws Throwable {
+        assertConstructor(new DummyBean("Bob"), "Bob");
+    }
+
+    public void testInvokeConstructorOneParamWhichIsNull() throws Throwable {
+        assertConstructor(new DummyBean("Bob", new Integer(1707)), new Object[] { "Bob", new Integer(1707)});
+    }
+
+    public void testConstructorWithGStringCoercion() throws Throwable {
+        GString gstring = new GString(new Object[] { new Integer(123)}) {
+            public String[] getStrings() {
+                return new String[] { "" };
+            }
+        };
+
+        Object expected = new Long(gstring.toString());
+
+        assertConstructor(expected, new Object[] { gstring });
+    }
+
+    protected void assertConstructor(Object expected, Object arguments) throws Throwable {
+        Object value = invoke(expected.getClass(), arguments);
+
+        assertEquals("Invoking overloaded method for arguments: " + InvokerHelper.toString(arguments), expected, value);
+    }
+
+    protected Object invoke(Class type, Object args) throws Throwable {
+        try {
+            return invoker.invokeConstructorOf(type, args);
+        }
+        catch (InvokerInvocationException e) {
+            throw e.getCause();
+        }
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/InvokeGroovyMethodTest.java b/groovy-core/src/test/org/codehaus/groovy/runtime/InvokeGroovyMethodTest.java
new file mode 100644
index 0000000..9041ebf
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/InvokeGroovyMethodTest.java
@@ -0,0 +1,111 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.Closure;
+import groovy.util.GroovyTestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests method invocation
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class InvokeGroovyMethodTest extends GroovyTestCase {
+
+    protected Invoker invoker = new Invoker();
+    private StringBuffer buffer;
+
+    // Method invocation tests
+    //-------------------------------------------------------------------------
+
+    public void testInvokeMethodNoParams() throws Throwable {
+        buffer = new StringBuffer();
+
+        List list = new ArrayList();
+        list.add("abc");
+        list.add("def");
+
+        invoker.invokeMethod(list, "each", new Closure(this) {
+            protected Object doCall(Object arguments) {
+                buffer.append(arguments.toString());
+                return null;
+            }
+        });
+
+        assertEquals("buffer", "abcdef", buffer.toString());
+    }
+
+    public void testMatchesWithObject() throws Throwable {
+        assertMatches(new Integer(1), new Integer(1), true);
+        assertMatches(new Integer(1), new Integer(2), false);
+    }
+
+    public void testMatchesWithClass() throws Throwable {
+        assertMatches(new Integer(1), Integer.class, true);
+        assertMatches(new Integer(1), Number.class, true);
+        assertMatches(new Integer(1), Double.class, false);
+    }
+
+    public void testMatchesWithList() throws Throwable {
+        assertMatches(new Integer(1), Arrays.asList(new Object[] { new Integer(2), new Integer(1)}), true);
+        assertMatches(new Integer(1), Arrays.asList(new Object[] { new Integer(2), new Integer(3)}), false);
+    }
+
+    // Implementation methods
+    //-------------------------------------------------------------------------
+    protected void assertMatches(Object switchValue, Object caseValue, boolean expected) {
+        assertEquals(
+            "Switch on: " + switchValue + " Case: " + caseValue,
+            expected,
+            ((Boolean) (InvokerHelper.invokeMethod(caseValue, "isCase", switchValue))).booleanValue());    }
+
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/InvokeMethodTest.java b/groovy-core/src/test/org/codehaus/groovy/runtime/InvokeMethodTest.java
new file mode 100644
index 0000000..745dd3d
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/InvokeMethodTest.java
@@ -0,0 +1,458 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.GString;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.IntRange;
+import groovy.util.GroovyTestCase;
+
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import junit.framework.AssertionFailedError;
+
+/**
+ * Tests method invocation
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class InvokeMethodTest extends GroovyTestCase {
+
+    protected Invoker invoker = InvokerHelper.getInstance();
+
+    // Method invocation tests
+    //-------------------------------------------------------------------------
+
+    public void testInvokeMethodNoParams() throws Throwable {
+        Object value = invoke(this, "mockCallWithNoParams", null);
+        assertEquals("return value", "NoParams", value);
+
+        value = invoke(this, "mockCallWithNoParams", new Object[0]);
+        assertEquals("return value", "NoParams", value);
+    }
+
+    public void testInvokeMethodOneParam() throws Throwable {
+        Object value = invoke(this, "mockCallWithOneParam", "abc");
+        assertEquals("return value", "OneParam", value);
+    }
+
+    public void testInvokeMethodOneParamWhichIsNull() throws Throwable {
+        Object value = invoke(this, "mockCallWithOneNullParam", new Object[] { null });
+        assertEquals("return value", "OneParamWithNull", value);
+
+        value = invoke(this, "mockCallWithOneNullParam", null);
+        assertEquals("return value", "OneParamWithNull", value);
+    }
+
+    public void testInvokeOverloadedMethodWithOneParamWhichIsNull() throws Throwable {
+        Object value = invoke(this, "mockOverloadedMethod", new Object[] { null });
+        assertEquals("return value", "Object", value);
+    }
+
+    public void testInvokeMethodOneCollectionParameter() throws Throwable {
+        Object[] foo = { "a", "b", "c" };
+
+        Object value = invoke(this, "mockCallWithOneCollectionParam", new Object[] { foo });
+        assertEquals("return value", new Integer(3), value);
+
+        List list = new ArrayList();
+        list.add("a");
+        list.add("b");
+        value = invoke(this, "mockCallWithOneCollectionParam", list);
+        assertEquals("return value", new Integer(2), value);
+    }
+
+    public void testInvokePrintlnMethod() throws Throwable {
+        Object value = invoke(System.out, "println", "testing System.out.println...");
+        assertEquals("return value", null, value);
+    }
+
+    public void testMethodChooserNull() throws Throwable {
+        assertMethodChooser("Object", new Object[] { null });
+    }
+
+    public void testMethodChooserNoParams() throws Throwable {
+        assertMethodChooser("void", null);
+    }
+
+    public void testMethodChooserObject() throws Throwable {
+        assertMethodChooser("Object", new Object());
+        assertMethodChooser("Object", new Date());
+    }
+
+    public void testMethodChooserString_FAILS() throws Throwable { if (notYetImplemented()) return;
+        assertMethodChooser("String", "foo");
+        assertMethodChooser("String", new StringBuffer());
+        assertMethodChooser("String", new Character('a'));
+    }
+
+    public void testMethodChooserNumber() throws Throwable {
+        assertMethodChooser("Number", new Integer(2));
+        assertMethodChooser("Number", new Double(2));
+    }
+
+    public void testMethodChooserTwoParams() throws Throwable {
+        List list = new ArrayList();
+        list.add("foo");
+        list.add("bar");
+        assertMethodChooser("Object,Object", list.toArray());
+
+        Object[] blah = { "a", "b" };
+        assertMethodChooser("Object,Object", blah);
+    }
+
+    public void testInstanceofWorksForArray() {
+        Class type = Object[].class;
+        Object value = new Object[1];
+        assertTrue("instanceof works for array", type.isInstance(value));
+    }
+
+    public void testMethodChooserTwoParamsWithSecondAnObjectArray() throws Throwable {
+        Object[] blah = { "a", new Object[] { "b" }
+        };
+        assertMethodChooser("Object,Object[]", blah);
+    }
+
+    public void testCollectionMethods() throws Throwable {
+        Object list = InvokerHelper.createList(new Object[] { "a", "b" });
+
+        Object value = invoke(list, "size", null);
+        assertEquals("size of collection", new Integer(2), value);
+
+        value = invoke(list, "contains", "a");
+        assertEquals("contains method", Boolean.TRUE, value);
+    }
+
+    public void testNewMethods() throws Throwable {
+        Object value = invoke("hello", "size", null);
+        assertEquals("size of string", new Integer(5), value);
+    }
+
+    public void testStaticMethod() throws Throwable {
+        Object value = invoke(DummyBean.class, "dummyStaticMethod", "abc");
+        assertEquals("size of string", "ABC", value);
+    }
+
+    public void testBaseClassMethod() throws Throwable {
+        Object object = new DummyBean();
+        Object value = invoke(object, "toString", null);
+        assertEquals("toString", object.toString(), value);
+    }
+
+	//SPG modified to reflect DefaultGroovyMethod name change and expected result from
+	//Integer/Integer division.
+    public void testDivideNumbers() throws Throwable {
+        assertMethodCall(new Double(10), "div", new Double(2), new Double(5));
+        assertMethodCall(new Double(10), "div", new Integer(2), new Double(5));
+        assertMethodCall(new Integer(10), "div", new Double(2), new Double(5));
+        assertMethodCall(new Integer(10), "div", new Integer(2), new java.math.BigDecimal("5"));
+    }
+
+    public void testBaseFailMethod() throws Throwable {
+        try {
+            invoke(this, "fail", "hello");
+        } catch (AssertionFailedError e) {
+            // worked
+        }
+    }
+
+    public void testToArrayOnList() throws Throwable {
+        List object = new ArrayList();
+        object.add("Hello");
+
+        Object[] value = (Object[]) invoke(object, "toArray", null);
+        assertArrayEquals(object.toArray(), value);
+        assertEquals(1, value.length);
+        assertEquals("Hello", value[0]);
+
+        value = (Object[]) invoke(object, "toArray", new Object[0]);
+        assertArrayEquals(object.toArray(), value);
+    }
+
+    public void testInvalidOverloading() throws Throwable {
+        try {
+            invoke(this, "badOverload", new Object[] { "a", "b" });
+            fail("Should fail as an unambiguous method is invoked");
+        }
+        catch (GroovyRuntimeException e) {
+            System.out.println("Caught: " + e);
+        }
+    }
+
+    public void testPlusWithNull() throws Throwable {
+        String param = "called with: ";
+        Object value = invoke(param, "plus", new Object[] { null });
+        assertEquals("called with null", param + null, value);
+    }
+
+    public void testCallIntMethodWithInteger() throws Throwable {
+        Object value = invoke(this, "overloadedRemove", new Object[] { new Integer(5)});
+        assertEquals("called with integer", "int5", value);
+    }
+
+    public void testCallListRemove() throws Throwable {
+        List list = new ArrayList();
+        list.add("foo");
+        list.add("bar");
+
+        invoke(list, "remove", new Object[] { new Integer(0)});
+
+        assertEquals("Should have just 1 item left: " + list, 1, list.size());
+    }
+
+    public void testCoerceGStringToString() throws Throwable {
+        GString param = new GString(new Object[] { "James" }) {
+            public String[] getStrings() {
+                return new String[] { "Hello " };
+            }
+        };
+        Object value = invoke(this, "methodTakesString", new Object[] { param });
+        assertEquals("converted GString to string", param.toString(), value);
+    }
+
+    public void testCoerceGStringToStringOnGetBytes() throws Throwable {
+        GString param = new GString(new Object[] { "US-ASCII" }) {
+            public String[] getStrings() {
+                return new String[] { "" };
+            }
+        };
+        Object value = invoke("test", "getBytes", new Object[] { param });
+        assertEquals("converted GString to string", "test".getBytes("US-ASCII").getClass(), value.getClass());
+    }
+
+    public void testBadBDToDoubleCoerce() throws Throwable {
+        try {
+            invoke(Math.class, "floor", new BigDecimal("1.7E309"));
+        } catch (IllegalArgumentException e) {
+            assertTrue("Math.floor(1.7E309) should fail because it is out of range for a Double. "
+                    +e,e.getMessage().indexOf("out of range") > 0);
+            return;
+        }
+        fail("Math.floor(1.7E309) should fail because it is out of range for a Double.");        
+    }
+
+    public void testClassMethod() throws Throwable {
+        Class c = String.class;
+        Object value = invoke(c, "getName", null);
+        assertEquals("Class.getName()", c.getName(), value);
+        c = getClass();
+        value = invoke(c, "getName", null);
+        assertEquals("Class.getName()", c.getName(), value);
+    }
+
+    public void testProtectedMethod() throws Throwable {
+        String param = "hello";
+        Object value = invoke(this, "aProtectedMethod", param);
+        assertEquals("protected method call", aProtectedMethod(param), value);
+    }
+
+    public void testPrivateMethod() throws Throwable {
+        String param = "hello";
+        Object value = invoke(this, "aPrivateMethod", param);
+        assertEquals("private method call", aPrivateMethod(param), value);
+    }
+
+    public void testStringSubstringMethod() throws Throwable {
+        String object = "hello";
+        Object value = invoke(object, "substring", new Integer(2));
+        assertEquals("substring(2)", object.substring(2), value);
+
+        value = invoke(object, "substring", new Object[] { new Integer(1), new Integer(3)});
+        assertEquals("substring(1,3)", object.substring(1, 3), value);
+    }
+
+    public void testListGetWithRange() throws Throwable {
+        List list = Arrays.asList(new Object[] { "a", "b", "c" });
+        Object range = new IntRange(0, 2);
+        Object value = invoke(list, "getAt", range);
+        assertTrue("Returned List: " + value, value instanceof List);
+        List retList = (List) value;
+        assertEquals("List size", 3, retList.size());
+    }
+
+    public void testSetLenientOnDateFormat() throws Throwable {
+        SimpleDateFormat a = new SimpleDateFormat( "MM/dd/yyyy" );
+        
+        Object value = invoke(a, "setLenient", new Object[] { Boolean.FALSE });
+        assertEquals("void method", null, value);
+    }
+
+    public void testInvokeUnknownMethod() throws Throwable {
+        try {
+            Object value = invoke(this, "unknownMethod", "abc");
+            fail("Should have thrown an exception");
+        }
+        catch (GroovyRuntimeException e) {
+            // worked
+        }
+    }
+
+    public void testInvokeMethodWithWrongNumberOfParameters() throws Throwable {
+        try {
+            Object[] args = { "a", "b" };
+            invoke(this, "unknownMethod", args);
+            fail("Should have thrown an exception");
+        }
+        catch (GroovyRuntimeException e) {
+            // worked
+        }
+    }
+
+    public void testInvokeMethodOnNullObject() throws Throwable {
+        try {
+            invoke(null, "mockCallWithNoParams", null);
+            fail("Should have thrown an exception");
+        }
+        catch (NullPointerException e) {
+            // worked
+        }
+    }
+
+    // Mock methods used for testing
+    //-------------------------------------------------------------------------
+
+    public Object mockCallWithNoParams() {
+        return "NoParams";
+    }
+
+    public Object mockCallWithOneParam(Object value) {
+        assertEquals("Method not passed in the correct value", "abc", value);
+        return "OneParam";
+    }
+
+    public Object mockCallWithOneNullParam(Object value) {
+        assertEquals("Method not passed in the correct value", null, value);
+        return "OneParamWithNull";
+    }
+
+    public Integer mockCallWithOneCollectionParam(Object collection) {
+        Collection coll = DefaultTypeTransformation.asCollection(collection);
+        return new Integer(coll.size());
+    }
+
+    public Object mockOverloadedMethod() {
+        return "void";
+    }
+
+    public Object mockOverloadedMethod(Object object) {
+        return "Object";
+    }
+
+    public Object mockOverloadedMethod(Number object) {
+        return "Number";
+    }
+
+    public Object mockOverloadedMethod(String object) {
+        return "String";
+    }
+
+    public Object mockOverloadedMethod(Object object, Object bar) {
+        return "Object,Object";
+    }
+
+    public Object mockOverloadedMethod(Object object, Object[] array) {
+        return "Object,Object[]";
+    }
+
+    public Object badOverload(String a, Object b) {
+        return "String, Object";
+    }
+
+    public Object badOverload(Object a, String b) {
+        return "Object, String";
+    }
+
+    public Object methodTakesString(String x) {
+        return x;
+    }
+
+    public Object overloadedRemove(int idx) {
+        return "int" + idx;
+    }
+
+    public Object overloadedRemove(Object value) {
+        return "Object" + value;
+    }
+
+    // Implementation methods
+    //-------------------------------------------------------------------------
+
+    protected Object aProtectedMethod(String param) {
+        return param + " there!";
+    }
+
+    private Object aPrivateMethod(String param) {
+        return param + " James!";
+    }
+
+    protected void assertMethodCall(Object object, String method, Object param, Object expected) {
+        Object value = InvokerHelper.invokeMethod(object, method, new Object[] { param });
+        assertEquals("result of method: " + method, expected, value);
+    }
+
+    /**
+	 * Asserts that invoking the method chooser finds the right overloaded
+	 * method implementation
+	 * 
+	 * @param expected
+	 *            is the expected value of the method
+	 * @param arguments
+	 *            the argument(s) to the method invocation
+	 */
+    protected void assertMethodChooser(Object expected, Object arguments) throws Throwable {
+        Object value = invoke(this, "mockOverloadedMethod", arguments);
+
+        assertEquals("Invoking overloaded method for arguments: " + InvokerHelper.toString(arguments), expected, value);
+    }
+
+    protected Object invoke(Object object, String method, Object args) throws Throwable {
+        try {
+            return invoker.invokeMethod(object, method, args);
+        }
+        catch (InvokerInvocationException e) {
+            throw e.getCause();
+        }
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/InvokerTest.java b/groovy-core/src/test/org/codehaus/groovy/runtime/InvokerTest.java
new file mode 100644
index 0000000..da4179e
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/InvokerTest.java
@@ -0,0 +1,193 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.GString;
+import groovy.util.GroovyTestCase;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Collections;
+import java.util.Arrays;
+
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+
+/**
+ * Test the Invoker class
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class InvokerTest extends GroovyTestCase {
+
+    protected Invoker invoker = new Invoker();
+
+    public void testAsCollectionWithArray() {
+        Object[] array = { "A", "B", "C" };
+        assertAsCollection(array, 3);
+    }
+
+    public void testAsCollectionWithMap() {
+        Map map = new HashMap();
+        map.put("A", "abc");
+        map.put("B", "def");
+        map.put("C", "xyz");
+        assertAsCollection(map, 3);
+    }
+
+    public void testAsCollectionWithList() {
+        List list = new ArrayList();
+        list.add("A");
+        list.add("B");
+        list.add("C");
+        assertAsCollection(list, 3);
+    }
+
+    public void testInvokerException() throws Throwable {
+        try {
+            throw new GroovyRuntimeException("message", new NullPointerException());
+        }
+        catch (GroovyRuntimeException e) {
+            // worked
+            assertEquals("message", e.getMessage());
+            assertTrue(e.getCause() instanceof NullPointerException);
+        }
+    }
+
+    public void testAsBoolean() {
+        assertAsBoolean(true, Boolean.TRUE);
+        assertAsBoolean(true, "true");
+        assertAsBoolean(true, "TRUE");
+        assertAsBoolean(true, "false");
+        assertAsBoolean(false, Boolean.FALSE);
+        assertAsBoolean(false, (String) null);
+        assertAsBoolean(false, "");
+        GString emptyGString = new GString(new Object[] { "" }) {
+            public String[] getStrings() {
+                return new String[] { "" };
+            }
+        };
+        assertAsBoolean(false, emptyGString);
+        GString nonEmptyGString = new GString(new Object[] { "x" }) {
+            public String[] getStrings() {
+                return new String[] { "x" };
+            }
+        };
+        assertAsBoolean(true, nonEmptyGString);
+        assertAsBoolean(true, new Integer(1234));
+        assertAsBoolean(false, new Integer(0));
+        assertAsBoolean(true, new Float(0.3f));
+        assertAsBoolean(true, new Double(3.0f));
+        assertAsBoolean(false, new Float(0.0f));
+        assertAsBoolean(true, new Character((char) 1));
+        assertAsBoolean(false, new Character((char) 0));
+        assertAsBoolean(false, Collections.EMPTY_LIST);
+		assertAsBoolean(true, Arrays.asList(new Integer[] { new Integer(1) }));
+       }
+    
+    public void testLessThan() {
+        assertTrue(ScriptBytecodeAdapter.compareLessThan(new Integer(1), new Integer(2)));
+        assertTrue(ScriptBytecodeAdapter.compareLessThanEqual(new Integer(2), new Integer(2)));
+    }
+    
+    public void testGreaterThan() {
+        assertTrue(ScriptBytecodeAdapter.compareGreaterThan(new Integer(3), new Integer(2)));
+        assertTrue(ScriptBytecodeAdapter.compareGreaterThanEqual(new Integer(2), new Integer(2)));
+    }
+    
+    public void testCompareTo() {
+        assertTrue(DefaultTypeTransformation.compareEqual("x", new Integer('x')));
+    }
+    
+    // Implementation methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Asserts the asBoolean method returns the given flag
+     */
+    protected void assertAsBoolean(boolean expected, Object value) {
+        boolean answer = DefaultTypeTransformation.castToBoolean(value);
+        assertEquals("value: " + value + " asBoolean()", expected, answer);
+    }
+
+    /**
+     * Asserts that the given object can be converted into a collection and iterator
+     * of the given size
+     */
+    protected void assertAsCollection(Object collectionObject, int count) {
+        Collection collection = DefaultTypeTransformation.asCollection(collectionObject);
+        assertTrue("Collection is not null", collection != null);
+        assertEquals("Collection size", count, collection.size());
+
+        assertIterator("collections iterator", collection.iterator(), count);
+        assertIterator("InvokerHelper.asIterator", InvokerHelper.asIterator(collectionObject), count);
+        assertIterator("InvokerHelper.asIterator(InvokerHelper.asCollection)", InvokerHelper.asIterator(collection), count);
+        assertIterator("InvokerHelper.asIterator(InvokerHelper.asIterator)", InvokerHelper.asIterator(InvokerHelper.asIterator(collectionObject)), count);
+    }
+
+    /**
+     * Asserts that the iterator is valid and of the right size
+     */
+    protected void assertIterator(String message, Iterator iterator, int count) {
+        for (int i = 0; i < count; i++) {
+            assertTrue(message + ": should have item: " + i, iterator.hasNext());
+            assertTrue(message + ": item: " + i + " should not be null", iterator.next() != null);
+        }
+
+        assertFalse(
+            message + ": should not have item after iterating through: " + count + " items",
+            iterator.hasNext());
+    }
+
+   
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/MetaClassHelperTest.java b/groovy-core/src/test/org/codehaus/groovy/runtime/MetaClassHelperTest.java
new file mode 100644
index 0000000..202116f
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/MetaClassHelperTest.java
@@ -0,0 +1,10 @@
+package org.codehaus.groovy.runtime;

+

+import junit.framework.TestCase;

+

+public class MetaClassHelperTest extends TestCase {

+    public void testGetClassName() {

+        // GROOVY-1262

+        MetaClassHelper.getClassName(null); 

+    }

+}
\ No newline at end of file
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/MethodFailureTest.java b/groovy-core/src/test/org/codehaus/groovy/runtime/MethodFailureTest.java
new file mode 100644
index 0000000..7ba5c18
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/MethodFailureTest.java
@@ -0,0 +1,104 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
+import groovy.util.GroovyTestCase;
+
+/**
+ * Tests failing method invocations to ensure correct exceptions
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MethodFailureTest extends GroovyTestCase {
+
+    public void testFailingMethod() {
+        MockGroovyObject object = new MockGroovyObject();
+        try {
+            object.invokeMethod("nonExistentMethod", "hello");
+
+            fail("Should have thrown an exception");
+        }
+        catch (GroovyRuntimeException e) {
+            System.out.println(e);
+        }
+    }
+
+    public void testMethodWhichCallsTheFailingMethod() {
+        MockGroovyObject object = new MockGroovyObject();
+        try {
+            object.invokeMethod("methodThatFails", null);
+
+            fail("Should have thrown an exception");
+        }
+        catch (GroovyRuntimeException e) {
+            System.out.println(e);
+            //e.printStackTrace();
+        }
+    }
+
+    public void testMethodWhichCallsTheFailingMethodInsideAClosure() {
+        MockGroovyObject object = new MockGroovyObject();
+        try {
+            object.invokeMethod("callClosure", new Closure(this) {
+                protected Object doCall(GroovyObject object) {
+                    return object.invokeMethod("nonExistentMethod", "hello");
+                }
+            });
+
+            fail("Should have thrown an exception");
+        }
+        catch (GroovyRuntimeException e) {
+            System.out.println(e);
+            //e.printStackTrace();
+        }
+    }
+
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/MethodKeyTest.java b/groovy-core/src/test/org/codehaus/groovy/runtime/MethodKeyTest.java
new file mode 100644
index 0000000..a35511b
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/MethodKeyTest.java
@@ -0,0 +1,92 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.runtime;
+
+import junit.framework.TestCase;
+
+/**
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MethodKeyTest extends TestCase {
+
+    public void testDefaultImplementation() throws Exception {
+        MethodKey a = new DefaultMethodKey(Object.class, "foo", new Class[] { Object.class, Integer.class },false);
+        MethodKey a2 = new DefaultMethodKey(Object.class, "foo", new Class[] { Object.class, Integer.class },false);
+        MethodKey b = new DefaultMethodKey(Object.class, "foo", new Class[] { Object.class },false);
+        MethodKey c = new DefaultMethodKey(Object.class, "bar", new Class[] { Object.class, Integer.class },false);
+
+        assertCompare(a, a, true);
+        assertCompare(a, a2, true);
+        assertCompare(b, b, true);
+
+        assertCompare(a, b, false);
+        assertCompare(a, c, false);
+        assertCompare(b, c, false);
+    }
+
+    public void testTemporaryImplementation() throws Exception {
+        MethodKey a = new DefaultMethodKey(Object.class, "foo", new Class[] { Object.class, Integer.class },false);
+        MethodKey a2 = new TemporaryMethodKey(Object.class, "foo", new Object[] { new Object(), new Integer(1) },false);
+        MethodKey b = new TemporaryMethodKey(Object.class, "foo", new Object[] { new Object() },false);
+        MethodKey c = new TemporaryMethodKey(Object.class, "bar", new Object[] { new Object(), new Integer(1) },false);
+
+        assertCompare(a, a, true);
+        assertCompare(a, a2, true);
+        assertCompare(b, b, true);
+
+        assertCompare(a, b, false);
+        assertCompare(a, c, false);
+        assertCompare(b, c, false);
+    }
+
+    protected void assertCompare(Object a, Object b, boolean expected) {
+        assertEquals("Compare " + a + " to " + b, expected, a.equals(b));
+        if (expected) {
+            assertEquals("hashCode " + a + " to " + b, a.hashCode(), b.hashCode());
+        }
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/MockGroovyObject.java b/groovy-core/src/test/org/codehaus/groovy/runtime/MockGroovyObject.java
new file mode 100644
index 0000000..62f22d9
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/MockGroovyObject.java
@@ -0,0 +1,68 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyObjectSupport;
+
+/**
+ * A POGO used by the test cases
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class MockGroovyObject extends GroovyObjectSupport {
+
+    public Object methodThatFails() {
+        return invokeMethod("nonExistentMethod", "hello");
+    }
+    
+    public Object callClosure(Closure closure) {
+        return closure.call(this);
+    }
+
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/NewStaticMetaMethodTest.java b/groovy-core/src/test/org/codehaus/groovy/runtime/NewStaticMetaMethodTest.java
new file mode 100644
index 0000000..bbbe0cb
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/NewStaticMetaMethodTest.java
@@ -0,0 +1,98 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.runtime;
+
+import java.lang.reflect.Method;
+
+import junit.framework.TestCase;
+
+/**
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class NewStaticMetaMethodTest extends TestCase {
+
+    public void testInvokeMetaMethod() throws Exception {
+        Method method = getClass().getMethod("dummyMethod", new Class[] { String.class, String.class });
+        assertTrue("Should have found a method", method != null);
+
+        NewInstanceMetaMethod metaMethod = createNewMetaMethod(method);
+
+        Object answer = metaMethod.invoke("abc", new Object[] { "xyz" });
+        assertEquals("def", answer);
+
+        assertTrue("Should not appear as static method", metaMethod.isStatic() == false);
+    }
+
+    public void testInvokeDefaultGroovyMethod() throws Exception {
+        Method method = DefaultGroovyMethods.class.getMethod("plus", new Class[] { String.class, Object.class });
+        assertTrue("Should have found a method", method != null);
+
+        NewInstanceMetaMethod metaMethod = createNewMetaMethod(method);
+
+        Object answer = metaMethod.invoke("abc", new Object[] { "123" });
+        assertEquals("abc123", answer);
+
+        System.out.println("Found: " + answer);
+    }
+
+    public void testInvokeDefaultGroovyMethodUsingMetaClass() {
+        Object answer = InvokerHelper.invokeMethod("abc", "plus", new Object[] { "123" });
+        assertEquals("abc123", answer);
+
+        System.out.println("Found: " + answer);
+    }
+
+    public static String dummyMethod(String foo, String bar) throws Exception {
+        assertEquals("abc", foo);
+        assertEquals("xyz", bar);
+        return "def";
+    }
+
+    protected NewInstanceMetaMethod createNewMetaMethod(Method method) {
+        return new NewInstanceMetaMethod(new ReflectionMetaMethod(method));
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/NullObjectTest.groovy b/groovy-core/src/test/org/codehaus/groovy/runtime/NullObjectTest.groovy
new file mode 100644
index 0000000..962a6af
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/NullObjectTest.groovy
@@ -0,0 +1,18 @@
+package org.codehaus.groovy.runtime
+
+class NullObjectTest extends GroovyTestCase {
+    void testCallingMethod() {
+        def foo = null
+        try {
+          println foo.bar
+        } catch (NullPointerException ex) {
+          // is successfull
+        }
+    }
+
+    void testEquals() {
+        def a = [1]
+        assert a[3] == a[4]
+        assert a[2].equals(a[4])
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/PropertyTest.java b/groovy-core/src/test/org/codehaus/groovy/runtime/PropertyTest.java
new file mode 100644
index 0000000..fe53ff9
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/PropertyTest.java
@@ -0,0 +1,259 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.runtime;
+
+import groovy.lang.MissingMethodException;
+import groovy.util.GroovyTestCase;
+import groovy.util.Node;
+
+import java.awt.HeadlessException;
+import java.awt.Point;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+/**
+ * Test the property access of the Invoker class
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class PropertyTest extends GroovyTestCase {
+
+    protected Invoker invoker = new Invoker();
+
+    public void testMapProperties() throws Exception {
+        Map map = new HashMap();
+        map.put("foo", "abc");
+        map.put("bar", new Integer(123));
+
+        assertGetSetProperty(map, "foo", "abc", "def");
+        assertGetSetProperty(map, "bar", new Integer(123), new Double(12.34));
+    }
+
+    public void testBeanProperties() throws Exception {
+        DummyBean bean = new DummyBean();
+
+        assertGetSetProperty(bean, "name", "James", "Bob");
+        assertGetSetProperty(bean, "i", new Integer(123), new Integer(455));
+
+        // dynamic properties
+        assertGetSetProperty(bean, "dynamicFoo", null, "aValue");
+        assertGetSetProperty(bean, "dynamicFoo", "aValue", "NewValue");
+    }
+
+/** todo this is no longer possible in new groovy
+    public void testUsingMethodProperty() throws Exception {
+        DummyBean bean = new DummyBean();
+
+        assertGetSetProperty(bean, "name", "James", "Bob");
+
+        Object value = InvokerHelper.getProperty(bean, "getName");
+        assertTrue("Should have returned a closure: " + value, value instanceof Closure);
+        Closure closure = (Closure) value;
+        Object result = closure.call(null);
+        assertEquals("Result of call to closure", "Bob", result);
+    }
+**/   
+    
+
+    public void testStaticProperty() throws Exception {
+        Object value = InvokerHelper.getProperty(System.class, "out");
+        assertEquals("static property out", System.out, value);
+    }
+
+    public void testClassProperty() throws Exception {
+        Class c = String.class;
+        Object value = InvokerHelper.getProperty(c, "name");
+        assertEquals("class name property", c.getName(), value);
+    }
+
+    public void testMapEntryProperty() throws Exception {
+        HashMap map = new HashMap();
+        map.put("a", "x");
+        Object[] array = map.entrySet().toArray();
+        Object entry = array[0];
+
+        Object key = InvokerHelper.getProperty(entry, "key");
+        assertEquals("key property", "a", key);
+
+        Object value = InvokerHelper.getProperty(entry, "value");
+        assertEquals("value property", "x", value);
+    }
+
+/** todo this is no longer possible in new groovy
+    public void testMethodProperty() throws Exception {
+        Object value = InvokerHelper.getProperty(this, "getCheese");
+        assertTrue("Should have returned a closure: " + value, value instanceof Closure);
+
+        Object result = ((Closure) value).call();
+        assertEquals("result of closure call", getCheese(), result);
+
+        System.out.println("Closure: " + value + " and cheese: " + result);
+    }
+**/
+
+    public void testListCoercionProperty() throws Exception {
+        DummyBean bean = new DummyBean();
+        List list = new ArrayList();
+        list.add(new Integer(10));
+        list.add(new Integer(20));
+
+        InvokerHelper.setProperty(bean, "point", list);
+        assertEquals("Should have set a point", new Point(10, 20), bean.getPoint());
+    }
+
+    public void testListCoercionPropertyOnJFrame() throws Exception {
+        try {
+	        JFrame bean = new JFrame();
+	        List list = new ArrayList();
+	        list.add(new Integer(10));
+	        list.add(new Integer(20));
+	
+	        InvokerHelper.setProperty(bean, "location", list);
+	        assertEquals("Should have set a point", new Point(10, 20), bean.getLocation());
+        }
+        catch (HeadlessException e) {
+            // its fine to not run this test on headless environments
+        }
+        catch (MissingMethodException e) {
+            System.out.println("Failed with cause: " + e);
+            e.printStackTrace();
+            fail("Should not have throw: " + e);
+        }
+    }
+
+    public void testListNavigationProperty() throws Exception {
+        List list = new ArrayList();
+        list.add(new DummyBean("James"));
+        list.add(new DummyBean("Bob"));
+
+        List value = (List) InvokerHelper.getProperty(list, "name");
+        assertArrayEquals(new Object[] { "James", "Bob" }, value.toArray());
+    }
+
+    public void testListOfListNavigationProperty() throws Exception {
+       List list = new ArrayList();
+       list.add(new DummyBean("James"));
+       list.add(new DummyBean("Bob"));
+
+       List listOfList = new ArrayList();
+       listOfList.add(list);
+       
+       List value = (List) InvokerHelper.getProperty(listOfList, "name");
+       assertArrayEquals(new Object[] { "James", "Bob" }, value.toArray());
+   }
+
+    public void testNodeNavigationProperty() throws Exception {
+        Node z = new Node(null, "z");
+        Node y = new Node(null, "y");
+
+        List children = new ArrayList();
+        children.add(y);
+        children.add(z);
+
+        Node x = new Node(null, "x", children);
+
+        children = new ArrayList();
+        children.add(x);
+        Node b = new Node(null, "b", children);
+
+        // @todo should try with just a node as the child
+
+        List value = (List) InvokerHelper.getProperty(b, "x");
+        assertArrayEquals(new Object[] { x }, value.toArray());
+
+        value = (List) InvokerHelper.getProperty(value, "z");
+        assertArrayEquals(new Object[] { z }, value.toArray());
+    }
+
+    public void testUsingInPropertyOnProcessViaGroovyMethod() throws Exception {
+        Process process = DefaultGroovyMethods.execute("java -version");
+        Object value = InvokerHelper.getProperty(process, "in");
+        assertNotNull(value);
+        
+        System.out.println("Found in: " + value);
+        
+        process.destroy();
+    }
+    
+    public Object getCheese() {
+        return "cheddar";
+    }
+
+    public void testComponentParent() {
+        JPanel panel = new JPanel();
+        JButton bean = new JButton();
+        
+        panel.add(bean);
+        
+        Object value = InvokerHelper.getProperty(bean, "parent");
+        assertTrue(value != null);
+    }
+    
+    // Implementation methods
+    //-------------------------------------------------------------------------
+
+    protected void assertGetSetProperty(Object object, String property, Object currentValue, Object newValue) {
+        assertGetProperty(object, property, currentValue);
+
+        InvokerHelper.setProperty(object, property, newValue);
+
+        assertGetProperty(object, property, newValue);
+    }
+
+    protected void assertGetProperty(Object object, String property, Object expected) {
+        Object value = InvokerHelper.getProperty(object, property);
+
+        assertEquals("property: " + property + " of: " + object, expected, value);
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/StaticPrintlnTest.groovy b/groovy-core/src/test/org/codehaus/groovy/runtime/StaticPrintlnTest.groovy
new file mode 100644
index 0000000..9126752
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/StaticPrintlnTest.groovy
@@ -0,0 +1,12 @@
+import groovy.bugs.TestSupport
+
+class StaticPrintlnTest extends TestSupport {
+
+    void testStaticPrint() {
+        main(getMockArguments())
+	}
+	
+    static void main(args) {
+        println("called with: " + args)
+    }
+}
\ No newline at end of file
diff --git a/groovy-core/src/test/org/codehaus/groovy/runtime/TupleListTest.java b/groovy-core/src/test/org/codehaus/groovy/runtime/TupleListTest.java
new file mode 100644
index 0000000..1e17c76
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/runtime/TupleListTest.java
@@ -0,0 +1,94 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.runtime;
+
+import groovy.util.GroovyTestCase;
+
+import java.util.Iterator;
+import java.util.Map;
+
+
+/**
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class TupleListTest extends GroovyTestCase {
+
+    public void testIterateOverTuple() throws Exception {
+        StringBuffer buffer = new StringBuffer();
+        for (Iterator iter = InvokerHelper.asIterator(InvokerHelper.createTuple(new Object[] { "a", "b", "c" }));
+            iter.hasNext();
+            ) {
+            Object i = iter.next();
+            buffer.append(i);
+        }
+
+        assertEquals("buffer", "abc", buffer.toString());
+    }
+
+    public void testIterateOverList() throws Exception {
+        StringBuffer buffer = new StringBuffer();
+        for (Iterator iter = InvokerHelper.asIterator(InvokerHelper.createList(new Object[] { "a", "b", "c" }));
+            iter.hasNext();
+            ) {
+            Object i = iter.next();
+            buffer.append(i);
+        }
+
+        assertEquals("buffer", "abc", buffer.toString());
+    }
+
+    public void testCreateMap() throws Exception {
+        Map map = InvokerHelper.createMap(new Object[] {"a", "x", "b", "y"});
+
+        assertNotNull("map", map);
+        assertEquals("size", 2, map.size());
+        assertEquals("value of a", "x", map.get("a"));
+        assertEquals("value of b", "y", map.get("b"));            
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/syntax/TokenTest.java b/groovy-core/src/test/org/codehaus/groovy/syntax/TokenTest.java
new file mode 100644
index 0000000..6bd9716
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/syntax/TokenTest.java
@@ -0,0 +1,754 @@
+package org.codehaus.groovy.syntax;
+
+
+import groovy.util.GroovyTestCase;
+
+public class TokenTest
+    extends GroovyTestCase
+{
+
+    public void testNothing()
+    {
+    }
+
+/*
+    private static final int LINE = 11;
+    private static final int COLUMN = 33;
+
+    public void testConstruct()
+    {
+        Token token = new Token( 42,
+                                 "forty-two",
+                                 11,
+                                 22 );
+
+        assertEquals( 42,
+                      token.getType() );
+
+        assertEquals( "forty-two",
+                      token.getText() );
+
+        assertEquals( 11,
+                      token.getStartLine() );
+
+        assertEquals( 22,
+                      token.getStartColumn() );
+    }
+
+    public void testLeftCurlyBrace()
+    {
+        Token token = Token.leftCurlyBrace( LINE,
+                                            COLUMN );
+
+        assertToken( token,
+                     Token.LEFT_CURLY_BRACE,
+                     "{" );
+    }
+
+    public void testRightCurlyBrace()
+    {
+        Token token = Token.rightCurlyBrace( LINE,
+                                             COLUMN );
+
+        assertToken( token,
+                     Token.RIGHT_CURLY_BRACE,
+                     "}" );
+    }
+
+    public void testLeftSquareBracket()
+    {
+        Token token = Token.leftSquareBracket( LINE,
+                                               COLUMN );
+
+        assertToken( token,
+                     Token.LEFT_SQUARE_BRACKET,
+                     "[" );
+    }
+
+    public void testRightSquareBracket()
+    {
+        Token token = Token.rightSquareBracket( LINE,
+                                                COLUMN );
+
+        assertToken( token,
+                     Token.RIGHT_SQUARE_BRACKET,
+                     "]" );
+    }
+
+    public void testLeftParenthesis()
+    {
+        Token token = Token.leftParenthesis( LINE,
+                                             COLUMN );
+
+        assertToken( token,
+                     Token.LEFT_PARENTHESIS,
+                     "(" );
+    }
+
+    public void testRightParenthesis()
+    {
+        Token token = Token.rightParenthesis( LINE,
+                                              COLUMN );
+
+        assertToken( token,
+                     Token.RIGHT_PARENTHESIS,
+                     ")" );
+    }
+
+    public void testDot()
+    {
+        Token token = Token.dot( LINE,
+                                 COLUMN );
+
+        assertToken( token,
+                     Token.DOT,
+                     "." );
+    }
+
+    public void testDotDot()
+    {
+        Token token = Token.dotDot( LINE,
+                                    COLUMN );
+
+        assertToken( token,
+                     Token.DOT_DOT,
+                     ".." );
+    }
+
+    public void testNot()
+    {
+        Token token = Token.not( LINE,
+                                 COLUMN );
+
+        assertToken( token,
+                     Token.NOT,
+                     "!" );
+    }
+
+    public void testCompareNotEqual()
+    {
+        Token token = Token.compareNotEqual( LINE,
+                                             COLUMN );
+
+        assertToken( token,
+                     Token.COMPARE_NOT_EQUAL,
+                     "!=" );
+    }
+
+    public void testEqual()
+    {
+        Token token = Token.equal( LINE,
+                                   COLUMN );
+
+        assertToken( token,
+                     Token.EQUAL,
+                     "=" );
+    }
+
+    public void testCompareIdentical()
+    {
+        Token token = Token.compareIdentical( LINE,
+                                              COLUMN );
+
+        assertToken( token,
+                     Token.COMPARE_IDENTICAL,
+                     "===" );
+    }
+
+    public void testCompareEqual()
+    {
+        Token token = Token.compareEqual( LINE,
+                                          COLUMN );
+
+        assertToken( token,
+                     Token.COMPARE_EQUAL,
+                     "==" );
+    }
+
+    public void testCompareLessThan()
+    {
+        Token token = Token.compareLessThan( LINE,
+                                             COLUMN );
+
+        assertToken( token,
+                     Token.COMPARE_LESS_THAN,
+                     "<" );
+    }
+
+    public void testCompareLessThanEqual()
+    {
+        Token token = Token.compareLessThanEqual( LINE,
+                                                  COLUMN );
+
+        assertToken( token,
+                     Token.COMPARE_LESS_THAN_EQUAL,
+                     "<=" );
+    }
+
+    public void testCompareGreaterThan()
+    {
+        Token token = Token.compareGreaterThan( LINE,
+                                                COLUMN );
+
+        assertToken( token,
+                     Token.COMPARE_GREATER_THAN,
+                     ">" );
+    }
+
+    public void testCompareGreaterThanEqual()
+    {
+        Token token = Token.compareGreaterThanEqual( LINE,
+                                                     COLUMN );
+
+        assertToken( token,
+                     Token.COMPARE_GREATER_THAN_EQUAL,
+                     ">=" );
+    }
+
+    public void testLogicalOr()
+    {
+        Token token = Token.logicalOr( LINE,
+                                       COLUMN );
+
+        assertToken( token,
+                     Token.LOGICAL_OR,
+                     "||" );
+    }
+
+    public void testLogicalAnd()
+    {
+        Token token = Token.logicalAnd( LINE,
+                                        COLUMN );
+
+        assertToken( token,
+                     Token.LOGICAL_AND,
+                     "&&" );
+    }
+
+    public void testPlus()
+    {
+        Token token = Token.plus( LINE,
+                                  COLUMN );
+
+        assertToken( token,
+                     Token.PLUS,
+                     "+" );
+    }
+
+    public void testPlusPlus()
+    {
+        Token token = Token.plusPlus( LINE,
+                                      COLUMN );
+
+        assertToken( token,
+                     Token.PLUS_PLUS,
+                     "++" );
+    }
+
+    public void testPlusEqual()
+    {
+        Token token = Token.plusEqual( LINE,
+                                       COLUMN );
+
+        assertToken( token,
+                     Token.PLUS_EQUAL,
+                     "+=" );
+    }
+
+    public void testMinus()
+    {
+        Token token = Token.minus( LINE,
+                                   COLUMN );
+
+        assertToken( token,
+                     Token.MINUS,
+                     "-" );
+    }
+
+    public void testMinusMinus()
+    {
+        Token token = Token.minusMinus( LINE,
+                                        COLUMN );
+
+        assertToken( token,
+                     Token.MINUS_MINUS,
+                     "--" );
+    }
+
+    public void testMinusEqual()
+    {
+        Token token = Token.minusEqual( LINE,
+                                        COLUMN );
+
+        assertToken( token,
+                     Token.MINUS_EQUAL,
+                     "-=" );
+    }
+
+    public void testDivide()
+    {
+        Token token = Token.divide( LINE,
+                                    COLUMN );
+
+        assertToken( token,
+                     Token.DIVIDE,
+                     "/" );
+    }
+
+    public void testDivideEqual()
+    {
+        Token token = Token.divideEqual( LINE,
+                                         COLUMN );
+
+        assertToken( token,
+                     Token.DIVIDE_EQUAL,
+                     "/=" );
+    }
+
+    public void testMod()
+    {
+        Token token = Token.mod( LINE,
+                                 COLUMN );
+
+        assertToken( token,
+                     Token.MOD,
+                     "%" );
+    }
+
+    public void testModEqual()
+    {
+        Token token = Token.modEqual( LINE,
+                                      COLUMN );
+
+        assertToken( token,
+                     Token.MOD_EQUAL,
+                     "%=" );
+    }
+
+    public void testMultiply()
+    {
+        Token token = Token.multiply( LINE,
+                                      COLUMN );
+
+        assertToken( token,
+                     Token.MULTIPLY,
+                     "*" );
+    }
+
+    public void testMultiplyEqual()
+    {
+        Token token = Token.multiplyEqual( LINE,
+                                           COLUMN );
+
+        assertToken( token,
+                     Token.MULTIPLY_EQUAL,
+                     "*=" );
+    }
+
+    public void testComma()
+    {
+        Token token = Token.comma( LINE,
+                                   COLUMN );
+
+        assertToken( token,
+                     Token.COMMA,
+                     "," );
+    }
+
+    public void testColon()
+    {
+        Token token = Token.colon( LINE,
+                                   COLUMN );
+
+        assertToken( token,
+                     Token.COLON,
+                     ":" );
+    }
+
+    public void testSemicolon()
+    {
+        Token token = Token.semicolon( LINE,
+                                       COLUMN );
+
+        assertToken( token,
+                     Token.SEMICOLON,
+                     ";" );
+    }
+
+    public void testQuestion()
+    {
+        Token token = Token.question( LINE,
+                                      COLUMN );
+
+        assertToken( token,
+                     Token.QUESTION,
+                     "?" );
+    }
+
+    public void testPipe()
+    {
+        Token token = Token.pipe( LINE,
+                                  COLUMN );
+
+        assertToken( token,
+                     Token.PIPE,
+                     "|" );
+    }
+
+    public void testDoubleQuoteString()
+    {
+        Token token = Token.doubleQuoteString( LINE,
+                                               COLUMN,
+                                               "cheese" );
+
+        assertToken( token,
+                     Token.DOUBLE_QUOTE_STRING,
+                     "cheese",
+                     "<string literal>");
+    }
+
+    public void testSingleQuoteString()
+    {
+        Token token = Token.singleQuoteString( LINE,
+                                               COLUMN,
+                                               "cheese" );
+
+        assertToken( token,
+                     Token.SINGLE_QUOTE_STRING,
+                     "cheese",
+                     "<string literal>" );
+    }
+
+    public void testIdentifier()
+    {
+        Token token = Token.identifier( LINE,
+                                        COLUMN,
+                                        "cheese" );
+
+        assertToken( token,
+                     Token.IDENTIFIER,
+                     "cheese",
+                     "<identifier>" );
+    }
+
+    public void testIntegerNumber()
+    {
+        Token token = Token.integerNumber( LINE,
+                                           COLUMN,
+                                           "42" );
+
+        assertToken( token,
+                     Token.INTEGER_NUMBER,
+                     "42",
+                     "<number>" );
+    }
+
+    public void testFloatNumber()
+    {
+        Token token = Token.floatNumber( LINE,
+                                         COLUMN,
+                                         "42.84" );
+
+        assertToken( token,
+                     Token.FLOAT_NUMBER,
+                     "42.84",
+                     "<number>" );
+    }
+
+    // ----------------------------------------------------------------------
+    // ----------------------------------------------------------------------
+
+    public void testKeyword_As()
+    {
+        assertKeywordToken( "as",
+                            Token.KEYWORD_AS );
+    }
+
+    public void testKeyword_Abstract()
+    {
+        assertKeywordToken( "abstract",
+                            Token.KEYWORD_ABSTRACT );
+    }
+
+    public void testKeyword_Break()
+    {
+        assertKeywordToken( "break",
+                            Token.KEYWORD_BREAK );
+    }
+
+    public void testKeyword_Case()
+    {
+        assertKeywordToken( "case",
+                            Token.KEYWORD_CASE );
+    }
+
+    public void testKeyword_Catch()
+    {
+        assertKeywordToken( "catch",
+                            Token.KEYWORD_CATCH );
+    }
+
+    public void testKeyword_Class()
+    {
+        assertKeywordToken( "class",
+                            Token.KEYWORD_CLASS );
+    }
+
+    public void testKeyword_Const()
+    {
+        assertKeywordToken( "const",
+                            Token.KEYWORD_CONST );
+    }
+
+    public void testKeyword_Continue()
+    {
+        assertKeywordToken( "continue",
+                            Token.KEYWORD_CONTINUE );
+    }
+
+    public void testKeyword_Default()
+    {
+        assertKeywordToken( "default",
+                            Token.KEYWORD_DEFAULT );
+    }
+
+    public void testKeyword_Do()
+    {
+        assertKeywordToken( "do",
+                            Token.KEYWORD_DO );
+    }
+
+    public void testKeyword_Else()
+    {
+        assertKeywordToken( "else",
+                            Token.KEYWORD_ELSE );
+    }
+
+    public void testKeyword_Extends()
+    {
+        assertKeywordToken( "extends",
+                            Token.KEYWORD_EXTENDS );
+    }
+
+    public void testKeyword_Final()
+    {
+        assertKeywordToken( "final",
+                            Token.KEYWORD_FINAL );
+    }
+
+    public void testKeyword_Finally()
+    {
+        assertKeywordToken( "finally",
+                            Token.KEYWORD_FINALLY );
+    }
+
+    public void testKeyword_For()
+    {
+        assertKeywordToken( "for",
+                            Token.KEYWORD_FOR );
+    }
+
+    public void testKeyword_Goto()
+    {
+        assertKeywordToken( "goto",
+                            Token.KEYWORD_GOTO );
+    }
+
+    public void testKeyword_If()
+    {
+        assertKeywordToken( "if",
+                            Token.KEYWORD_IF );
+    }
+
+    public void testKeyword_Implements()
+    {
+        assertKeywordToken( "implements",
+                            Token.KEYWORD_IMPLEMENTS );
+    }
+
+    public void testKeyword_Import()
+    {
+        assertKeywordToken( "import",
+                            Token.KEYWORD_IMPORT );
+    }
+
+    public void testKeyword_Instanceof()
+    {
+        assertKeywordToken( "instanceof",
+                            Token.KEYWORD_INSTANCEOF );
+    }
+
+    public void testKeyword_Interface()
+    {
+        assertKeywordToken( "interface",
+                            Token.KEYWORD_INTERFACE );
+    }
+
+    public void testKeyword_Native()
+    {
+        assertKeywordToken( "native",
+                            Token.KEYWORD_NATIVE );
+    }
+
+    public void testKeyword_New()
+    {
+        assertKeywordToken( "new",
+                            Token.KEYWORD_NEW );
+    }
+
+    public void testKeyword_Package()
+    {
+        assertKeywordToken( "package",
+                            Token.KEYWORD_PACKAGE );
+    }
+
+    public void testKeyword_Private()
+    {
+        assertKeywordToken( "private",
+                            Token.KEYWORD_PRIVATE );
+    }
+
+    public void testKeyword_Property()
+    {
+        assertKeywordToken( "property",
+                            Token.KEYWORD_PROPERTY );
+    }
+
+    public void testKeyword_Protected()
+    {
+        assertKeywordToken( "protected",
+                            Token.KEYWORD_PROTECTED );
+    }
+
+    public void testKeyword_Public()
+    {
+        assertKeywordToken( "public",
+                            Token.KEYWORD_PUBLIC );
+    }
+
+    public void testKeyword_Return()
+    {
+        assertKeywordToken( "return",
+                            Token.KEYWORD_RETURN );
+    }
+
+    public void testKeyword_Static()
+    {
+        assertKeywordToken( "static",
+                            Token.KEYWORD_STATIC );
+    }
+
+    public void testKeyword_Super()
+    {
+        assertKeywordToken( "super",
+                            Token.KEYWORD_SUPER );
+    }
+
+    public void testKeyword_Switch()
+    {
+        assertKeywordToken( "switch",
+                            Token.KEYWORD_SWITCH );
+    }
+
+    public void testKeyword_Synchronized()
+    {
+        assertKeywordToken( "synchronized",
+                            Token.KEYWORD_SYNCHRONIZED );
+    }
+
+    public void testKeyword_This()
+    {
+        assertKeywordToken( "this",
+                            Token.KEYWORD_THIS );
+    }
+
+    public void testKeyword_Throw()
+    {
+        assertKeywordToken( "throw",
+                            Token.KEYWORD_THROW );
+    }
+
+    public void testKeyword_Throws()
+    {
+        assertKeywordToken( "throws",
+                            Token.KEYWORD_THROWS );
+    }
+
+    public void testKeyword_Try()
+    {
+        assertKeywordToken( "try",
+                            Token.KEYWORD_TRY );
+    }
+
+    public void testKeyword_While()
+    {
+        assertKeywordToken( "while",
+                            Token.KEYWORD_WHILE );
+    }
+
+    public void testUniqueKeywordTypes()
+    {
+        Map keywords = Token.getKeywordMap();
+
+        Set types = new HashSet();
+
+        types.addAll( keywords.values() );
+
+        assertEquals( types.size(),
+                      keywords.size() );
+    }
+
+    public void testUnknownTokenType()
+    {
+        assertEquals( "<unknown>",
+                      Token.getTokenDescription( 6666 ) );
+    }
+
+    // ----------------------------------------------------------------------
+    // ----------------------------------------------------------------------
+
+    protected void assertKeywordToken(String text,
+                                      int expectedType)
+    {
+        Token token = Token.keyword( LINE,
+                                     COLUMN,
+                                     text );
+
+        assertToken( token,
+                     expectedType,
+                     text );
+    }
+
+    protected void assertToken(Token token,
+                               int type,
+                               String text)
+    {
+        assertToken( token,
+                     type,
+                     text,
+                     '"' + text + '"' );
+    }
+
+    protected void assertToken(Token token,
+                               int type,
+                               String text,
+                               String description)
+    {
+        assertEquals( type,
+                      token.getType() );
+
+        assertEquals( text,
+                      token.getText() );
+
+        assertEquals( description,
+                      token.getDescription() );
+
+        assertEquals( LINE,
+                      token.getStartLine() );
+
+        assertEquals( COLUMN,
+                      token.getStartColumn() );
+    }
+    
+*/
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/syntax/parser/TestParserSupport.java b/groovy-core/src/test/org/codehaus/groovy/syntax/parser/TestParserSupport.java
new file mode 100644
index 0000000..bef4115
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/syntax/parser/TestParserSupport.java
@@ -0,0 +1,58 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package org.codehaus.groovy.syntax.parser;
+
+import groovy.util.GroovyTestCase;
+
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.control.SourceUnit;
+
+
+
+/**
+ * An abstract base class useful for AST parser related test cases
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public abstract class TestParserSupport extends GroovyTestCase {
+    
+    public ModuleNode parse(String text, String description) throws Exception {
+        SourceUnit unit = SourceUnit.create( description, text );
+        unit.parse();
+        unit.convert();
+        
+        return unit.getAST();
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/tools/CompilerTest.java b/groovy-core/src/test/org/codehaus/groovy/tools/CompilerTest.java
new file mode 100644
index 0000000..ff501dd
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/tools/CompilerTest.java
@@ -0,0 +1,92 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.tools;
+
+import groovy.util.GroovyTestCase;
+
+import java.io.File;
+
+import org.codehaus.groovy.control.CompilerConfiguration;
+
+/**
+ * A handy unit test case for dumping the output of the compiler
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class CompilerTest extends GroovyTestCase {
+
+    Compiler compiler  = null;
+    boolean  dumpClass = true;
+
+    public void testMethodCall() throws Exception {
+        //runTest("ClosureMethodTest.groovy");
+        //runTest("tree/VerboseTreeTest.groovy");
+        //runTest("tree/NestedClosureBugTest.groovy");
+        runTest("tree/SmallTreeTest.groovy");
+        //runTest("LittleClosureTest.groovy");
+    }
+
+    protected void runTest(String name) throws Exception {
+        File file = new File("src/test/groovy/" + name);
+        
+        assertTrue("Could not find source file: " + file, file.exists());
+
+        compiler.compile(file);
+    }
+
+    protected void setUp() throws Exception {
+        File dir = new File("target/test-generated-classes");
+        dir.mkdirs();
+        
+        CompilerConfiguration config = new CompilerConfiguration();
+        config.setDebug( dumpClass );
+        
+        compiler = new Compiler( config );
+    }
+
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/tools/DocGeneratorMain.java b/groovy-core/src/test/org/codehaus/groovy/tools/DocGeneratorMain.java
new file mode 100644
index 0000000..b28baa0
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/tools/DocGeneratorMain.java
@@ -0,0 +1,20 @@
+package org.codehaus.groovy.tools;
+
+import groovy.lang.GroovyShell;
+
+import java.io.File;
+
+public class DocGeneratorMain {
+
+    public static void main(String[] args) {
+        try {
+            GroovyShell shell = new GroovyShell();
+            //shell.run("src/main/org/codehaus/groovy/tools/DocGenerator.groovy", "org.codehaus.groovy.tools.DocGenerator.groovy", args);
+            shell.run(new File("src/main/org/codehaus/groovy/tools/DocGenerator.groovy"), args);
+        }
+        catch (Exception e) {
+            System.out.println("Failed: " + e);
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/tools/FileSystemCompilerTest.java b/groovy-core/src/test/org/codehaus/groovy/tools/FileSystemCompilerTest.java
new file mode 100644
index 0000000..8afef40
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/tools/FileSystemCompilerTest.java
@@ -0,0 +1,93 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package org.codehaus.groovy.tools;
+
+import groovy.util.GroovyTestCase;
+
+import java.io.File;
+
+import org.codehaus.groovy.control.CompilerConfiguration;
+
+/**
+ * Tests the compiling & running of GroovyTestCases
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class FileSystemCompilerTest extends GroovyTestCase {
+
+    FileSystemCompiler compiler = null;
+    boolean dumpClass = true;
+
+    public void testMethodCall() throws Exception {
+        //runTest("ClosureMethodTest.groovy");
+        //runTest("tree/VerboseTreeTest.groovy");
+        //runTest("tree/NestedClosureBugTest.groovy");
+        runTest("tree/SmallTreeTest.groovy");
+        //runTest("LittleClosureTest.groovy");
+    }
+
+    protected void runTest(String name) throws Exception {
+        File file = new File("src/test/groovy/" + name);
+        
+        assertTrue("Could not find source file: " + file, file.exists());
+
+        compiler.compile(new File[] { file });
+    }
+
+    protected void setUp() throws Exception {
+        File dir = new File("target/test-generated-classes");
+        dir.mkdirs();
+        
+        CompilerConfiguration configuration = new CompilerConfiguration();
+        configuration.setTargetDirectory(dir);
+        configuration.setVerbose(dumpClass);
+        
+        compiler = new FileSystemCompiler( configuration );
+    }
+
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/tools/FindAllTestsSuite.java b/groovy-core/src/test/org/codehaus/groovy/tools/FindAllTestsSuite.java
new file mode 100644
index 0000000..61631ef
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/tools/FindAllTestsSuite.java
@@ -0,0 +1,131 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+package org.codehaus.groovy.tools;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A TestSuite which will run a Groovy unit test case inside any Java IDE
+ * either as a unit test case or as an application.
+ * <p/>
+ * You can specify the GroovyUnitTest to run by running this class as an appplication
+ * and specifying the script to run on the command line.
+ * <p/>
+ * <code>
+ * java groovy.util.GroovyTestSuite src/test/Foo.groovy
+ * </code>
+ * <p/>
+ * Or to run the test suite as a unit test suite in an IDE you can use
+ * the 'test' system property to define the test script to run.
+ * e.g. pass this into the JVM when the unit test plugin runs...
+ * <p/>
+ * <code>
+ * -Dtest=src/test/Foo.groovy
+ * </code>
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class FindAllTestsSuite extends TestSuite {
+
+    protected static String testDirectory = "target/test-classes";
+
+    public static void main(String[] args) {
+        TestRunner.run(suite());
+    }
+
+    public static Test suite() {
+        FindAllTestsSuite suite = new FindAllTestsSuite();
+        try {
+            suite.loadTestSuite();
+        } catch (Exception e) {
+            throw new RuntimeException("Could not create the test suite: " + e, e);
+        }
+        return suite;
+    }
+
+    public void loadTestSuite() throws Exception {
+        recurseDirectory(new File(testDirectory));
+    }
+
+    protected void recurseDirectory(File dir) throws Exception {
+        File[] files = dir.listFiles();
+        List traverseList = new ArrayList();
+        for (int i = 0; i < files.length; i++) {
+            File file = files[i];
+            if (file.isDirectory()) {
+                traverseList.add(file);
+            } else {
+                String name = file.getName();
+                if (name.endsWith("Test.class") || name.endsWith("Bug.class")) {
+                    addTest(file);
+                }
+            }
+        }
+        for (Iterator iter = traverseList.iterator(); iter.hasNext();) {
+            recurseDirectory((File) iter.next());
+        }
+    }
+
+    protected void addTest(File file) throws Exception {
+        String name = file.getPath();
+
+        name = name.substring(testDirectory.length() + 1, name.length() - ".class".length());
+        name = name.replace(File.separatorChar, '.');
+        
+        //System.out.println("Found: " + name);
+        Class type = loadClass(name);
+        addTestSuite(type);
+    }
+
+    protected Class loadClass(String name) throws ClassNotFoundException {
+        try {
+            return Thread.currentThread().getContextClassLoader().loadClass(name);
+        } catch (ClassNotFoundException e) {
+            try {
+                return getClass().getClassLoader().loadClass(name);
+            } catch (ClassNotFoundException e1) {
+                return Class.forName(name);
+            }
+        }
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/tools/xml/DomToGroovyTest.groovy b/groovy-core/src/test/org/codehaus/groovy/tools/xml/DomToGroovyTest.groovy
new file mode 100644
index 0000000..d606b8d
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/tools/xml/DomToGroovyTest.groovy
@@ -0,0 +1,116 @@
+package org.codehaus.groovy.tools.xml

+

+import java.io.*

+import javax.xml.parsers.DocumentBuilder

+import javax.xml.parsers.DocumentBuilderFactory

+import org.w3c.dom.Document

+import org.xml.sax.InputSource

+import org.xml.sax.SAXException

+

+/**

+ * @author James Strachan

+ * @author paulk

+ * @version $Revision: 4111 $

+ */

+public class DomToGroovyTest extends GroovyTestCase {

+    private static final String LS = System.getProperty("line.separator")

+    private static final String TEST_XML_1 =

+        "<a href='http://groovy.codehaus.org'>Groovy</a>"

+    private static final String TEST_XML_2 =

+        "<project name='testProject'><target name='testTarget'><echo>message</echo><echo/></target></project>"

+    private static final String TEST_XML_3 = '''<?xml version="1.0"?>

+        <!-- this example demonstrates using markup to specify a rich user interface -->

+        <frame text="My Window" size="[300,300]">

+          <label text="Save changes" bounds="[10,10,290,30]"/>

+          <panel bounds="[10,40,290,290]">

+            <button text="OK" action="save()"/>

+            <button text="Cancel" action="close()"/>

+          </panel>

+        </frame>'''

+    private static final String TEST_XML_4 = '''

+        <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

+          <xsd:simpleType name="SKU">

+            <xsd:restriction base="xsd:string">

+              <xsd:pattern value="\\d{3}-[A-Z]{2}"/>

+            </xsd:restriction>

+          </xsd:simpleType>

+        </xsd:schema>'''

+    private static final String EXPECTED_BUILDER_SCRIPT_1 =

+        "a(href:'http://groovy.codehaus.org', 'Groovy')"

+    private static final String EXPECTED_BUILDER_SCRIPT_2 = '''

+        project(name:'testProject') {

+          target(name:'testTarget') {

+            echo('message')

+            echo()

+          }

+        }'''

+    private static final String EXPECTED_BUILDER_SCRIPT_3 = '''

+        /* this example demonstrates using markup to specify a rich user interface */

+        frame(size:'[300,300]', text:'My Window') {

+          label(bounds:'[10,10,290,30]', text:'Save changes')

+          panel(bounds:'[10,40,290,290]') {

+            button(action:'save()', text:'OK')

+            button(action:'close()', text:'Cancel')

+          }

+        }'''

+    private static final String EXPECTED_BUILDER_SCRIPT_4 = '''

+        xsd = xmlns.namespace('http://www.w3.org/2001/XMLSchema')

+        xsd.schema(xmlns=[xmlns.xsd:'http://www.w3.org/2001/XMLSchema']) {

+          xsd.simpleType(name:'SKU') {

+            xsd.restriction(base:'xsd:string') {

+              xsd.pattern(value:'\\d{3}-[A-Z]{2}')

+            }

+          }

+        }'''

+

+    protected DocumentBuilder builder

+    protected DomToGroovy converter

+    protected File dir = new File("target/generated-groovyxml")

+

+    public void testConversion() throws Exception {

+        convert("test1.xml", "test1.groovy")

+        convert("po.xsd", "poSchema.groovy")

+        convert("swing.xml", "swing.groovy")

+    }

+

+    public void testConversionFormat() throws Exception {

+        checkConversion(TEST_XML_1, EXPECTED_BUILDER_SCRIPT_1)

+        checkConversion(TEST_XML_2, EXPECTED_BUILDER_SCRIPT_2)

+        checkConversion(TEST_XML_3, EXPECTED_BUILDER_SCRIPT_3)

+        checkConversion(TEST_XML_4, EXPECTED_BUILDER_SCRIPT_4)

+    }

+

+    private void checkConversion(String testXml, String expectedScript) throws SAXException, IOException {

+        ByteArrayInputStream inputStream = new ByteArrayInputStream(testXml.getBytes())

+        Document document = builder.parse(inputStream)

+        StringWriter writer = new StringWriter()

+        converter = new DomToGroovy(new PrintWriter(writer))

+        converter.print(document)

+        StringTestUtil.assertMultilineStringsEqual(expectedScript, writer.toString())

+    }

+

+    private void convert(String name, String output) throws Exception {

+        Document document = parse(name)

+        PrintWriter writer = new PrintWriter(new FileWriter(new File(dir, output)))

+        converter = new DomToGroovy(writer)

+        writer.println("#!/bin/groovy")

+        writer.println()

+        writer.println("// generated from " + name)

+        writer.println()

+        converter.print(document)

+        writer.close()

+    }

+

+    private Document parse(String name) throws SAXException, IOException {

+        URL resource = getClass().getResource(name)

+        assertTrue("Could not find resource: " + name, resource != null)

+        return builder.parse(new InputSource(resource.toString()))

+    }

+

+    protected void setUp() throws Exception {

+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance()

+        factory.setNamespaceAware(true)

+        builder = factory.newDocumentBuilder()

+        dir.mkdirs()

+    }

+}

diff --git a/groovy-core/src/test/org/codehaus/groovy/tools/xml/po.xsd b/groovy-core/src/test/org/codehaus/groovy/tools/xml/po.xsd
new file mode 100644
index 0000000..399f959
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/tools/xml/po.xsd
@@ -0,0 +1,66 @@
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+
+ <xsd:annotation>
+  <xsd:documentation xml:lang="en">
+   Purchase order schema for Example.com.
+   Copyright 2000 Example.com. All rights reserved.
+  </xsd:documentation>
+ </xsd:annotation>
+
+ <xsd:element name="purchaseOrder" type="PurchaseOrderType"/>
+
+ <xsd:element name="comment" type="xsd:string"/>
+
+ <xsd:complexType name="PurchaseOrderType">
+  <xsd:sequence>
+   <xsd:element name="shipTo" type="USAddress"/>
+   <xsd:element name="billTo" type="USAddress"/>
+   <xsd:element ref="comment" minOccurs="0"/>
+   <xsd:element name="items"  type="Items"/>
+  </xsd:sequence>
+  <xsd:attribute name="orderDate" type="xsd:date"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="USAddress">
+  <xsd:sequence>
+   <xsd:element name="name"   type="xsd:string"/>
+   <xsd:element name="street" type="xsd:string"/>
+   <xsd:element name="city"   type="xsd:string"/>
+   <xsd:element name="state"  type="xsd:string"/>
+   <xsd:element name="zip"    type="xsd:decimal"/>
+  </xsd:sequence>
+  <xsd:attribute name="country" type="xsd:NMTOKEN"
+     fixed="US"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="Items">
+  <xsd:sequence>
+   <xsd:element name="item" minOccurs="0" maxOccurs="unbounded">
+    <xsd:complexType>
+     <xsd:sequence>
+      <xsd:element name="productName" type="xsd:string"/>
+      <xsd:element name="quantity">
+       <xsd:simpleType>
+        <xsd:restriction base="xsd:positiveInteger">
+         <xsd:maxExclusive value="100"/>
+        </xsd:restriction>
+       </xsd:simpleType>
+      </xsd:element>
+      <xsd:element name="USPrice"  type="xsd:decimal"/>
+      <xsd:element ref="comment"   minOccurs="0"/>
+      <xsd:element name="shipDate" type="xsd:date" minOccurs="0"/>
+     </xsd:sequence>
+     <xsd:attribute name="partNum" type="SKU" use="required"/>
+    </xsd:complexType>
+   </xsd:element>
+  </xsd:sequence>
+ </xsd:complexType>
+
+ <!-- Stock Keeping Unit, a code for identifying products -->
+ <xsd:simpleType name="SKU">
+  <xsd:restriction base="xsd:string">
+   <xsd:pattern value="\d{3}-[A-Z]{2}"/>
+  </xsd:restriction>
+ </xsd:simpleType>
+
+</xsd:schema> 
\ No newline at end of file
diff --git a/groovy-core/src/test/org/codehaus/groovy/tools/xml/swing.xml b/groovy-core/src/test/org/codehaus/groovy/tools/xml/swing.xml
new file mode 100644
index 0000000..2a64c7e
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/tools/xml/swing.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<!-- this example demonstrates using markup to specify a rich user interface -->
+<frame text="My Window" size="[300,300]">
+  <label text="Save changes" bounds="[10,10,290,30]"/>
+  <panel bounds="[10,40,290,290]">
+    <button text="OK" action="save()"/>
+    <button text="Cancel" action="close()"/>
+  </panel>
+</frame>
+ 
\ No newline at end of file
diff --git a/groovy-core/src/test/org/codehaus/groovy/tools/xml/swing2.xml b/groovy-core/src/test/org/codehaus/groovy/tools/xml/swing2.xml
new file mode 100644
index 0000000..2a64c7e
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/tools/xml/swing2.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<!-- this example demonstrates using markup to specify a rich user interface -->
+<frame text="My Window" size="[300,300]">
+  <label text="Save changes" bounds="[10,10,290,30]"/>
+  <panel bounds="[10,40,290,290]">
+    <button text="OK" action="save()"/>
+    <button text="Cancel" action="close()"/>
+  </panel>
+</frame>
+ 
\ No newline at end of file
diff --git a/groovy-core/src/test/org/codehaus/groovy/tools/xml/test1.xml b/groovy-core/src/test/org/codehaus/groovy/tools/xml/test1.xml
new file mode 100644
index 0000000..31c81de
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/tools/xml/test1.xml
@@ -0,0 +1,16 @@
+<html>
+  <head>
+	<title>XML encoding with Groovy</title>
+  </head>
+  <body>
+    <h1>XML encoding with Groovy</h1>
+    <p>this format can be used as an alternative markup to XML</p>
+    <!-- an element with attributes and text content -->
+    <a href="http://groovy.codehaus.org">Groovy</a>
+    <!-- mixed content -->
+    <p>This is some <b>mixed</b> text. For more see the
+    <a href="http://groovy.codehaus.org">Groovy</a> project
+    </p>
+    <p>some text</p>
+  </body>
+</html>
\ No newline at end of file
diff --git a/groovy-core/src/test/org/codehaus/groovy/wiki/Html2Wiki.groovy b/groovy-core/src/test/org/codehaus/groovy/wiki/Html2Wiki.groovy
new file mode 100644
index 0000000..d6789f5
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/wiki/Html2Wiki.groovy
@@ -0,0 +1,104 @@
+import groovy.util.XmlParser
+
+import java.io.File
+
+import org.cyberneko.html.parsers.SAXParser
+
+class Html2Wiki {
+    
+    protected out
+    
+    static void main(args) {
+        def gen = new Html2Wiki()
+        for (arg in args) {
+            gen.createWiki(arg)
+        }
+    }
+    
+    void createWiki(fileName) {
+        def htmlParser = new SAXParser()
+        htmlParser.setProperty("http://cyberneko.org/html/properties/names/elems", "lower")
+        htmlParser.setProperty("http://cyberneko.org/html/properties/names/attrs", "lower")
+        def parser = new XmlParser(htmlParser)
+        println "Parsing ${fileName}"
+        def node = parser.parse(fileName)
+        
+        def outputName = getOutputName(fileName)
+        new File(outputName).eachPrintWriter { out = it; makeWikiPage(node) }
+    }
+
+    def getOutputName(fileName) {
+	    def lastIdx = fileName.lastIndexOf(".")
+	    if (lastIdx > 0) {
+	        fileName = fileName.substring(0, lastIdx)
+	    }
+	    return fileName + ".wiki"
+	}
+    
+    void makeWikiPage(node) {
+        def body = node.html.body
+        if (body == null) {
+            println "Warning empty document, no <html><body> section"
+        }
+        else {
+            applyTemplatesForChildren(node)
+        }
+    }
+    
+    void applyTemplates(node) {
+        switch (node.name()) {
+            case "h1":
+                out.println "1 " + node.text() 
+                out.println()
+                break
+            case "h2":
+                out.println "1.1 " + node.text()
+                out.println()
+                break
+            case "h3":
+                out.println "1.1.1 " + node.text()
+                out.println()
+                break
+            case "h4":
+                out.println "1.1.1.1 " + node.text()
+                out.println()
+                break
+            case "a":
+                out.print "{link:${node.text()}${node.attribute('href')}} "
+                break
+            case "b":
+                out.print "__${node.text()}__ "
+                break
+            case "i":
+                out.print "~~${node.text()}~~ "
+                break
+            case "source":
+                out.println """{code:groovysh}
+${node.text()}
+{code}
+"""
+               break
+            case "li":
+                out.print "* "
+                applyTemplatesForChildren(node)
+                out.println()
+                break
+            case "p":
+            default:
+                applyTemplatesForChildren(node)
+                out.println()
+                out.println()
+        }
+    }
+    
+    void applyTemplatesForChildren(node) {
+        for (c in node.children()) {
+            if (c instanceof String) {
+                out.print c + " "
+            }
+            else {
+                applyTemplates(c)
+            }
+        }
+    }
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/wiki/RunWikiTest.java b/groovy-core/src/test/org/codehaus/groovy/wiki/RunWikiTest.java
new file mode 100644
index 0000000..bdac3d2
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/wiki/RunWikiTest.java
@@ -0,0 +1,76 @@
+/*
+ * $Id$
+ * 
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ * 
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met:
+ *  1. Redistributions of source code must retain copyright statements and
+ * notices. Redistributions must also contain a copy of this document.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *  3. The name "groovy" must not be used to endorse or promote products
+ * derived from this Software without prior written permission of The Codehaus.
+ * For written permission, please contact info@codehaus.org.
+ *  4. Products derived from this Software may not be called "groovy" nor may
+ * "groovy" appear in their names without prior written permission of The
+ * Codehaus. "groovy" is a registered trademark of The Codehaus.
+ *  5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *  
+ */
+
+package org.codehaus.groovy.wiki;
+
+import java.io.File;
+
+import org.codehaus.groovy.classgen.TestSupport;
+
+import groovy.util.GroovyTestSuite;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Tests the execution of wiki-generated test cases
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public class RunWikiTest extends TestSupport {
+
+    public RunWikiTest(String name) {
+        setName(name);
+    }
+
+    public void testMakeAtLeastOneTestCaseAvailable(){}
+
+    public static Test suite() {
+        TestSuite suite = new TestSuite();
+        suite.addTest(new RunWikiTest("testMakeAtLeastOneTestCaseAvailable"));
+        File dir = new File("xdocs");
+        File[] files = dir.listFiles();
+        for (int i = 0; i < files.length; i++) {
+            File file = files[i];
+            String name = file.getName();
+            if (name.endsWith(".wiki")) {
+                name = "target/test-classes/wiki/" + name.replaceAll(".wiki", "Test.groovy");
+                System.setProperty("test", name);
+                suite.addTest(GroovyTestSuite.suite());
+            }
+        }
+        return suite; 
+    }    
+}
diff --git a/groovy-core/src/test/org/codehaus/groovy/wiki/TestCaseRenderEngineTest.java b/groovy-core/src/test/org/codehaus/groovy/wiki/TestCaseRenderEngineTest.java
new file mode 100644
index 0000000..b293d4b
--- /dev/null
+++ b/groovy-core/src/test/org/codehaus/groovy/wiki/TestCaseRenderEngineTest.java
@@ -0,0 +1,86 @@
+/*
+ $Id$
+
+ Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+
+ Redistribution and use of this software and associated documentation
+ ("Software"), with or without modification, are permitted provided
+ that the following conditions are met:
+
+ 1. Redistributions of source code must retain copyright
+    statements and notices.  Redistributions must also contain a
+    copy of this document.
+
+ 2. Redistributions in binary form must reproduce the
+    above copyright notice, this list of conditions and the
+    following disclaimer in the documentation and/or other
+    materials provided with the distribution.
+
+ 3. The name "groovy" must not be used to endorse or promote
+    products derived from this Software without prior written
+    permission of The Codehaus.  For written permission,
+    please contact info@codehaus.org.
+
+ 4. Products derived from this Software may not be called "groovy"
+    nor may "groovy" appear in their names without prior written
+    permission of The Codehaus. "groovy" is a registered
+    trademark of The Codehaus.
+
+ 5. Due credit should be given to The Codehaus -
+    http://groovy.codehaus.org/
+
+ THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package org.codehaus.groovy.wiki;
+
+import junit.framework.TestCase;
+
+import org.radeox.engine.context.BaseRenderContext;
+
+/**
+ * @author James Strachan
+ * @version $Revision$
+ */
+public class TestCaseRenderEngineTest extends TestCase {
+
+    private BaseRenderContext context = new BaseRenderContext();
+
+    public void testRender() {
+        assertRender(
+            "blah blah {code:groovy}x = 1; assert x == 1{code} whatnot",
+            "package wiki\nclass someFileTest extends GroovyTestCase {\n\n/*\nblah blah */ \n\n  void testCase1() {\nx = 1; assert x == 1\n}\n\n /* whatnot\n*/\n\nvoid testDummy() {\n// this is a dummy test case\n}\n\n}\n");		
+    }
+
+    public void testRenderWithScript() {
+        assertRender(
+            "blah blah {code:groovysh}x = 1; println 'hello ${x}'{code} whatnot",
+             "package wiki\nclass someFileTest extends GroovyTestCase {\n\n/*\nblah blah */ \n\n  void testScript1() {\n    assertScript( <<<SCRIPT_EOF1\nx = 1; println 'hello \\${x}'\nSCRIPT_EOF1 )\n}    \n\n /* whatnot\n*/\n\nvoid testDummy() {\n// this is a dummy test case\n}\n\n}\n");
+    }
+
+    protected void assertRender(String input, String expected) {
+        TestCaseRenderEngine test = new TestCaseRenderEngine();
+        context.set("name", "someFile.wiki");
+        String answer = test.render(input, context);
+
+        System.out.println("Converted: " + input);
+        System.out.println("Into: " + answer);
+
+        // lets convert the output to a String we can cut-n-paste
+        System.out.println(answer.replaceAll("\n", "\\\\n"));
+        
+        assertEquals("Rendering", expected, answer);
+    }
+
+}
diff --git a/groovy-core/src/whiteboard/org/codehaus/groovy/classgen/JavacClassGenerator.java b/groovy-core/src/whiteboard/org/codehaus/groovy/classgen/JavacClassGenerator.java
new file mode 100644
index 0000000..3240bbd
--- /dev/null
+++ b/groovy-core/src/whiteboard/org/codehaus/groovy/classgen/JavacClassGenerator.java
@@ -0,0 +1,812 @@
+/*
+ * $Id$
+ *
+ * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
+ *
+ * Redistribution and use of this software and associated documentation
+ * ("Software"), with or without modification, are permitted provided that the
+ * following conditions are met: 1. Redistributions of source code must retain
+ * copyright statements and notices. Redistributions must also contain a copy
+ * of this document. 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution. 3.
+ * The name "groovy" must not be used to endorse or promote products derived
+ * from this Software without prior written permission of The Codehaus. For
+ * written permission, please contact info@codehaus.org. 4. Products derived
+ * from this Software may not be called "groovy" nor may "groovy" appear in
+ * their names without prior written permission of The Codehaus. "groovy" is a
+ * registered trademark of The Codehaus. 5. Due credit should be given to The
+ * Codehaus - http://groovy.codehaus.org/
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+package org.codehaus.groovy.classgen;
+
+import groovy.lang.Closure;
+import groovy.lang.GString;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.MissingClassException;
+import groovy.lang.Reference;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.security.AccessControlException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassNode;
+//import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+//import org.codehaus.groovy.ast.GroovyClassVisitor;
+//import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.Type;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.ArrayExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ExpressionTransformer;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.GStringExpression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.MapEntryExpression;
+import org.codehaus.groovy.ast.expr.MapExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.NegationExpression;
+import org.codehaus.groovy.ast.expr.NotExpression;
+import org.codehaus.groovy.ast.expr.PostfixExpression;
+import org.codehaus.groovy.ast.expr.PrefixExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.RangeExpression;
+import org.codehaus.groovy.ast.expr.RegexExpression;
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
+import org.codehaus.groovy.ast.expr.TernaryExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.AssertStatement;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.BreakStatement;
+import org.codehaus.groovy.ast.stmt.CaseStatement;
+import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.stmt.ContinueStatement;
+import org.codehaus.groovy.ast.stmt.DoWhileStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.stmt.SwitchStatement;
+import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
+import org.codehaus.groovy.ast.stmt.ThrowStatement;
+import org.codehaus.groovy.ast.stmt.TryCatchStatement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
+import org.codehaus.groovy.syntax.parser.RuntimeParserException;
+//import org.objectweb.asm.ClassVisitor;
+//import org.objectweb.asm.MethodVisitor;
+//import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Label;
+import com.sun.tools.javac.v8.tree.Tree;
+import com.sun.tools.javac.v8.tree.TreeMaker;
+import com.sun.tools.javac.v8.util.Name;
+import com.sun.tools.javac.v8.util.List;
+import com.sun.tools.javac.v8.code.Symbol;
+import com.sun.tools.javac.v8.code.Scope;
+
+/**
+ * Generates Java class versions of Groovy classes using Sun's Javac Java AST model
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @version $Revision$
+ */
+public abstract class JavacClassGenerator extends ClassGenerator {
+
+    private Logger log = Logger.getLogger(getClass().getName());
+
+    private Tree.Factory factory;
+    private Tree.TopLevel topLevel;
+    private Name.Table nameTable = new Name.Table();
+    private Name sourceFileName;
+
+    public JavacClassGenerator(GeneratorContext context, ClassLoader classLoader, String sourceFile) {
+        super(classLoader);
+        sourceFileName = nameTable.fromString(sourceFile);
+    }
+
+
+    // GroovyClassVisitor interface
+    //-------------------------------------------------------------------------
+//
+//    public void visitClass(ClassNode classNode) {
+//
+//        //className = nameTable.fromString(classNode.getName());
+//
+//        Tree pid = null;
+//        List defs = new List();
+//        Symbol.PackageSymbol packageSymbol = null;
+//
+//        Symbol owner = null; /// new Symbol.ClassSymbol()
+//        Scope namedImportScope = new Scope(owner);
+//        Scope starImportScope = new Scope(owner);
+//
+//        topLevel = new Tree.TopLevel(pid, defs, sourceFileName, packageSymbol, namedImportScope, starImportScope);
+//        factory = new TreeMaker(topLevel);
+//
+//
+//
+//        try {
+//            syntheticStaticFields.clear();
+//            this.classNode = classNode;
+//            this.outermostClass = null;
+//
+//            //System.out.println("Generating class: " + classNode.getName());
+//
+//            // lets check that the classes are all valid
+//            classNode.setSuperClass(checkValidType(classNode.getSuperClass(), classNode, "Must be a valid base class"));
+//            String[] interfaces = classNode.getInterfaces();
+//            for (int i = 0; i < interfaces.length; i++ ) {
+//                interfaces[i] = checkValidType(interfaces[i], classNode, "Must be a valid interface name");
+//            }
+//
+//
+//            classNode.visitContents(this);
+//
+//            createSyntheticStaticFields();
+//
+//
+//            factory.ClassDef();
+//
+//            for (Iterator iter = innerClasses.iterator(); iter.hasNext();) {
+//                ClassNode innerClass = (ClassNode) iter.next();
+//
+//                /** TODO process innner classes */
+//            }
+//        }
+//        catch (GroovyRuntimeException e) {
+//            e.setModule(classNode.getModule());
+//            throw e;
+//        }
+//    }
+//
+//    public void visitConstructor(ConstructorNode node) {
+//        this.constructorNode = node;
+//        this.methodNode = null;
+//        this.variableScope = null;
+//
+//        visitParameters(node, node.getParameters());
+//
+//        findMutableVariables();
+//        resetVariableStack(node.getParameters());
+//
+//        Statement code = node.getCode();
+//        if (code != null) {
+//            code.visit(this);
+//        }
+//        factory.MethodDef();
+//    }
+//
+//    public void visitMethod(MethodNode node) {
+//        this.constructorNode = null;
+//        this.methodNode = node;
+//        this.variableScope = null;
+//
+//        visitParameters(node, node.getParameters());
+//
+//        node.setReturnType(checkValidType(node.getReturnType(), node, "Must be a valid return type"));
+//
+//        findMutableVariables();
+//        resetVariableStack(node.getParameters());
+//
+//        node.getCode().visit(this);
+//        factory.MethodDef();
+//    }
+//
+//    protected void visitParameters(ASTNode node, Parameter[] parameters) {
+//        for (int i = 0, size = parameters.length; i < size; i++ ) {
+//            visitParameter(node, parameters[i]);
+//        }
+//    }
+//
+//    protected void visitParameter(ASTNode node, Parameter parameter) {
+//        if (! parameter.isDynamicType()) {
+//            parameter.setType(checkValidType(parameter.getType(), node, "Must be a valid parameter class"));
+//        }
+//    }
+//
+//    public void visitField(FieldNode fieldNode) {
+//        onLineNumber(fieldNode);
+//
+//        // lets check that the classes are all valid
+//        fieldNode.setType(checkValidType(fieldNode.getType(), fieldNode, "Must be a valid field class for field: " + fieldNode.getName()));
+//
+//        //System.out.println("Visiting field: " + fieldNode.getName() + " on
+//        // class: " + classNode.getName());
+//
+//        Object fieldValue = null;
+//        Expression expression = fieldNode.getInitialValueExpression();
+//        if (expression instanceof ConstantExpression) {
+//            ConstantExpression constantExp = (ConstantExpression) expression;
+//            Object value = constantExp.getValue();
+//            if (isPrimitiveFieldType(fieldNode.getType())) {
+//                // lets convert any primitive types
+//                Class type = null;
+//                try {
+//                    type = loadClass(fieldNode.getType());
+//                    fieldValue = InvokerHelper.asType(value, type);
+//                }
+//                catch (Exception e) {
+//                    log.warning("Caught unexpected: " + e);
+//                }
+//            }
+//        }
+//
+//    }
+//
+//    /**
+//     * Creates a getter, setter and field
+//     */
+//    public void visitProperty(PropertyNode statement) {
+//        onLineNumber(statement);
+//        //this.propertyNode = statement;
+//        this.methodNode = null;
+//    }
+//
+//    // GroovyCodeVisitor interface
+//    //-------------------------------------------------------------------------
+//
+//    // Statements
+//    //-------------------------------------------------------------------------
+//
+//    public void visitForLoop(ForStatement loop) {
+//        onLineNumber(loop);
+//
+//
+//        factory.ForLoop()
+//
+//        //
+//        // Declare the loop counter.
+//
+//        Type variableType = checkValidType(loop.getVariableType(), loop, "for loop variable");
+//        Variable variable = defineVariable(loop.getVariable(), variableType, true);
+//
+//        if( isInScriptBody() ) {
+//            variable.setProperty( true );
+//        }
+//
+//
+//        //
+//        // Then initialize the iterator and generate the loop control
+//
+//        loop.getCollectionExpression().visit(this);
+//
+//        asIteratorMethod.call(cv);
+//
+//        final int iteratorIdx = defineVariable(createVariableName("iterator"), "java.util.Iterator", false).getIndex();
+//        cv.visitVarInsn(ASTORE, iteratorIdx);
+//
+//        pushBlockScope();
+//
+//        Label continueLabel = scope.getContinueLabel();
+//        cv.visitJumpInsn(GOTO, continueLabel);
+//        Label label2 = new Label();
+//        cv.visitLabel(label2);
+//
+//        BytecodeExpression expression = new BytecodeExpression() {
+//            public void visit(GroovyCodeVisitor visitor) {
+//                cv.visitVarInsn(ALOAD, iteratorIdx);
+//
+//                iteratorNextMethod.call(cv);
+//            }
+//        };
+//
+//        evaluateEqual( BinaryExpression.newAssignmentExpression(loop.getVariable(), expression) );
+//
+//
+//        //
+//        // Generate the loop body
+//
+//        loop.getLoopBlock().visit(this);
+//
+//
+//        //
+//        // Generate the loop tail
+//
+//        cv.visitLabel(continueLabel);
+//        cv.visitVarInsn(ALOAD, iteratorIdx);
+//
+//        iteratorHasNextMethod.call(cv);
+//
+//        cv.visitJumpInsn(IFNE, label2);
+//
+//        cv.visitLabel(scope.getBreakLabel());
+//        popScope();
+//    }
+//
+//    public void visitWhileLoop(WhileStatement loop) {
+//        onLineNumber(loop);
+//
+//        /*
+//         * // quick hack if (!methodNode.isStatic()) { cv.visitVarInsn(ALOAD,
+//         * 0); }
+//         */
+//
+//        pushBlockScope();
+//
+//        Label continueLabel = scope.getContinueLabel();
+//
+//        cv.visitJumpInsn(GOTO, continueLabel);
+//        Label l1 = new Label();
+//        cv.visitLabel(l1);
+//
+//        loop.getLoopBlock().visit(this);
+//
+//        cv.visitLabel(continueLabel);
+//        //cv.visitVarInsn(ALOAD, 0);
+//
+//        loop.getBooleanExpression().visit(this);
+//
+//        cv.visitJumpInsn(IFNE, l1);
+//
+//        cv.visitLabel(scope.getBreakLabel());
+//        popScope();
+//    }
+//
+//    public void visitDoWhileLoop(DoWhileStatement loop) {
+//        onLineNumber(loop);
+//
+//        pushBlockScope();
+//
+//        Label breakLabel = scope.getBreakLabel();
+//
+//        Label continueLabel = scope.getContinueLabel();
+//        cv.visitLabel(continueLabel);
+//        Label l1 = new Label();
+//
+//        loop.getLoopBlock().visit(this);
+//
+//        cv.visitLabel(l1);
+//
+//        loop.getBooleanExpression().visit(this);
+//
+//        cv.visitJumpInsn(IFNE, continueLabel);
+//
+//        cv.visitLabel(breakLabel);
+//        popScope();
+//    }
+//
+//    public void visitIfElse(IfStatement ifElse) {
+//        onLineNumber(ifElse);
+//
+//        ifElse.getBooleanExpression().visit(this);
+//
+//        Label l0 = new Label();
+//        cv.visitJumpInsn(IFEQ, l0);
+//        ifElse.getIfBlock().visit(this);
+//
+//        Label l1 = new Label();
+//        cv.visitJumpInsn(GOTO, l1);
+//        cv.visitLabel(l0);
+//
+//        ifElse.getElseBlock().visit(this);
+//        cv.visitLabel(l1);
+//    }
+//
+//    public void visitTernaryExpression(TernaryExpression expression) {
+//        onLineNumber(expression);
+//
+//        expression.getBooleanExpression().visit(this);
+//
+//        Label l0 = new Label();
+//        cv.visitJumpInsn(IFEQ, l0);
+//        expression.getTrueExpression().visit(this);
+//
+//        Label l1 = new Label();
+//        cv.visitJumpInsn(GOTO, l1);
+//        cv.visitLabel(l0);
+//
+//        expression.getFalseExpression().visit(this);
+//        cv.visitLabel(l1);
+//    }
+//
+//    public void visitAssertStatement(AssertStatement statement) {
+//        onLineNumber(statement);
+//
+//        //System.out.println("Assert: " + statement.getLineNumber() + " for: "
+//        // + statement.getText());
+//
+//        BooleanExpression booleanExpression = statement.getBooleanExpression();
+//        booleanExpression.visit(this);
+//
+//        Label l0 = new Label();
+//        cv.visitJumpInsn(IFEQ, l0);
+//
+//        // do nothing
+//
+//        Label l1 = new Label();
+//        cv.visitJumpInsn(GOTO, l1);
+//        cv.visitLabel(l0);
+//
+//        // push expression string onto stack
+//        String expressionText = booleanExpression.getText();
+//        List list = new ArrayList();
+//        addVariableNames(booleanExpression, list);
+//        if (list.isEmpty()) {
+//            cv.visitLdcInsn(expressionText);
+//        }
+//        else {
+//            boolean first = true;
+//
+//            // lets create a new expression
+//            cv.visitTypeInsn(NEW, "java/lang/StringBuffer");
+//            cv.visitInsn(DUP);
+//            cv.visitLdcInsn(expressionText + ". Values: ");
+//
+//            cv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "(Ljava/lang/String;)V");
+//
+//            int tempIndex = defineVariable(createVariableName("assert"), "java.lang.Object", false).getIndex();
+//
+//            cv.visitVarInsn(ASTORE, tempIndex);
+//
+//            for (Iterator iter = list.iterator(); iter.hasNext();) {
+//                String name = (String) iter.next();
+//                String text = name + " = ";
+//                if (first) {
+//                    first = false;
+//                }
+//                else {
+//                    text = ", " + text;
+//                }
+//
+//                cv.visitVarInsn(ALOAD, tempIndex);
+//                cv.visitLdcInsn(text);
+//                cv.visitMethodInsn(
+//                    INVOKEVIRTUAL,
+//                    "java/lang/StringBuffer",
+//                    "append",
+//                    "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
+//                cv.visitInsn(POP);
+//
+//                cv.visitVarInsn(ALOAD, tempIndex);
+//                new VariableExpression(name).visit(this);
+//                cv.visitMethodInsn(
+//                    INVOKEVIRTUAL,
+//                    "java/lang/StringBuffer",
+//                    "append",
+//                    "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
+//                cv.visitInsn(POP);
+//
+//            }
+//            cv.visitVarInsn(ALOAD, tempIndex);
+//        }
+//
+//        // now the optional exception expression
+//        statement.getMessageExpression().visit(this);
+//
+//        assertFailedMethod.call(cv);
+//        cv.visitLabel(l1);
+//    }
+//
+//    public void visitTryCatchFinally(TryCatchStatement statement) {
+//        onLineNumber(statement);
+//
+//        CatchStatement catchStatement = statement.getCatchStatement(0);
+//
+//        Statement tryStatement = statement.getTryStatement();
+//
+//        if (tryStatement.isEmpty() || catchStatement == null) {
+//            final Label l0 = new Label();
+//            cv.visitLabel(l0);
+//
+//            tryStatement.visit(this);
+//
+//            int index1 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
+//            int index2 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
+//
+//            final Label l1 = new Label();
+//            cv.visitJumpInsn(JSR, l1);
+//            final Label l2 = new Label();
+//            cv.visitLabel(l2);
+//            final Label l3 = new Label();
+//            cv.visitJumpInsn(GOTO, l3);
+//            final Label l4 = new Label();
+//            cv.visitLabel(l4);
+//            cv.visitVarInsn(ASTORE, index1);
+//            cv.visitJumpInsn(JSR, l1);
+//            final Label l5 = new Label();
+//            cv.visitLabel(l5);
+//            cv.visitVarInsn(ALOAD, index1);
+//            cv.visitInsn(ATHROW);
+//            cv.visitLabel(l1);
+//            cv.visitVarInsn(ASTORE, index2);
+//
+//            statement.getFinallyStatement().visit(this);
+//
+//            cv.visitVarInsn(RET, index2);
+//            cv.visitLabel(l3);
+//
+//            exceptionBlocks.add(new Runnable() {
+//                public void run() {
+//                    cv.visitTryCatchBlock(l0, l2, l4, null);
+//                    cv.visitTryCatchBlock(l4, l5, l4, null);
+//                }
+//            });
+//
+//        }
+//        else {
+//            String exceptionVar = catchStatement.getVariable();
+//            String exceptionType =
+//                checkValidType(catchStatement.getExceptionType(), catchStatement, "in catch statement");
+//
+//            int exceptionIndex = defineVariable(exceptionVar, exceptionType, false).getIndex();
+//            int index2 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
+//            int index3 = defineVariable(this.createVariableName("exception"), "java.lang.Object").getIndex();
+//
+//            final Label l0 = new Label();
+//            cv.visitLabel(l0);
+//
+//            tryStatement.visit(this);
+//
+//            final Label l1 = new Label();
+//            cv.visitLabel(l1);
+//            Label l2 = new Label();
+//            cv.visitJumpInsn(JSR, l2);
+//            final Label l3 = new Label();
+//            cv.visitLabel(l3);
+//            Label l4 = new Label();
+//            cv.visitJumpInsn(GOTO, l4);
+//            final Label l5 = new Label();
+//            cv.visitLabel(l5);
+//
+//            cv.visitVarInsn(ASTORE, exceptionIndex);
+//
+//            if (catchStatement != null) {
+//                catchStatement.visit(this);
+//            }
+//
+//            cv.visitJumpInsn(JSR, l2);
+//            final Label l6 = new Label();
+//            cv.visitLabel(l6);
+//            cv.visitJumpInsn(GOTO, l4);
+//
+//            final Label l7 = new Label();
+//            cv.visitLabel(l7);
+//            cv.visitVarInsn(ASTORE, index2);
+//            cv.visitJumpInsn(JSR, l2);
+//
+//            final Label l8 = new Label();
+//            cv.visitLabel(l8);
+//            cv.visitVarInsn(ALOAD, index2);
+//            cv.visitInsn(ATHROW);
+//            cv.visitLabel(l2);
+//            cv.visitVarInsn(ASTORE, index3);
+//
+//            statement.getFinallyStatement().visit(this);
+//
+//            cv.visitVarInsn(RET, index3);
+//            cv.visitLabel(l4);
+//
+//            // rest of code goes here...
+//
+//            //final String exceptionTypeInternalName = (catchStatement !=
+//            // null) ?
+//            // getTypeDescription(exceptionType) : null;
+//            final String exceptionTypeInternalName =
+//                (catchStatement != null) ? BytecodeHelper.getClassInternalName(exceptionType) : null;
+//
+//            exceptionBlocks.add(new Runnable() {
+//                public void run() {
+//                    cv.visitTryCatchBlock(l0, l1, l5, exceptionTypeInternalName);
+//                    cv.visitTryCatchBlock(l0, l3, l7, null);
+//                    cv.visitTryCatchBlock(l5, l6, l7, null);
+//                    cv.visitTryCatchBlock(l7, l8, l7, null);
+//                }
+//            });
+//        }
+//    }
+//
+//    public void visitSwitch(SwitchStatement statement) {
+//        onLineNumber(statement);
+//
+//        statement.getExpression().visit(this);
+//
+//        pushBlockScope();
+//
+//        int switchVariableIndex = defineVariable(createVariableName("switch"), "java.lang.Object").getIndex();
+//        cv.visitVarInsn(ASTORE, switchVariableIndex);
+//
+//        List caseStatements = statement.getCaseStatements();
+//        int caseCount = caseStatements.size();
+//        Label[] labels = new Label[caseCount + 1];
+//        for (int i = 0; i < caseCount; i++) {
+//            labels[i] = new Label();
+//        }
+//
+//        int i = 0;
+//        for (Iterator iter = caseStatements.iterator(); iter.hasNext(); i++) {
+//            CaseStatement caseStatement = (CaseStatement) iter.next();
+//            visitCaseStatement(caseStatement, switchVariableIndex, labels[i], labels[i + 1]);
+//        }
+//
+//        statement.getDefaultStatement().visit(this);
+//
+//        cv.visitLabel(scope.getBreakLabel());
+//
+//        popScope();
+//    }
+//
+//    public void visitCaseStatement(CaseStatement statement) {
+//    }
+//
+//    public void visitCaseStatement(
+//        CaseStatement statement,
+//        int switchVariableIndex,
+//        Label thisLabel,
+//        Label nextLabel) {
+//
+//        onLineNumber(statement);
+//
+//        cv.visitVarInsn(ALOAD, switchVariableIndex);
+//        statement.getExpression().visit(this);
+//
+//        isCaseMethod.call(cv);
+//
+//        Label l0 = new Label();
+//        cv.visitJumpInsn(IFEQ, l0);
+//
+//        cv.visitLabel(thisLabel);
+//
+//        statement.getCode().visit(this);
+//
+//        // now if we don't finish with a break we need to jump past
+//        // the next comparison
+//        if (nextLabel != null) {
+//            cv.visitJumpInsn(GOTO, nextLabel);
+//        }
+//
+//        cv.visitLabel(l0);
+//    }
+//
+//    public void visitBreakStatement(BreakStatement statement) {
+//        onLineNumber(statement);
+//
+//        cv.visitJumpInsn(GOTO, scope.getBreakLabel());
+//    }
+//
+//    public void visitContinueStatement(ContinueStatement statement) {
+//        onLineNumber(statement);
+//
+//        cv.visitJumpInsn(GOTO, scope.getContinueLabel());
+//    }
+//
+//    public void visitSynchronizedStatement(SynchronizedStatement statement) {
+//        onLineNumber(statement);
+//
+//        statement.getExpression().visit(this);
+//
+//        int index = defineVariable(createVariableName("synchronized"), "java.lang.Integer").getIndex();
+//
+//        cv.visitVarInsn(ASTORE, index);
+//        cv.visitInsn(MONITORENTER);
+//        final Label l0 = new Label();
+//        cv.visitLabel(l0);
+//
+//        statement.getCode().visit(this);
+//
+//        cv.visitVarInsn(ALOAD, index);
+//        cv.visitInsn(MONITOREXIT);
+//        final Label l1 = new Label();
+//        cv.visitJumpInsn(GOTO, l1);
+//        final Label l2 = new Label();
+//        cv.visitLabel(l2);
+//        cv.visitVarInsn(ALOAD, index);
+//        cv.visitInsn(MONITOREXIT);
+//        cv.visitInsn(ATHROW);
+//        cv.visitLabel(l1);
+//
+//        exceptionBlocks.add(new Runnable() {
+//            public void run() {
+//                cv.visitTryCatchBlock(l0, l2, l2, null);
+//            }
+//        });
+//    }
+//
+//    public void visitThrowStatement(ThrowStatement statement) {
+//        statement.getExpression().visit(this);
+//
+//        // we should infer the type of the exception from the expression
+//        cv.visitTypeInsn(CHECKCAST, "java/lang/Throwable");
+//
+//        cv.visitInsn(ATHROW);
+//    }
+//
+//    public void visitReturnStatement(ReturnStatement statement) {
+//        onLineNumber(statement);
+//
+//        Expression expression = statement.getExpression();
+//        evaluateExpression(expression);
+//
+//        //return is based on class type
+//        //TODO: make work with arrays
+//        // we may need to cast
+//        String returnType = methodNode.getReturnType();
+//        helper.unbox(returnType);
+//        if (returnType.equals("double")) {
+//            cv.visitInsn(DRETURN);
+//        }
+//        else if (returnType.equals("float")) {
+//            cv.visitInsn(FRETURN);
+//        }
+//        else if (returnType.equals("long")) {
+//            cv.visitInsn(LRETURN);
+//        }
+//        else if (returnType.equals("boolean")) {
+//            cv.visitInsn(IRETURN);
+//        }
+//        else if (
+//            returnType.equals("char")
+//                || returnType.equals("byte")
+//                || returnType.equals("int")
+//                || returnType.equals("short")) { //byte,short,boolean,int are
+//            // all IRETURN
+//            cv.visitInsn(IRETURN);
+//        }
+//        else {
+//            doConvertAndCast(returnType, expression);
+//            cv.visitInsn(ARETURN);
+//
+//            /*
+//            if (c == Boolean.class) {
+//                Label l0 = new Label();
+//                cv.visitJumpInsn(IFEQ, l0);
+//                cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
+//                cv.visitInsn(ARETURN);
+//                cv.visitLabel(l0);
+//                cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
+//                cv.visitInsn(ARETURN);
+//            }
+//            else {
+//                if (isValidTypeForCast(returnType) && !returnType.equals(c.getName())) {
+//                    doConvertAndCast(returnType, expression);
+//                }
+//                cv.visitInsn(ARETURN);
+//            }
+//            */
+//        }
+//
+//        outputReturn = true;
+//    }
+
+
+}
diff --git a/groovy-core/xdocs/faq.fml b/groovy-core/xdocs/faq.fml
new file mode 100644
index 0000000..2ca3eff
--- /dev/null
+++ b/groovy-core/xdocs/faq.fml
@@ -0,0 +1,386 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faqs title="Frequently Asked Questions">
+
+  <part id="general">
+    <title>General</title>
+    
+    <faq id="whats-groovy">
+      <question>
+        What is Groovy?
+      </question>
+      <answer>
+        <p>
+          Groovy is a powerful high level language for the Java platform which compiles 
+          down to Java bytecode.
+        </p>
+        <p>
+          Think of it as a Ruby or Python like language that is tightly integrated with
+          the Java platform - allowing you the same powerful and concise coding syntax as
+          Ruby or Pyton but allowing you to stay on the JVM and protect your investment in
+          J2SE, J2EE and all the plethora of great useful Java code out there.
+        </p>
+      </answer>
+    </faq>
+    
+    <faq id="why-groovy">
+      <question>
+        Why Groovy? Why don't you just use Jython, JRuby, bsh, rhino, pnuts, ...
+      </question>
+      <answer>
+        <p>
+          Firstly ports of existing languages like Python, Ruby, Smalltalk and JavaScript to the JVM
+          are a good thing and we welcome them. If you already use and/or are fond of these languages
+          please be our guests to use the Java-port of them.
+        </p>
+        <p>
+          One of the main design goals of Groovy is to be a scripting language for Java developers to use.
+          So we wanted to reuse both Java's semantics and the whole set of J2SE APIs rather than introduce
+          a port of a different language with different semantics and APIs to learn and implement/maintain. 
+        </p>
+        <p>
+          e.g. in Groovy, java.lang.Object is the root of the object hierarchy, 
+          Object.equals(), Object.hashCode() and Comparable are used for comparions 
+          and lookups of objects, that java.util.List and java.util.Map are used for collections, 
+          Java Beans are fully supported and that Java and Groovy classes are interchangable 
+          inside the JVM.
+          Groovy is built on top of the J2SE APIs, rather than having 2 parallel platforms etc.
+        </p>
+        <p>
+          In other words we wanted the Groovy language to be very easy to pick up if you're already a Java developer
+          and for there to be a very small number of new APIs to learn.
+          By this statement we're not implying that Python / Ruby / JavaScript are hard to learn per se - its just
+          there's more to know, things are more different and there's more APIs to learn.
+        </p>
+        <p>
+          Think of Groovy as a Ruby or Python like language that is tightly integrated with
+          the Java platform (as opposed to the Unix/Posix command shell and C-libraries) 
+          - allowing you the same powerful and concise coding syntax as
+          Ruby or Pyton but allowing you to stay on the JVM and protect your investment in
+          J2SE, J2EE and all the plethora of great useful Java code out there without any adapter layers or
+          parallel API sets etc.
+        </p>
+        <p>
+ 	       There is a more detailed set of comparisions to other languages 
+    	    <a href="http://wiki.codehaus.org/groovy/ComparisonToOtherLanguages">here</a>
+        </p>
+        
+      </answer>
+    </faq>
+    
+    <faq id="dependencies">
+      <question>
+        What are the dependencies for Groovy?
+      </question>
+      <answer>
+		<p>As well as Java 1.4 and the Groovy jar we also depend at runtime on the ASM library</p>
+      </answer>
+    </faq>
+
+    <faq id="licence">
+      <question>
+        What is the licence for Groovy?
+      </question>
+      <answer>
+		<p>Groovy is open source using a BSD / Apache style <a href="http://cvs.groovy.codehaus.org/viewcvs.cgi/groovy/groovy-core/LICENSE.txt?rev=HEAD&amp;view=auto">licence</a></p>
+      </answer>
+    </faq>
+
+    <faq id="contribute">
+      <question>
+        How can I contribute to Groovy?
+      </question>
+      <answer>
+        <p>
+		  There are many ways you can help and contribute to Groovy. 
+		  Please read the <a href="contribute.html">contributing guide</a>
+       </p>
+      </answer>
+    </faq>   
+  </part>
+
+  <part id="using">
+    <title>Using Groovy</title>
+    
+    <faq id="how-embed">
+      <question>
+        How can I embed Groovy into my Java application
+      </question>
+      <answer>
+        <p>
+		  Please see this description of <a href="embedding.html">embedding Groovy</a>
+       </p>
+      </answer>
+    </faq>   
+    
+    <faq id="how-compile">
+      <question>
+        How can I compile Groovy to bytecode either at runtime or build time?
+      </question>
+      <answer>
+        <p>
+		  Please see this description of <a href="compiling.html">compiling Groovy</a>
+       </p>
+      </answer>
+    </faq>   
+    
+    <faq id="how-run">
+      <question>
+        How can I run Groovy scripts?
+      </question>
+      <answer>
+        <p>
+		  Please see this description of <a href="running.html">running Groovy code</a>
+       </p>
+      </answer>
+    </faq>   
+    
+    <faq id="problems">
+      <question>
+        I get errors when trying to run groovy, groovysh or groovyConsole. Whats wrong?
+      </question>
+      <answer>
+        <p>
+          Groovy depends on JDK 1.4 or later. Common errors people have when trying to run
+          Groovy is that there's an old groovy jar on the CLASSPATH somewhere (have you 
+          checked in java/lib/ext?) or that JAVA_HOME points to an old JDK before JDK 1.4.x.
+        </p>
+        <p>
+		  For more help please see this description of <a href="running.html">running Groovy code</a>
+       </p>
+      </answer>
+    </faq>   
+    
+    <faq id="classpath">
+      <question>
+        How can I add stuff to the classpath when running things in groovysh or groovy?
+      </question>
+      <answer>
+        <p>
+          You can add things to your $CLASSPATH environment variable. Another popular option
+          is to create a .groovy/lib directory in your home directory and add whatever jars you
+          want to be available by default.
+        </p>
+        <p>
+          e.g. if you wish to connect to your favourite JDBC database and do some scripting with it
+          then add your JDBC driver to ~/.groovy/lib.
+       </p>
+      </answer>
+    </faq>   
+  </part>
+
+
+  <part id="language">
+    <title>Questions about the Groovy language</title>
+    
+    <faq id="newline-before-brace">
+      <question>
+        Things work if I use Suns conventions and put { on the same line, but if I add a new line things break?
+      </question>
+      <answer>
+        <p>
+		  When using closures with method calls we have some syntax sugar in Groovy which is sensitive to whitespace (newlines to be preceise). 
+		  Please see this description in <a href="javadiff.html">common gotchas</a> for a full description
+       </p>
+      </answer>
+    </faq>   
+  </part>
+
+  <part id="gdk">
+    <title>GDK (Groovy Development Kit)</title>
+    
+    <faq id="groovy-jgk">
+      <question>
+        What new methods are available on standard JDK classes?
+      </question>
+      <answer>
+        <p>
+		  Please see this description of the <a href="groovy-jdk.html">Groovy JDK</a>
+       </p>
+      </answer>
+    </faq>   
+    
+    <faq id="what-closure">
+      <question>
+        What are Closures?
+      </question>
+      <answer>
+        <p>
+		  Please see this description of <a href="closures.html">closures</a>
+       </p>
+      </answer>
+    </faq>   
+    
+    <faq id="operators">
+      <question>
+        How does operator overloading work?
+      </question>
+      <answer>
+        <p>
+		  Please see this description of <a href="operators.html">operator overloading</a>
+       </p>
+      </answer>
+    </faq>   
+  </part>
+
+
+  <part id="developer">
+    <title>Groovy Developers FAQ</title>
+    
+    <faq id="build">
+      <question>
+        How do I build Groovy from the source code?
+      </question>
+      <answer>
+        <p>
+        We use <a href="">Maven</a> as the build tool for Groovy.
+        From a source distribution, or <a href="cvs-usage.html">CVS checkout</a>
+        you need to install Maven as per the instructions on Maven's website.
+        </p>
+        <p>
+        Basically this involves setting the JAVA_HOME and MAVEN_HOME environment
+        variables and adding JAVA_HOME/bin and MAVEN_HOME/bin to your path.
+        Once you have installed Maven you can build Groovy and run all the unit tests
+        by typing the following in a command line shell
+       </p>
+		<source>
+		maven
+		</source>
+      </answer>
+    </faq>   
+
+    <faq id="quick-build">
+      <question>
+        All the unit test cases take a while to run. Can I do a quicker build?
+      </question>
+      <answer>
+        <p>
+        You can do a full clean binary build without running the unit tests via..
+       </p>
+		<source>
+		maven rebuild
+		</source>
+		
+        <p>
+		If you want to run all the unit test cases inside the same JVM, which saves quite a bit of time
+		although the output isn't as nice, you can use this command.
+        </p>
+		<source>
+	    maven groovy:test-quick
+		</source>
+      </answer>
+    </faq>   
+
+    <faq id="some-tests">
+      <question>
+        All the unit test cases take a while to run. Can I run just some of the tests?
+      </question>
+      <answer>
+        <p>
+		Or to run a specific test case you can do
+        </p>
+		<source>
+		maven test:single -Dtestcase=CharsetToolkitTest
+		</source>
+
+		<p>
+		Where you pass in the name of a test case. If you want to run a single unit test case
+		written in Groovy in a slightly faster way you can try this...
+		</p>
+		
+		<source>
+		maven groovy:test-single -Dtest=src/test/groovy/SomeTest.groovy
+		</source>
+		
+        <p>
+		or to run tests matching a certain pattern...
+        </p>
+		<source>
+		maven test:match -Dtestmatch=Foo*Test.* 
+		</source>
+		
+		<p>
+		There is more details on unit testing groovy scripts <a href="unitTesting.html">here</a>
+		</p>
+      </answer>
+    </faq>   
+  </part>
+
+	<!-- More faqs or parts here -->
+  <part id="committer">
+    <title>Groovy Committers FAQ</title>
+    
+    <faq id="start">
+      <question>
+        I've just been given CVS commit access; what should I do now?
+      </question>
+      <answer>
+        <p>
+        If you've just been given CVS commit access see if you can do a commit.
+        You'll need to do an SSH based CVS checkout. Once you've done this 
+        you should be able to edit the project.xml file and change yourself 
+        from being a committer to being a developer. Then try commit that
+        and see if it works.
+        If you need more help, please ask on IRC or email.
+       </p>
+      </answer>
+    </faq>   
+    
+    <faq id="rules">
+      <question>
+        What are the development rules?
+      </question>
+      <answer>
+        <p>
+        Please try and write unit test cases for all new features, patches or fixes.
+       </p>
+        <p>
+        Its considered very bad form to commit code that doesn't compile or breaks the unit tests.
+        We run a continuous integration build (using DamageControl) to ensure that the build in CVS
+        works and the tests pass.
+       </p>
+        <p>
+        Its useful to subscribe to all 3 mail lists, especially groovy-scm which shows all CVS commits
+        along with any continuous integration build failures and JIRA issue changes.
+       </p>
+      </answer>
+    </faq>   
+    
+    <faq id="dc">
+      <question>
+        Where is the continuous integration build?
+      </question>
+      <answer>
+        <p>
+        We run DamageControl at codehaus. If a build fails a nag mail is sent to the groovy-scm mail list.
+        You can watch DC do its stuff using your IRC client and joining 
+        <a href="irc://irc.codehaus.org/damagecontrol">#damagecontrol</a>.
+       </p>
+        <p>
+        You can also view the latest DC <a href="http://builds.codehaus.org/log/groovy-core/">build logs</a> 
+        or see the <a href="http://builds.codehaus.org/checkout/groovy-core/target/test-reports/">test case results</a>
+       </p>
+      </answer>
+    </faq>   
+    
+    <faq id="cvs">
+      <question>
+        How do I use codehaus's CVS?
+      </question>
+      <answer>
+        <p>
+        Codehaus uses SSH for CVS access. So from the command line you'd type
+        </p>
+        <source>
+export CVS_RSH=ssh
+		</source>
+		<p>
+		Or if you're using eclipse you might find 
+		<a href="http://www.jcraft.com/eclipse-cvsssh2/">this plugin</a>
+		handy.
+		I use it with extssh2 and it works great!        
+       </p>
+      </answer>
+    </faq>   
+  </part>
+
+</faqs>
diff --git a/groovy-core/xdocs/images/groovy-logo.png b/groovy-core/xdocs/images/groovy-logo.png
new file mode 100644
index 0000000..54af4c1
--- /dev/null
+++ b/groovy-core/xdocs/images/groovy-logo.png
Binary files differ