diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/expression/StaticMemberCompilingExpression.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/expression/StaticMemberCompilingExpression.java index d1234b918..da0e19dae 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/expression/StaticMemberCompilingExpression.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/expression/StaticMemberCompilingExpression.java @@ -9,6 +9,7 @@ import org.openzen.zenscript.codemodel.type.TypeID; import java.util.Optional; +import java.util.stream.Stream; public class StaticMemberCompilingExpression extends AbstractCompilingExpression { private final TypeID type; @@ -27,12 +28,29 @@ public Expression eval() { return compiler.at(position).invalid(CompileErrors.typeArgumentsNotAllowedHere()); ResolvedType resolved = compiler.resolve(type); - return resolved.findStaticGetter(name.name) - .map(getter -> getter.call(compiler, position, TypeID.NONE)) - .orElseGet(() -> - resolved.getContextMember(name.name) - .map(member -> member.compile(compiler).eval()) - .orElseGet(() -> compiler.at(position).invalid(CompileErrors.noMemberInType(type, name.name)))); + + /*Optional asGetter = resolved.findStaticGetter(name.name) + .map(getter -> getter.call(compiler, position, TypeID.NONE)); + if (asGetter.isPresent()) { + return asGetter.get(); + }*/ + + Optional staticGetter = resolved.findStaticGetter(name.name); + if(staticGetter.isPresent()){ + return staticGetter.get().call(compiler, position, TypeID.NONE); + } + Optional contextMember = resolved.getContextMember(name.name); + if(contextMember.isPresent()){ + return contextMember.get().compile(compiler).eval(); + } + return compiler.at(position).invalid(CompileErrors.noMemberInType(type, name.name)); + +// return resolved.findStaticGetter(name.name) +// .map(getter -> getter.call(compiler, position, TypeID.NONE)) +// .orElseGet(() -> +// resolved.getContextMember(name.name) +// .map(member -> member.compile(compiler).eval()) +// .orElseGet(() -> compiler.at(position).invalid(CompileErrors.noMemberInType(type, name.name)))); } @Override diff --git a/JavaAnnotations/src/main/java/org/openzen/zencode/java/ZenCodeType.java b/JavaAnnotations/src/main/java/org/openzen/zencode/java/ZenCodeType.java index 37f3aed5f..bd760deb7 100644 --- a/JavaAnnotations/src/main/java/org/openzen/zencode/java/ZenCodeType.java +++ b/JavaAnnotations/src/main/java/org/openzen/zencode/java/ZenCodeType.java @@ -63,6 +63,12 @@ enum OperatorType { String value(); } + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @interface Inner { + String value() default ""; + } + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @interface Struct { diff --git a/JavaIntegration/src/main/java/org/openzen/zencode/java/impl/conversion/ConversionUtils.java b/JavaIntegration/src/main/java/org/openzen/zencode/java/impl/conversion/ConversionUtils.java new file mode 100644 index 000000000..3e3b66246 --- /dev/null +++ b/JavaIntegration/src/main/java/org/openzen/zencode/java/impl/conversion/ConversionUtils.java @@ -0,0 +1,20 @@ +package org.openzen.zencode.java.impl.conversion; + +import org.openzen.zencode.java.ZenCodeType; +import org.openzen.zenscript.javashared.JavaClass; + +public class ConversionUtils { + private ConversionUtils() {} + + public static JavaClass.Kind getKindFromAnnotations(Class cls) { + if (cls.isAnnotationPresent(ZenCodeType.Expansion.class)) { + return JavaClass.Kind.EXPANSION; + } else if (cls.isInterface()) { + return JavaClass.Kind.INTERFACE; + } else if (cls.isEnum()) { + return JavaClass.Kind.ENUM; + } else { + return JavaClass.Kind.CLASS; + } + } +} diff --git a/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaNativeModule.java b/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaNativeModule.java index ab56dcb88..1c1facde9 100644 --- a/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaNativeModule.java +++ b/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaNativeModule.java @@ -10,6 +10,7 @@ import org.openzen.zencode.java.ZenCodeGlobals; import org.openzen.zencode.java.ZenCodeType; import org.openzen.zencode.java.impl.JavaNativeModuleSpace; +import org.openzen.zencode.java.impl.conversion.ConversionUtils; import org.openzen.zencode.java.impl.conversion.JavaNativeHeaderConverter; import org.openzen.zencode.java.impl.conversion.JavaRuntimeTypeConverterImpl; import org.openzen.zencode.shared.logging.IZSLogger; @@ -97,22 +98,17 @@ public JavaRuntimeClass addClass(Class cls) { return classes.get(cls); } - JavaClass.Kind kind; + JavaClass.Kind kind = ConversionUtils.getKindFromAnnotations(cls); TypeID target = null; - if (cls.isAnnotationPresent(ZenCodeType.Expansion.class)) { - kind = JavaClass.Kind.EXPANSION; + if (kind == JavaClass.Kind.EXPANSION) { ZenCodeType.Expansion expansion = cls.getAnnotation(ZenCodeType.Expansion.class); target = typeConverter.parseType(expansion.value()); - } else if (cls.isInterface()) { - kind = JavaClass.Kind.INTERFACE; - } else if (cls.isEnum()) { - kind = JavaClass.Kind.ENUM; - } else { - kind = JavaClass.Kind.CLASS; } - JavaRuntimeClass class_ = new JavaRuntimeClass(this, cls, target, kind); + ParsedName name = getClassName(packageInfo.getPkg(), cls); + JavaRuntimeClass class_ = new JavaRuntimeClass(this, cls, name.name, target, kind); classes.put(cls, class_); + name.pkg.register(class_); return class_; } @@ -194,4 +190,55 @@ public JavaRuntimeTypeConverter getTypeConverter() { public JavaNativeHeaderConverter getHeaderConverter() { return headerConverter; } + + private ParsedName getClassName(ZSPackage pkg, Class cls) { + boolean isStruct = cls.isAnnotationPresent(ZenCodeType.Struct.class); + final String specifiedName = getNameForScripts(cls); + + ZSPackage classPkg; + boolean hasAnnotation = cls.isAnnotationPresent(ZenCodeType.Name.class); + String className = specifiedName.contains(".") ? specifiedName.substring(specifiedName.lastIndexOf('.') + 1) : specifiedName; + if (!hasAnnotation) { + if (!specifiedName.startsWith(packageInfo.getPkg().fullName)) { + classPkg = packageInfo.getPackage(className); + } else { + classPkg = packageInfo.getPackage(packageInfo.getBasePackage() + specifiedName.substring(packageInfo.getPkg().fullName.length())); + className = specifiedName.substring(specifiedName.lastIndexOf('.') + 1); + } + } else { + if (specifiedName.startsWith(".")) { + classPkg = packageInfo.getPackage(specifiedName); + className = specifiedName.substring(specifiedName.lastIndexOf('.') + 1); + } else if (specifiedName.indexOf('.') >= 0) { + if (!specifiedName.startsWith(packageInfo.getPkg().fullName)) + throw new IllegalArgumentException("Specified @Name as \"" + specifiedName + "\" for class: \"" + cls + .toString() + "\" but it's not in the module root package: \"" + packageInfo.getPkg().fullName + "\""); + + classPkg = packageInfo.getPackage(packageInfo.getBasePackage() + specifiedName.substring(packageInfo.getPkg().fullName.length())); + className = specifiedName.substring(specifiedName.lastIndexOf('.') + 1); + } else { + classPkg = packageInfo.getPackage(specifiedName); + className = specifiedName; + } + } + + return new ParsedName(classPkg, className); + } + + private static String getNameForScripts(Class cls) { + if (cls.isAnnotationPresent(ZenCodeType.Name.class)) { + return cls.getAnnotation(ZenCodeType.Name.class).value(); + } + return cls.getName(); + } + + private static class ParsedName { + private final ZSPackage pkg; + private final String name; + + public ParsedName(ZSPackage pkg, String name) { + this.pkg = pkg; + this.name = name; + } + } } 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 3eec48800..78c4855f8 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 @@ -13,6 +13,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.function.UnaryOperator; import java.util.stream.Collectors; public class JavaNativeTypeMembers implements ResolvedType { @@ -104,7 +105,7 @@ public Optional findField(String name) { @Override public Optional findInnerType(String name) { - return Optional.empty(); // not yet supported + return template.getInnerType(name).map(UnaryOperator.identity()); } @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 44123a68d..f505173d9 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 @@ -3,6 +3,7 @@ import org.objectweb.asm.Type; import org.openzen.zencode.java.TypeVariableContext; import org.openzen.zencode.java.ZenCodeType; +import org.openzen.zencode.java.impl.conversion.ConversionUtils; import org.openzen.zencode.java.impl.conversion.JavaNativeHeaderConverter; import org.openzen.zencode.shared.CodePosition; import org.openzen.zenscript.codemodel.FunctionHeader; @@ -17,6 +18,7 @@ import org.openzen.zenscript.codemodel.ssa.CodeBlockStatement; import org.openzen.zenscript.codemodel.ssa.SSAVariableCollector; import org.openzen.zenscript.codemodel.type.TypeID; +import org.openzen.zenscript.javashared.JavaClass; import org.openzen.zenscript.javashared.JavaModifiers; import org.openzen.zenscript.javashared.JavaNativeField; @@ -35,6 +37,7 @@ public class JavaNativeTypeTemplate { private List constructors; private Map fields; private Map> methods; + private Map innerTypes; public List getConstructors() { if (constructors == null) { @@ -74,6 +77,14 @@ public Optional getField(String name) { return Optional.ofNullable(fields.get(name)); } + public Optional getInnerType(String name) { + if (innerTypes == null) { + loadInnerTypes(); + } + + return Optional.ofNullable(innerTypes.get(name)); + } + public Optional getContextMember(String name) { return getField(name) .filter(JavaRuntimeField::isEnumConstant) @@ -153,6 +164,18 @@ private void loadMethods() { } } + private void loadInnerTypes() { + innerTypes = new HashMap<>(); + + for (Class cls : class_.cls.getDeclaredClasses()) { + ZenCodeType.Inner innerType = cls.getAnnotation(ZenCodeType.Inner.class); + String name = innerType.value().isEmpty() ? cls.getSimpleName() : innerType.value(); + JavaClass.Kind kind = ConversionUtils.getKindFromAnnotations(cls); + JavaRuntimeClass innerClass = new JavaRuntimeClass(class_.module, cls, name, null, kind); + innerTypes.put(name, innerClass); + } + } + private boolean isNotAccessible(Method method) { return !Modifier.isPublic(method.getModifiers()); } diff --git a/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaRuntimeClass.java b/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaRuntimeClass.java index c05aae162..eb06c7ead 100644 --- a/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaRuntimeClass.java +++ b/JavaIntegration/src/main/java/org/openzen/zencode/java/module/JavaRuntimeClass.java @@ -23,15 +23,17 @@ public class JavaRuntimeClass implements TypeSymbol { public final JavaNativeModule module; public final JavaClass javaClass; public final Class cls; + public final String name; private final Modifiers modifiers; private final JavaNativeTypeTemplate template; private final TypeParameter[] typeParameters; private final TypeVariableContext context = new TypeVariableContext(); - public JavaRuntimeClass(JavaNativeModule module, Class cls, TypeID target, JavaClass.Kind kind) { + public JavaRuntimeClass(JavaNativeModule module, Class cls, String name, TypeID target, JavaClass.Kind kind) { this.module = module; this.cls = cls; + this.name = name; this.javaClass = JavaClass.fromInternalName(Type.getInternalName(cls), kind); this.modifiers = translateModifiers(cls.getModifiers()); this.typeParameters = translateTypeParameters(cls); @@ -49,7 +51,7 @@ public ModuleSymbol getModule() { @Override public String describe() { - return cls.getName(); + return name; } @Override @@ -79,7 +81,7 @@ public boolean isEnum() { @Override public String getName() { - return cls.getName(); + return name; } @Override diff --git a/ScriptingEngineTester/src/main/resources/zencode-tests/classes/inner_classes.zc b/ScriptingEngineTester/src/main/resources/zencode-tests/classes/inner_classes-1.zc similarity index 100% rename from ScriptingEngineTester/src/main/resources/zencode-tests/classes/inner_classes.zc rename to ScriptingEngineTester/src/main/resources/zencode-tests/classes/inner_classes-1.zc diff --git a/ScriptingEngineTester/src/main/resources/zencode-tests/classes/inner_classes-2.zc b/ScriptingEngineTester/src/main/resources/zencode-tests/classes/inner_classes-2.zc new file mode 100644 index 000000000..f4555b5a2 --- /dev/null +++ b/ScriptingEngineTester/src/main/resources/zencode-tests/classes/inner_classes-2.zc @@ -0,0 +1,12 @@ +#output: Inner + +public class Outer { + + public static class Inner { + public static getName(): string { + return "Inner"; + } + } +} + +println(Outer.Inner.getName()); diff --git a/ScriptingExample/src/test/java/org/openzen/zenscript/scriptingexample/tests/actual_test/classes/InnerClassesCanBeAddedViaJavaTest.java b/ScriptingExample/src/test/java/org/openzen/zenscript/scriptingexample/tests/actual_test/classes/InnerClassesCanBeAddedViaJavaTest.java index 94a5ffaec..f75827057 100644 --- a/ScriptingExample/src/test/java/org/openzen/zenscript/scriptingexample/tests/actual_test/classes/InnerClassesCanBeAddedViaJavaTest.java +++ b/ScriptingExample/src/test/java/org/openzen/zenscript/scriptingexample/tests/actual_test/classes/InnerClassesCanBeAddedViaJavaTest.java @@ -29,8 +29,8 @@ public void testInnerClassesCanBeAddedViaJava_Outer() { @Test public void testInnerClassesCanBeAddedViaJava_Inner() { ScriptBuilder.create() - .add("import test_module.Outer.Inner;") - .add("println(Inner.getName());") + .add("import test_module.Outer;") + .add("println(Outer.Inner.getName());") .execute(this); this.logger.assertPrintOutputSize(1); @@ -41,7 +41,6 @@ public void testInnerClassesCanBeAddedViaJava_Inner() { public List> getRequiredClasses() { List> requiredClasses = super.getRequiredClasses(); requiredClasses.add(Outer.class); - requiredClasses.add(Outer.Inner.class); return requiredClasses; } @@ -53,7 +52,7 @@ public static String getName() { return "Outer"; } - @ZenCodeType.Name("test_module.Outer.Inner") + @ZenCodeType.Inner public static class Inner { @ZenCodeType.Method public static String getName() { diff --git a/StdLibs b/StdLibs index cfa5b45a8..08927818c 160000 --- a/StdLibs +++ b/StdLibs @@ -1 +1 @@ -Subproject commit cfa5b45a8bbae5a372a6ff599db79710c0563f39 +Subproject commit 08927818c710ae6e68c5a6dae675873622062d84