Skip to content

Commit

Permalink
Fix concrete usages of generic functional interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
stanhebben committed Apr 5, 2024
1 parent b2713f0 commit d76a28d
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -132,21 +132,24 @@ private void registerFunction(String id, Class<?> clazz, String methodName, Type
FunctionHeader functionHeader = new FunctionHeader(returnType, parameterTypes);
JavaClass javaClass = new JavaClass(clazz.getPackage().getName(), clazz.getSimpleName(), JavaClass.Kind.INTERFACE);

functions.put(id, new JavaSynthesizedFunction(
javaClass,
typeParameters,
functionHeader,
methodName));

FunctionTypeSymbol type = new FunctionTypeSymbol(functionHeader);
modules.get(ModuleSymbol.BUILTIN).setMethodInfo(new BuiltinFunctionValueCall(type), new JavaNativeMethod(
JavaMethod method = new JavaNativeMethod(
javaClass,
JavaNativeMethod.Kind.INTERFACE,
methodName,
false,
getMethodDescriptor(functionHeader),
JavaModifiers.PUBLIC | JavaModifiers.ABSTRACT,
functionHeader.getReturnType().isGeneric()));
functionHeader.getReturnType().isGeneric());

functions.put(id, new JavaSynthesizedFunction(
javaClass,
typeParameters,
functionHeader,
methodName,
method));

FunctionTypeSymbol type = new FunctionTypeSymbol(functionHeader);
modules.get(ModuleSymbol.BUILTIN).setMethodInfo(new BuiltinFunctionValueCall(type), method);
}

