Implement the new parser
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/91c04014 Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/91c04014 Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/91c04014 Branch: refs/heads/parrot Commit: 91c04014fb6cc6a2e09f93d81fd0bd95ea84d7dc Parents: 7efbf9a Author: Daniel Sun <sun...@apache.org> Authored: Fri Nov 11 21:24:16 2016 +0800 Committer: Daniel Sun <sun...@apache.org> Committed: Fri Nov 11 21:24:20 2016 +0800 ---------------------------------------------------------------------- .travis.yml | 2 +- src/main/groovy/lang/MetaClassImpl.java | 172 +- .../groovy/ast/expr/BinaryExpression.java | 18 +- .../groovy/ast/expr/DeclarationExpression.java | 12 +- .../groovy/ast/expr/LambdaExpression.java | 47 + .../ast/expr/MethodReferenceExpression.java | 45 + .../groovy/ast/stmt/TryCatchStatement.java | 30 +- .../classgen/asm/BinaryExpressionHelper.java | 30 +- .../groovy/classgen/asm/CallSiteWriter.java | 23 +- .../groovy/classgen/asm/InvocationWriter.java | 20 +- .../groovy/classgen/asm/StatementWriter.java | 67 +- .../classgen/asm/indy/IndyCallSiteWriter.java | 2 +- .../classgen/asm/indy/InvokeDynamicWriter.java | 4 +- .../asm/sc/StaticTypesCallSiteWriter.java | 2 +- .../codehaus/groovy/runtime/ArrayTypeUtils.java | 98 + .../codehaus/groovy/runtime/MethodClosure.java | 83 +- src/spec/test/builder/CliBuilderTest.groovy | 2 +- src/test/groovy/EqualsTest.groovy | 15 +- src/test/groovy/EscapedUnicodeTest.groovy | 9 + .../apache/groovy/parser/antlr4/GroovyLexer.g4 | 804 + .../apache/groovy/parser/antlr4/GroovyParser.g4 | 1183 ++ .../groovy/parser/antlr4/Java.g4.v20160306.zip | Bin 0 -> 5805 bytes .../parser/antlr4/util/GroovyTestRig.groovy | 74 + .../apache/groovy/parser/AbstractParser.java | 83 + .../org/apache/groovy/parser/Antlr2Parser.java | 34 + .../org/apache/groovy/parser/Antlr4Parser.java | 39 + .../parser/antlr4/Antlr4ParserPlugin.java | 45 + .../parser/antlr4/Antlr4PluginFactory.java | 17 + .../apache/groovy/parser/antlr4/AstBuilder.java | 4344 +++++ .../groovy/parser/antlr4/GroovyLangLexer.java | 45 + .../groovy/parser/antlr4/GroovyLangParser.java | 38 + .../parser/antlr4/SemanticPredicates.java | 94 + .../TryWithResourcesASTTransformation.java | 339 + .../parser/antlr4/internal/AtnManager.java | 107 + .../internal/DescriptiveErrorStrategy.java | 102 + .../groovy/parser/antlr4/util/StringUtils.java | 145 + .../parser/antlr4/Geb10SourcesTest.groovy | 1684 ++ .../parser/antlr4/Gradle310SourcesTest.groovy | 15941 +++++++++++++++++ .../parser/antlr4/Grails320SourcesTest.groovy | 4648 +++++ .../parser/antlr4/Groovy250ScriptsTest.groovy | 11081 ++++++++++++ .../parser/antlr4/Groovy250SourcesTest.groovy | 7427 ++++++++ .../parser/antlr4/GroovyParserTest.groovy | 303 + .../parser/antlr4/Spock11RC2SourcesTest.groovy | 1224 ++ .../groovy/parser/antlr4/SyntaxErrorTest.groovy | 132 + .../groovy/parser/antlr4/TestUtils.groovy | 259 + .../antlr4/util/ASTComparatorCategory.groovy | 526 + .../groovy/parser/antlr4/util/AstDumper.groovy | 1025 ++ .../core/AnnotationDeclaration_01.groovy | 39 + .../test/resources/core/Annotation_01.groovy | 1 + .../test/resources/core/Annotation_02.groovy | 2 + .../test/resources/core/Annotation_03.groovy | 3 + .../test/resources/core/Annotation_04.groovy | 2 + .../test/resources/core/Annotation_05.groovy | 1 + .../test/resources/core/Annotation_06.groovy | 2 + .../test/resources/core/Annotation_07.groovy | 2 + .../test/resources/core/Annotation_08.groovy | 10 + .../test/resources/core/Annotation_09.groovy | 14 + .../test/resources/core/Annotation_10x.groovy | 20 + .../src/test/resources/core/Assert_01.groovy | 28 + .../src/test/resources/core/Assert_02x.groovy | 37 + .../src/test/resources/core/Assert_03x.groovy | 26 + .../resources/core/ClassDeclaration_01.groovy | 47 + .../resources/core/ClassDeclaration_02.groovy | 42 + .../resources/core/ClassDeclaration_03.groovy | 51 + .../resources/core/ClassDeclaration_04.groovy | 22 + .../resources/core/ClassDeclaration_05.groovy | 20 + .../resources/core/ClassDeclaration_06.groovy | 83 + .../resources/core/ClassDeclaration_07.groovy | 27 + .../src/test/resources/core/Closure_01.groovy | 1 + .../src/test/resources/core/Closure_02.groovy | 1 + .../src/test/resources/core/Closure_03.groovy | 1 + .../src/test/resources/core/Closure_04.groovy | 3 + .../src/test/resources/core/Closure_05.groovy | 3 + .../src/test/resources/core/Closure_06.groovy | 9 + .../src/test/resources/core/Closure_07.groovy | 3 + .../src/test/resources/core/Closure_08.groovy | 16 + .../src/test/resources/core/Closure_09.groovy | 16 + .../src/test/resources/core/Closure_10.groovy | 4 + .../src/test/resources/core/Command_01.groovy | 14 + .../src/test/resources/core/Command_02.groovy | 11 + .../src/test/resources/core/Command_03.groovy | 66 + .../src/test/resources/core/Command_04.groovy | 7 + .../src/test/resources/core/Command_05.groovy | 59 + .../src/test/resources/core/Command_06x.groovy | 8 + .../src/test/resources/core/Comments_01.groovy | 28 + .../src/test/resources/core/Comments_02.groovy | 107 + .../src/test/resources/core/DoWhile_01x.groovy | 7 + .../src/test/resources/core/DoWhile_02x.groovy | 8 + .../src/test/resources/core/DoWhile_03x.groovy | 11 + .../src/test/resources/core/DoWhile_04x.groovy | 14 + .../resources/core/EnumDeclaration_01.groovy | 44 + .../resources/core/EnumDeclaration_02.groovy | 52 + .../resources/core/EnumDeclaration_03.groovy | 6 + .../test/resources/core/Expression_01.groovy | 230 + .../test/resources/core/Expression_02.groovy | 6 + .../test/resources/core/Expression_03.groovy | 31 + .../test/resources/core/Expression_04.groovy | 62 + .../test/resources/core/Expression_05.groovy | 40 + .../test/resources/core/Expression_06.groovy | 6 + .../test/resources/core/Expression_07.groovy | 9 + .../test/resources/core/Expression_08.groovy | 6 + .../test/resources/core/Expression_09.groovy | 16 + .../test/resources/core/Expression_10.groovy | 25 + .../test/resources/core/Expression_11.groovy | 16 + .../test/resources/core/Expression_12.groovy | 17 + .../test/resources/core/Expression_13.groovy | 45 + .../test/resources/core/Expression_14.groovy | 22 + .../test/resources/core/Expression_15.groovy | 127 + .../test/resources/core/Expression_16.groovy | 22 + .../test/resources/core/Expression_17.groovy | 141 + .../test/resources/core/Expression_18.groovy | 26 + .../test/resources/core/Expression_19.groovy | 32 + .../test/resources/core/Expression_20.groovy | 2 + .../test/resources/core/Expression_21x.groovy | 6 + .../src/test/resources/core/For_01.groovy | 55 + .../src/test/resources/core/For_02.groovy | 36 + .../src/test/resources/core/For_03.groovy | 37 + .../src/test/resources/core/GString_01.groovy | 30 + .../src/test/resources/core/GString_02.groovy | 59 + .../src/test/resources/core/GString_03.groovy | 49 + .../test/resources/core/IdenticalOp_01x.groovy | 10 + .../src/test/resources/core/IfElse_01.groovy | 44 + .../resources/core/ImportDeclaration_01.groovy | 1 + .../resources/core/ImportDeclaration_02.groovy | 1 + .../resources/core/ImportDeclaration_03.groovy | 4 + .../resources/core/ImportDeclaration_04.groovy | 5 + .../resources/core/ImportDeclaration_05.groovy | 1 + .../resources/core/ImportDeclaration_06.groovy | 3 + .../resources/core/ImportDeclaration_07.groovy | 6 + .../resources/core/ImportDeclaration_08.groovy | 28 + .../core/InterfaceDeclaration_01.groovy | 36 + .../core/InterfaceDeclaration_02.groovy | 42 + .../core/InterfaceDeclaration_03.groovy | 7 + .../src/test/resources/core/Label_01.groovy | 15 + .../src/test/resources/core/Lambda_01x.groovy | 47 + .../src/test/resources/core/List_01.groovy | 15 + .../src/test/resources/core/Literal_01.groovy | 79 + .../src/test/resources/core/Literal_02.groovy | 48 + .../src/test/resources/core/Literal_03.groovy | 3 + .../core/LocalVariableDeclaration_01.groovy | 110 + .../src/test/resources/core/Map_01.groovy | 29 + .../resources/core/MethodDeclaration_01.groovy | 32 + .../resources/core/MethodDeclaration_02.groovy | 41 + .../resources/core/MethodPointer_01x.groovy | 5 + .../resources/core/MethodReference_01x.groovy | 85 + .../resources/core/PackageDeclaration_01.groovy | 1 + .../resources/core/PackageDeclaration_02.groovy | 1 + .../resources/core/PackageDeclaration_03.groovy | 1 + .../resources/core/PackageDeclaration_04.groovy | 20 + .../resources/core/PackageDeclaration_05.groovy | 23 + .../resources/core/PackageDeclaration_06.groovy | 1 + .../src/test/resources/core/Return_01.groovy | 8 + .../test/resources/core/SafeIndex_01x.groovy | 10 + .../src/test/resources/core/Switch_01.groovy | 60 + .../test/resources/core/Synchronized_01.groovy | 36 + .../src/test/resources/core/Throw_01.groovy | 2 + .../resources/core/TraitDeclaration_01.groovy | 42 + .../resources/core/TraitDeclaration_02.groovy | 40 + .../resources/core/TraitDeclaration_03.groovy | 48 + .../resources/core/TraitDeclaration_04.groovy | 28 + .../resources/core/TraitDeclaration_05.groovy | 23 + .../src/test/resources/core/TryCatch_01.groovy | 112 + .../resources/core/TryWithResources_01x.groovy | 241 + .../src/test/resources/core/Unicode_01.groovy | 24 + .../src/test/resources/core/While_01.groovy | 58 + .../src/test/resources/core/While_02x.groovy | 5 + .../resources/fail/AbstractMethod_01x.groovy | 3 + .../resources/fail/AbstractMethod_02x.groovy | 4 + .../resources/fail/AbstractMethod_03x.groovy | 3 + .../resources/fail/AbstractMethod_04x.groovy | 1 + .../resources/fail/AbstractMethod_05x.groovy | 1 + .../resources/fail/AbstractMethod_06x.groovy | 1 + .../src/test/resources/fail/Break_01x.groovy | 1 + .../src/test/resources/fail/Break_02x.groovy | 3 + .../src/test/resources/fail/Continue_01x.groovy | 1 + .../src/test/resources/fail/Continue_02x.groovy | 3 + .../src/test/resources/fail/DoWhile_01x.groovy | 4 + .../test/resources/fail/Expression_01.groovy | 1 + .../test/resources/fail/Expression_02.groovy | 1 + .../test/resources/fail/Expression_03.groovy | 1 + .../test/resources/fail/Expression_04.groovy | 1 + .../test/resources/fail/Expression_05.groovy | 1 + .../test/resources/fail/Expression_06.groovy | 1 + .../test/resources/fail/Expression_07.groovy | 1 + .../test/resources/fail/Expression_08.groovy | 1 + .../test/resources/fail/Expression_09.groovy | 1 + .../src/test/resources/fail/List_01.groovy | 1 + .../fail/LocalVariableDeclaration_01.groovy | 1 + .../resources/fail/ParExpression_01x.groovy | 1 + .../resources/fail/ParExpression_02x.groovy | 1 + .../resources/fail/ParExpression_03x.groovy | 1 + .../src/test/resources/fail/Super_01x.groovy | 6 + .../src/test/resources/fail/Switch_01.groovy | 9 + .../src/test/resources/fail/This_01x.groovy | 8 + .../fail/UnexpectedCharacter_01x.groovy | 1 + .../src/test/resources/geb-1.0/allsources.txt | 409 + .../resources/geb-1.0/geb-1.0-allsources.zip | Bin 0 -> 503324 bytes .../test/resources/gradle-3.1/allsources.txt | 3963 ++++ .../gradle-3.1/gradle-3.1-allsources.zip | Bin 0 -> 5966721 bytes .../test/resources/grails-3.2.0/allsources.txt | 1150 ++ .../grails-3.2.0/grails-3.2.0-allsources.zip | Bin 0 -> 1674411 bytes .../test/resources/groovy-2.5.0/allscripts.txt | 2744 +++ .../test/resources/groovy-2.5.0/allsources.txt | 1844 ++ ...roovy-2.5.0-SNAPSHOT-20160921-allscripts.zip | Bin 0 -> 1071812 bytes ...roovy-2.5.0-SNAPSHOT-20160921-allsources.zip | Bin 0 -> 2711417 bytes .../spock-spock-1.1-rc-2/allsources.txt | 294 + .../spock-spock-1.1-rc-2-allsources.zip | Bin 0 -> 338519 bytes 207 files changed, 66305 insertions(+), 198 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/.travis.yml ---------------------------------------------------------------------- diff --git a/.travis.yml b/.travis.yml index 09d1e5f..43a3aa3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ matrix: install: true -script: travis_wait 35 ./gradlew test +script: travis_wait 60 ./gradlew -PuseAntlr4=true test before_cache: - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/main/groovy/lang/MetaClassImpl.java ---------------------------------------------------------------------- diff --git a/src/main/groovy/lang/MetaClassImpl.java b/src/main/groovy/lang/MetaClassImpl.java index d7d8d9b..2814dd1 100644 --- a/src/main/groovy/lang/MetaClassImpl.java +++ b/src/main/groovy/lang/MetaClassImpl.java @@ -24,66 +24,23 @@ import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.classgen.asm.BytecodeHelper; import org.codehaus.groovy.control.CompilationUnit; import org.codehaus.groovy.control.Phases; -import org.codehaus.groovy.reflection.CachedClass; -import org.codehaus.groovy.reflection.CachedConstructor; -import org.codehaus.groovy.reflection.CachedField; -import org.codehaus.groovy.reflection.CachedMethod; -import org.codehaus.groovy.reflection.ClassInfo; -import org.codehaus.groovy.reflection.GeneratedMetaMethod; -import org.codehaus.groovy.reflection.ParameterTypes; -import org.codehaus.groovy.reflection.ReflectionCache; -import org.codehaus.groovy.runtime.ConvertedClosure; -import org.codehaus.groovy.runtime.CurriedClosure; -import org.codehaus.groovy.runtime.DefaultGroovyMethods; -import org.codehaus.groovy.runtime.GeneratedClosure; -import org.codehaus.groovy.runtime.GroovyCategorySupport; -import org.codehaus.groovy.runtime.InvokerHelper; -import org.codehaus.groovy.runtime.InvokerInvocationException; -import org.codehaus.groovy.runtime.MetaClassHelper; -import org.codehaus.groovy.runtime.MethodClosure; -import org.codehaus.groovy.runtime.callsite.AbstractCallSite; -import org.codehaus.groovy.runtime.callsite.CallSite; -import org.codehaus.groovy.runtime.callsite.ConstructorSite; -import org.codehaus.groovy.runtime.callsite.MetaClassConstructorSite; -import org.codehaus.groovy.runtime.callsite.PogoMetaClassSite; -import org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite; -import org.codehaus.groovy.runtime.callsite.PojoMetaClassSite; -import org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite; -import org.codehaus.groovy.runtime.callsite.StaticMetaClassSite; -import org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite; -import org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod; +import org.codehaus.groovy.reflection.*; +import org.codehaus.groovy.reflection.android.AndroidSupport; +import org.codehaus.groovy.runtime.*; +import org.codehaus.groovy.runtime.callsite.*; +import org.codehaus.groovy.runtime.metaclass.*; import org.codehaus.groovy.runtime.metaclass.MethodMetaProperty.GetBeanMethodMetaProperty; import org.codehaus.groovy.runtime.metaclass.MethodMetaProperty.GetMethodMetaProperty; -import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl; -import org.codehaus.groovy.runtime.metaclass.MetaMethodIndex; -import org.codehaus.groovy.runtime.metaclass.MethodSelectionException; -import org.codehaus.groovy.runtime.metaclass.MissingMethodExceptionNoStack; -import org.codehaus.groovy.runtime.metaclass.MissingMethodExecutionFailed; -import org.codehaus.groovy.runtime.metaclass.MissingPropertyExceptionNoStack; -import org.codehaus.groovy.runtime.metaclass.MixinInstanceMetaMethod; -import org.codehaus.groovy.runtime.metaclass.MultipleSetterProperty; -import org.codehaus.groovy.runtime.metaclass.NewInstanceMetaMethod; -import org.codehaus.groovy.runtime.metaclass.NewMetaMethod; -import org.codehaus.groovy.runtime.metaclass.NewStaticMetaMethod; -import org.codehaus.groovy.runtime.metaclass.TransformMetaMethod; import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation; import org.codehaus.groovy.runtime.typehandling.NumberMathModificationInfo; import org.codehaus.groovy.runtime.wrappers.Wrapper; import org.codehaus.groovy.util.ComplexKeyHashMap; import org.codehaus.groovy.util.FastArray; import org.codehaus.groovy.util.SingleKeyHashMap; -import org.codehaus.groovy.reflection.android.AndroidSupport; import org.objectweb.asm.ClassVisitor; -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.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Proxy; +import java.beans.*; +import java.lang.reflect.*; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedActionException; @@ -139,8 +96,8 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { private final MetaProperty arrayLengthProperty = new MetaArrayLengthProperty(); private final Index classPropertyIndexForSuper = new MethodIndex(); private final Set<MetaMethod> newGroovyMethodsSet = new HashSet<MetaMethod>(); - private final MetaMethod [] myNewMetaMethods; - private final MetaMethod [] additionalMetaMethods; + private final MetaMethod[] myNewMetaMethods; + private final MetaMethod[] additionalMetaMethods; protected MetaMethod getPropertyMethod; protected MetaMethod invokeMethodMethod; @@ -162,7 +119,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { * @param theClass The class this is the metaclass dor * @param add The methods for this class */ - public MetaClassImpl(final Class theClass, MetaMethod [] add) { + public MetaClassImpl(final Class theClass, MetaMethod[] add) { this.theClass = theClass; theCachedClass = ReflectionCache.getCachedClass(theClass); this.isGroovyObject = GroovyObject.class.isAssignableFrom(theClass); @@ -226,7 +183,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { /** * Returns the registry for this metaclass - * + * * @return The resgistry */ public MetaClassRegistry getRegistry() { @@ -310,7 +267,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { /** *Returns the class this object this is the metaclass of. - * + * * @return The class contained by this metaclass */ public Class getTheClass() { @@ -557,7 +514,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { int to = index; while (to < mopMethods.length-1 && mopMethods[to+1].getName().equals(fixedMopName)) to++; - + int matchingMethod = findMatchingMethod(mopMethods, from, to, method); if (matchingMethod != -1) { e.methodsForSuper = mopMethods[matchingMethod]; @@ -741,7 +698,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { } /** - * Returns all the normal static methods on this class for the given name + * Returns all the normal static methods on this class for the given name * * @return all the normal static methods available on this class for the * given name @@ -840,7 +797,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { public Object invokeMissingMethod(Object instance, String methodName, Object[] arguments) { return invokeMissingMethod(instance, methodName, arguments, null, false); } - + /** * Invoke a missing property on the given object with the given arguments. * @@ -955,13 +912,13 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { } catch (InvokerInvocationException iie) { if (methodMissing instanceof ClosureMetaMethod && iie.getCause() instanceof MissingMethodException) { MissingMethodException mme = (MissingMethodException) iie.getCause(); - throw new MissingMethodExecutionFailed (mme.getMethod(), mme.getClass(), + throw new MissingMethodExecutionFailed(mme.getMethod(), mme.getClass(), mme.getArguments(),mme.isStatic(),mme); } throw iie; } catch (MissingMethodException mme) { if (methodMissing instanceof ClosureMetaMethod) - throw new MissingMethodExecutionFailed (mme.getMethod(), mme.getClass(), + throw new MissingMethodExecutionFailed(mme.getMethod(), mme.getClass(), mme.getArguments(),mme.isStatic(),mme); else throw mme; @@ -1019,9 +976,9 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { throw new MissingPropertyException(propertyName, theClass); } - + /** - * Invokes a method on the given receiver for the specified arguments. + * Invokes a method on the given receiver for the specified arguments. * The MetaClass will attempt to establish the method to invoke based on the name and arguments provided. * * @@ -1030,13 +987,79 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { * @param originalArguments The arguments to the method * * @return The return value of the method - * + * * @see MetaClass#invokeMethod(Class, Object, String, Object[], boolean, boolean) */ public Object invokeMethod(Object object, String methodName, Object[] originalArguments) { return invokeMethod(theClass, object, methodName, originalArguments, false, false); } + private Object invokeMethodClosure(Object object, String methodName, Object[] arguments) { + final MethodClosure mc = (MethodClosure) object; + final Object owner = mc.getOwner(); + + methodName = mc.getMethod(); + final Class ownerClass = owner instanceof Class ? (Class) owner : owner.getClass(); + final MetaClass ownerMetaClass = registry.getMetaClass(ownerClass); + + // To conform to "Least Surprise" principle, try to invoke method with original arguments first, which can match most of use cases + try { + return ownerMetaClass.invokeMethod(ownerClass, owner, methodName, arguments, false, false); + } catch (MissingMethodExceptionNoStack e) { + // CONSTRUCTOR REFERENCE + if (owner instanceof Class && MethodClosure.NEW.equals(methodName)) { + if (ownerClass.isArray()) { + if (0 == arguments.length) { + throw new GroovyRuntimeException("The arguments(specifying size) are required to create array[" + ownerClass.getCanonicalName() + "]"); + } + + int arrayDimension = ArrayTypeUtils.dimension(ownerClass); + + if (arguments.length > arrayDimension) { + throw new GroovyRuntimeException("The length[" + arguments.length + "] of arguments should not be greater than the dimensions[" + arrayDimension + "] of array[" + ownerClass.getCanonicalName() + "]"); + } + + int[] sizeArray = new int[arguments.length]; + + for (int i = 0, n = sizeArray.length; i < n; i++) { + Object argument = arguments[i]; + + if (argument instanceof Integer) { + sizeArray[i] = (Integer) argument; + } else { + sizeArray[i] = Integer.parseInt(String.valueOf(argument)); + } + } + + Class arrayType = + arguments.length == arrayDimension + ? ArrayTypeUtils.elementType(ownerClass) // Just for better performance, though we can use reduceDimension only + : ArrayTypeUtils.reduceDimension(ownerClass, (arrayDimension - arguments.length)); + return Array.newInstance(arrayType, sizeArray); + } + + return ownerMetaClass.invokeConstructor(arguments); + } + + // METHOD REFERENCE + // if and only if the owner is a class and the method closure can be related to some instance methods, + // try to invoke method with adjusted arguments(first argument is the actual owner) again. + // otherwise throw the MissingMethodExceptionNoStack. + if (!(owner instanceof Class + && ((Boolean) mc.getProperty(MethodClosure.ANY_INSTANCE_METHOD_EXISTS)).booleanValue())) { + + throw e; + } + + if (arguments.length <= 0) { + return invokeMissingMethod(object, methodName, arguments); + } + + Object newOwner = arguments[0]; + Object[] newArguments = Arrays.copyOfRange(arguments, 1, arguments.length); + return ownerMetaClass.invokeMethod(ownerClass, newOwner, methodName, newArguments, false, false); + } + } /** * <p>Invokes a method on the given receiver for the specified arguments. The sender is the class that invoked the method on the object. @@ -1070,7 +1093,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { MetaMethod method = null; if (CLOSURE_CALL_METHOD.equals(methodName) && object instanceof GeneratedClosure) { method = getMethodWithCaching(sender, "doCall", arguments, isCallToSuper); - } + } if (method==null) { method = getMethodWithCaching(sender, methodName, arguments, isCallToSuper); } @@ -1082,17 +1105,12 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { final boolean isClosure = object instanceof Closure; if (isClosure) { final Closure closure = (Closure) object; - final Object owner = closure.getOwner(); if (CLOSURE_CALL_METHOD.equals(methodName) || CLOSURE_DO_CALL_METHOD.equals(methodName)) { final Class objectClass = object.getClass(); if (objectClass == MethodClosure.class) { - final MethodClosure mc = (MethodClosure) object; - methodName = mc.getMethod(); - final Class ownerClass = owner instanceof Class ? (Class) owner : owner.getClass(); - final MetaClass ownerMetaClass = registry.getMetaClass(ownerClass); - return ownerMetaClass.invokeMethod(ownerClass, owner, methodName, arguments, false, false); + return this.invokeMethodClosure(object, methodName, arguments); } else if (objectClass == CurriedClosure.class) { final CurriedClosure cc = (CurriedClosure) object; // change the arguments for an uncurried call @@ -1659,7 +1677,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { "before any invocation or field/property " + "access can be done"); } - + /** * This is a helper class introduced in Groovy 2.1.0, which is used only by * indy. This class is for internal use only. @@ -1689,7 +1707,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { public CachedConstructor getCachedConstrcutor() { return cc; } public boolean isBeanConstructor() { return beanConstructor; } } - + /** * This is a helper method added in Groovy 2.1.0, which is used only by indy. * This method is for internal use only. @@ -1707,9 +1725,9 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { if (arguments.length == 1 && arguments[0] instanceof Map) { res = chooseMethod("<init>", constructors, MetaClassHelper.EMPTY_TYPE_ARRAY); } else if ( - arguments.length == 2 && arguments[1] instanceof Map && - theClass.getEnclosingClass()!=null && - theClass.getEnclosingClass().isAssignableFrom(argClasses[0])) + arguments.length == 2 && arguments[1] instanceof Map && + theClass.getEnclosingClass()!=null && + theClass.getEnclosingClass().isAssignableFrom(argClasses[0])) { res = chooseMethod("<init>", constructors, new Class[]{argClasses[0]}); } @@ -1719,7 +1737,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { return null; } - + private Object invokeConstructor(Class at, Object[] arguments) { checkInitalised(); if (arguments == null) arguments = EMPTY_ARGUMENTS; @@ -2460,7 +2478,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { if (name == null) { // assume "is" or "[gs]et" String stripped = methodName.startsWith("is") ? methodName.substring(2) : methodName.substring(3); - String propName = java.beans.Introspector.decapitalize(stripped); + String propName = Introspector.decapitalize(stripped); PROP_NAMES.putIfAbsent(methodName, propName); name = PROP_NAMES.get(methodName); } http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/main/org/codehaus/groovy/ast/expr/BinaryExpression.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/ast/expr/BinaryExpression.java b/src/main/org/codehaus/groovy/ast/expr/BinaryExpression.java index 5cd35f7..1487dfc 100644 --- a/src/main/org/codehaus/groovy/ast/expr/BinaryExpression.java +++ b/src/main/org/codehaus/groovy/ast/expr/BinaryExpression.java @@ -34,6 +34,7 @@ public class BinaryExpression extends Expression { private Expression leftExpression; private Expression rightExpression; private final Token operation; + private boolean safe = false; public BinaryExpression(Expression leftExpression, Token operation, @@ -43,6 +44,14 @@ public class BinaryExpression extends Expression { this.rightExpression = rightExpression; } + public BinaryExpression(Expression leftExpression, + Token operation, + Expression rightExpression, + boolean safe) { + this(leftExpression, operation, rightExpression); + this.safe = safe; + } + public String toString() { return super.toString() + "[" + leftExpression + operation + rightExpression + "]"; } @@ -52,7 +61,7 @@ public class BinaryExpression extends Expression { } public Expression transformExpression(ExpressionTransformer transformer) { - Expression ret = new BinaryExpression(transformer.transform(leftExpression), operation, transformer.transform(rightExpression)); + Expression ret = new BinaryExpression(transformer.transform(leftExpression), operation, transformer.transform(rightExpression), safe); ret.setSourcePosition(this); ret.copyNodeMetaData(this); return ret; @@ -85,6 +94,13 @@ public class BinaryExpression extends Expression { return "(" + leftExpression.getText() + " " + operation.getText() + " " + rightExpression.getText() + ")"; } + public boolean isSafe() { + return safe; + } + + public void setSafe(boolean safe) { + this.safe = safe; + } /** * Creates an assignment expression in which the specified expression http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/main/org/codehaus/groovy/ast/expr/DeclarationExpression.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/ast/expr/DeclarationExpression.java b/src/main/org/codehaus/groovy/ast/expr/DeclarationExpression.java index 51dad92..6c082a7 100644 --- a/src/main/org/codehaus/groovy/ast/expr/DeclarationExpression.java +++ b/src/main/org/codehaus/groovy/ast/expr/DeclarationExpression.java @@ -100,7 +100,11 @@ public class DeclarationExpression extends BinaryExpression { * @throws ClassCastException if the left hand side is not a VariableExpression (and is probably a multiple assignment statement). */ public VariableExpression getVariableExpression() { - return (VariableExpression) this.getLeftExpression(); + Expression leftExpression = this.getLeftExpression(); + + return leftExpression instanceof VariableExpression + ? (VariableExpression) leftExpression + : null; } /** @@ -116,7 +120,11 @@ public class DeclarationExpression extends BinaryExpression { * */ public TupleExpression getTupleExpression() { - return (TupleExpression) this.getLeftExpression(); + Expression leftExpression = this.getLeftExpression(); + + return leftExpression instanceof TupleExpression + ? (TupleExpression) leftExpression + : null; } /** http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/main/org/codehaus/groovy/ast/expr/LambdaExpression.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/ast/expr/LambdaExpression.java b/src/main/org/codehaus/groovy/ast/expr/LambdaExpression.java new file mode 100644 index 0000000..f4f1001 --- /dev/null +++ b/src/main/org/codehaus/groovy/ast/expr/LambdaExpression.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.codehaus.groovy.ast.expr; + +import org.codehaus.groovy.ast.AstToTextHelper; +import org.codehaus.groovy.ast.Parameter; +import org.codehaus.groovy.ast.stmt.Statement; + +/** + * Represents a lambda expression such as e -> e * 2 + * or (x, y) -> x + y or (x, y) -> { x + y } or (int x, int y) -> { x + y } + * + * @author <a href="mailto:realblue...@hotmail.com">Daniel.Sun</a> + * Created on 2016/10/18 + */ +public class LambdaExpression extends ClosureExpression { + public LambdaExpression(Parameter[] parameters, Statement code) { + super(parameters, code); + } + + @Override + public String getText() { + String paramText = AstToTextHelper.getParametersText(this.getParameters()); + if (paramText.length() > 0) { + return "(" + paramText + ") -> { ... }"; + } else { + return "() -> { ... }"; + } + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/main/org/codehaus/groovy/ast/expr/MethodReferenceExpression.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/ast/expr/MethodReferenceExpression.java b/src/main/org/codehaus/groovy/ast/expr/MethodReferenceExpression.java new file mode 100644 index 0000000..0a8ebc8 --- /dev/null +++ b/src/main/org/codehaus/groovy/ast/expr/MethodReferenceExpression.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.codehaus.groovy.ast.expr; + +/** + * Represents a method reference or a constructor reference, + * e.g. System.out::println OR Objects::requireNonNull OR Integer::new OR int[]::new + * + * @author <a href="mailto:realblue...@hotmail.com">Daniel.Sun</a> + * Created on 2016/10/19 + */ +public class MethodReferenceExpression extends MethodPointerExpression { + public MethodReferenceExpression(Expression expression, Expression methodName) { + super(expression, methodName); + } + + @Override + public String getText() { + Expression expression = this.getExpression(); + Expression methodName = this.getMethodName(); + + if (expression == null) { + return "::" + methodName; + } else { + return expression.getText() + "::" + methodName.getText(); + } + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/main/org/codehaus/groovy/ast/stmt/TryCatchStatement.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/ast/stmt/TryCatchStatement.java b/src/main/org/codehaus/groovy/ast/stmt/TryCatchStatement.java index e8dea4e..f05460f 100644 --- a/src/main/org/codehaus/groovy/ast/stmt/TryCatchStatement.java +++ b/src/main/org/codehaus/groovy/ast/stmt/TryCatchStatement.java @@ -18,11 +18,12 @@ */ package org.codehaus.groovy.ast.stmt; +import org.codehaus.groovy.ast.GroovyCodeVisitor; +import org.codehaus.groovy.ast.expr.DeclarationExpression; + import java.util.ArrayList; import java.util.List; -import org.codehaus.groovy.ast.GroovyCodeVisitor; - /** * Represents a try { ... } catch () finally {} statement in Groovy * @@ -31,6 +32,7 @@ import org.codehaus.groovy.ast.GroovyCodeVisitor; public class TryCatchStatement extends Statement { private Statement tryStatement; + private List<ExpressionStatement> resourceStatements = new ArrayList<ExpressionStatement>(); private List<CatchStatement> catchStatements = new ArrayList<CatchStatement>(); private Statement finallyStatement; @@ -43,7 +45,11 @@ public class TryCatchStatement extends Statement { public void visit(GroovyCodeVisitor visitor) { visitor.visitTryCatchFinally(this); } - + + public List<ExpressionStatement> getResourceStatements() { + return resourceStatements; + } + public List<CatchStatement> getCatchStatements() { return catchStatements; } @@ -56,6 +62,14 @@ public class TryCatchStatement extends Statement { return tryStatement; } + public void addResource(ExpressionStatement resourceStatement) { + if (!(resourceStatement.getExpression() instanceof DeclarationExpression)) { + throw new IllegalArgumentException("resourceStatement should be a variable declaration statement"); + } + + resourceStatements.add(resourceStatement); + } + public void addCatch(CatchStatement catchStatement) { catchStatements.add(catchStatement); } @@ -70,6 +84,16 @@ public class TryCatchStatement extends Statement { return null; } + /** + * @return the resource statement of the given index or null + */ + public ExpressionStatement getResourceStatement(int idx) { + if (idx >= 0 && idx < resourceStatements.size()) { + return resourceStatements.get(idx); + } + return null; + } + public void setTryStatement(Statement tryStatement) { this.tryStatement = tryStatement; } http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java b/src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java index 633f447..d86c58d 100644 --- a/src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java +++ b/src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java @@ -23,23 +23,7 @@ import groovy.lang.GroovyRuntimeException; import org.codehaus.groovy.GroovyBugError; import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.ClassNode; -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.ClassExpression; -import org.codehaus.groovy.ast.expr.ConstantExpression; -import org.codehaus.groovy.ast.expr.ElvisOperatorExpression; -import org.codehaus.groovy.ast.expr.EmptyExpression; -import org.codehaus.groovy.ast.expr.Expression; -import org.codehaus.groovy.ast.expr.FieldExpression; -import org.codehaus.groovy.ast.expr.ListExpression; -import org.codehaus.groovy.ast.expr.MethodCallExpression; -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.TernaryExpression; -import org.codehaus.groovy.ast.expr.TupleExpression; -import org.codehaus.groovy.ast.expr.VariableExpression; +import org.codehaus.groovy.ast.expr.*; import org.codehaus.groovy.ast.tools.WideningCategories; import org.codehaus.groovy.classgen.AsmClassGenerator; import org.codehaus.groovy.classgen.BytecodeExpression; @@ -55,6 +39,8 @@ import static org.objectweb.asm.Opcodes.*; public class BinaryExpressionHelper { //compare + private static final MethodCaller compareIdenticalMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareIdentical"); + private static final MethodCaller compareNotIdenticalMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareNotIdentical"); private static final MethodCaller compareEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareEqual"); private static final MethodCaller compareNotEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareNotEqual"); private static final MethodCaller compareToMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareTo"); @@ -251,10 +237,12 @@ public class BinaryExpressionHelper { break; case COMPARE_IDENTICAL: + evaluateCompareExpression(compareIdenticalMethod, expression); + break; + case COMPARE_NOT_IDENTICAL: - Token op = expression.getOperation(); - Throwable cause = new SyntaxException("Operator " + op + " not supported", op.getStartLine(), op.getStartColumn(), op.getStartLine(), op.getStartColumn()+3); - throw new GroovyRuntimeException(cause); + evaluateCompareExpression(compareNotIdenticalMethod, expression); + break; default: throw new GroovyBugError("Operation: " + expression.getOperation() + " not supported"); @@ -526,7 +514,7 @@ public class BinaryExpressionHelper { // ensure VariableArguments are read, not stored compileStack.pushLHS(false); - controller.getInvocationWriter().makeSingleArgumentCall(receiver, message, arguments); + controller.getInvocationWriter().makeSingleArgumentCall(receiver, message, arguments, binExp.isSafe()); compileStack.popLHS(); } http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/main/org/codehaus/groovy/classgen/asm/CallSiteWriter.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/classgen/asm/CallSiteWriter.java b/src/main/org/codehaus/groovy/classgen/asm/CallSiteWriter.java index 0e3910d..0309138 100644 --- a/src/main/org/codehaus/groovy/classgen/asm/CallSiteWriter.java +++ b/src/main/org/codehaus/groovy/classgen/asm/CallSiteWriter.java @@ -18,26 +18,17 @@ */ package org.codehaus.groovy.classgen.asm; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.InterfaceHelperClassNode; -import org.codehaus.groovy.ast.expr.ArgumentListExpression; -import org.codehaus.groovy.ast.expr.CastExpression; -import org.codehaus.groovy.ast.expr.ClassExpression; -import org.codehaus.groovy.ast.expr.Expression; -import org.codehaus.groovy.ast.expr.TupleExpression; +import org.codehaus.groovy.ast.expr.*; import org.codehaus.groovy.classgen.AsmClassGenerator; import org.codehaus.groovy.runtime.callsite.CallSite; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; +import java.util.*; + import static org.objectweb.asm.Opcodes.*; /** @@ -247,14 +238,18 @@ public class CallSiteWriter { } } - public void makeSingleArgumentCall(Expression receiver, String message, Expression arguments) { + public final void makeSingleArgumentCall(Expression receiver, String message, Expression arguments) { + makeSingleArgumentCall(receiver, message, arguments, false); + } + + public void makeSingleArgumentCall(Expression receiver, String message, Expression arguments, boolean safe) { OperandStack operandStack = controller.getOperandStack(); int m1 = operandStack.getStackLength(); //slow Path prepareSiteAndReceiver(receiver, message, false, controller.getCompileStack().isLHS()); visitBoxedArgument(arguments); int m2 = operandStack.getStackLength(); - controller.getMethodVisitor().visitMethodInsn(INVOKEINTERFACE, "org/codehaus/groovy/runtime/callsite/CallSite", "call", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", true); + controller.getMethodVisitor().visitMethodInsn(INVOKEINTERFACE, "org/codehaus/groovy/runtime/callsite/CallSite", safe ? "callSafe" : "call", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", true); operandStack.replace(ClassHelper.OBJECT_TYPE, m2-m1); } http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/main/org/codehaus/groovy/classgen/asm/InvocationWriter.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/classgen/asm/InvocationWriter.java b/src/main/org/codehaus/groovy/classgen/asm/InvocationWriter.java index 5557983..49cdc95 100644 --- a/src/main/org/codehaus/groovy/classgen/asm/InvocationWriter.java +++ b/src/main/org/codehaus/groovy/classgen/asm/InvocationWriter.java @@ -18,15 +18,6 @@ */ package org.codehaus.groovy.classgen.asm; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.TreeMap; - import org.codehaus.groovy.ast.*; import org.codehaus.groovy.ast.expr.*; import org.codehaus.groovy.ast.tools.WideningCategories; @@ -39,6 +30,9 @@ import org.codehaus.groovy.syntax.SyntaxException; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; +import java.lang.reflect.Modifier; +import java.util.*; + import static org.objectweb.asm.Opcodes.*; public class InvocationWriter { @@ -617,8 +611,12 @@ public class InvocationWriter { } } - public void makeSingleArgumentCall(Expression receiver, String message, Expression arguments) { - controller.getCallSiteWriter().makeSingleArgumentCall(receiver, message, arguments); + public final void makeSingleArgumentCall(Expression receiver, String message, Expression arguments) { + makeSingleArgumentCall(receiver, message, arguments, false); + } + + public void makeSingleArgumentCall(Expression receiver, String message, Expression arguments, boolean safe) { + controller.getCallSiteWriter().makeSingleArgumentCall(receiver, message, arguments, safe); } public void writeSpecialConstructorCall(final ConstructorCallExpression call) { http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/main/org/codehaus/groovy/classgen/asm/StatementWriter.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/classgen/asm/StatementWriter.java b/src/main/org/codehaus/groovy/classgen/asm/StatementWriter.java index 5c14e73..4ff1a99 100644 --- a/src/main/org/codehaus/groovy/classgen/asm/StatementWriter.java +++ b/src/main/org/codehaus/groovy/classgen/asm/StatementWriter.java @@ -18,41 +18,18 @@ */ package org.codehaus.groovy.classgen.asm; -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.Parameter; -import org.codehaus.groovy.ast.expr.ArgumentListExpression; -import org.codehaus.groovy.ast.expr.BooleanExpression; -import org.codehaus.groovy.ast.expr.ClosureListExpression; -import org.codehaus.groovy.ast.expr.ConstantExpression; -import org.codehaus.groovy.ast.expr.EmptyExpression; -import org.codehaus.groovy.ast.expr.Expression; -import org.codehaus.groovy.ast.expr.MethodCallExpression; -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.EmptyStatement; -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.ast.expr.*; +import org.codehaus.groovy.ast.stmt.*; import org.codehaus.groovy.classgen.asm.CompileStack.BlockRecorder; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; +import java.util.Iterator; +import java.util.List; + import static org.objectweb.asm.Opcodes.*; public class StatementWriter { @@ -218,18 +195,7 @@ public class StatementWriter { } } - public void writeWhileLoop(WhileStatement loop) { - controller.getAcg().onLineNumber(loop,"visitWhileLoop"); - writeStatementLabel(loop); - - MethodVisitor mv = controller.getMethodVisitor(); - - controller.getCompileStack().pushLoop(loop.getStatementLabels()); - Label continueLabel = controller.getCompileStack().getContinueLabel(); - Label breakLabel = controller.getCompileStack().getBreakLabel(); - - mv.visitLabel(continueLabel); - BooleanExpression bool = loop.getBooleanExpression(); + private void visitConditionOfLoopingStatement(BooleanExpression bool, Label breakLabel, MethodVisitor mv) { boolean boolHandled = false; if (bool.getExpression() instanceof ConstantExpression) { ConstantExpression constant = (ConstantExpression) bool.getExpression(); @@ -246,7 +212,21 @@ public class StatementWriter { bool.visit(controller.getAcg()); controller.getOperandStack().jump(IFEQ, breakLabel); } + } + + public void writeWhileLoop(WhileStatement loop) { + controller.getAcg().onLineNumber(loop,"visitWhileLoop"); + writeStatementLabel(loop); + MethodVisitor mv = controller.getMethodVisitor(); + + controller.getCompileStack().pushLoop(loop.getStatementLabels()); + Label continueLabel = controller.getCompileStack().getContinueLabel(); + Label breakLabel = controller.getCompileStack().getBreakLabel(); + + mv.visitLabel(continueLabel); + + this.visitConditionOfLoopingStatement(loop.getBooleanExpression(), breakLabel, mv); loop.getLoopBlock().visit(controller.getAcg()); mv.visitJumpInsn(GOTO, continueLabel); @@ -262,14 +242,15 @@ public class StatementWriter { MethodVisitor mv = controller.getMethodVisitor(); controller.getCompileStack().pushLoop(loop.getStatementLabels()); - Label breakLabel = controller.getCompileStack().getBreakLabel(); Label continueLabel = controller.getCompileStack().getContinueLabel(); + Label breakLabel = controller.getCompileStack().getBreakLabel(); + mv.visitLabel(continueLabel); loop.getLoopBlock().visit(controller.getAcg()); + this.visitConditionOfLoopingStatement(loop.getBooleanExpression(), breakLabel, mv); - loop.getBooleanExpression().visit(controller.getAcg()); - controller.getOperandStack().jump(IFEQ, continueLabel); + mv.visitJumpInsn(GOTO, continueLabel); mv.visitLabel(breakLabel); controller.getCompileStack().pop(); http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/main/org/codehaus/groovy/classgen/asm/indy/IndyCallSiteWriter.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/classgen/asm/indy/IndyCallSiteWriter.java b/src/main/org/codehaus/groovy/classgen/asm/indy/IndyCallSiteWriter.java index 45acea8..963fa04 100644 --- a/src/main/org/codehaus/groovy/classgen/asm/indy/IndyCallSiteWriter.java +++ b/src/main/org/codehaus/groovy/classgen/asm/indy/IndyCallSiteWriter.java @@ -42,7 +42,7 @@ public class IndyCallSiteWriter extends CallSiteWriter { Expression arguments, boolean safe, boolean implicitThis, boolean callCurrent, boolean callStatic) {} @Override - public void makeSingleArgumentCall(Expression receiver, String message, Expression arguments) {} + public void makeSingleArgumentCall(Expression receiver, String message, Expression arguments, boolean safe) {} @Override public void prepareCallSite(String message) {} @Override http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/main/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java b/src/main/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java index 9cd08c5..9cd5ac3 100644 --- a/src/main/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java +++ b/src/main/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java @@ -166,8 +166,8 @@ public class InvokeDynamicWriter extends InvocationWriter { } @Override - public void makeSingleArgumentCall(Expression receiver, String message, Expression arguments) { - makeIndyCall(invokeMethod, receiver, false, false, message, arguments); + public void makeSingleArgumentCall(Expression receiver, String message, Expression arguments, boolean safe) { + makeIndyCall(invokeMethod, receiver, false, safe, message, arguments); } private static int getPropertyFlags(boolean safe, boolean implicitThis, boolean groovyObject) { http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java index a2900b4..3a13c6b 100644 --- a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java +++ b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java @@ -621,7 +621,7 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes } @Override - public void makeSingleArgumentCall(final Expression receiver, final String message, final Expression arguments) { + public void makeSingleArgumentCall(final Expression receiver, final String message, final Expression arguments, boolean safe) { TypeChooser typeChooser = controller.getTypeChooser(); ClassNode classNode = controller.getClassNode(); ClassNode rType = typeChooser.resolveType(receiver, classNode); http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/main/org/codehaus/groovy/runtime/ArrayTypeUtils.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/runtime/ArrayTypeUtils.java b/src/main/org/codehaus/groovy/runtime/ArrayTypeUtils.java new file mode 100644 index 0000000..2a6e409 --- /dev/null +++ b/src/main/org/codehaus/groovy/runtime/ArrayTypeUtils.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.codehaus.groovy.runtime; + +/** + * Utilities for handling array types + * + * @author <a href="mailto:realblue...@hotmail.com">Daniel.Sun</a> + * Created on 2016/10/28 + */ +public class ArrayTypeUtils { + + /** + * Calculate the dimension of array + * + * @param clazz the type of array + * @return the dimension of array + */ + public static int dimension(Class clazz) { + checkArrayType(clazz); + + int result = 0; + while (clazz.isArray()) { + result++; + clazz = clazz.getComponentType(); + } + + return result; + } + + /** + * Get the type of array elements + * + * @param clazz the type of array + * @return the type of elements + */ + public static Class elementType(Class clazz) { + checkArrayType(clazz); + + while (clazz.isArray()) { + clazz = clazz.getComponentType(); + } + + return clazz; + } + + /** + * Reduce the dimension of array + * + * @param clazz the type of array + * @param dim the target dimension + * @return the result array + */ + public static Class reduceDimension(Class clazz, int dim) { + checkArrayType(clazz); + + if (dim < 0) { + throw new IllegalArgumentException("The target dimension should not be less than zero: " + dim); + } + + while (clazz.isArray() && dimension(clazz) > dim) { + clazz = clazz.getComponentType(); + } + + return clazz; + } + + /** + * Check whether the type passed in is array type. + * If the type is not array type, throw IllegalArgumentException. + */ + private static void checkArrayType(Class clazz) { + if (null == clazz) { + throw new IllegalArgumentException("clazz can not be null"); + } + + if (!clazz.isArray()) { + throw new IllegalArgumentException(clazz.getCanonicalName() + " is not array type"); + } + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/main/org/codehaus/groovy/runtime/MethodClosure.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/runtime/MethodClosure.java b/src/main/org/codehaus/groovy/runtime/MethodClosure.java index 7ead0c7..60a6a3f 100644 --- a/src/main/org/codehaus/groovy/runtime/MethodClosure.java +++ b/src/main/org/codehaus/groovy/runtime/MethodClosure.java @@ -20,8 +20,11 @@ package org.codehaus.groovy.runtime; import groovy.lang.Closure; import groovy.lang.MetaMethod; +import org.codehaus.groovy.reflection.CachedConstructor; +import org.codehaus.groovy.reflection.ReflectionCache; import java.io.IOException; +import java.util.Arrays; import java.util.List; @@ -32,36 +35,90 @@ import java.util.List; * @author <a href="mailto:ja...@coredevelopers.net">James Strachan</a> */ public class MethodClosure extends Closure { - + public static final String NEW = "new"; + public static final String ANY_INSTANCE_METHOD_EXISTS = "anyInstanceMethodExists"; public static boolean ALLOW_RESOLVE = false; private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; private final String method; + private final boolean anyInstanceMethodExists; // whether the method closure is related to instance 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; - parameterTypes = EMPTY_CLASS_ARRAY; + final Class clazz = owner.getClass() == Class.class ? (Class) owner : owner.getClass(); + + this.maximumNumberOfParameters = 0; + this.parameterTypes = EMPTY_CLASS_ARRAY; List<MetaMethod> methods = InvokerHelper.getMetaClass(clazz).respondsTo(owner, method); - - for(MetaMethod m : methods) { - if (m.getParameterTypes().length > maximumNumberOfParameters) { - Class[] pt = m.getNativeParameterTypes(); - maximumNumberOfParameters = pt.length; - parameterTypes = pt; + + int instanceMethodCnt = 0; + for (MetaMethod m : methods) { + Class[] newParameterTypes = this.makeParameterTypes(owner, m); + + this.setParameterTypesAndNumber(newParameterTypes); + + if (!m.isStatic()) { + instanceMethodCnt++; + } + } + + this.anyInstanceMethodExists = instanceMethodCnt > 0; + + if (NEW.equals(method)) { + if (clazz.isArray()) { + Class[] sizeTypes = new Class[ArrayTypeUtils.dimension(clazz)]; + Arrays.fill(sizeTypes, int.class); + + this.setParameterTypesAndNumber(sizeTypes); + } else { + for (CachedConstructor c : ReflectionCache.getCachedClass(clazz).getConstructors()) { + Class[] newParameterTypes = c.getNativeParameterTypes(); + + this.setParameterTypesAndNumber(newParameterTypes); + } } } } + + private void setParameterTypesAndNumber(Class[] newParameterTypes) { + if (!(newParameterTypes.length > this.maximumNumberOfParameters)) { + return; + } + + this.maximumNumberOfParameters = newParameterTypes.length; + this.parameterTypes = newParameterTypes; + } + + /* + * Create a new array of parameter type. + * + * If the owner is a class instance(e.g. String) and the method is instance method, + * we expand the original array of parameter type by inserting the owner at the first place of the expanded array + */ + private Class[] makeParameterTypes(Object owner, MetaMethod m) { + Class[] newParameterTypes; + + if (owner instanceof Class && !m.isStatic()) { + Class[] nativeParameterTypes = m.getNativeParameterTypes(); + newParameterTypes = new Class[nativeParameterTypes.length + 1]; + + System.arraycopy(nativeParameterTypes, 0, newParameterTypes, 1, nativeParameterTypes.length); + newParameterTypes[0] = (Class) owner; + } else { + newParameterTypes = m.getNativeParameterTypes(); + } + + return newParameterTypes; + } public String getMethod() { return method; } + // TODO confirm: The "doCall" method seems to be never called..., because MetaClassImpl.invokeMethod will intercept calls and return the result protected Object doCall(Object arguments) { return InvokerHelper.invokeMethod(getOwner(), method, arguments); } @@ -83,6 +140,8 @@ public class MethodClosure extends Closure { public Object getProperty(String property) { if ("method".equals(property)) { return getMethod(); - } else return super.getProperty(property); + } else if (ANY_INSTANCE_METHOD_EXISTS.equals(property)) { + return this.anyInstanceMethodExists; + } else return super.getProperty(property); } } http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/spec/test/builder/CliBuilderTest.groovy ---------------------------------------------------------------------- diff --git a/src/spec/test/builder/CliBuilderTest.groovy b/src/spec/test/builder/CliBuilderTest.groovy index 1d039a1..b086fe6 100644 --- a/src/spec/test/builder/CliBuilderTest.groovy +++ b/src/spec/test/builder/CliBuilderTest.groovy @@ -264,7 +264,7 @@ class CliBuilderTest extends GroovyTestCase { def options = cli.parse(argz) assert options.a == 'john' assert options.b == 'MARY' - assert options.d.format('dd-MMM-yyyy') == '01-Jan-2016' + assert options.d.format('yyyy-MM-dd') == '2016-01-01' assert options.arguments() == ['and', 'some', 'more'] // end::withConvert[] } http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/test/groovy/EqualsTest.groovy ---------------------------------------------------------------------- diff --git a/src/test/groovy/EqualsTest.groovy b/src/test/groovy/EqualsTest.groovy index 8011ea9..afe20f4 100644 --- a/src/test/groovy/EqualsTest.groovy +++ b/src/test/groovy/EqualsTest.groovy @@ -38,14 +38,13 @@ class EqualsTest extends GroovyShellTestCase { } void testIdentical() { - shouldFail { - shell.evaluate """ - def x = [] - def y = [] - - assert y !== x - """ - } + assert 'a' === 'a' + assert null === null + + def x = [] + def y = [] + assert y !== x + } } http://git-wip-us.apache.org/repos/asf/groovy/blob/91c04014/src/test/groovy/EscapedUnicodeTest.groovy ---------------------------------------------------------------------- diff --git a/src/test/groovy/EscapedUnicodeTest.groovy b/src/test/groovy/EscapedUnicodeTest.groovy index b3826f1..a463218 100644 --- a/src/test/groovy/EscapedUnicodeTest.groovy +++ b/src/test/groovy/EscapedUnicodeTest.groovy @@ -16,6 +16,13 @@ * specific language governing permissions and limitations * under the License. */ +package groovy + +class EscapedUnicodeTest extends GroovyTestCase { + void testNothing() {} +} + +/* \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 @@ -42,3 +49,5 @@ \u0020\u0020\u0020\u0020\u007d \u0009\u0020\u0020\u0020\u0020 \u007d +*/ +