aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2016-03-08 11:01:29 +0000
committerMichael Williamson <mike@zwobble.org>2016-03-08 11:01:29 +0000
commit95669601271985c89a10d673571dd89133f1e2e8 (patch)
tree866d294696522f721cab97b8a1fb020945cf1d75
parentc532706e0f20a07be960e4d2ca4d89d850312174 (diff)
Read formal type parameters
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ClassNode.java57
-rw-r--r--src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java9
-rw-r--r--src/main/java/org/zwobble/couscous/ast/FormalTypeParameterNode.java43
-rw-r--r--src/main/java/org/zwobble/couscous/ast/InterfaceNode.java32
-rw-r--r--src/main/java/org/zwobble/couscous/ast/TypeNode.java1
-rw-r--r--src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java13
-rw-r--r--src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java1
-rw-r--r--src/test/java/org/zwobble/couscous/tests/backends/csharp/CsharpSerializerTests.java12
-rw-r--r--src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java24
9 files changed, 157 insertions, 35 deletions
diff --git a/src/main/java/org/zwobble/couscous/ast/ClassNode.java b/src/main/java/org/zwobble/couscous/ast/ClassNode.java
index bdb3499..745fb64 100644
--- a/src/main/java/org/zwobble/couscous/ast/ClassNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/ClassNode.java
@@ -15,16 +15,19 @@ public class ClassNode implements TypeNode {
}
public static ClassNode declareClass(
- TypeName name,
- Set<TypeName> superTypes,
- List<FieldDeclarationNode> fields,
- List<StatementNode> staticConstructor,
- ConstructorNode constructor,
- List<MethodNode> methods) {
- return new ClassNode(name, superTypes, fields, staticConstructor, constructor, methods);
+ TypeName name,
+ List<FormalTypeParameterNode> typeParameters,
+ Set<TypeName> superTypes,
+ List<FieldDeclarationNode> fields,
+ List<StatementNode> staticConstructor,
+ ConstructorNode constructor,
+ List<MethodNode> methods)
+ {
+ return new ClassNode(name, typeParameters, superTypes, fields, staticConstructor, constructor, methods);
}
private final TypeName name;
+ private final List<FormalTypeParameterNode> typeParameters;
private final Set<TypeName> superTypes;
private final List<FieldDeclarationNode> fields;
private final List<StatementNode> staticConstructor;
@@ -33,6 +36,7 @@ public class ClassNode implements TypeNode {
public ClassNode(
TypeName name,
+ List<FormalTypeParameterNode> typeParameters,
Set<TypeName> superTypes,
List<FieldDeclarationNode> fields,
List<StatementNode> staticConstructor,
@@ -40,6 +44,7 @@ public class ClassNode implements TypeNode {
List<MethodNode> methodNodes)
{
this.name = name;
+ this.typeParameters = typeParameters;
this.superTypes = superTypes;
this.fields = fields;
this.staticConstructor = staticConstructor;
@@ -53,6 +58,11 @@ public class ClassNode implements TypeNode {
}
@Override
+ public List<FormalTypeParameterNode> getTypeParameters() {
+ return typeParameters;
+ }
+
+ @Override
public Set<TypeName> getSuperTypes() {
return superTypes;
}
@@ -87,13 +97,30 @@ public class ClassNode implements TypeNode {
public ClassNode transform(NodeTransformer transformer) {
return new ClassNode(
transformer.transform(name),
+ // TODO: transform
+ typeParameters,
transformer.transformTypes(superTypes),
transformer.transformFields(fields),
- staticConstructor, transformer.transformConstructor(constructor),
+ // TODO: transform
+ staticConstructor,
+ transformer.transformConstructor(constructor),
transformer.transformMethods(methods));
}
@Override
+ public String toString() {
+ return "ClassNode(" +
+ "name=" + name +
+ ", typeParameters=" + typeParameters +
+ ", superTypes=" + superTypes +
+ ", fields=" + fields +
+ ", staticConstructor=" + staticConstructor +
+ ", constructor=" + constructor +
+ ", methods=" + methods +
+ ')';
+ }
+
+ @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@@ -101,6 +128,7 @@ public class ClassNode implements TypeNode {
ClassNode classNode = (ClassNode) o;
if (!name.equals(classNode.name)) return false;
+ if (!typeParameters.equals(classNode.typeParameters)) return false;
if (!superTypes.equals(classNode.superTypes)) return false;
if (!fields.equals(classNode.fields)) return false;
if (!staticConstructor.equals(classNode.staticConstructor)) return false;
@@ -112,6 +140,7 @@ public class ClassNode implements TypeNode {
@Override
public int hashCode() {
int result = name.hashCode();
+ result = 31 * result + typeParameters.hashCode();
result = 31 * result + superTypes.hashCode();
result = 31 * result + fields.hashCode();
result = 31 * result + staticConstructor.hashCode();
@@ -119,16 +148,4 @@ public class ClassNode implements TypeNode {
result = 31 * result + methods.hashCode();
return result;
}
-
- @Override
- public String toString() {
- return "ClassNode(" +
- "name=" + name +
- ", superTypes=" + superTypes +
- ", fields=" + fields +
- ", staticConstructor=" + staticConstructor +
- ", constructor=" + constructor +
- ", methods=" + methods +
- ')';
- }
}
diff --git a/src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java b/src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java
index 04491ab..3a1b81b 100644
--- a/src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java
+++ b/src/main/java/org/zwobble/couscous/ast/ClassNodeBuilder.java
@@ -104,6 +104,7 @@ public class ClassNodeBuilder {
public ClassNode build() {
return ClassNode.declareClass(
name,
+ list(),
superTypes.build(),
fields.build(),
staticConstructor,
@@ -111,6 +112,14 @@ public class ClassNodeBuilder {
methods.build());
}
+ public InterfaceNode buildInterface() {
+ return InterfaceNode.declareInterface(
+ name,
+ list(),
+ superTypes.build(),
+ methods.build());
+ }
+
public class MethodBuilder<T> {
private final Function<MethodBuilder<?>, T> build;
private final ImmutableList.Builder<AnnotationNode> annotations;
diff --git a/src/main/java/org/zwobble/couscous/ast/FormalTypeParameterNode.java b/src/main/java/org/zwobble/couscous/ast/FormalTypeParameterNode.java
new file mode 100644
index 0000000..4056548
--- /dev/null
+++ b/src/main/java/org/zwobble/couscous/ast/FormalTypeParameterNode.java
@@ -0,0 +1,43 @@
+package org.zwobble.couscous.ast;
+
+import org.zwobble.couscous.ast.visitors.NodeMapper;
+
+public class FormalTypeParameterNode implements Node {
+ public static FormalTypeParameterNode formalTypeParameter(String name) {
+ return new FormalTypeParameterNode(name);
+ }
+
+ private final String name;
+
+ public FormalTypeParameterNode(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public <T> T accept(NodeMapper<T> visitor) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ return "FormalTypeParameterNode(" +
+ "name=" + name +
+ ')';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ FormalTypeParameterNode that = (FormalTypeParameterNode) o;
+
+ return name.equals(that.name);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+}
diff --git a/src/main/java/org/zwobble/couscous/ast/InterfaceNode.java b/src/main/java/org/zwobble/couscous/ast/InterfaceNode.java
index 854728f..6353a45 100644
--- a/src/main/java/org/zwobble/couscous/ast/InterfaceNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/InterfaceNode.java
@@ -9,22 +9,26 @@ import java.util.Set;
public class InterfaceNode implements TypeNode {
public static InterfaceNode declareInterface(
TypeName name,
+ List<FormalTypeParameterNode> typeParameters,
Set<TypeName> superTypes,
List<MethodNode> methods)
{
- return new InterfaceNode(name, superTypes, methods);
+ return new InterfaceNode(name, typeParameters, superTypes, methods);
}
private final TypeName name;
+ private final List<FormalTypeParameterNode> typeParameters;
private final Set<TypeName> superTypes;
private final List<MethodNode> methods;
private InterfaceNode(
TypeName name,
+ List<FormalTypeParameterNode> typeParameters,
Set<TypeName> superTypes,
List<MethodNode> methodNodes)
{
this.name = name;
+ this.typeParameters = typeParameters;
this.superTypes = superTypes;
methods = methodNodes;
}
@@ -35,6 +39,11 @@ public class InterfaceNode implements TypeNode {
}
@Override
+ public List<FormalTypeParameterNode> getTypeParameters() {
+ return typeParameters;
+ }
+
+ @Override
public Set<TypeName> getSuperTypes() {
return superTypes;
}
@@ -50,23 +59,26 @@ public class InterfaceNode implements TypeNode {
}
@Override
- public InterfaceNode transform(NodeTransformer transformer) {
- return new InterfaceNode(
- transformer.transform(name),
- transformer.transformTypes(superTypes),
- transformer.transformMethods(methods));
- }
-
- @Override
public String toString() {
return "InterfaceNode(" +
"name=" + name +
+ ", typeParameters=" + typeParameters +
", superTypes=" + superTypes +
", methods=" + methods +
')';
}
@Override
+ public InterfaceNode transform(NodeTransformer transformer) {
+ return new InterfaceNode(
+ transformer.transform(name),
+ // TODO: transform
+ typeParameters,
+ transformer.transformTypes(superTypes),
+ transformer.transformMethods(methods));
+ }
+
+ @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@@ -74,6 +86,7 @@ public class InterfaceNode implements TypeNode {
InterfaceNode that = (InterfaceNode) o;
if (!name.equals(that.name)) return false;
+ if (!typeParameters.equals(that.typeParameters)) return false;
if (!superTypes.equals(that.superTypes)) return false;
return methods.equals(that.methods);
@@ -82,6 +95,7 @@ public class InterfaceNode implements TypeNode {
@Override
public int hashCode() {
int result = name.hashCode();
+ result = 31 * result + typeParameters.hashCode();
result = 31 * result + superTypes.hashCode();
result = 31 * result + methods.hashCode();
return result;
diff --git a/src/main/java/org/zwobble/couscous/ast/TypeNode.java b/src/main/java/org/zwobble/couscous/ast/TypeNode.java
index 8277cda..e3a78af 100644
--- a/src/main/java/org/zwobble/couscous/ast/TypeNode.java
+++ b/src/main/java/org/zwobble/couscous/ast/TypeNode.java
@@ -7,6 +7,7 @@ import java.util.Set;
public interface TypeNode extends Node {
TypeName getName();
+ List<FormalTypeParameterNode> getTypeParameters();
Set<TypeName> getSuperTypes();
List<MethodNode> getMethods();
TypeNode transform(NodeTransformer transformer);
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 a071127..73cf749 100644
--- a/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java
+++ b/src/main/java/org/zwobble/couscous/frontends/java/JavaReader.java
@@ -25,6 +25,7 @@ import static org.zwobble.couscous.ast.AssignmentNode.assignStatement;
import static org.zwobble.couscous.ast.ConstructorNode.constructor;
import static org.zwobble.couscous.ast.FieldAccessNode.fieldAccess;
import static org.zwobble.couscous.ast.FieldDeclarationNode.field;
+import static org.zwobble.couscous.ast.FormalTypeParameterNode.formalTypeParameter;
import static org.zwobble.couscous.ast.InstanceReceiver.instanceReceiver;
import static org.zwobble.couscous.ast.StaticReceiver.staticReceiver;
import static org.zwobble.couscous.ast.ThisReferenceNode.thisReference;
@@ -82,14 +83,16 @@ public class JavaReader {
private TypeNode readTypeDeclaration(TypeDeclaration type) {
TypeName name = typeOf(type.resolveBinding());
Scope scope = topScope.enterClass(name);
+ List<FormalTypeParameterNode> typeParameters = readTypeParameters(type);
TypeDeclarationBody body = readTypeDeclarationBody(scope, name, type.bodyDeclarations());
Set<TypeName> superTypes = superTypes(type);
if (type.isInterface()) {
// TODO: throw exception if other parts of body are declared
- return InterfaceNode.declareInterface(name, superTypes, body.getMethods());
+ return InterfaceNode.declareInterface(name, typeParameters, superTypes, body.getMethods());
} else {
return ClassNode.declareClass(
name,
+ typeParameters,
superTypes,
body.getFields(),
body.getStaticConstructor(),
@@ -98,6 +101,12 @@ public class JavaReader {
}
}
+ private List<FormalTypeParameterNode> readTypeParameters(TypeDeclaration typeDeclaration) {
+ return eagerMap(
+ asList(typeDeclaration.resolveBinding().getTypeParameters()),
+ parameter -> formalTypeParameter(parameter.getName()));
+ }
+
GeneratedClosure readExpressionMethodReference(Scope outerScope, ExpressionMethodReference expression) {
return readLambda(
outerScope,
@@ -226,6 +235,7 @@ public class JavaReader {
ClassNode generatedClass = new ClassNode(
classNode.getName(),
+ classNode.getTypeParameters(),
classNode.getSuperTypes(),
fields,
list(),
@@ -248,6 +258,7 @@ public class JavaReader {
) {
return classWithCapture(scope, ClassNode.declareClass(
className,
+ list(),
anonymousClass.getSuperTypes(),
anonymousClass.getFields(),
list(),
diff --git a/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java b/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java
index 66a7a63..8e5d7c8 100644
--- a/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java
+++ b/src/test/java/org/zwobble/couscous/tests/ValueObjectTests.java
@@ -50,6 +50,7 @@ public class ValueObjectTests {
{FieldAccessNode.class},
{FieldDeclarationNode.class},
{FormalArgumentNode.class},
+ {FormalTypeParameterNode.class},
{IfStatementNode.class},
{InstanceReceiver.class},
{InterfaceNode.class},
diff --git a/src/test/java/org/zwobble/couscous/tests/backends/csharp/CsharpSerializerTests.java b/src/test/java/org/zwobble/couscous/tests/backends/csharp/CsharpSerializerTests.java
index 1cb7935..4964113 100644
--- a/src/test/java/org/zwobble/couscous/tests/backends/csharp/CsharpSerializerTests.java
+++ b/src/test/java/org/zwobble/couscous/tests/backends/csharp/CsharpSerializerTests.java
@@ -14,7 +14,6 @@ import static org.zwobble.couscous.ast.ExpressionStatementNode.expressionStateme
import static org.zwobble.couscous.ast.FieldAccessNode.fieldAccess;
import static org.zwobble.couscous.ast.FormalArgumentNode.formalArg;
import static org.zwobble.couscous.ast.IfStatementNode.ifStatement;
-import static org.zwobble.couscous.ast.InterfaceNode.declareInterface;
import static org.zwobble.couscous.ast.LiteralNode.literal;
import static org.zwobble.couscous.ast.LocalVariableDeclarationNode.localVariableDeclaration;
import static org.zwobble.couscous.ast.MethodCallNode.methodCall;
@@ -27,7 +26,6 @@ import static org.zwobble.couscous.ast.VariableDeclaration.var;
import static org.zwobble.couscous.ast.VariableReferenceNode.reference;
import static org.zwobble.couscous.ast.WhileNode.whileLoop;
import static org.zwobble.couscous.util.ExtraLists.list;
-import static org.zwobble.couscous.util.ExtraSets.set;
public class CsharpSerializerTests {
@Test
@@ -317,7 +315,7 @@ public class CsharpSerializerTests {
@Test
public void interfaceIsInNamespace() {
- Node node = declareInterface(TypeName.of("com.example.Example"), set(), list());
+ Node node = new ClassNodeBuilder(TypeName.of("com.example.Example")).buildInterface();
String output = serialize(node);
@@ -326,7 +324,9 @@ public class CsharpSerializerTests {
@Test
public void interfaceWithSuperTypes() {
- Node node = declareInterface(TypeName.of("com.example.Example"), set(TypeName.of("com.example.Base")), list());
+ Node node = new ClassNodeBuilder(TypeName.of("com.example.Example"))
+ .addSuperType("com.example.Base")
+ .buildInterface();
String output = serialize(node);
@@ -336,7 +336,9 @@ public class CsharpSerializerTests {
@Test
public void interfaceWithMethod() {
MethodNode method = MethodNode.builder("get").isAbstract().returns(IntegerValue.REF).build();
- Node node = declareInterface(TypeName.of("com.example.Example"), set(), list(method));
+ Node node = new ClassNodeBuilder(TypeName.of("com.example.Example"))
+ .method(method)
+ .buildInterface();
String output = serialize(node);
diff --git a/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java b/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java
index f7016ff..4694f85 100644
--- a/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java
+++ b/src/test/java/org/zwobble/couscous/tests/frontends/java/JavaReaderTests.java
@@ -17,6 +17,7 @@ import static org.zwobble.couscous.ast.AssignmentNode.assign;
import static org.zwobble.couscous.ast.AssignmentNode.assignStatement;
import static org.zwobble.couscous.ast.ExpressionStatementNode.expressionStatement;
import static org.zwobble.couscous.ast.FieldAccessNode.fieldAccess;
+import static org.zwobble.couscous.ast.FormalTypeParameterNode.formalTypeParameter;
import static org.zwobble.couscous.ast.IfStatementNode.ifStatement;
import static org.zwobble.couscous.ast.LiteralNode.literal;
import static org.zwobble.couscous.ast.LocalVariableDeclarationNode.localVariableDeclaration;
@@ -311,6 +312,29 @@ public class JavaReaderTests {
assertEquals(TypeName.of("com.example.Example"), classNode.getName());
assertEquals(list(), classNode.getMethods());
assertEquals(set(), classNode.getSuperTypes());
+ assertEquals(list(), classNode.getTypeParameters());
+ }
+
+ @Test
+ public void canReadClassWithGenericTypeParameters() {
+ String source = "package com.example;" +
+ "public class Example<T> {}";
+ List<TypeNode> classes = readSource("com/example/Example.java", source);
+ assertThat(classes, hasSize(1));
+ ClassNode classNode = (ClassNode) classes.get(0);
+ assertEquals(TypeName.of("com.example.Example"), classNode.getName());
+ assertEquals(list(formalTypeParameter("T")), classNode.getTypeParameters());
+ }
+
+ @Test
+ public void canReadInterfaceWithGenericTypeParameters() {
+ String source = "package com.example;" +
+ "public interface Example<T> {}";
+ List<TypeNode> classes = readSource("com/example/Example.java", source);
+ assertThat(classes, hasSize(1));
+ InterfaceNode classNode = (InterfaceNode) classes.get(0);
+ assertEquals(TypeName.of("com.example.Example"), classNode.getName());
+ assertEquals(list(formalTypeParameter("T")), classNode.getTypeParameters());
}
@Test