private void registerFunction(Function<String, TypeParameter> paramConverter, Class<?> clazz) {
Expand Down Expand Up @@ -176,21 +179,24 @@ private void registerFunction(Function<String, TypeParameter> paramConverter, Cl
}

FunctionHeader functionHeader = new FunctionHeader(convertTypeToTypeID(parameterMapping, genericReturnType), parameterTypes);
functions.put(idBuilder.toString(), new JavaSynthesizedFunction(
new JavaClass(clazz.getPackage().getName(), clazz.getSimpleName(), JavaClass.Kind.INTERFACE),
parameters,
functionHeader,
method.getName()));

FunctionTypeSymbol type = new FunctionTypeSymbol(functionHeader);
modules.get(ModuleSymbol.BUILTIN).setMethodInfo(new BuiltinFunctionValueCall(type), new JavaNativeMethod(
JavaMethod javaMethod = new JavaNativeMethod(
new JavaClass(clazz.getPackage().getName(), clazz.getSimpleName(), JavaClass.Kind.INTERFACE),
JavaNativeMethod.Kind.INTERFACE,
method.getName(),
false,
getMethodDescriptor(functionHeader),
JavaModifiers.PUBLIC | JavaModifiers.ABSTRACT,
functionHeader.getReturnType().isGeneric()));
functionHeader.getReturnType().isGeneric());

functions.put(idBuilder.toString(), new JavaSynthesizedFunction(
new JavaClass(clazz.getPackage().getName(), clazz.getSimpleName(), JavaClass.Kind.INTERFACE),
parameters,
functionHeader,
method.getName(),
javaMethod));

FunctionTypeSymbol type = new FunctionTypeSymbol(functionHeader);
modules.get(ModuleSymbol.BUILTIN).setMethodInfo(new BuiltinFunctionValueCall(type), javaMethod);
} else {
throw new IllegalArgumentException(String.format("Unable to find any applicable methods in class: '%s'", clazz.getName()));
}
Expand Down Expand Up @@ -420,6 +426,8 @@ public String getEnumConstructorDescriptor(FunctionHeader header) {
public JavaSynthesizedFunctionInstance getFunction(FunctionTypeID type) {
String id = getFunctionId(type.header);
JavaSynthesizedFunction function;

JavaCompiledModule builtinModule = modules.get(ModuleSymbol.BUILTIN);
if (!functions.containsKey(id)) {
JavaClass cls = new JavaClass("zsynthetic", "Function" + id, JavaClass.Kind.INTERFACE);
List<TypeParameter> typeParameters = new ArrayList<>();
Expand Down Expand Up @@ -465,9 +473,15 @@ public JavaSynthesizedFunctionInstance getFunction(FunctionTypeID type) {

functions.put(id, function);
JavaMethod javaMethod = getTypeGenerator().synthesizeFunction(function);
function.javaMethod = javaMethod;

modules.get(ModuleSymbol.BUILTIN).setMethodInfo(new BuiltinFunctionValueCall(type.type), javaMethod);
builtinModule.setMethodInfo(new BuiltinFunctionValueCall(type.type), javaMethod);
} else {
BuiltinFunctionValueCall call = new BuiltinFunctionValueCall(type.type);
if (builtinModule.optMethodInfo(call) == null) { // because we might be using a concrete usage of a generic functional interface
JavaMethod javaMethod = functions.get(id).javaMethod;
builtinModule.setMethodInfo(call, javaMethod);
}
function = functions.get(id);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,20 @@ public class JavaSynthesizedFunction {
public final TypeParameter[] typeParameters;
public final FunctionHeader header;
public final String method;
public JavaMethod javaMethod;

public JavaSynthesizedFunction(JavaClass cls, TypeParameter[] parameters, FunctionHeader header, String method) {
this.cls = cls;
this.typeParameters = parameters;
this.header = header;
this.method = method;
}

public JavaSynthesizedFunction(JavaClass cls, TypeParameter[] parameters, FunctionHeader header, String method, JavaMethod javaMethod) {
this.cls = cls;
this.typeParameters = parameters;
this.header = header;
this.method = method;
this.javaMethod = javaMethod;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@

import org.openzen.zencode.shared.StringExpansion;
import org.openzen.zenscript.codemodel.FunctionHeader;
import org.openzen.zenscript.codemodel.FunctionParameter;
import org.openzen.zenscript.codemodel.OperatorType;
import org.openzen.zenscript.codemodel.annotations.NativeTag;
import org.openzen.zenscript.codemodel.identifiers.instances.MethodInstance;
import org.openzen.zenscript.codemodel.member.*;
import org.openzen.zenscript.codemodel.type.BasicTypeID;
import org.openzen.zenscript.codemodel.type.GenericTypeID;
import org.openzen.zenscript.codemodel.type.TypeID;
import org.openzen.zenscript.javashared.*;
import org.openzen.zenscript.javashared.compiling.JavaCompilingClass;
import org.openzen.zenscript.javashared.compiling.JavaCompilingMethod;
Expand All @@ -29,6 +28,7 @@ public class JavaPrepareClassMethodVisitor implements MemberVisitor<Void> {
private final JavaCompilingModule module;
private final JavaCompilingClass class_;
private final JavaPrepareDefinitionMemberVisitor memberPreparer;
private final JavaPrepareTypeVisitor typePreparer;

public JavaPrepareClassMethodVisitor(
JavaCompilingClass class_,
Expand All @@ -38,6 +38,7 @@ public JavaPrepareClassMethodVisitor(
this.module = class_.module;
this.class_ = class_;
this.memberPreparer = memberPreparer;
this.typePreparer = new JavaPrepareTypeVisitor(context);

class_.empty = startsEmpty;
}
Expand All @@ -54,6 +55,7 @@ public Void visitField(FieldMember member) {
visitSetter(member.autoSetter);
class_.module.module.setFieldInfo(member.autoSetter, field);
}
member.getType().accept(typePreparer);

return null;
}
Expand Down Expand Up @@ -247,6 +249,11 @@ private void visitFunctional(FunctionalMember member, FunctionHeader header, Str
method = new JavaCompilingMethod(class_.compiled, (JavaNativeMethod) class_.nativeClass.getMethod(nativeTag.value), signature);
}

for (FunctionParameter parameter : header.parameters) {
parameter.type.accept(typePreparer);
}
header.getReturnType().accept(typePreparer);

int modifiers = class_.compiled.kind == JavaClass.Kind.INTERFACE ? JavaModifiers.ABSTRACT : 0;
if (member.getOverrides().isPresent()) {
MethodInstance base = member.getOverrides().get();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.openzen.zenscript.javashared.prepare;

import org.openzen.zenscript.codemodel.type.*;
import org.openzen.zenscript.javashared.JavaContext;

public class JavaPrepareTypeVisitor implements TypeVisitor<Void> {
private final JavaContext context;

public JavaPrepareTypeVisitor(JavaContext context) {
this.context = context;
}

@Override
public Void visitBasic(BasicTypeID basic) {
return null;
}

@Override
public Void visitArray(ArrayTypeID array) {
return array.elementType.accept(this);
}

@Override
public Void visitAssoc(AssocTypeID assoc) {
assoc.keyType.accept(this);
assoc.valueType.accept(this);
return null;
}

@Override
public Void visitGenericMap(GenericMapTypeID map) {
map.value.accept(this);
return null;
}

@Override
public Void visitIterator(IteratorTypeID iterator) {
return null;
}

@Override
public Void visitFunction(FunctionTypeID function) {
context.getFunction(function);
return null;
}

@Override
public Void visitDefinition(DefinitionTypeID definition) {
for (TypeID argument : definition.typeArguments)
argument.accept(this);
return null;
}

@Override
public Void visitGeneric(GenericTypeID generic) {
return null;
}

@Override
public Void visitRange(RangeTypeID range) {
return null;
}

@Override
public Void visitOptional(OptionalTypeID type) {
type.baseType.accept(this);
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#output: Hello

var accept as function(value: string): void = (value) => println(value);
accept("Hello");
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#output: Hello

var accept as function(value: string, x: int, y: int): void = (value, x, y) => println(value);
accept("Hello", 0, 0);
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#output: Hello world

public variant Optional<T> {
Present(T),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ public variant Optional<T> {
Present(value) => true,
Empty => false
};

public expect() as T {
return match this {
Present(value) => value,
Empty() => panic('Expect called on empty value')
};
}
}

var opt as Optional<string> = Present('Hello World');
var opt as Optional<string> = Present('Hello world');
opt.ifPresent((value) => println(value));
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ public variant OptionalString {
Present(value) => true,
Empty => false
};

public expect() as string {
return match this {
Present(value) => value,
Empty() => 'Expect called on empty value'
};
}
}

var opt as OptionalString = Present('Hello World');
var opt as OptionalString = Present('Hello world');
opt.ifPresent((value) => println(value));

0 comments on commit d76a28d

Please sign in to comment.