diff options
Diffstat (limited to 'src/main')
4 files changed, 85 insertions, 17 deletions
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/java/JavaGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/java/JavaGenerator.java index 901171c..5421e58 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/java/JavaGenerator.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/java/JavaGenerator.java @@ -140,23 +140,34 @@ public class JavaGenerator { } public JavaTypeRef generateTypeRef(Type type) { - return this.generateTypeRef(type, false); + return this.generateTypeRef(type, false, Set.of()); } public JavaTypeRef generateReferenceTypeRef(Type type) { - return this.generateTypeRef(type, true); + return this.generateTypeRef(type, true, Set.of()); } - private JavaTypeRef generateTypeRef(Type type, boolean referenceType) { + public JavaTypeRef generateReferenceTypeRef(Type type, Set<TypeParam> wildcardTypeParams) { + return this.generateTypeRef(type, true, wildcardTypeParams); + } + + private JavaTypeRef generateTypeRef(Type type, boolean referenceType, Set<TypeParam> wildcardTypeParams) { return switch (collapseType(type)) { case ConstructedType constructedType -> { var innerTypeRef = generateTypeRef( constructedType.constructor().genericType(), - referenceType + referenceType, + wildcardTypeParams ); var javaArgs = constructedType.args().stream() - .map(arg -> JavaTypeArg.invariant(generateTypeRef(arg, true))) + .map(arg -> { + if (wildcardTypeParams.contains(arg)) { + return JavaTypeArg.wildcard(); + } else { + return JavaTypeArg.invariant(generateTypeRef(arg, true, wildcardTypeParams)); + } + }) .toList(); yield JavaTypeRef.generic(innerTypeRef.packageName(), innerTypeRef.typeNames(), javaArgs); @@ -200,8 +211,13 @@ public class JavaGenerator { case TypeLevelValueType typeLevelValueType -> throw new UnsupportedOperationException("TODO"); - case TypeParam typeParam -> - JavaTypeRef.local(this.generateTypeName(typeParam.name())); + case TypeParam typeParam -> { + if (wildcardTypeParams.contains(typeParam)) { + yield JavaTypeRef.OBJECT; + } else { + yield JavaTypeRef.local(this.generateTypeName(typeParam.name())); + } + } }; } diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javapreciselymatchers/JavaPreciselyMatchersGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javapreciselymatchers/JavaPreciselyMatchersGenerator.java index 760e01e..2a00d2b 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javapreciselymatchers/JavaPreciselyMatchersGenerator.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javapreciselymatchers/JavaPreciselyMatchersGenerator.java @@ -16,6 +16,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.Set; import static org.zwobble.hobgoblin.compiler.util.Casing.lowerCamelCaseToUpperCamelCase; @@ -89,12 +90,25 @@ public class JavaPreciselyMatchersGenerator implements Generator { TypedStructDefinitionNode structDefinition, Context context ) { - var structType = structDefinition.typeOrThrow(); + var javaStructTypeRef = switch (structDefinition.typeOrConstructor()) { + case TypeOrConstructor.Constructor<SimpleStructType> constructor -> { + var args = constructor.value().params().stream() + .map(_ -> JavaTypeArg.wildcard()) + .toList(); + + yield this.javaGenerator.generateTypeRef(constructor.unboundType()) + .withArgs(args); + } + + case TypeOrConstructor.Type<SimpleStructType> type -> { + yield this.javaGenerator.generateTypeRef(type.value()); + } + }; - var javaStructTypeRef = this.javaGenerator.generateTypeRef(structType); + var javaStructRawTypeRef = this.javaGenerator.generateTypeRef(structDefinition.typeOrConstructor().unboundType()); - var javaMatcherTypeRef = this.structMatcherRef(structType); - var matcherTypeName = this.structMatcherTypeName(structType); + var javaMatcherTypeRef = this.structMatcherRef(structDefinition.typeOrConstructor()); + var matcherTypeName = this.structMatcherTypeName(structDefinition.typeOrConstructor()); var submatchersIdentifier = JavaIdentifier.of("submatchers"); var methods = new ArrayList<JavaClassBodyDeclaration>(List.of( @@ -191,8 +205,19 @@ public class JavaPreciselyMatchersGenerator implements Generator { List.of(), JavaIdentifier.of("instanceOf"), List.of( - new JavaClassLiteral(javaStructTypeRef), - new JavaFieldAccess(JavaRef.THIS, submatchersIdentifier) + new JavaClassLiteral(javaStructRawTypeRef), + switch (structDefinition.typeOrConstructor()) { + case TypeOrConstructor.Constructor<SimpleStructType> _ -> + // This should be a safe cast since X and X<?, ..., ?> + // should be compatible. + new JavaCast( + JavaTypeRef.LIST, + new JavaFieldAccess(JavaRef.THIS, submatchersIdentifier) + ); + + case TypeOrConstructor.Type<SimpleStructType> _ -> + new JavaFieldAccess(JavaRef.THIS, submatchersIdentifier); + } ) )) )) @@ -201,7 +226,14 @@ public class JavaPreciselyMatchersGenerator implements Generator { for (var field : structDefinition.fields().orElse(List.of())) { var fieldType = field.type().value(); - var javaFieldTypeRef = this.javaGenerator.generateReferenceTypeRef(fieldType); + var typeParams = switch (structDefinition.typeOrConstructor()) { + case TypeOrConstructor.Constructor<SimpleStructType> constructor -> + Set.copyOf(constructor.value().params()); + + case TypeOrConstructor.Type<SimpleStructType> _ -> + Set.<TypeParam>of(); + }; + var javaFieldTypeRef = this.javaGenerator.generateReferenceTypeRef(fieldType, typeParams); var javaFieldName = this.javaGenerator.generateFieldName(field.name()); methods.add(new JavaMethodDeclaration( @@ -233,7 +265,15 @@ public class JavaPreciselyMatchersGenerator implements Generator { List.of( new JavaStringLiteral(field.name()), new JavaMethodRef(javaStructTypeRef, javaFieldName), - new JavaRef(javaFieldName) + // TODO: the use of wildcards should make this safe, + // but it would be nice to avoid the cast if possible. + new JavaCast( + JavaTypeRef.topLevel( + PRECISELY_PACKAGE_NAME, + JavaIdentifier.of("Matcher") + ), + new JavaRef(javaFieldName) + ) ) )) )), @@ -291,7 +331,7 @@ public class JavaPreciselyMatchersGenerator implements Generator { ); } - private JavaTypeRef structMatcherRef(SimpleStructType structType) { + private JavaTypeRef structMatcherRef(TypeOrConstructor<SimpleStructType> structType) { var matcherTypeName = structMatcherTypeName(structType); return JavaTypeRef.topLevel( @@ -300,7 +340,7 @@ public class JavaPreciselyMatchersGenerator implements Generator { ); } - private JavaIdentifier structMatcherTypeName(SimpleStructType structType) { + private JavaIdentifier structMatcherTypeName(TypeOrConstructor<SimpleStructType> structType) { return this.javaGenerator.generateTypeName(structType.name() + "Matcher"); } } diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/ConstructibleType.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/ConstructibleType.java index 05fd042..8f3b931 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/types/ConstructibleType.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/ConstructibleType.java @@ -1,4 +1,5 @@ package org.zwobble.hobgoblin.compiler.types; public sealed interface ConstructibleType extends Type permits SimpleNativeType, SimpleStructType { + NamespaceName namespaceName(); } diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeOrConstructor.java b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeOrConstructor.java index 7904d29..4269686 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeOrConstructor.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/types/TypeOrConstructor.java @@ -11,6 +11,11 @@ public sealed interface TypeOrConstructor<T extends ConstructibleType> { record Type<T extends ConstructibleType>(T value) implements TypeOrConstructor<T> { @Override + public NamespaceName namespaceName() { + return this.value.namespaceName(); + } + + @Override public String name() { return this.value.name(); } @@ -23,6 +28,11 @@ public sealed interface TypeOrConstructor<T extends ConstructibleType> { record Constructor<T extends ConstructibleType>(TypeConstructor<T> value) implements TypeOrConstructor<T> { @Override + public NamespaceName namespaceName() { + return value.genericType().namespaceName(); + } + + @Override public String name() { return this.value.name(); } @@ -33,6 +43,7 @@ public sealed interface TypeOrConstructor<T extends ConstructibleType> { } } + NamespaceName namespaceName(); String name(); TypeLevelValue value(); T unboundType(); |
