diff options
| author | Michael Williamson <mike@zwobble.org> | 2016-04-11 21:23:30 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2016-04-11 21:23:30 +0100 |
| commit | 4b645195d711c7a306d6d08a6c271c303948af73 (patch) | |
| tree | 2ddd3ff359ec97262d4539f38f9fba8099f55c2a /src/main/java | |
| parent | 77959af7d24286addc555aa02c774aa26cecdcbf (diff) | |
Add hacktastic type parameter capturing
Diffstat (limited to 'src/main/java')
4 files changed, 67 insertions, 8 deletions
diff --git a/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java b/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java index 00184b1..9e507dc 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java @@ -1,7 +1,10 @@ package org.zwobble.couscous.frontends.java; import org.zwobble.couscous.ast.*; +import org.zwobble.couscous.ast.visitors.NodeTransformer; +import org.zwobble.couscous.types.*; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -12,6 +15,41 @@ import static org.zwobble.couscous.util.Casts.tryCast; import static org.zwobble.couscous.util.ExtraStreams.toStream; public class FreeVariables { + public static Set<TypeParameter> findFreeTypeParameters(Node node) { + // TODO: this assumes that *all* type parameters are free, which is often but not always true in inner types + Set<TypeParameter> freeTypeParameters = new HashSet<>(); + + NodeTransformer.builder().transformType(type -> { + type.accept(new Type.Visitor<Void>() { + @Override + public Void visit(ScalarType type) { + return null; + } + + @Override + public Void visit(TypeParameter parameter) { + freeTypeParameters.add(parameter); + return null; + } + + @Override + public Void visit(ParameterizedType type) { + type.getParameters().forEach(parameter -> parameter.accept(this)); + return null; + } + + @Override + public Void visit(BoundTypeParameter type) { + type.getValue().accept(this); + return null; + } + }); + return type; + }).build().transform(node); + + return freeTypeParameters; + } + public static List<ReferenceNode> findFreeVariables(List<? extends Node> body) { Set<VariableDeclaration> declarations = body.stream() .flatMap(FreeVariables::findDeclarations) diff --git a/src/main/java/org/zwobble/couscous/frontends/java/GeneratedClosure.java b/src/main/java/org/zwobble/couscous/frontends/java/GeneratedClosure.java index b7059e2..9bad1d2 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/GeneratedClosure.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/GeneratedClosure.java @@ -1,23 +1,28 @@ package org.zwobble.couscous.frontends.java; +import com.google.common.collect.ImmutableList; import org.zwobble.couscous.ast.ClassNode; import org.zwobble.couscous.ast.ConstructorCallNode; import org.zwobble.couscous.ast.ExpressionNode; import org.zwobble.couscous.ast.ReferenceNode; import org.zwobble.couscous.types.ScalarType; +import org.zwobble.couscous.types.TypeParameter; import org.zwobble.couscous.util.InsertionOrderSet; import static org.zwobble.couscous.ast.ConstructorCallNode.constructorCall; +import static org.zwobble.couscous.types.Types.addTypeParameters; import static org.zwobble.couscous.util.ExtraLists.concat; import static org.zwobble.couscous.util.ExtraLists.list; public class GeneratedClosure { private final ClassNode classNode; - private final InsertionOrderSet<ReferenceNode> captures; + private final InsertionOrderSet<TypeParameter> capturedTypes; + private final InsertionOrderSet<ReferenceNode> capturedVariables; - public GeneratedClosure(ClassNode classNode, InsertionOrderSet<ReferenceNode> captures) { + public GeneratedClosure(ClassNode classNode, InsertionOrderSet<TypeParameter> capturedTypes, InsertionOrderSet<ReferenceNode> capturedVariables) { this.classNode = classNode; - this.captures = captures; + this.capturedTypes = capturedTypes; + this.capturedVariables = capturedVariables; } public ClassNode getClassNode() { @@ -30,8 +35,9 @@ public class GeneratedClosure { public ConstructorCallNode generateConstructor(Iterable<ExpressionNode> arguments) { return constructorCall( - getType(), - concat(captures, arguments)); + // TODO: tidy up type parameters to avoid copy + addTypeParameters(getType(), ImmutableList.copyOf(capturedTypes.asList())), + concat(capturedVariables, arguments)); } private ScalarType getType() { diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java index 8353dac..e096429 100644 --- a/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java +++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java @@ -11,7 +11,7 @@ import org.zwobble.couscous.ast.sugar.AnonymousClass; import org.zwobble.couscous.ast.sugar.Lambda; import org.zwobble.couscous.ast.sugar.TypeDeclarationBody; import org.zwobble.couscous.ast.visitors.NodeTransformer; -import org.zwobble.couscous.types.ScalarType; +import org.zwobble.couscous.types.*; import org.zwobble.couscous.types.Type; import org.zwobble.couscous.util.ExtraLists; import org.zwobble.couscous.util.InsertionOrderSet; @@ -40,6 +40,7 @@ import static org.zwobble.couscous.ast.ReturnNode.returns; import static org.zwobble.couscous.ast.StaticReceiver.staticReceiver; import static org.zwobble.couscous.ast.ThisReferenceNode.thisReference; import static org.zwobble.couscous.ast.VariableReferenceNode.reference; +import static org.zwobble.couscous.frontends.java.FreeVariables.findFreeTypeParameters; import static org.zwobble.couscous.frontends.java.FreeVariables.findFreeVariables; import static org.zwobble.couscous.frontends.java.JavaMethods.signature; import static org.zwobble.couscous.frontends.java.JavaTypes.*; @@ -257,6 +258,9 @@ public class JavaReader { Scope scope, ClassNode classNode ) { + InsertionOrderSet<org.zwobble.couscous.types.TypeParameter> freeTypeParameters = InsertionOrderSet.copyOf( + findFreeTypeParameters(classNode)); + InsertionOrderSet<ReferenceNode> freeVariables = InsertionOrderSet.copyOf(Iterables.filter( findFreeVariables(ExtraLists.concat( classNode.getFields(), @@ -278,14 +282,15 @@ public class JavaReader { ClassNode generatedClass = new ClassNode( classNode.getName(), - classNode.getTypeParameters(), + // TODO: generate fresh type parameter and replace in body + ExtraLists.concat(lazyMap(freeTypeParameters, parameter -> formalTypeParameter(parameter)), classNode.getTypeParameters()), classNode.getSuperTypes(), fields, list(), buildConstructor(scope, classNode.getName(), capturedVariables, classNode.getConstructor()), eagerMap(classNode.getMethods(), method -> method.mapBody(body -> replaceCaptureReferences(classNode.getName(), body, capturedVariables)))); - return new GeneratedClosure(generatedClass, freeVariables); + return new GeneratedClosure(generatedClass, freeTypeParameters, freeVariables); } private boolean isThisReference(ScalarType name, ReferenceNode reference) { diff --git a/src/main/java/org/zwobble/couscous/types/Types.java b/src/main/java/org/zwobble/couscous/types/Types.java index 505d9a7..5338eb3 100644 --- a/src/main/java/org/zwobble/couscous/types/Types.java +++ b/src/main/java/org/zwobble/couscous/types/Types.java @@ -1,7 +1,9 @@ package org.zwobble.couscous.types; +import java.util.List; import java.util.Map; +import static org.zwobble.couscous.types.ParameterizedType.parameterizedType; import static org.zwobble.couscous.util.ExtraLists.eagerMap; import static org.zwobble.couscous.util.ExtraLists.list; @@ -16,6 +18,14 @@ public class Types { public static final ScalarType BOXED_BOOLEAN = ScalarType.of("java.lang.Boolean"); public static final ScalarType ARRAY = ScalarType.of("array"); + public static Type addTypeParameters(ScalarType rawType, List<Type> typeParameters) { + if (typeParameters.isEmpty()) { + return rawType; + } else { + return parameterizedType(rawType, typeParameters); + } + } + public static Type array(Type elementType) { return new ParameterizedType(ARRAY, list(elementType)); } |
