diff --git a/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaNativeTypeMembers.java b/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaNativeTypeMembers.java index 899e3a406..fd1227e15 100644 --- a/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaNativeTypeMembers.java +++ b/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaNativeTypeMembers.java @@ -76,12 +76,12 @@ public Optional findStaticMethod(String name) { @Override public Optional findStaticGetter(String name) { - return loadStatic(MethodID.getter(name)); + return loadStatic(MethodID.staticGetter(name)); } @Override public Optional findStaticSetter(String name) { - return loadStatic(MethodID.setter(name)); + return loadStatic(MethodID.staticSetter(name)); } @Override diff --git a/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaNativeTypeTemplate.java b/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaNativeTypeTemplate.java index d861941ef..8bd2a942f 100644 --- a/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaNativeTypeTemplate.java +++ b/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaNativeTypeTemplate.java @@ -18,7 +18,9 @@ import org.openzen.zenscript.codemodel.identifiers.instances.FieldInstance; import org.openzen.zenscript.codemodel.ssa.CodeBlockStatement; import org.openzen.zenscript.codemodel.ssa.SSAVariableCollector; +import org.openzen.zenscript.codemodel.type.ArrayTypeID; import org.openzen.zenscript.codemodel.type.TypeID; +import org.openzen.zenscript.codemodel.type.builtin.BuiltinMethodSymbol; import org.openzen.zenscript.javashared.JavaClass; import org.openzen.zenscript.javashared.JavaModifiers; import org.openzen.zenscript.javashared.JavaNativeField; @@ -29,6 +31,7 @@ import java.lang.reflect.Modifier; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; public class JavaNativeTypeTemplate { protected final JavaRuntimeClass class_; @@ -138,13 +141,16 @@ private void loadMethods() { for (Method method : class_.cls.getMethods()) { if (isNotAccessible(method) || isOverridden(class_.cls, method)) continue; + if (expansion && !JavaModifiers.isStatic(method.getModifiers())) continue; - Collection ids = new LinkedList<>(); - boolean isStaticExpansion = false; + Collection ids = new LinkedHashSet<>(); // LinkedHashSet to prevent collision if a static method has both @Global and @Method + boolean isStaticExpansionMethod = expansion && method.isAnnotationPresent(ZenCodeType.StaticExpansionMethod.class); + boolean isStaticMethodInsideZc = (!expansion || isStaticExpansionMethod) && JavaModifiers.isStatic(method.getModifiers()); + boolean implicit = false; - boolean isStaticMethod = false; + if (method.isAnnotationPresent(ZenCodeType.Operator.class)) { ZenCodeType.Operator operator = method.getAnnotation(ZenCodeType.Operator.class); MethodID id = MethodID.operator(OperatorType.valueOf(operator.value().toString())); @@ -153,13 +159,13 @@ private void loadMethods() { if (method.isAnnotationPresent(ZenCodeType.Getter.class)) { ZenCodeType.Getter getter = method.getAnnotation(ZenCodeType.Getter.class); String name = getter.value().isEmpty() ? method.getName() : getter.value(); - MethodID id = MethodID.getter(name); + MethodID id = isStaticMethodInsideZc ? MethodID.staticGetter(name) : MethodID.getter(name); ids.add(id); } if (method.isAnnotationPresent(ZenCodeType.Setter.class)) { ZenCodeType.Setter setter = method.getAnnotation(ZenCodeType.Setter.class); String name = setter.value().isEmpty() ? method.getName() : setter.value(); - MethodID id = MethodID.setter(name); + MethodID id = isStaticMethodInsideZc ? MethodID.staticSetter(name) : MethodID.setter(name); ids.add(id); } if (method.isAnnotationPresent(ZenCodeType.Caster.class)) { @@ -171,20 +177,17 @@ private void loadMethods() { if (method.isAnnotationPresent(ZenCodeType.Method.class)) { ZenCodeType.Method methodAnnotation = method.getAnnotation(ZenCodeType.Method.class); String name = methodAnnotation.value().isEmpty() ? method.getName() : methodAnnotation.value(); - boolean hasStaticModifier = JavaModifiers.isStatic(method.getModifiers()); - MethodID id = hasStaticModifier && !expansion ? MethodID.staticMethod(name) : MethodID.instanceMethod(name); + MethodID id = isStaticMethodInsideZc ? MethodID.staticMethod(name) : MethodID.instanceMethod(name); implicit |= methodAnnotation.implicit(); - isStaticMethod |= hasStaticModifier; ids.add(id); } - if (expansion && method.isAnnotationPresent(ZenCodeType.StaticExpansionMethod.class)) { + if (isStaticExpansionMethod) { ZenCodeType.StaticExpansionMethod methodAnnotation = method.getAnnotation(ZenCodeType.StaticExpansionMethod.class); String name = methodAnnotation.value().isEmpty() ? method.getName() : methodAnnotation.value(); MethodID id = MethodID.staticMethod(name); ids.add(id); - isStaticExpansion = true; } - if (!isStaticMethod && method.isAnnotationPresent(ZenCodeGlobals.Global.class) && JavaModifiers.isStatic(method.getModifiers())) { + if (isStaticMethodInsideZc && method.isAnnotationPresent(ZenCodeGlobals.Global.class)) { ZenCodeGlobals.Global methodAnnotation = method.getAnnotation(ZenCodeGlobals.Global.class); String name = methodAnnotation.value().isEmpty() ? method.getName() : methodAnnotation.value(); MethodID id = MethodID.staticMethod(name); @@ -194,18 +197,42 @@ private void loadMethods() { continue; FunctionHeader header = headerConverter.getHeader(typeVariableContext, method); - - if (expansion && !isStaticExpansion) { + if (expansion && !isStaticExpansionMethod) { FunctionParameter[] withoutFirst = Arrays.copyOfRange(header.parameters, 1, header.parameters.length); header = new FunctionHeader(header.typeParameters, header.getReturnType(), header.thrownType, withoutFirst); } for (MethodID id : ids) { - JavaRuntimeMethod runtimeMethod = new JavaRuntimeMethod(class_, target, method, id, header, implicit, expansion && !isStaticExpansion); + JavaRuntimeMethod runtimeMethod = new JavaRuntimeMethod(class_, target, method, id, header, implicit, expansion && !isStaticExpansionMethod); methods.computeIfAbsent(id, x -> new ArrayList<>()).add(runtimeMethod); class_.module.getCompiled().setMethodInfo(runtimeMethod, runtimeMethod); } } + + + if (class_.cls.isEnum()) { + Stream.of( + BuiltinMethodSymbol.ENUM_NAME, + BuiltinMethodSymbol.ENUM_ORDINAL, + //BuiltinMethodSymbol.ENUM_VALUES, + BuiltinMethodSymbol.ENUM_COMPARE + ).forEach(method -> methods + .computeIfAbsent(method.getID(), x -> new ArrayList<>()) + .add(method) + ); + + try { + MethodID id = MethodID.staticGetter("values"); + FunctionHeader header = new FunctionHeader(new ArrayTypeID(target)); + Method method = class_.cls.getMethod("values"); + JavaRuntimeMethod runtimeMethod = new JavaRuntimeMethod(class_, target, method, id, header, false, false); + methods.computeIfAbsent(id, x -> new ArrayList<>()).add(runtimeMethod); + class_.module.getCompiled().setMethodInfo(runtimeMethod, runtimeMethod); + } catch (ReflectiveOperationException exception) { + throw new IllegalStateException("We found an enum class without values() method: " + class_.cls.getCanonicalName(), exception); + } + + } } private void loadInnerTypes() { diff --git a/ScriptingExample/src/test/java/org/openzen/zenscript/scriptingexample/tests/actual_test/java_native/enums/EnumMemberTests.java b/ScriptingExample/src/test/java/org/openzen/zenscript/scriptingexample/tests/actual_test/java_native/enums/EnumMemberTests.java index 648bc9074..8c52af4b7 100644 --- a/ScriptingExample/src/test/java/org/openzen/zenscript/scriptingexample/tests/actual_test/java_native/enums/EnumMemberTests.java +++ b/ScriptingExample/src/test/java/org/openzen/zenscript/scriptingexample/tests/actual_test/java_native/enums/EnumMemberTests.java @@ -28,6 +28,34 @@ void EnumMembersMustBeRetrievableByTypeHintAndName() { logger.assertPrintOutput(0, "A"); } + @Test + void EnumMembersMustBeRetrievableByFullName() { + ScriptBuilder.create() + .add("public class MyClass {") + .add(" public this(thing as test_module.MyEnum) {") + .add(" println(thing.name);") + .add(" }") + .add("}") + .add("new MyClass(test_module.MyEnum.A);") + .execute(this); + + logger.assertPrintOutputSize(1); + logger.assertPrintOutput(0, "A"); + } + + @Test + void EnumMembersMustHaveValuesGetter() { + ScriptBuilder.create() + .add("var values = test_module.MyEnum.values;") + .add("var a = values[0];") + .add("var name = a.name;") + .add("println(a.name);") + .execute(this); + + logger.assertPrintOutputSize(1); + logger.assertPrintOutput(0, "A"); + } + @ZenCodeType.Name("test_module.MyEnum") public enum MyEnum { diff --git a/ScriptingExample/src/test/java/org/openzen/zenscript/scriptingexample/tests/actual_test/joined_tests/TypeInferenceBlockingTest.java b/ScriptingExample/src/test/java/org/openzen/zenscript/scriptingexample/tests/actual_test/joined_tests/TypeInferenceBlockingTest.java deleted file mode 100644 index c6bd7efd6..000000000 --- a/ScriptingExample/src/test/java/org/openzen/zenscript/scriptingexample/tests/actual_test/joined_tests/TypeInferenceBlockingTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.openzen.zenscript.scriptingexample.tests.actual_test.joined_tests; - -import org.junit.jupiter.api.Test; -import org.openzen.zencode.java.ZenCodeType; -import org.openzen.zenscript.scriptingexample.tests.helpers.ScriptBuilder; -import org.openzen.zenscript.scriptingexample.tests.helpers.ZenCodeTest; - -import java.util.List; - -class TypeInferenceBlockingTest extends ZenCodeTest { - - @Test - void doTheTest() { - ScriptBuilder.create() - .add("public class MyClass {") - .add(" public this(thing as test_module.MyEnum) {") - .add(" println(thing.name);") - .add(" }") - .add("}") - .add("new MyClass(test_module.MyEnum.A);") - .execute(this); - - logger.assertPrintOutputSize(1); - logger.assertPrintOutput(0, "A"); - } - - - @Override - public List> getRequiredClasses() { - final List> requiredClasses = super.getRequiredClasses(); - requiredClasses.add(MyEnum.class); - return requiredClasses; - } - - @ZenCodeType.Name("test_module.MyEnum") - public enum MyEnum { - A, B, C - } -}