Skip to content

Commit e6d940d

Browse files
committed
upgrade to utility class
1 parent 8d16897 commit e6d940d

File tree

2 files changed

+63
-19
lines changed

2 files changed

+63
-19
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.falsepattern.jfunge.interpreter;
2+
3+
import lombok.*;
4+
import lombok.experimental.*;
5+
6+
import java.lang.invoke.LambdaMetafactory;
7+
import java.lang.invoke.MethodHandle;
8+
import java.lang.invoke.MethodHandles;
9+
import java.lang.invoke.MethodType;
10+
import java.lang.reflect.Method;
11+
import java.util.Arrays;
12+
13+
@UtilityClass
14+
public final class LambdaHelper {
15+
public static MethodHandle newLambdaMetaFactory(Class<?> functionalInterface, Method staticMethod) {
16+
try {
17+
val interfaceMethod = Arrays.stream(functionalInterface.getDeclaredMethods())
18+
.filter(method1 -> !method1.isDefault())
19+
.findFirst()
20+
.orElseThrow(() -> new IllegalArgumentException(functionalInterface.getName() + " does not have a single abstract method"));
21+
val interfaceMethodName = interfaceMethod.getName();
22+
val factoryType = MethodType.methodType(functionalInterface);
23+
val interfaceMethodType = MethodType.methodType(interfaceMethod.getReturnType(),
24+
interfaceMethod.getParameterTypes());
25+
26+
// Get the method handle for the static method
27+
val lookup = MethodHandles.lookup();
28+
val implementation = lookup.unreflect(staticMethod);
29+
val dynamicMethodType = implementation.type();
30+
31+
return LambdaMetafactory
32+
.metafactory(lookup,
33+
interfaceMethodName,
34+
factoryType,
35+
interfaceMethodType,
36+
implementation,
37+
dynamicMethodType)
38+
.getTarget();
39+
} catch (Throwable throwable) {
40+
val errStr = "Failed to bind method: %s to functional interface: %s";
41+
throw new RuntimeException(String.format(errStr, staticMethod.getName(), functionalInterface.getName()),
42+
throwable);
43+
}
44+
}
45+
}

src/main/java/com/falsepattern/jfunge/interpreter/instructions/InstructionSet.java

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
package com.falsepattern.jfunge.interpreter.instructions;
22

3-
import com.falsepattern.jfunge.interpreter.ExecutionContext;
3+
import com.falsepattern.jfunge.interpreter.LambdaHelper;
44
import lombok.val;
55

66
import java.lang.annotation.Retention;
77
import java.lang.annotation.RetentionPolicy;
8-
import java.lang.invoke.LambdaMetafactory;
9-
import java.lang.invoke.MethodHandles;
10-
import java.lang.invoke.MethodType;
118
import java.lang.reflect.Modifier;
129
import java.util.Arrays;
1310
import java.util.function.IntConsumer;
@@ -16,25 +13,27 @@
1613
public interface InstructionSet {
1714
default void load(ObjIntConsumer<Instruction> instructionSet) {
1815
val clazz = this.getClass();
19-
Arrays.stream(clazz.getDeclaredMethods()).filter((method) -> Modifier.isStatic(method.getModifiers()) && method.isAnnotationPresent(Instr.class)).forEach((method) -> {
20-
val lookup = MethodHandles.lookup();
21-
val methodType = MethodType.methodType(void.class, ExecutionContext.class);
22-
try {
23-
val lambda = (Instruction) LambdaMetafactory.metafactory(lookup, "process", MethodType.methodType(Instruction.class), methodType, lookup.findStatic(clazz, method.getName(), methodType), methodType).getTarget().invokeExact();
24-
val ann = method.getAnnotation(Instr.class);
25-
instructionSet.accept(lambda, ann.value());
26-
} catch (Throwable e) {
27-
throw new RuntimeException(e);
28-
}
29-
});
16+
Arrays.stream(clazz.getDeclaredMethods())
17+
.filter((method) -> Modifier.isStatic(method.getModifiers()) && method.isAnnotationPresent(Instr.class))
18+
.forEach((method) -> {
19+
try {
20+
val lambda = (Instruction) LambdaHelper.newLambdaMetaFactory(Instruction.class, method).invokeExact();
21+
val ann = method.getAnnotation(Instr.class);
22+
instructionSet.accept(lambda, ann.value());
23+
} catch (Throwable e) {
24+
throw new RuntimeException(e);
25+
}
26+
});
3027
}
3128

3229
default void unload(IntConsumer instructionSet) {
3330
val clazz = this.getClass();
34-
Arrays.stream(clazz.getDeclaredMethods()).filter((method) -> Modifier.isStatic(method.getModifiers()) && method.isAnnotationPresent(Instr.class)).forEach((method) -> {
35-
val ann = method.getAnnotation(Instr.class);
36-
instructionSet.accept(ann.value());
37-
});
31+
Arrays.stream(clazz.getDeclaredMethods())
32+
.filter((method) -> Modifier.isStatic(method.getModifiers()) && method.isAnnotationPresent(Instr.class))
33+
.forEach((method) -> {
34+
val ann = method.getAnnotation(Instr.class);
35+
instructionSet.accept(ann.value());
36+
});
3837
}
3938

4039
@Retention(RetentionPolicy.RUNTIME)

0 commit comments

Comments
 (0)