aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2015-11-28 19:43:34 +0000
committerMichael Williamson <mike@zwobble.org>2015-11-28 19:43:34 +0000
commit5cda2705b321cbea53249e181921195326c5fd55 (patch)
treea04f24d41daca7d5fb27dd0368b778a6f7e5ca7d /src/main
parent05867c4658abaa0fc7ca7c0139e2cae4522e7057 (diff)
Simplify generation of anonymous classes
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/org/zwobble/couscous/ast/CallableNode.java1
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ClassNode.java1
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java21
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ConstructorNode.java8
-rw-r--r--src/main/java/org/zwobble/couscous/ast/MethodNode.java5
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java97
-rw-r--r--src/main/java/org/zwobble/couscous/util/ExtraLists.java23
7 files changed, 107 insertions, 49 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/CallableNode.java b/src/main/java/org/zwobble/couscous/ast/CallableNode.java
index 79d2e84..6d6fc7b 100644
--- a/src/main/java/org/zwobble/couscous/ast/CallableNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/CallableNode.java
@@ -5,5 +5,4 @@ import java.util.List;
public interface CallableNode extends Node {
List<FormalArgumentNode> getArguments();
List<StatementNode> getBody();
-
}
diff --git a/src/main/java/org/zwobble/couscous/ast/ClassNode.java b/src/main/java/org/zwobble/couscous/ast/ClassNode.java
index c252bb3..55453f4 100644
--- a/src/main/java/org/zwobble/couscous/ast/ClassNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ClassNode.java
@@ -8,7 +8,6 @@ public class ClassNode implements Node {
public static ClassNodeBuilder builder(String name) {
return new ClassNodeBuilder(name);
}
-
public static ClassNode declareClass(
TypeName name,
List<FieldDeclarationNode> fields,
diff --git a/src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java b/src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java
index 75aa5a3..5981e34 100644
--- a/src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java
+++ b/src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java
@@ -13,12 +13,17 @@ public class ClassNodeBuilder {
private final ImmutableList.Builder<FieldDeclarationNode> fields;
private Optional<ConstructorNode> constructor;
private final ImmutableList.Builder<MethodNode> methods;
-
- public ClassNodeBuilder(String name) {
- this.name = TypeName.of(name);
+
+ public ClassNodeBuilder(TypeName name) {
+ this.name = name;
this.fields = ImmutableList.builder();
this.constructor = Optional.empty();
this.methods = ImmutableList.builder();
+
+ }
+
+ public ClassNodeBuilder(String name) {
+ this(TypeName.of(name));
}
public ClassNodeBuilder field(String name, TypeName type) {
@@ -30,14 +35,6 @@ public class ClassNodeBuilder {
return this;
}
- public ClassNodeBuilder callable(CallableNode callable) {
- if (callable instanceof ConstructorNode) {
- return constructor((ConstructorNode) callable);
- } else {
- return method((MethodNode) callable);
- }
- }
-
public ClassNodeBuilder constructor(ConstructorNode constructor) {
this.constructor = Optional.of(constructor);
return this;
@@ -85,7 +82,7 @@ public class ClassNodeBuilder {
return ClassNode.declareClass(
name,
fields.build(),
- constructor.orElse(constructorBuilder().build()),
+ constructor.orElse(ConstructorNode.DEFAULT),
methods.build());
}
diff --git a/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java b/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java
index 2e8b85a..0d4bad8 100644
--- a/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ConstructorNode.java
@@ -1,11 +1,13 @@
package org.zwobble.couscous.ast;
-import java.util.List;
-
import org.zwobble.couscous.ast.visitors.NodeMapper;
-import org.zwobble.couscous.ast.visitors.NodeVisitor;
+
+import java.util.Collections;
+import java.util.List;
public class ConstructorNode implements CallableNode {
+ public static final ConstructorNode DEFAULT = constructor(Collections.emptyList(), Collections.emptyList());
+
public static ConstructorNode constructor(
List<FormalArgumentNode> arguments,
List<StatementNode> body) {
diff --git a/src/main/java/org/zwobble/couscous/ast/MethodNode.java b/src/main/java/org/zwobble/couscous/ast/MethodNode.java
index 3e97a36..5763b11 100644
--- a/src/main/java/org/zwobble/couscous/ast/MethodNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/MethodNode.java
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
import org.zwobble.couscous.ast.visitors.NodeMapper;
import java.util.List;
+import java.util.function.Function;
public class MethodNode implements CallableNode {
public static Builder staticMethod(String name) {
@@ -115,6 +116,10 @@ public class MethodNode implements CallableNode {
return body;
}
+ public MethodNode mapBody(Function<List<StatementNode>, List<StatementNode>> function) {
+ return new MethodNode(annotations, isStatic, name, arguments, function.apply(body));
+ }
+
@Override
public <T> T accept(NodeMapper<T> visitor) {
return visitor.visit(this);
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 c8dc854..04ee748 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java
@@ -43,7 +43,12 @@ public class JavaReader {
private ClassNode readCompilationUnit(CompilationUnit ast) {
String name = generateClassName(ast);
TypeDeclaration type = (TypeDeclaration)ast.types().get(0);
- return readTypeDeclarationBody(name, type.bodyDeclarations());
+ TypeDeclarationBody body = readTypeDeclarationBody(type.bodyDeclarations());
+ return ClassNode.declareClass(
+ TypeName.of(name),
+ body.getFields(),
+ body.getConstructor(),
+ body.getMethods());
}
GeneratedClosure readLambda(LambdaExpression expression) {
@@ -105,23 +110,19 @@ public class JavaReader {
GeneratedClosure readAnonymousClass(AnonymousClassDeclaration declaration) {
String className = generateClassName(declaration);
- ClassNode classNode = readTypeDeclarationBody(className, declaration.bodyDeclarations());
- List<VariableDeclaration> freeVariables = findFreeVariables(asList(classNode));
+ TypeDeclarationBody bodyDeclarations = readTypeDeclarationBody(declaration.bodyDeclarations());
+ List<VariableDeclaration> freeVariables = findFreeVariables(bodyDeclarations.getNodes());
List<StatementNode> restoreCaptures = generateCaptureRestoration(className, freeVariables);
- // TODO: map over methods rather than rebuilding entire class
- ClassNodeBuilder classBuilder = new ClassNodeBuilder(className);
- classBuilder.constructor(buildConstructor(TypeName.of(className), freeVariables));
- classNode.getFields().forEach(classBuilder::field);
- classNode.getMethods().forEach(method ->
- classBuilder.method(MethodNode.method(
- method.getAnnotations(),
- method.isStatic(),
- method.getName(),
- method.getArguments(),
- concat(restoreCaptures, method.getBody()))));
-
- classes.add(classBuilder.build());
+ List<MethodNode> methods = eagerMap(bodyDeclarations.getMethods(), method ->
+ method.mapBody(body -> concat(restoreCaptures, body)));
+
+ ClassNode classNode = ClassNode.declareClass(
+ TypeName.of(className),
+ bodyDeclarations.getFields(),
+ buildConstructor(TypeName.of(className), freeVariables),
+ methods);
+ classes.add(classNode);
return new GeneratedClosure(classNode.getName(), freeVariables);
}
@@ -137,25 +138,61 @@ public class JavaReader {
return type.getQualifiedName() + "_Anonymous_" + (anonymousClassCount++);
}
- private ClassNode readTypeDeclarationBody(String name, List<Object> bodyDeclarations) {
- ClassNodeBuilder classBuilder = new ClassNodeBuilder(name);
- readFields(ofType(bodyDeclarations, FieldDeclaration.class), classBuilder);
- readMethods(ofType(bodyDeclarations, MethodDeclaration.class))
- .forEach(classBuilder::callable);
- return classBuilder.build();
- }
+ private static class TypeDeclarationBody {
+ private final List<FieldDeclarationNode> fields;
+ private final ConstructorNode constructor;
+ private final List<MethodNode> methods;
+
+ public TypeDeclarationBody(List<FieldDeclarationNode> fields, ConstructorNode constructor, List<MethodNode> methods) {
+ this.fields = fields;
+ this.constructor = constructor;
+ this.methods = methods;
+ }
+
+ public List<FieldDeclarationNode> getFields() {
+ return fields;
+ }
+
+ public ConstructorNode getConstructor() {
+ return constructor;
+ }
- private void readFields(List<FieldDeclaration> fields, ClassNodeBuilder classBuilder) {
- for (FieldDeclaration field : fields) {
- readField(field, classBuilder);
+ public List<MethodNode> getMethods() {
+ return methods;
+ }
+
+ public List<Node> getNodes() {
+ return concat(fields, asList(constructor), methods);
}
}
- private void readField(FieldDeclaration field, ClassNodeBuilder classBuilder) {
- for (Object fragment : field.fragments()) {
- String name = ((VariableDeclarationFragment)fragment).getName().getIdentifier();
- classBuilder.field(name, typeOf(field.getType()));
+ private TypeDeclarationBody readTypeDeclarationBody(List<Object> bodyDeclarations) {
+ ImmutableList.Builder<MethodNode> methods = ImmutableList.builder();
+ ConstructorNode constructor = ConstructorNode.DEFAULT;
+
+ for (CallableNode callable : readMethods(ofType(bodyDeclarations, MethodDeclaration.class))) {
+ if (callable instanceof ConstructorNode) {
+ constructor = (ConstructorNode) callable;
+ } else {
+ methods.add((MethodNode) callable);
+ }
}
+ return new TypeDeclarationBody(
+ readFields(ofType(bodyDeclarations, FieldDeclaration.class)),
+ constructor,
+ methods.build());
+ }
+
+ private List<FieldDeclarationNode> readFields(List<FieldDeclaration> fields) {
+ return eagerFlatMap(fields, this::readField);
+ }
+
+ private List<FieldDeclarationNode> readField(FieldDeclaration field) {
+ @SuppressWarnings("unchecked")
+ List<VariableDeclarationFragment> fragments = field.fragments();
+ TypeName type = typeOf(field.getType());
+ return eagerMap(fragments, fragment ->
+ FieldDeclarationNode.field(fragment.getName().getIdentifier(), type));
}
private List<CallableNode> readMethods(List<MethodDeclaration> methods) {
diff --git a/src/main/java/org/zwobble/couscous/util/ExtraLists.java b/src/main/java/org/zwobble/couscous/util/ExtraLists.java
index de28f21..e0c183a 100644
--- a/src/main/java/org/zwobble/couscous/util/ExtraLists.java
+++ b/src/main/java/org/zwobble/couscous/util/ExtraLists.java
@@ -2,6 +2,7 @@ package org.zwobble.couscous.util;
import java.util.List;
import java.util.function.Function;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@@ -15,10 +16,14 @@ public class ExtraLists {
return Stream.concat(list.stream(), Stream.of(value)).collect(Collectors.toList());
}
- public static <T> List<T> concat(List<T> first, List<T> second) {
+ public static <T> List<T> concat(List<? extends T> first, List<? extends T> second) {
return Stream.concat(first.stream(), second.stream()).collect(Collectors.toList());
}
+ public static <T> List<T> concat(List<? extends T> first, List<? extends T> second, List<? extends T> third) {
+ return Stream.concat(Stream.concat(first.stream(), second.stream()), third.stream()).collect(Collectors.toList());
+ }
+
@SuppressWarnings("unchecked")
public static <T, R extends T> List<R> ofType(List<T> list, Class<R> clazz) {
return (List<R>)list.stream()
@@ -44,7 +49,13 @@ public class ExtraLists {
throw (E)exception.exception;
}
}
-
+
+ public static <T> List<T> eagerFilter(Iterable<T> iterable, Predicate<T> predicate) {
+ return StreamSupport.stream(iterable.spliterator(), false)
+ .filter(predicate)
+ .collect(Collectors.toList());
+ }
+
public static <T, R> List<R> eagerMap(
Iterable<T> iterable,
Function<T, R> function) {
@@ -52,6 +63,14 @@ public class ExtraLists {
.map(function)
.collect(Collectors.toList());
}
+
+ public static <T, R> List<R> eagerFlatMap(
+ Iterable<T> iterable,
+ Function<T, Iterable<R>> function) {
+ return StreamSupport.stream(iterable.spliterator(), false)
+ .flatMap(element -> StreamSupport.stream(function.apply(element).spliterator(), false))
+ .collect(Collectors.toList());
+ }
@FunctionalInterface
public interface CheckedFunction<T, R, E extends Exception> {