Repository: groovy Updated Branches: refs/heads/native-lambda [created] d746dd7ff
Support very basic native lambda Project: http://git-wip-us.apache.org/repos/asf/groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/d746dd7f Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/d746dd7f Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/d746dd7f Branch: refs/heads/native-lambda Commit: d746dd7ff222abad8e61aefd7d5b153bb9c28250 Parents: 3e167cc Author: sunlan <[email protected]> Authored: Thu Jan 11 15:35:02 2018 +0800 Committer: sunlan <[email protected]> Committed: Thu Jan 11 15:35:02 2018 +0800 ---------------------------------------------------------------------- .../codehaus/groovy/ast/GroovyCodeVisitor.java | 5 + .../groovy/ast/expr/LambdaExpression.java | 5 + .../groovy/classgen/AsmClassGenerator.java | 10 + .../classgen/asm/DelegatingController.java | 7 +- .../groovy/classgen/asm/LambdaWriter.java | 31 +++ .../groovy/classgen/asm/WriterController.java | 6 + .../classgen/asm/sc/StaticInvocationWriter.java | 4 + .../asm/sc/StaticTypesLambdaWriter.java | 122 +++++++++ .../asm/sc/StaticTypesWriterController.java | 11 + src/test/groovy/transform/stc/LambdaTest.groovy | 56 ++++ .../apache/groovy/parser/antlr4/AstBuilder.java | 273 ++++++++++++++++++- 11 files changed, 527 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/groovy/blob/d746dd7f/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java b/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java index 12787c0..db793cc 100644 --- a/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java +++ b/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java @@ -34,6 +34,7 @@ import org.codehaus.groovy.ast.expr.DeclarationExpression; import org.codehaus.groovy.ast.expr.ElvisOperatorExpression; import org.codehaus.groovy.ast.expr.FieldExpression; import org.codehaus.groovy.ast.expr.GStringExpression; +import org.codehaus.groovy.ast.expr.LambdaExpression; import org.codehaus.groovy.ast.expr.ListExpression; import org.codehaus.groovy.ast.expr.MapEntryExpression; import org.codehaus.groovy.ast.expr.MapExpression; @@ -138,6 +139,10 @@ public interface GroovyCodeVisitor { void visitClosureExpression(ClosureExpression expression); + default void visitLambdaExpression(LambdaExpression expression) { + visitClosureExpression(expression); + } + void visitTupleExpression(TupleExpression expression); void visitMapExpression(MapExpression expression); http://git-wip-us.apache.org/repos/asf/groovy/blob/d746dd7f/src/main/java/org/codehaus/groovy/ast/expr/LambdaExpression.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/expr/LambdaExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/LambdaExpression.java index f4f1001..ab30513 100644 --- a/src/main/java/org/codehaus/groovy/ast/expr/LambdaExpression.java +++ b/src/main/java/org/codehaus/groovy/ast/expr/LambdaExpression.java @@ -20,6 +20,7 @@ package org.codehaus.groovy.ast.expr; import org.codehaus.groovy.ast.AstToTextHelper; +import org.codehaus.groovy.ast.GroovyCodeVisitor; import org.codehaus.groovy.ast.Parameter; import org.codehaus.groovy.ast.stmt.Statement; @@ -35,6 +36,10 @@ public class LambdaExpression extends ClosureExpression { super(parameters, code); } + public void visit(GroovyCodeVisitor visitor) { + visitor.visitLambdaExpression(this); + } + @Override public String getText() { String paramText = AstToTextHelper.getParametersText(this.getParameters()); http://git-wip-us.apache.org/repos/asf/groovy/blob/d746dd7f/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java index 099bc9c..7721260 100644 --- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java +++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java @@ -55,6 +55,7 @@ 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.GStringExpression; +import org.codehaus.groovy.ast.expr.LambdaExpression; import org.codehaus.groovy.ast.expr.ListExpression; import org.codehaus.groovy.ast.expr.MapEntryExpression; import org.codehaus.groovy.ast.expr.MapExpression; @@ -717,6 +718,11 @@ public class AsmClassGenerator extends ClassGenerator { controller.getClosureWriter().writeClosure(expression); } + @Override + public void visitLambdaExpression(LambdaExpression expression) { + controller.getLambdaWriter().writeLambda(expression); + } + /** * Loads either this object or if we're inside a closure then load the top level owner */ @@ -2174,4 +2180,8 @@ public class AsmClassGenerator extends ClassGenerator { mn.getUnit().addGeneratedInnerClass((InnerClassNode)innerClass); return innerClasses.add(innerClass); } + + public ClassVisitor getClassVisitor() { + return cv; + } } http://git-wip-us.apache.org/repos/asf/groovy/blob/d746dd7f/src/main/java/org/codehaus/groovy/classgen/asm/DelegatingController.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/DelegatingController.java b/src/main/java/org/codehaus/groovy/classgen/asm/DelegatingController.java index 22acbaa..3553a82 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/DelegatingController.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/DelegatingController.java @@ -112,7 +112,12 @@ public class DelegatingController extends WriterController { @Override public ClosureWriter getClosureWriter() { return delegationController.getClosureWriter(); - } + } + + @Override + public LambdaWriter getLambdaWriter() { + return delegationController.getLambdaWriter(); + } @Override public CompileStack getCompileStack() { http://git-wip-us.apache.org/repos/asf/groovy/blob/d746dd7f/src/main/java/org/codehaus/groovy/classgen/asm/LambdaWriter.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/LambdaWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/LambdaWriter.java new file mode 100644 index 0000000..3a39688 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/classgen/asm/LambdaWriter.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.codehaus.groovy.classgen.asm; + +import org.codehaus.groovy.ast.expr.LambdaExpression; + +public class LambdaWriter extends ClosureWriter { + public LambdaWriter(WriterController wc) { + super(wc); + } + + public void writeLambda(LambdaExpression expression) { + super.writeClosure(expression); + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/d746dd7f/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java b/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java index 3c9d843..fe7a21e 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java @@ -55,6 +55,7 @@ public class WriterController { private CallSiteWriter callSiteWriter; private ClassVisitor cv; private ClosureWriter closureWriter; + private LambdaWriter lambdaWriter; private String internalClassName; private InvocationWriter invocationWriter; private BinaryExpressionHelper binaryExpHelper, fastPathBinaryExpHelper; @@ -120,6 +121,7 @@ public class WriterController { this.operandStack = new OperandStack(this); this.assertionWriter = new AssertionWriter(this); this.closureWriter = new ClosureWriter(this); + this.lambdaWriter = new LambdaWriter(this); this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass()); this.acg = asmClassGenerator; this.sourceUnit = acg.getSourceUnit(); @@ -197,6 +199,10 @@ public class WriterController { return closureWriter; } + public LambdaWriter getLambdaWriter() { + return lambdaWriter; + } + public ClassVisitor getCv() { return cv; } http://git-wip-us.apache.org/repos/asf/groovy/blob/d746dd7f/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java index d2b5bc7..22482e5 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java @@ -102,6 +102,7 @@ public class StaticInvocationWriter extends InvocationWriter { new Parameter(ClassHelper.OBJECT_TYPE, "args") } ); + public static final String PARAMETER_TYPE = "_parameter_type"; private final AtomicInteger labelCounter = new AtomicInteger(); @@ -435,6 +436,7 @@ public class StaticInvocationWriter extends InvocationWriter { // first parameters as usual for (int i = 0; i < para.length - 1; i++) { Expression expression = argumentList.get(i); + expression.putNodeMetaData(PARAMETER_TYPE, para[i].getType()); expression.visit(acg); if (!isNullConstant(expression)) { operandStack.doGroovyCast(para[i].getType()); @@ -460,6 +462,7 @@ public class StaticInvocationWriter extends InvocationWriter { } else if (argumentListSize == para.length) { for (int i = 0; i < argumentListSize; i++) { Expression expression = argumentList.get(i); + expression.putNodeMetaData(PARAMETER_TYPE, para[i].getType()); expression.visit(acg); if (!isNullConstant(expression)) { operandStack.doGroovyCast(para[i].getType()); @@ -491,6 +494,7 @@ public class StaticInvocationWriter extends InvocationWriter { } for (int i = 0; i < arguments.length; i++) { Expression expression = arguments[i]; + expression.putNodeMetaData(PARAMETER_TYPE, para[i].getType()); expression.visit(acg); if (!isNullConstant(expression)) { operandStack.doGroovyCast(para[i].getType()); http://git-wip-us.apache.org/repos/asf/groovy/blob/d746dd7f/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java new file mode 100644 index 0000000..6feaba5 --- /dev/null +++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.codehaus.groovy.classgen.asm.sc; + +import org.codehaus.groovy.ast.ClassHelper; +import org.codehaus.groovy.ast.ClassNode; +import org.codehaus.groovy.ast.MethodNode; +import org.codehaus.groovy.ast.expr.ClosureExpression; +import org.codehaus.groovy.ast.expr.LambdaExpression; +import org.codehaus.groovy.classgen.AsmClassGenerator; +import org.codehaus.groovy.classgen.asm.BytecodeHelper; +import org.codehaus.groovy.classgen.asm.LambdaWriter; +import org.codehaus.groovy.classgen.asm.WriterController; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Handle; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +import java.util.List; +import java.util.stream.Collectors; + +import static org.apache.groovy.parser.antlr4.AstBuilder.LAMBDA_ENCLOSING_CLASSNODE; +import static org.apache.groovy.parser.antlr4.AstBuilder.SYNTHETIC_LAMBDA_METHOD_NODE; +import static org.codehaus.groovy.classgen.asm.sc.StaticInvocationWriter.PARAMETER_TYPE; +import static org.objectweb.asm.Opcodes.ACC_FINAL; +import static org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static org.objectweb.asm.Opcodes.ACC_STATIC; + +/** + * Writer responsible for generating lambda classes in statically compiled mode. + * + */ +public class StaticTypesLambdaWriter extends LambdaWriter { + private StaticTypesClosureWriter staticTypesClosureWriter; + private WriterController controller; + + public StaticTypesLambdaWriter(WriterController wc) { + super(wc); + this.staticTypesClosureWriter = new StaticTypesClosureWriter(wc); + this.controller = wc; + } + + @Override + public void writeLambda(LambdaExpression expression) { + ClassNode parameterType = expression.getNodeMetaData(PARAMETER_TYPE); + + List<MethodNode> abstractMethodNodeList = + parameterType.redirect().getMethods().stream() + .filter(MethodNode::isAbstract) + .collect(Collectors.toList()); + + if (abstractMethodNodeList.size() != 1) { + super.writeClosure(expression); + return; + } + + MethodNode abstractMethodNode = abstractMethodNodeList.get(0); + String abstractMethodName = abstractMethodNode.getName(); + String abstractMethodDesc = "()L" + parameterType.redirect().getPackageName().replace('.', '/') + "/" + parameterType.redirect().getNameWithoutPackage() + ";"; + + + AsmClassGenerator acg = controller.getAcg(); + ClassVisitor cw = acg.getClassVisitor(); + cw.visitInnerClass( + "java/lang/invoke/MethodHandles$Lookup", + "java/lang/invoke/MethodHandles", + "Lookup", + ACC_PUBLIC + ACC_FINAL + ACC_STATIC); + + MethodVisitor mv = controller.getMethodVisitor(); + MethodNode syntheticLambdaMethodNode = expression.getNodeMetaData(SYNTHETIC_LAMBDA_METHOD_NODE); + ClassNode lambdaEnclosingClassNode = expression.getNodeMetaData(LAMBDA_ENCLOSING_CLASSNODE); + + String syntheticLambdaMethodDesc = BytecodeHelper.getMethodDescriptor(syntheticLambdaMethodNode); + + controller.getOperandStack().push(ClassHelper.OBJECT_TYPE); + + mv.visitInvokeDynamicInsn( + abstractMethodName, + abstractMethodDesc, + new Handle( + Opcodes.H_INVOKESTATIC, + "java/lang/invoke/LambdaMetafactory", + "metafactory", + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", + false), + new Object[] { + Type.getType(syntheticLambdaMethodDesc), + new Handle( + Opcodes.H_INVOKESTATIC, + lambdaEnclosingClassNode.getName(), + syntheticLambdaMethodNode.getName(), + syntheticLambdaMethodDesc, + false), + Type.getType(syntheticLambdaMethodDesc) + }); + + } + + @Override + protected ClassNode createClosureClass(final ClosureExpression expression, final int mods) { + return staticTypesClosureWriter.createClosureClass(expression, mods); + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/d746dd7f/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterController.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterController.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterController.java index 47ef3d4..15943e5 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterController.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterController.java @@ -31,6 +31,7 @@ import org.codehaus.groovy.classgen.asm.CallSiteWriter; import org.codehaus.groovy.classgen.asm.ClosureWriter; import org.codehaus.groovy.classgen.asm.DelegatingController; import org.codehaus.groovy.classgen.asm.InvocationWriter; +import org.codehaus.groovy.classgen.asm.LambdaWriter; import org.codehaus.groovy.classgen.asm.StatementWriter; import org.codehaus.groovy.classgen.asm.TypeChooser; import org.codehaus.groovy.classgen.asm.UnaryExpressionHelper; @@ -60,6 +61,7 @@ public class StaticTypesWriterController extends DelegatingController { private BinaryExpressionMultiTypeDispatcher binaryExprHelper; private UnaryExpressionHelper unaryExpressionHelper; private ClosureWriter closureWriter; + private LambdaWriter lambdaWriter; public StaticTypesWriterController(WriterController normalController) { super(normalController); @@ -74,6 +76,7 @@ public class StaticTypesWriterController extends DelegatingController { this.typeChooser = new StaticTypesTypeChooser(); this.invocationWriter = new StaticInvocationWriter(this); this.closureWriter = new StaticTypesClosureWriter(this); + this.lambdaWriter = new StaticTypesLambdaWriter(this); this.unaryExpressionHelper = new StaticTypesUnaryExpressionHelper(this); CompilerConfiguration config = cn.getCompileUnit().getConfig(); @@ -183,4 +186,12 @@ public class StaticTypesWriterController extends DelegatingController { } return super.getClosureWriter(); } + + @Override + public LambdaWriter getLambdaWriter() { + if (isInStaticallyCheckedMethod) { + return lambdaWriter; + } + return super.getLambdaWriter(); + } } http://git-wip-us.apache.org/repos/asf/groovy/blob/d746dd7f/src/test/groovy/transform/stc/LambdaTest.groovy ---------------------------------------------------------------------- diff --git a/src/test/groovy/transform/stc/LambdaTest.groovy b/src/test/groovy/transform/stc/LambdaTest.groovy new file mode 100644 index 0000000..0ee1ac3 --- /dev/null +++ b/src/test/groovy/transform/stc/LambdaTest.groovy @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package groovy.transform.stc + +class LambdaTest extends GroovyTestCase { + void testMethodCall() { + assertScript ''' + import groovy.transform.CompileStatic + import java.util.stream.Collectors + import java.util.stream.Stream + + @CompileStatic + public class Test1 { + public static void main(String[] args) { + p1(); + // p2(); + // p3(); + } + + public static void p1() { + assert [2, 3, 4] == Stream.of(1, 2, 3).map(e -> e + 1).collect(Collectors.toList()); + } + + /* + public static void p2() { + assert 13 == Stream.of(1, 2, 3).reduce(7, (r, e) -> r + e); + } + */ + + /* + public static void p3() { + Stream.of(1, 2, 3).forEach(e -> { System.out.println(e + 1); }); + } + */ + } + ''' + + } +} http://git-wip-us.apache.org/repos/asf/groovy/blob/d746dd7f/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java ---------------------------------------------------------------------- diff --git a/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java b/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java index 675255b..f808dde 100644 --- a/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java +++ b/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java @@ -137,7 +137,212 @@ import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.apache.groovy.parser.antlr4.GroovyLangParser.*; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ADD; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.AS; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.AdditiveExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.AndExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.AnnotatedQualifiedClassNameContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.AnnotationContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.AnnotationNameContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.AnnotationsOptContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.AnonymousInnerClassDeclarationContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ArgumentsContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ArrayInitializerContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.AssertStatementContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.AssertStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.AssignmentExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.BlockContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.BlockStatementContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.BlockStatementsContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.BlockStatementsOptContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.BooleanLiteralAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.BreakStatementContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.BreakStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.BuiltInTypeContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.CASE; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.CastExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.CastParExpressionContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.CatchClauseContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.CatchTypeContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClassBodyContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClassBodyDeclarationContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClassDeclarationContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClassNameContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClassOrInterfaceModifierContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClassOrInterfaceModifiersContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClassOrInterfaceModifiersOptContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClassOrInterfaceTypeContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClassicalForControlContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClassifiedModifiersContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClosureContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClosurePrmrAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.CommandArgumentContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.CommandExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.CommandExpressionContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.CompilationUnitContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ConditionalExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ConditionalStatementContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ConditionalStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ContinueStatementContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ContinueStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.CreatedNameContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.CreatorContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.DEC; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.DEF; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.DEFAULT; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.DimsContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.DimsOptContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.DoWhileStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.DynamicMemberNameContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ElementValueArrayInitializerContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ElementValueContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ElementValuePairContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ElementValuePairsContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ElementValuesContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.EnhancedArgumentListContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.EnhancedArgumentListElementContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.EnhancedExpressionContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.EnhancedForControlContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.EnhancedStatementExpressionContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.EnumConstantContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.EnumConstantsContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.EqualityExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ExclusiveOrExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ExpressionContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ExpressionInParContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ExpressionListContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ExpressionListElementContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ExpressionStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.FieldDeclarationContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.FinallyBlockContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.FloatingPointLiteralAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ForControlContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ForInitContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ForStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ForUpdateContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.FormalParameterContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.FormalParameterListContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.FormalParametersContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.GE; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.GT; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.GroovyParserRuleContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.GstringContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.GstringPathContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.GstringPrmrAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.GstringValueContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.IN; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.INC; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.INSTANCEOF; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.IdentifierContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.IdentifierPrmrAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.IfElseStatementContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ImportDeclarationContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ImportStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.InclusiveOrExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.IndexPropertyArgsContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.IntegerLiteralAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.KeywordsContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.LE; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.LT; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.LabeledStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.LambdaBodyContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.LambdaPrmrAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ListContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ListPrmrAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.LiteralPrmrAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.LocalVariableDeclarationContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.LocalVariableDeclarationStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.LogicalAndExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.LogicalOrExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.LoopStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.MapContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.MapEntryContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.MapEntryLabelContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.MapEntryListContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.MapPrmrAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.MemberDeclarationContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.MethodBodyContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.MethodDeclarationContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.MethodDeclarationStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.MethodNameContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ModifierContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ModifiersContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ModifiersOptContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.MultipleAssignmentExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.MultiplicativeExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.NOT_IN; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.NOT_INSTANCEOF; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.NamePartContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.NamedPropertyArgsContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.NewPrmrAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.NonWildcardTypeArgumentsContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.NormalExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.NullLiteralAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.PRIVATE; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.PackageDeclarationContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ParExpressionContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ParenPrmrAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.PathElementContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.PathExpressionContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.PostfixExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.PostfixExpressionContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.PowerExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.PrimitiveTypeContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.QualifiedClassNameContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.QualifiedClassNameListContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.QualifiedNameContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.QualifiedStandardClassNameContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.RegexExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.RelationalExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ResourceContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ResourceListContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ResourcesContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ReturnStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ReturnTypeContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.STATIC; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.SUB; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ShiftExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.StandardLambdaExpressionContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.StandardLambdaParametersContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.StatementsContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.StringLiteralAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.StringLiteralContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.SuperPrmrAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.SwitchBlockStatementGroupContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.SwitchLabelContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.SwitchStatementContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.SynchronizedStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ThisFormalParameterContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ThisPrmrAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.ThrowStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.TryCatchStatementContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.TryCatchStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.TypeArgumentContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.TypeArgumentsContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.TypeArgumentsOrDiamondContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.TypeBoundContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.TypeContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.TypeDeclarationContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.TypeDeclarationStmtAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.TypeListContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.TypeNamePairContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.TypeNamePairsContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.TypeParameterContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.TypeParametersContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.TypePrmrAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.UnaryAddExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.UnaryNotExprAltContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.VariableDeclarationContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.VariableDeclaratorContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.VariableDeclaratorIdContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.VariableDeclaratorsContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.VariableInitializerContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.VariableInitializersContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.VariableModifierContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.VariableModifiersContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.VariableModifiersOptContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.VariableNamesContext; +import static org.apache.groovy.parser.antlr4.GroovyLangParser.WhileStmtAltContext; import static org.apache.groovy.parser.antlr4.util.PositionConfigureUtils.configureAST; import static org.codehaus.groovy.runtime.DefaultGroovyMethods.asBoolean; import static org.codehaus.groovy.runtime.DefaultGroovyMethods.last; @@ -149,6 +354,7 @@ import static org.codehaus.groovy.runtime.DefaultGroovyMethods.last; * Created on 2016/08/14 */ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements GroovyParserVisitor<Object> { + public AstBuilder(SourceUnit sourceUnit) { this.sourceUnit = sourceUnit; this.moduleNode = new ModuleNode(sourceUnit); @@ -1060,9 +1266,49 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov this.visitClassBodyDeclaration(e); }); + genSyntheticLambdaMethodNode(classNode); + return null; } + private void genSyntheticLambdaMethodNode(ClassNode classNode) { + if (null == classNode) { + classNode = moduleNode.getScriptClassDummy(); + } + + if (null == classNode) { + return; + } + + List<LambdaExpression> lambdaExpressionList = lambdaExpressionRegistry.get(classNode); + + if (null == lambdaExpressionList) { + return; + } + + for (LambdaExpression lambdaExpression : lambdaExpressionList) { + String syntheticLambdaMethodNodeName = createSyntheticLambdaMethodNodeName(); + + Parameter[] parameters = lambdaExpression.getParameters(); + if (parameters == null) { + parameters = Parameter.EMPTY_ARRAY; + } + + MethodNode methodNode = + classNode.addMethod(syntheticLambdaMethodNodeName, Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, lambdaExpression.getCode()); + + lambdaExpression.putNodeMetaData(SYNTHETIC_LAMBDA_METHOD_NODE, methodNode); + lambdaExpression.putNodeMetaData(LAMBDA_ENCLOSING_CLASSNODE, classNode); + + configureAST(methodNode, lambdaExpression); + } + } + + private int syntheticLambdaMethodNodeCount = 0; + private String createSyntheticLambdaMethodNodeName() { + return "lambda$" + syntheticLambdaMethodNodeCount++; + } + @Override public List<FieldNode> visitEnumConstants(EnumConstantsContext ctx) { ClassNode classNode = ctx.getNodeMetaData(CLASS_DECLARATION_CLASS_NODE); @@ -3374,7 +3620,26 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov @Override public LambdaExpression visitStandardLambdaExpression(StandardLambdaExpressionContext ctx) { - return configureAST(this.createLambda(ctx.standardLambdaParameters(), ctx.lambdaBody()), ctx); + LambdaExpression lambdaExpression = configureAST(this.createLambda(ctx.standardLambdaParameters(), ctx.lambdaBody()), ctx); + + registerLambdaExpression(lambdaExpression); + + return lambdaExpression; + } + + private void registerLambdaExpression(LambdaExpression lambdaExpression) { + ClassNode classNode = classNodeStack.peek(); + + if (null == classNode) { + classNode = moduleNode.getScriptClassDummy(); + } + + List<LambdaExpression> lambdaExpressionList = lambdaExpressionRegistry.get(classNode); + if (null == lambdaExpressionList) { + lambdaExpressionList = new LinkedList<>(); + lambdaExpressionRegistry.put(classNode, lambdaExpressionList); + } + lambdaExpressionList.add(lambdaExpression); } private LambdaExpression createLambda(StandardLambdaParametersContext standardLambdaParametersContext, LambdaBodyContext lambdaBodyContext) { @@ -4282,6 +4547,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov scriptClassNode.setLastLineNumber(lastStatement.getLastLineNumber()); } + genSyntheticLambdaMethodNode(scriptClassNode); } private boolean isTrue(NodeMetaDataHandler nodeMetaDataHandler, String key) { @@ -4447,6 +4713,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov private final List<ClassNode> classNodeList = new LinkedList<>(); private final Deque<ClassNode> classNodeStack = new ArrayDeque<>(); private final Deque<List<InnerClassNode>> anonymousInnerClassesDefinedInMethodStack = new ArrayDeque<>(); + private final Map<ClassNode, List<LambdaExpression>> lambdaExpressionRegistry = new LinkedHashMap<>(); private int anonymousInnerClassCounter = 1; private Tuple2<GroovyParserRuleContext, Exception> numberFormatError; @@ -4505,4 +4772,6 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov private static final String FLOATING_POINT_LITERAL_TEXT = "_FLOATING_POINT_LITERAL_TEXT"; private static final String CLASS_NAME = "_CLASS_NAME"; + public static final String LAMBDA_ENCLOSING_CLASSNODE = "_LAMBDA_ENCLOSING_CLASSNODE"; + public static final String SYNTHETIC_LAMBDA_METHOD_NODE = "_SYNTHETIC_LAMBDA_METHOD_NODE"; }
