aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/zwobble/couscous/frontends
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/frontends
parent62ea20e20ed1c0d6b2564f8fff862d380da15fce (diff)
Defer generation of classes for lambdas
Diffstat (limited to 'src/main/java/org/zwobble/couscous/frontends')
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/AnonymousType.java6
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java4
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java13
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java91
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/Scope.java4
5 files changed, 36 insertions, 82 deletions
diff --git a/src/main/java/org/zwobble/couscous/frontends/java/AnonymousType.java b/src/main/java/org/zwobble/couscous/frontends/java/AnonymousType.java
index 5d5915d..4adf7ab 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/AnonymousType.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/AnonymousType.java
@@ -15,6 +15,10 @@ public class AnonymousType implements Type {
this.key = key;
}
+ public String getKey() {
+ return key;
+ }
+
@Override
public <T> T accept(Visitor<T> visitor) {
throw new UnsupportedOperationException();
@@ -22,7 +26,7 @@ public class AnonymousType implements Type {
@Override
public Type transformSubTypes(Function<Type, Type> transform) {
- throw new UnsupportedOperationException();
+ return this;
}
@Override
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 7679431..7917a49 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/FreeVariables.java
@@ -59,6 +59,10 @@ public class FreeVariables {
public Stream<TypeParameter> visit(MethodNode methodNode) {
return methodNode.getTypeParameters().stream().map(parameter -> parameter.getType());
}
+
+ public Stream<TypeParameter> visit(ClassNode classNode) {
+ return classNode.getTypeParameters().stream().map(parameter -> parameter.getType());
+ }
}
public static Set<TypeParameter> findFreeTypeParameters(Node root) {
diff --git a/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java b/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java
index 747bcac..caeb8aa 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaExpressionReader.java
@@ -281,9 +281,7 @@ public class JavaExpressionReader {
ITypeBinding declaringClass = constructor.getDeclaringClass();
if (declaringClass.isAnonymous()) {
- GeneratedClosure closure =
- javaReader.readAnonymousClass(scope, expression.getAnonymousClassDeclaration());
- return closure.generateConstructor(arguments);
+ return javaReader.readAnonymousClass(scope, expression.getAnonymousClassDeclaration());
} else {
if (expression.getExpression() != null) {
throw new UnsupportedOperationException();
@@ -293,18 +291,15 @@ public class JavaExpressionReader {
}
private ExpressionNode readLambdaExpression(LambdaExpression expression) {
- GeneratedClosure closure = javaReader.readLambda(scope, expression);
- return closure.generateConstructor();
+ return javaReader.readLambda(scope, expression);
}
private ExpressionNode readExpressionMethodReference(ExpressionMethodReference expression) {
- GeneratedClosure closure = javaReader.readExpressionMethodReference(scope, expression);
- return closure.generateConstructor();
+ return javaReader.readExpressionMethodReference(scope, expression);
}
private ExpressionNode readCreationReference(CreationReference expression) {
- GeneratedClosure closure = javaReader.readCreationReference(scope, expression);
- return closure.generateConstructor();
+ return javaReader.readCreationReference(scope, expression);
}
private List<ExpressionNode> readArguments(IMethodBinding method, List<Expression> javaArguments) {
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 4acea74..6553b91 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java
@@ -8,8 +8,6 @@ import org.zwobble.couscous.ast.identifiers.Identifier;
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.transforms.ClosureGenerator;
import org.zwobble.couscous.types.ScalarType;
import org.zwobble.couscous.types.Type;
import org.zwobble.couscous.util.ExtraLists;
@@ -39,8 +37,8 @@ import static org.zwobble.couscous.frontends.java.JavaMethods.signature;
import static org.zwobble.couscous.frontends.java.JavaTypes.*;
import static org.zwobble.couscous.types.Types.erasure;
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;
public class JavaReader {
public static List<TypeNode> readClassesFromFiles(List<Path> sourcePaths, List<Path> sourceFiles) throws IOException {
@@ -143,32 +141,30 @@ public class JavaReader {
parameter -> formalTypeParameter(declaringScope, parameter.getName()));
}
- GeneratedClosure readExpressionMethodReference(Scope outerScope, ExpressionMethodReference expression) {
+ AnonymousClass readExpressionMethodReference(Scope outerScope, ExpressionMethodReference expression) {
return readLambda(
outerScope,
expression,
scope -> new JavaMethodReferenceReader(this).toLambda(scope, expression));
}
- GeneratedClosure readCreationReference(Scope outerScope, CreationReference expression) {
+ AnonymousClass readCreationReference(Scope outerScope, CreationReference expression) {
return readLambda(
outerScope,
expression,
scope -> new JavaMethodReferenceReader(this).toLambda(scope, expression));
}
- GeneratedClosure readLambda(Scope outerScope, LambdaExpression expression) {
+ AnonymousClass readLambda(Scope outerScope, LambdaExpression expression) {
return readLambda(
outerScope,
expression,
scope -> new JavaLambdaExpressionReader(this).toLambda(scope, expression));
}
- private GeneratedClosure readLambda(Scope outerScope, Expression expression, Function<Scope, Lambda> lambda) {
- ScalarType name = generateAnonymousName(expression);
- Scope scope = outerScope.enterClass(name);
+ private AnonymousClass readLambda(Scope outerScope, Expression expression, Function<Scope, Lambda> lambda) {
IMethodBinding functionalInterfaceMethod = expression.resolveTypeBinding().getFunctionalInterfaceMethod();
- return generateClosure(scope, name, toAnonymousClass(functionalInterfaceMethod, lambda.apply(scope)));
+ return toAnonymousClass(functionalInterfaceMethod, lambda.apply(outerScope));
}
private AnonymousClass toAnonymousClass(IMethodBinding functionalInterfaceMethod, Lambda lambda) {
@@ -186,74 +182,24 @@ public class JavaReader {
return new AnonymousClass(
Optional.empty(),
- superTypesAndSelf(functionalInterfaceMethod.getDeclaringClass()),
+ only(superTypesAndSelf(functionalInterfaceMethod.getDeclaringClass())),
list(),
list(method));
}
- GeneratedClosure readAnonymousClass(Scope outerScope, AnonymousClassDeclaration declaration) {
- ScalarType className = generateAnonymousName(declaration);
- Scope scope = outerScope.enterClass(className);
- TypeDeclarationBody bodyDeclarations = readTypeDeclarationBody(scope, className, declaration.bodyDeclarations(), false);
- AnonymousClass anonymousClass = new AnonymousClass(
- Optional.of((AnonymousType) typeOf(declaration.resolveBinding())),
- superTypes(declaration),
+ AnonymousClass readAnonymousClass(Scope outerScope, AnonymousClassDeclaration declaration) {
+ AnonymousType type = (AnonymousType) typeOf(declaration.resolveBinding());
+ Scope scope = outerScope.enterType(type);
+ TypeDeclarationBody bodyDeclarations = readTypeDeclarationBody(scope, type, declaration.bodyDeclarations(), false);
+ return new AnonymousClass(
+ Optional.of(type),
+ only(superTypes(declaration)),
bodyDeclarations.getFields(),
- bodyDeclarations.getMethods());
- return generateClosure(scope, className, anonymousClass);
- }
-
- GeneratedClosure generateClosure(Scope scope, ScalarType className, AnonymousClass anonymousClass) {
- GeneratedClosure closure = classWithCapture(scope, className, anonymousClass);
- classes.add(closure.getClassNode());
- return closure;
- }
-
- private GeneratedClosure classWithCapture(
- Scope scope,
- ScalarType className,
- AnonymousClass anonymousClass
- ) {
- ClassNode classNode = ClassNode.declareClass(
- className,
- list(),
- anonymousClass.getSuperTypes(),
- anonymousClass.getFields(),
- list(),
- ConstructorNode.DEFAULT,
- anonymousClass.getMethods(),
- list()
+ bodyDeclarations.getMethods()
);
- if (anonymousClass.getType().isPresent()) {
- NodeTransformer nodeTransformer = NodeTransformer.replaceExpressions(map(
- thisReference(anonymousClass.getType().get()),
- thisReference(className)
- ));
- classNode = nodeTransformer.transformClass(classNode);
- }
- return ClosureGenerator.classWithCapture(scope, classNode);
- }
-
- private ScalarType generateAnonymousName(ASTNode node) {
- ITypeBinding type = findDeclaringClass(node);
- while (type.isAnonymous()) {
- type = type.getDeclaringClass();
- }
- ScalarType typeName = erasure(typeOf(type));
- while (typeName.outerType().isPresent()) {
- typeName = typeName.outerType().get();
- }
- return ScalarType.topLevel(typeName.getQualifiedName() + "_Anonymous_" + (anonymousClassCount++));
- }
-
- private ITypeBinding findDeclaringClass(ASTNode node) {
- while (!(node instanceof AbstractTypeDeclaration)) {
- node = node.getParent();
- }
- return ((AbstractTypeDeclaration)node).resolveBinding();
}
- private TypeDeclarationBody readTypeDeclarationBody(Scope scope, ScalarType type, List<Object> bodyDeclarations, boolean isInterface) {
+ private TypeDeclarationBody readTypeDeclarationBody(Scope scope, Type type, List<Object> bodyDeclarations, boolean isInterface) {
TypeDeclarationBody.Builder body = TypeDeclarationBody.builder();
for (Object declaration : bodyDeclarations) {
@@ -274,7 +220,7 @@ public class JavaReader {
return body.build();
}
- private void readField(TypeDeclarationBody.Builder builder, Scope scope, ScalarType declaringType, FieldDeclaration field, boolean isInterface) {
+ private void readField(TypeDeclarationBody.Builder builder, Scope scope, Type declaringType, FieldDeclaration field, boolean isInterface) {
@SuppressWarnings("unchecked")
List<VariableDeclarationFragment> fragments = field.fragments();
boolean isStatic = isInterface || Modifier.isStatic(field.getModifiers());
@@ -284,8 +230,9 @@ public class JavaReader {
if (fragment.getInitializer() != null) {
ExpressionNode value = readExpression(scope, type, fragment.getInitializer());
String name = fragment.getName().getIdentifier();
+ // TODO: support static values for anonymous classes
Receiver receiver = isStatic
- ? staticReceiver(declaringType)
+ ? staticReceiver((ScalarType)declaringType)
: instanceReceiver(thisReference(declaringType));
StatementNode assignment = assignStatement(fieldAccess(receiver, name, type), value);
diff --git a/src/main/java/org/zwobble/couscous/frontends/java/Scope.java b/src/main/java/org/zwobble/couscous/frontends/java/Scope.java
index d4af1f5..0ee9148 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/Scope.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/Scope.java
@@ -51,6 +51,10 @@ public class Scope {
return enter(identifier.type(className.getQualifiedName()));
}
+ public Scope enterType(AnonymousType type) {
+ return enter(identifier.type(type.getKey()));
+ }
+
public Scope enterConstructor() {
return enter(identifier.constructor());
}