Browse Source

Added support for functional interfaces.

Stan Hebben 6 years ago
parent
commit
70bd868af4

+ 62
- 17
JavaIntegration/src/main/java/org/openzen/zencode/java/JavaNativeModule.java View File

@@ -54,9 +54,11 @@ import org.openzen.zenscript.codemodel.type.TypeID;
54 54
 import org.openzen.zenscript.codemodel.type.member.BuiltinID;
55 55
 import org.openzen.zenscript.codemodel.type.member.TypeMembers;
56 56
 import org.openzen.zenscript.codemodel.type.storage.AutoStorageTag;
57
+import org.openzen.zenscript.codemodel.type.storage.StorageTag;
57 58
 import org.openzen.zenscript.javashared.JavaClass;
58 59
 import org.openzen.zenscript.javashared.JavaCompiledModule;
59 60
 import org.openzen.zenscript.javashared.JavaField;
61
+import org.openzen.zenscript.javashared.JavaFunctionalInterfaceStorageTag;
60 62
 import org.openzen.zenscript.javashared.JavaImplementation;
61 63
 import org.openzen.zenscript.javashared.JavaMethod;
62 64
 import stdlib.Strings;
@@ -251,7 +253,7 @@ public class JavaNativeModule {
251 253
 			TypeVariable<Class<T>> typeVariable = javaTypeParameters[i];
252 254
 			TypeParameter parameter = new TypeParameter(CodePosition.NATIVE, typeVariable.getName());
253 255
 			for (AnnotatedType bound : typeVariable.getAnnotatedBounds()) {
254
-				TypeID type = loadType(context, bound);
256
+				TypeID type = loadType(context, bound).type;
255 257
 				parameter.addBound(new ParameterTypeBound(CodePosition.NATIVE, type));
256 258
 			}
257 259
 			typeParameters[i] = parameter;
@@ -275,13 +277,13 @@ public class JavaNativeModule {
275 277
 			javaClass = JavaClass.fromInternalName(internalName, JavaClass.Kind.CLASS);
276 278
 			
277 279
 			if (cls.getAnnotatedSuperclass() != null && shouldLoadType(cls.getAnnotatedSuperclass().getType())) {
278
-				definition.setSuperType(loadType(context, cls.getAnnotatedSuperclass()));
280
+				definition.setSuperType(loadType(context, cls.getAnnotatedSuperclass()).type);
279 281
 			}
280 282
 		}
281 283
 		
282 284
 		for (AnnotatedType iface : cls.getAnnotatedInterfaces()) {
283 285
 			if (shouldLoadType(iface.getType())) {
284
-				TypeID type = loadType(context, iface);
286
+				TypeID type = loadType(context, iface).type;
285 287
 				ImplementationMember member = new ImplementationMember(CodePosition.NATIVE, definition, Modifiers.PUBLIC, type);
286 288
 				definition.members.add(member);
287 289
 				compiled.setImplementationInfo(member, new JavaImplementation(true, javaClass));
@@ -515,7 +517,7 @@ public class JavaNativeModule {
515 517
 			context.put(javaTypeParameter, typeParameters[i]);
516 518
 			
517 519
 			for (AnnotatedType bound : javaTypeParameter.getAnnotatedBounds())
518
-				typeParameters[i].addBound(new ParameterTypeBound(CodePosition.NATIVE, loadType(context, bound)));
520
+				typeParameters[i].addBound(new ParameterTypeBound(CodePosition.NATIVE, loadType(context, bound).type));
519 521
 		}
520 522
 		
521 523
 		if (exceptionTypes.length > 1)
@@ -526,15 +528,14 @@ public class JavaNativeModule {
526 528
 	}
527 529
 	
528 530
 	private StoredType loadStoredType(TypeVariableContext context, AnnotatedType annotatedType) {
529
-		TypeID baseType = loadType(context, annotatedType);
530
-		return baseType.stored();
531
+		return loadType(context, annotatedType);
531 532
 	}
532 533
 	
533
-	private TypeID loadType(TypeVariableContext context, AnnotatedType annotatedType) {
534
+	private StoredType loadType(TypeVariableContext context, AnnotatedType annotatedType) {
534 535
 		if (annotatedType.isAnnotationPresent(ZenCodeType.USize.class))
535
-			return BasicTypeID.USIZE;
536
+			return BasicTypeID.USIZE.stored;
536 537
 		else if (annotatedType.isAnnotationPresent(ZenCodeType.NullableUSize.class))
537
-			return registry.getOptional(BasicTypeID.USIZE);
538
+			return registry.getOptional(BasicTypeID.USIZE).stored();
538 539
 		
539 540
 		boolean nullable = annotatedType.isAnnotationPresent(ZenCodeType.Nullable.class);
540 541
 		boolean unsigned = annotatedType.isAnnotationPresent(ZenCodeType.Unsigned.class);
@@ -543,42 +544,86 @@ public class JavaNativeModule {
543 544
 		return loadType(context, type, nullable, unsigned);
544 545
 	}
545 546
 	
546
-	private TypeID loadType(TypeVariableContext context, Type type, boolean nullable, boolean unsigned) {
547
+	private StoredType loadType(TypeVariableContext context, Type type, boolean nullable, boolean unsigned) {
547 548
 		if (type instanceof Class) {
548 549
 			Class<?> classType = (Class<?>) type;
549 550
 			if (unsigned) {
550 551
 				if (unsignedByClass.containsKey(classType))
551
-					return unsignedByClass.get(classType);
552
+					return unsignedByClass.get(classType).stored();
552 553
 				else
553 554
 					throw new IllegalArgumentException("This class cannot be used as unsigned: " + classType);
554 555
 			} else if (classType.isArray()) {
555
-				return registry.getArray(loadType(context, classType.getComponentType(), false, false).stored(), 1);
556
+				return registry.getArray(loadType(context, classType.getComponentType(), false, false), 1).stored();
557
+			} else if (classType.isAnnotationPresent(FunctionalInterface.class)) {
558
+				return loadFunctionalInterface(context, classType, new Type[0]);
556 559
 			}
557 560
 			
558 561
 			if (typeByClass.containsKey(classType))
559
-				return typeByClass.get(classType);
562
+				return typeByClass.get(classType).stored();
560 563
 			
561 564
 			HighLevelDefinition definition = addClass(classType);
562
-			return registry.getForDefinition(definition);
565
+			return registry.getForDefinition(definition).stored();
563 566
 		} else if (type instanceof ParameterizedType) {
564 567
 			ParameterizedType parameterizedType = (ParameterizedType) type;
565 568
 			Class<?> rawType = (Class) parameterizedType.getRawType();
569
+			if (rawType.isAnnotationPresent(FunctionalInterface.class))
570
+				return loadFunctionalInterface(context, rawType, parameterizedType.getActualTypeArguments());
566 571
 			
567 572
 			HighLevelDefinition definition = addClass(rawType);
568 573
 			Type[] parameters = parameterizedType.getActualTypeArguments();
569 574
 			StoredType[] codeParameters = new StoredType[parameters.length];
570 575
 			for (int i = 0; i < parameters.length; i++)
571
-				codeParameters[i] = loadType(context, parameters[i], false, false).stored();
576
+				codeParameters[i] = loadType(context, parameters[i], false, false);
572 577
 			
573
-			return registry.getForDefinition(definition, codeParameters);
578
+			return registry.getForDefinition(definition, codeParameters).stored();
574 579
 		} else if (type instanceof TypeVariable) {
575 580
 			TypeVariable variable = (TypeVariable)type;
576
-			return registry.getGeneric(context.get(variable));
581
+			return registry.getGeneric(context.get(variable)).stored();
577 582
 		} else {
578 583
 			throw new IllegalArgumentException("Could not analyze type: " + type);
579 584
 		}
580 585
 	}
581 586
 	
587
+	private StoredType loadFunctionalInterface(TypeVariableContext loadContext, Class<?> cls, Type[] parameters) {
588
+		Method functionalInterfaceMethod = getFunctionalInterfaceMethod(cls);
589
+		TypeVariableContext context = convertTypeParameters(cls);
590
+		FunctionHeader header = getHeader(context, functionalInterfaceMethod);
591
+		
592
+		Map<TypeParameter, StoredType> mapping = new HashMap<>();
593
+		TypeVariable[] javaParameters = cls.getTypeParameters();
594
+		for (int i = 0; i < javaParameters.length; i++)
595
+			mapping.put(context.get(javaParameters[i]), loadType(loadContext, parameters[i], false, false));
596
+		
597
+		StorageTag tag = new JavaFunctionalInterfaceStorageTag(functionalInterfaceMethod);
598
+		return registry.getFunction(header).stored(tag);
599
+	}
600
+	
601
+	private <T> TypeVariableContext convertTypeParameters(Class<T> cls) {
602
+		TypeVariableContext context = new TypeVariableContext();
603
+		TypeVariable<Class<T>>[] javaTypeParameters = cls.getTypeParameters();
604
+		TypeParameter[] typeParameters = new TypeParameter[cls.getTypeParameters().length];
605
+		for (int i = 0; i < javaTypeParameters.length; i++) {
606
+			TypeVariable<Class<T>> typeVariable = javaTypeParameters[i];
607
+			TypeParameter parameter = new TypeParameter(CodePosition.NATIVE, typeVariable.getName());
608
+			for (AnnotatedType bound : typeVariable.getAnnotatedBounds()) {
609
+				TypeID type = loadType(context, bound).type;
610
+				parameter.addBound(new ParameterTypeBound(CodePosition.NATIVE, type));
611
+			}
612
+			typeParameters[i] = parameter;
613
+			context.put(typeVariable, parameter);
614
+		}
615
+		return context;
616
+	}
617
+	
618
+	private Method getFunctionalInterfaceMethod(Class<?> functionalInterface) {
619
+		for (Method method : functionalInterface.getDeclaredMethods()) {
620
+			if (!method.isDefault())
621
+				return method;
622
+		}
623
+		
624
+		return null;
625
+	}
626
+	
582 627
 	private int getMethodModifiers(Method method) {
583 628
 		int result = Modifiers.PUBLIC;
584 629
 		if (isStatic(method.getModifiers()))

+ 58
- 0
JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaFunctionalInterfaceStorageTag.java View File

@@ -0,0 +1,58 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.zenscript.javashared;
7
+
8
+import java.lang.reflect.Method;
9
+import org.openzen.zenscript.codemodel.type.storage.AutoStorageTag;
10
+import org.openzen.zenscript.codemodel.type.storage.BorrowStorageTag;
11
+import org.openzen.zenscript.codemodel.type.storage.SharedStorageTag;
12
+import org.openzen.zenscript.codemodel.type.storage.StorageTag;
13
+import org.openzen.zenscript.codemodel.type.storage.StorageType;
14
+import org.openzen.zenscript.codemodel.type.storage.UniqueStorageTag;
15
+
16
+public class JavaFunctionalInterfaceStorageTag implements StorageTag {
17
+	public final Method funtionalInterfaceMethod;
18
+	
19
+	public JavaFunctionalInterfaceStorageTag(Method functionalInterfaceMethod) {
20
+		this.funtionalInterfaceMethod = functionalInterfaceMethod;
21
+	}
22
+
23
+	@Override
24
+	public StorageType getType() {
25
+		return JavaFunctionalInterfaceStorageType.INSTANCE;
26
+	}
27
+
28
+	@Override
29
+	public boolean canCastTo(StorageTag other) {
30
+		return other instanceof JavaFunctionalInterfaceStorageTag
31
+				|| other instanceof AutoStorageTag
32
+				|| other instanceof SharedStorageTag
33
+				|| other instanceof BorrowStorageTag;
34
+	}
35
+
36
+	@Override
37
+	public boolean canCastFrom(StorageTag other) {
38
+		return other instanceof JavaFunctionalInterfaceStorageTag
39
+				|| other instanceof AutoStorageTag
40
+				|| other instanceof SharedStorageTag
41
+				|| other instanceof UniqueStorageTag;
42
+	}
43
+
44
+	@Override
45
+	public boolean isDestructible() {
46
+		return false;
47
+	}
48
+
49
+	@Override
50
+	public boolean isConst() {
51
+		return true;
52
+	}
53
+
54
+	@Override
55
+	public boolean isImmutable() {
56
+		return true;
57
+	}
58
+}

+ 30
- 0
JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaFunctionalInterfaceStorageType.java View File

@@ -0,0 +1,30 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.zenscript.javashared;
7
+
8
+import org.openzen.zencode.shared.CodePosition;
9
+import org.openzen.zenscript.codemodel.type.storage.StorageTag;
10
+import org.openzen.zenscript.codemodel.type.storage.StorageType;
11
+
12
+/**
13
+ *
14
+ * @author Hoofdgebruiker
15
+ */
16
+public class JavaFunctionalInterfaceStorageType implements StorageType {
17
+	public static final JavaFunctionalInterfaceStorageType INSTANCE = new JavaFunctionalInterfaceStorageType();
18
+
19
+	private JavaFunctionalInterfaceStorageType() {}
20
+	
21
+	@Override
22
+	public String getName() {
23
+		return "JavaFunctionalInterface";
24
+	}
25
+
26
+	@Override
27
+	public StorageTag instance(CodePosition position, String[] arguments) {
28
+		throw new UnsupportedOperationException("This tag can only be instanced by java interfacing code");
29
+	}
30
+}

+ 2
- 0
ScriptingExample/scripts/integration.zs View File

@@ -43,3 +43,5 @@ addShapedRecipe("TestRecipe", diamond, [[dirt, dirt, dirt],[dirt, dirt, dirt],[d
43 43
 
44 44
 var count = 10;
45 45
 floatMethod(5f * count);
46
+
47
+invokeFunctional(name => "Hello " + name);

+ 10
- 0
ScriptingExample/src/main/java/org/openzen/zenscript/scriptingexample/Globals.java View File

@@ -47,7 +47,17 @@ public class Globals implements ZenCodeGlobals {
47 47
 		System.out.println(argument);
48 48
 	}
49 49
 	
50
+	@Global
51
+	public static void invokeFunctional(MyFunctionalInterface greeter) {
52
+		System.out.println("doSomething: " + greeter.doSomething("world"));
53
+	}
54
+	
50 55
 	public static TestClass bracket(String value) {
51 56
 		return new TestClass(value);
52 57
 	}
58
+	
59
+	@FunctionalInterface
60
+	public static interface MyFunctionalInterface {
61
+		String doSomething(String value);
62
+	}
53 63
 }

+ 5
- 0
ScriptingExample/src/main/java/org/openzen/zenscript/scriptingexample/TestClass.java View File

@@ -43,6 +43,11 @@ public class TestClass implements TestInterface {
43 43
 		return "Interface method of " + name;
44 44
 	}
45 45
 	
46
+	@Override
47
+	public String getValue() {
48
+		return "getValue " + name;
49
+	}
50
+	
46 51
 	@Method
47 52
 	public TestGenericInterface<String> generate() {
48 53
 		return () -> name;

+ 1
- 1
ScriptingExample/src/main/java/org/openzen/zenscript/scriptingexample/TestInterface.java View File

@@ -11,7 +11,7 @@ import org.openzen.zencode.java.ZenCodeType;
11 11
  *
12 12
  * @author Hoofdgebruiker
13 13
  */
14
-public interface TestInterface extends ZenCodeType {
14
+public interface TestInterface extends ZenCodeType, TestGenericInterface<String> {
15 15
 	@Method
16 16
 	String interfaceMethod();
17 17
 }

Loading…
Cancel
Save