diff options
| author | Michael Williamson <mike@zwobble.org> | 2016-03-08 11:01:29 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2016-03-08 11:01:29 +0000 |
| commit | 95669601271985c89a10d673571dd89133f1e2e8 (patch) | |
| tree | 866d294696522f721cab97b8a1fb020945cf1d75 /src | |
| parent | c532706e0f20a07be960e4d2ca4d89d850312174 (diff) | |
Read formal type parameters
Diffstat (limited to 'src')
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 |
