summaryrefslogtreecommitdiff
path: root/src/main/java/org/zwobble
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/zwobble')
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/analysis/ArbitraryValueAnalysis.java121
-rw-r--r--src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java81
2 files changed, 163 insertions, 39 deletions
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/analysis/ArbitraryValueAnalysis.java b/src/main/java/org/zwobble/hobgoblin/compiler/analysis/ArbitraryValueAnalysis.java
index 39d9e3f..b803b3d 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/analysis/ArbitraryValueAnalysis.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/analysis/ArbitraryValueAnalysis.java
@@ -9,8 +9,129 @@ import org.zwobble.hobgoblin.compiler.types.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.IntStream;
public class ArbitraryValueAnalysis {
+ public sealed interface ArbitraryValue {
+ void collectTypeParams(Set<TypeParam> typeParams);
+
+ record NativeFunctionCall(SimpleNativeType type) implements ArbitraryValue {
+ @Override
+ public void collectTypeParams(Set<TypeParam> typeParams) {
+ }
+ }
+
+ record ConstructedStructBuilder(
+ ConstructedStructType type,
+ List<ArbitraryValue> args
+ ) implements ArbitraryValue {
+ @Override
+ public void collectTypeParams(Set<TypeParam> typeParams) {
+ for (var arg : args) {
+ arg.collectTypeParams(typeParams);
+ }
+ }
+ }
+
+ record SimpleStructBuilder(SimpleStructType type) implements ArbitraryValue {
+ @Override
+ public void collectTypeParams(Set<TypeParam> typeParams) {
+ }
+ }
+
+ record EnumFirstVariant(EnumType type) implements ArbitraryValue {
+ @Override
+ public void collectTypeParams(Set<TypeParam> typeParams) {
+ }
+ }
+
+ record TypeParamThunk(TypeParam typeParam) implements ArbitraryValue {
+ @Override
+ public void collectTypeParams(Set<TypeParam> typeParams) {
+ typeParams.add(typeParam);
+ }
+ }
+
+ record Box(ArbitraryValue value) implements ArbitraryValue {
+ @Override
+ public void collectTypeParams(Set<TypeParam> typeParams) {
+ value.collectTypeParams(typeParams);
+ }
+ }
+
+ record Shared(ArbitraryValue value) implements ArbitraryValue {
+ @Override
+ public void collectTypeParams(Set<TypeParam> typeParams) {
+ value.collectTypeParams(typeParams);
+ }
+ }
+ }
+
+ public static ArbitraryValue arbitraryValue(Type type, TypesInfo typesInfo) {
+ // TODO: unify logic for constructed types?
+ return switch (type) {
+ case ConstructedNativeType constructedNativeType -> {
+ if (constructedNativeType.constructor().equals(NativeTypes.BOX)) {
+ yield new ArbitraryValue.Box(arbitraryValue(constructedNativeType.args().getFirst(), typesInfo));
+ }
+
+ if (constructedNativeType.constructor().equals(NativeTypes.SHARED)) {
+ yield new ArbitraryValue.Shared(arbitraryValue(constructedNativeType.args().getFirst(), typesInfo));
+ }
+
+ yield new ArbitraryValue.NativeFunctionCall(constructedNativeType.constructor().genericType());
+ }
+
+ case ConstructedStructType constructedStructType -> {
+ var fields = typesInfo.fieldsOf(constructedStructType.constructor().genericType())
+ // TODO: better error
+ .orElseThrow();
+ var usedTypeParams = new HashSet<TypeParam>();
+ for (var field : fields) {
+ arbitraryValue(field.type(), typesInfo).collectTypeParams(usedTypeParams);
+ }
+
+ var allTypeParams = constructedStructType.constructor().params();
+ var args = IntStream.range(0, constructedStructType.args().size())
+ .filter(paramIndex -> usedTypeParams.contains(allTypeParams.get(paramIndex)))
+ .mapToObj(paramIndex -> arbitraryValue(constructedStructType.args().get(paramIndex), typesInfo))
+ .toList();
+
+ yield new ArbitraryValue.ConstructedStructBuilder(
+ constructedStructType,
+ args
+ );
+ }
+
+ case EnumType enumType ->
+ new ArbitraryValue.EnumFirstVariant(enumType);
+
+ case SimpleNativeType simpleNativeType ->
+ new ArbitraryValue.NativeFunctionCall(simpleNativeType);
+
+ case SimpleStructType simpleStructType ->
+ new ArbitraryValue.SimpleStructBuilder(simpleStructType);
+
+ case SumType sumType -> {
+ var firstVariant = selectArbitraryVariant(sumType, typesInfo);
+ yield arbitraryValue(firstVariant, typesInfo);
+ }
+
+ case TypeLevelValueType _ ->
+ throw new UnsupportedOperationException("TODO");
+
+ case TypeParam typeParam ->
+ new ArbitraryValue.TypeParamThunk(typeParam);
+ };
+ }
+
+ private static void collectUsedTypeParams(
+ ConstructedStructType structType,
+ Set<TypeParam> usedTypeParams
+ ) {
+
+ }
+
public static Type selectArbitraryVariant(SumType sumType, TypesInfo typesInfo) {
var sumTypeInfo = typesInfo.sumTypeInfo(sumType);
if (sumTypeInfo.variants().isEmpty()) {
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java
index 93047d3..1fe01c9 100644
--- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java
+++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/javatypes/JavaTypesGenerator.java
@@ -1,5 +1,6 @@
package org.zwobble.hobgoblin.compiler.output.generators.javatypes;
+import org.zwobble.hobgoblin.compiler.analysis.ArbitraryValueAnalysis;
import org.zwobble.hobgoblin.compiler.ast.DocComment;
import org.zwobble.hobgoblin.compiler.ast.typed.*;
import org.zwobble.hobgoblin.compiler.builtins.NativeTypes;
@@ -16,9 +17,11 @@ import org.zwobble.json5.reader.Json5ObjectReader;
import java.io.IOException;
import java.nio.file.Path;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
-import static org.zwobble.hobgoblin.compiler.analysis.ArbitraryValueAnalysis.selectArbitraryVariant;
import static org.zwobble.hobgoblin.compiler.util.Casing.lowerCamelCaseToUpperCamelCase;
public class JavaTypesGenerator implements Generator {
@@ -188,7 +191,16 @@ public class JavaTypesGenerator implements Generator {
var arbitraryValueExpression = new JavaNewExpression(
builderJavaTypeRef,
structDefinition.fields().orElse(List.of()).stream()
- .map(field -> arbitraryValue(field.type(), typeParamsUsedInArbitraryValue, context))
+ .map(field -> {
+ var arbitraryValue = ArbitraryValueAnalysis.arbitraryValue(
+ field.type().value(),
+ context.typesInfo
+ );
+
+ arbitraryValue.collectTypeParams(typeParamsUsedInArbitraryValue);
+
+ return abstractArbitraryValueToJava(arbitraryValue, context);
+ })
.toList()
);
@@ -632,36 +644,24 @@ public class JavaTypesGenerator implements Generator {
return JavaTypeRef.inner(javaPackageName, generateTypeName(name), BUILDER_TYPE_NAME);
}
- private JavaExpression arbitraryValue(
- TypedTypeLevelExpressionNode<Type> type,
- Set<TypeParam> typeParamsUsedInArbitraryValue,
+ private JavaExpression abstractArbitraryValueToJava(
+ ArbitraryValueAnalysis.ArbitraryValue arbitraryValue,
Context context
) {
- return arbitraryValue(type.value(), typeParamsUsedInArbitraryValue, context);
- }
-
- private JavaExpression arbitraryValue(
- Type type,
- Set<TypeParam> typeParamsUsedInArbitraryValue,
- Context context
- ) {
- // TODO: unify logic for constructed types.
- return switch (this.javaGenerator.collapseType(type)) {
- case ConstructedNativeType constructedType -> {
- yield arbitraryValue(constructedType.constructor().genericType(), typeParamsUsedInArbitraryValue, context);
- }
-
- case ConstructedStructType constructedType -> {
+ return switch (arbitraryValue) {
+ case ArbitraryValueAnalysis.ArbitraryValue.ConstructedStructBuilder constructedStructBuilder -> {
yield new JavaMethodCall(
new JavaStaticMethodCall(
- generateTypeRef(constructedType.constructor().genericType(), context),
- List.of(),
+ generateTypeRef(constructedStructBuilder.type().constructor().genericType(), context),
+ constructedStructBuilder.type().args().stream()
+ .map(typeArg -> this.javaGenerator.generateTypeRef(typeArg))
+ .toList(),
ARBITRARY_METHOD_NAME,
- constructedType.args().stream()
- .<JavaExpression>map(typeArg -> new JavaLambdaExpression(
+ constructedStructBuilder.args().stream()
+ .<JavaExpression>map(arg -> new JavaLambdaExpression(
List.of(),
new JavaBlock(List.of(
- new JavaReturn(arbitraryValue(typeArg, typeParamsUsedInArbitraryValue, context))
+ new JavaReturn(abstractArbitraryValueToJava(arg, context))
))
))
.toList()
@@ -671,14 +671,18 @@ public class JavaTypesGenerator implements Generator {
);
}
- case EnumType enumType -> {
+ case ArbitraryValueAnalysis.ArbitraryValue.EnumFirstVariant enumFirstVariant -> {
+ var enumType = enumFirstVariant.type();
+
yield new JavaStaticFieldAccess(
generateTypeRef(enumType, context),
generateEnumConstantName(context.enumVariants(enumType).getFirst().name())
);
}
- case SimpleNativeType simpleNativeType -> {
+ case ArbitraryValueAnalysis.ArbitraryValue.NativeFunctionCall nativeFunctionCall -> {
+ var simpleNativeType = nativeFunctionCall.type();
+
yield nativeTypeConfig(simpleNativeType)
.flatMap(nativeTypeConfig -> nativeTypeConfig.arbitraryValue())
.orElseGet(() -> {
@@ -693,7 +697,9 @@ public class JavaTypesGenerator implements Generator {
});
}
- case SimpleStructType structType -> {
+ case ArbitraryValueAnalysis.ArbitraryValue.SimpleStructBuilder simpleStructBuilder -> {
+ var structType = simpleStructBuilder.type();
+
yield new JavaMethodCall(
new JavaStaticMethodCall(
generateTypeRef(structType, context),
@@ -706,23 +712,20 @@ public class JavaTypesGenerator implements Generator {
);
}
- case SumType sumType -> {
- var firstVariant = selectArbitraryVariant(sumType, context.typesInfo);
- yield arbitraryValue(firstVariant, typeParamsUsedInArbitraryValue, context);
- }
-
- case TypeLevelValueType typeLevelValueType -> {
- throw new UnsupportedOperationException("TODO");
- }
+ case ArbitraryValueAnalysis.ArbitraryValue.TypeParamThunk typeParamThunk -> {
+ var typeParam = typeParamThunk.typeParam();
- case TypeParam typeParam -> {
- typeParamsUsedInArbitraryValue.add(typeParam);
yield new JavaMethodCall(
new JavaRef(arbitraryValueSupplier(typeParam)),
JavaIdentifier.of("get"),
List.of()
);
}
+ case ArbitraryValueAnalysis.ArbitraryValue.Box box ->
+ abstractArbitraryValueToJava(box.value(), context);
+
+ case ArbitraryValueAnalysis.ArbitraryValue.Shared shared ->
+ abstractArbitraryValueToJava(shared.value(), context);
};
}