aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/zwobble/couscous/transforms
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-10-30 23:55:19 +0000
committerMichael Williamson <mike@zwobble.org>2016-10-30 23:56:10 +0000
commit1ef4865a040ae94b69a5c4dabcb5dca837cae67c (patch)
tree581f7a0fdc72e616f748333fc5d061c5b1e01fd8 /src/main/java/org/zwobble/couscous/transforms
parent62ea20e20ed1c0d6b2564f8fff862d380da15fce (diff)
Defer generation of classes for lambdas
Diffstat (limited to 'src/main/java/org/zwobble/couscous/transforms')
-rw-r--r--src/main/java/org/zwobble/couscous/transforms/AnonymousClassToInnerClass.java86
1 files changed, 86 insertions, 0 deletions
diff --git a/src/main/java/org/zwobble/couscous/transforms/AnonymousClassToInnerClass.java b/src/main/java/org/zwobble/couscous/transforms/AnonymousClassToInnerClass.java
new file mode 100644
index 0000000..4a44a0c
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/transforms/AnonymousClassToInnerClass.java
@@ -0,0 +1,86 @@
+package org.zwobble.couscous.transforms;
+
+import com.google.common.collect.ImmutableList;
+import org.zwobble.couscous.ast.*;
+import org.zwobble.couscous.ast.sugar.AnonymousClass;
+import org.zwobble.couscous.ast.visitors.NodeTransformer;
+import org.zwobble.couscous.frontends.java.GeneratedClosure;
+import org.zwobble.couscous.frontends.java.Scope;
+import org.zwobble.couscous.types.ScalarType;
+
+import java.util.List;
+import java.util.Optional;
+
+import static org.zwobble.couscous.ast.ThisReferenceNode.thisReference;
+import static org.zwobble.couscous.util.Casts.tryCast;
+import static org.zwobble.couscous.util.ExtraIterables.only;
+import static org.zwobble.couscous.util.ExtraLists.*;
+import static org.zwobble.couscous.util.ExtraMaps.map;
+import static org.zwobble.couscous.util.ExtraSets.set;
+
+public class AnonymousClassToInnerClass {
+ public static TypeNode transform(TypeNode type) {
+ Scope scope = Scope.create().temporaryPrefix("_couscous_anonymous_class_to_inner_class");
+ AnonymousClassToInnerClass transformer = new AnonymousClassToInnerClass(scope, type);
+ return transformer.transformTypeDeclaration(type);
+ }
+
+ private final Scope scope;
+ private final TypeNode type;
+ private final ImmutableList.Builder<TypeNode> innerTypes = ImmutableList.builder();
+ private int anonymousClassCount = 0;
+
+ private AnonymousClassToInnerClass(Scope scope, TypeNode type) {
+ this.scope = scope;
+ this.type = type;
+ }
+
+ private TypeNode transformTypeDeclaration(TypeNode type) {
+ NodeTransformer transformer = NodeTransformer.builder()
+ .transformExpression(this::transformExpression)
+ .build();
+ return only(transformer.transformTypeDeclaration(type)).addInnerTypes(innerTypes.build());
+ }
+
+ private Optional<ExpressionNode> transformExpression(ExpressionNode expression) {
+ return tryCast(AnonymousClass.class, expression)
+ .map(anonymous -> {
+ ScalarType className = ScalarType.innerType(type.getName(), "Anonymous_" + anonymousClassCount++);
+ GeneratedClosure closure = classWithCapture(scope, className, anonymous);
+ innerTypes.add(closure.getClassNode());
+ return closure.generateConstructor();
+ });
+ }
+
+ private GeneratedClosure classWithCapture(
+ Scope scope,
+ ScalarType className,
+ AnonymousClass anonymousClass
+ ) {
+ ClassNode classNode = ClassNode.declareClass(
+ className,
+ list(),
+ set(anonymousClass.getType()),
+ anonymousClass.getFields(),
+ list(),
+ ConstructorNode.DEFAULT,
+ anonymousClass.getMethods(),
+ list()
+ );
+ if (anonymousClass.getAnonymousType().isPresent()) {
+ NodeTransformer nodeTransformer = NodeTransformer.replaceExpressions(map(
+ thisReference(anonymousClass.getAnonymousType().get()),
+ thisReference(className)
+ ));
+ classNode = nodeTransformer.transformClass(classNode);
+ }
+ return ClosureGenerator.classWithCapture(scope, classNode);
+ }
+
+ private List<Node> relevantDescendants(Node root) {
+ return eagerFlatMap(
+ eagerFilter(root.childNodes(), node -> !(node instanceof TypeNode)),
+ node -> cons(node, relevantDescendants(node))
+ );
+ }
+}