diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/JavaBytecodeContext.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/JavaBytecodeContext.java index 1d1195377..f80375609 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/JavaBytecodeContext.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/JavaBytecodeContext.java @@ -31,7 +31,6 @@ public class JavaBytecodeContext extends JavaContext { private final TypeGenerator typeGenerator; private final JavaTypeInternalNameVisitor internalNameVisitor; private final JavaTypeDescriptorVisitor descriptorVisitor; - private int lambdaCounter = 0; private final Map bytecodeLoopLabels = new HashMap<>(); public JavaBytecodeContext(JavaBytecodeModule target, JavaCompileSpace space, ZSPackage modulePackage, String basePackage, IZSLogger logger) { @@ -130,10 +129,6 @@ private void createSharedClass() { // TODO } - public int getLambdaCounter() { - return ++lambdaCounter; - } - public BytecodeLoopLabels getLoopLabels(LoopStatement loopStatement) { return bytecodeLoopLabels.get(loopStatement.objectId); } diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/JavaCompiler.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/JavaCompiler.java index acce1c4d7..082d365eb 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/JavaCompiler.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/JavaCompiler.java @@ -27,10 +27,7 @@ import org.openzen.zenscript.javashared.prepare.JavaPrepareDefinitionMemberVisitor; import org.openzen.zenscript.javashared.prepare.JavaPrepareDefinitionVisitor; -import java.io.File; import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; /** * @author Hoofdgebruiker @@ -38,11 +35,11 @@ public class JavaCompiler { private final IZSLogger logger; - private int generatedScriptBlockCounter = 0; - private int expansionCounter = 0; + private final JavaMangler mangler; public JavaCompiler(IZSLogger logger) { this.logger = logger; + this.mangler = new JavaMangler(); } public JavaBytecodeModule compile(String packageName, SemanticModule module, JavaCompileSpace space, JavaEnumMapper enumMapper) { @@ -51,8 +48,8 @@ public JavaBytecodeModule compile(String packageName, SemanticModule module, Jav // Scripts with a higher priority load before scripts with a lower priority. module.scripts.sort(Comparator.comparingInt(a -> a.file.getOrder()).reversed()); module.scripts.forEach(script -> { - final String className = getClassName(script.file == null ? null : script.file.getFilename()); - getScriptFile(scriptBlocks, script.pkg.fullName + "/" + className); + final String className = this.mangler.mangleScriptName(script.file); + getScriptFile(scriptBlocks, script.pkg.fullName + '/' + className); }); Set scriptFilesThatAreActuallyUsedInScripts = new HashSet<>(); @@ -66,13 +63,7 @@ public JavaBytecodeModule compile(String packageName, SemanticModule module, Jav allDefinitions.addAll(module.expansions); for (HighLevelDefinition definition : allDefinitions) { - final String className = getClassName(getFilename(definition)); - final String filename; - if (definition instanceof FunctionDefinition) { - filename = className; - } else { - filename = className + "_" + (definition.name == null ? "generated" : definition.name) + "_" + expansionCounter++; - } + final String filename = this.mangler.mangleDefinitionName(definition); JavaPrepareDefinitionVisitor definitionPreparer = new JavaPrepareDefinitionVisitor(compiling, filename, null, filename); definition.accept(definitionPreparer); } @@ -88,8 +79,8 @@ public JavaBytecodeModule compile(String packageName, SemanticModule module, Jav final String internalName; final JavaScriptFile scriptFile; if (definition instanceof FunctionDefinition) { - internalName = getClassName(getFilename(definition)); - scriptFile = getScriptFile(scriptBlocks, definition.pkg.fullName.replace('.', '/') + "/" + internalName); + internalName = this.mangler.mangleSourceFileName(definition); + scriptFile = getScriptFile(scriptBlocks, definition.pkg.fullName.replace('.', '/') + '/' + internalName); scriptFilesThatAreActuallyUsedInScripts.add(scriptFile); } else { JavaClass cls = definition instanceof ExpansionDefinition ? context.getJavaExpansionClass(definition) : context @@ -98,7 +89,7 @@ public JavaBytecodeModule compile(String packageName, SemanticModule module, Jav internalName = cls.internalName; } scriptFile.classWriter.visitSource(definition.position.getFilename(), null); - target.addClass(internalName, definition.accept(new JavaDefinitionVisitor(context, compiling, scriptFile.classWriter))); + target.addClass(internalName, definition.accept(new JavaDefinitionVisitor(context, compiling, scriptFile.classWriter, mangler))); } FunctionHeader scriptHeader = new FunctionHeader(BasicTypeID.VOID, module.parameters); @@ -113,14 +104,14 @@ public JavaBytecodeModule compile(String packageName, SemanticModule module, Jav for (ScriptBlock script : module.scripts) { final SourceFile sourceFile = script.file; - final String className = getClassName(sourceFile == null ? null : sourceFile.getFilename()); - JavaScriptFile scriptFile = getScriptFile(scriptBlocks, script.pkg.fullName + "/" + className); + final String className = this.mangler.mangleScriptName(sourceFile); + JavaScriptFile scriptFile = getScriptFile(scriptBlocks, script.pkg.fullName + '/' + className); scriptFilesThatAreActuallyUsedInScripts.add(scriptFile); if (sourceFile != null) { scriptFile.classWriter.visitSource(sourceFile.getFilename(), null); } - String methodName = scriptFile.scriptMethods.isEmpty() ? "run" : "run" + scriptFile.scriptMethods.size(); + String methodName = this.mangler.mangleScriptBodyMethod(scriptFile.scriptMethods.size()); // convert scripts into methods (add them to a Scripts class?) // (TODO: can we break very long scripts into smaller methods? for the extreme scripts) @@ -130,7 +121,8 @@ public JavaBytecodeModule compile(String packageName, SemanticModule module, Jav JavaCompilingMethod compilingMethod = new JavaCompilingMethod(scriptsClass, method, scriptDescriptor); scriptFile.scriptMethods.add(new JavaScriptMethod(method, module.parameters, javaScriptParameters)); - final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, context.getJavaModule(script.module), new JavaWriter(logger, CodePosition.UNKNOWN, visitor, compilingMethod, null)); + final JavaWriter writer = new JavaWriter(logger, CodePosition.UNKNOWN, visitor, compilingMethod, null); + final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, context.getJavaModule(script.module), writer, mangler); statementVisitor.start(); for (Statement statement : script.statements) { statement.accept(statementVisitor); @@ -151,35 +143,6 @@ public JavaBytecodeModule compile(String packageName, SemanticModule module, Jav return target; } - private String getFilename(HighLevelDefinition definition) { - SourceFile source = definition.position.file; - if (source != null) { - List parts = source.getFilePath(); - return parts.get(parts.size() - 1); - } else { - return definition.name == null ? "Expansion" : definition.name; - } - } - - private String getClassName(String filename) { - if (filename == null) { - return "generatedBlock" + (generatedScriptBlockCounter++); - } else { - // TODO: find all special characters - final String specialCharRegex = Stream.of('/', '\\', '.', ';') - .filter(character -> character != File.separatorChar) - .map(String::valueOf) - .collect(Collectors.joining("", "[", "]")); - - return filename - .substring(0, filename.lastIndexOf('.')) //remove the .zs part - .replaceAll(specialCharRegex, "_") - .replace('[', '_') - .replace(File.separatorChar, '/') - .concat("$"); - } - } - private JavaScriptFile getScriptFile(Map scriptBlocks, String className) { if (!scriptBlocks.containsKey(className)) { JavaClassWriter scriptFileWriter = new JavaClassWriter(ClassWriter.COMPUTE_FRAMES); diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/JavaMangler.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/JavaMangler.java new file mode 100644 index 000000000..f68bbafd9 --- /dev/null +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/JavaMangler.java @@ -0,0 +1,247 @@ +package org.openzen.zenscript.javabytecode; + +import org.openzen.zencode.shared.SourceFile; +import org.openzen.zenscript.codemodel.FunctionHeader; +import org.openzen.zenscript.codemodel.FunctionParameter; +import org.openzen.zenscript.codemodel.HighLevelDefinition; +import org.openzen.zenscript.codemodel.definition.ExpansionDefinition; +import org.openzen.zenscript.codemodel.definition.FunctionDefinition; +import org.openzen.zenscript.codemodel.generic.TypeParameter; +import org.openzen.zenscript.codemodel.type.BasicTypeID; +import org.openzen.zenscript.codemodel.type.IteratorTypeID; +import org.openzen.zenscript.codemodel.type.TypeID; + +import java.nio.file.FileSystems; +import java.util.*; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public final class JavaMangler { + private static final class MangleCounter { + private final Map counters; + + MangleCounter() { + this.counters = new HashMap<>(); + } + + int get(final Object key) { + return this.counters.compute(key, (k, v) -> v == null? 0 : ++v); + } + } + + private static final String EXP_TAR_MANGLE_ARRAY_ID = "_l"; + private static final String EXP_TAR_MANGLE_ASSOC_ID = "_m"; + private static final String EXP_TAR_MANGLE_BASIC_ID = "_b"; + private static final String EXP_TAR_MANGLE_DEFINITION_ID = "_c"; + private static final String EXP_TAR_MANGLE_FUNCTION_ID = "_f"; + private static final String EXP_TAR_MANGLE_GENERIC_ID = "_g"; + private static final String EXP_TAR_MANGLE_GENERIC_MAP_ID = "_h"; + private static final String EXP_TAR_MANGLE_ITERATOR_ID = "_i"; + private static final String EXP_TAR_MANGLE_OPTIONAL_ID = "_o"; + private static final String EXP_TAR_MANGLE_RANGE_ID = "_r"; + + private final MangleCounter mangleCounters; + + public JavaMangler() { + this.mangleCounters = new MangleCounter(); + } + + public String mangleScriptName(final SourceFile sourceFile) { + return this.mangleScriptName(sourceFile == null? null : sourceFile.getFilename()); + } + + public String mangleScriptBodyMethod(final int methodsAmount) { + return "script-body" + (methodsAmount == 0? "" : ('-' + Integer.toString(methodsAmount))); + } + + public String mangleSourceFileName(final HighLevelDefinition definition) { + final SourceFile file = definition.position.file; + if (file != null) { + final List path = file.getFilePath(); + assert !path.isEmpty(); + return this.mangleScriptName(path.get(path.size() - 1)); + } + + // Only expansions have a null name + // TODO: Why is this mangled too? + return this.mangleScriptName(definition.name == null? "Expansion" : definition.name); + } + + public String mangleDefinitionName(final HighLevelDefinition definition) { + final String mangledSource = this.mangleSourceFileName(definition); + if (definition instanceof FunctionDefinition) { + // We want function definitions to be in the same place as the script, so we will not mangle them further + return mangledSource; + } + + final Class clazz = definition.getClass(); + final StringBuilder builder = new StringBuilder(mangledSource); + builder.append('$'); + builder.append(clazz.getSimpleName().replace("Definition", "")); + builder.append('$'); + + if (definition instanceof ExpansionDefinition) { + final class ExpansionId { + private final String id; + + ExpansionId(final String id) { + this.id = id; + } + + @Override + public boolean equals(final Object o) { + return this == o || o instanceof ExpansionId && this.id.equals(((ExpansionId) o).id); + } + + @Override + public int hashCode() { + return 31 * this.id.hashCode(); + } + } + + // Expansions not only do not have a name, but they can be for different types: for ease of debugging, we + // want to include information on the type that is expanded + final String target = this.mangleExpansionTarget(((ExpansionDefinition) definition).target); + builder.append(target); + builder.append('$'); + builder.append(this.mangleCounters.get(new ExpansionId(target))); + } else { + builder.append(definition.name); + builder.append('$'); + builder.append(this.mangleCounters.get(clazz)); + } + + return builder.toString(); + } + + public String mangleGeneratedLambdaName(final String interfaceName) { + final class LambdaId { + final String target; + + LambdaId(final String target) { + this.target = target; + } + + @Override + public boolean equals(final Object o) { + return this == o || o instanceof LambdaId && this.target.equals(((LambdaId) o).target); + } + + @Override + public int hashCode() { + return 17 * this.target.hashCode(); + } + } + + final String interfaceTarget = interfaceName.replace('/', '_').replace('.', '_'); + // TODO("Rework package structure") + return "zsynthetic/$Lambda$" + interfaceTarget + '$' + this.mangleCounters.get(new LambdaId(interfaceTarget)); + } + + public String mangleGeneratedLambdaName(final FunctionHeader header) { + return this.mangleGeneratedLambdaName("$Generated" + EXP_TAR_MANGLE_FUNCTION_ID + this.encodeLengthNameFormat(this.mangleFunctionHeader(header))); + } + + public String mangleCapturedParameter(final int parameterId, final boolean isThis) { + if (isThis) { + return "$this"; + } else { + return "$" + parameterId; + } + } + + private String mangleScriptName(final String rawName) { + if (rawName == null) { + class GeneratedBlock {} + return "$GeneratedBlock" + this.mangleCounters.get(GeneratedBlock.class); + } + final String separator = FileSystems.getDefault().getSeparator(); + final String specialCharRegex = Stream.of("/", "\\", ".", ";", "\\[") + .filter(character -> !character.equals(separator)) + .collect(Collectors.joining("", "[", "]")); + return rawName.substring(0, rawName.lastIndexOf('.')) // remove .zs/.zc + .replaceAll(specialCharRegex, "_") + .replace(separator, "/") + .concat("$"); + } + + private String mangleExpansionTarget(final TypeID target) { + return this.oneOf( + () -> this.mangleIf(EXP_TAR_MANGLE_ARRAY_ID, target::asArray, it -> Character.toString('D') + it.dimension + 'C' + this.mangleExpansionTarget(it.elementType)), + () -> this.mangleIf(EXP_TAR_MANGLE_ASSOC_ID, target::asAssoc, it -> this.mangleKv(this.mangleExpansionTarget(it.keyType), this.mangleExpansionTarget(it.valueType))), + () -> this.mangleIf(EXP_TAR_MANGLE_BASIC_ID, target, BasicTypeID.class, it -> it.name), + () -> this.mangleIf(EXP_TAR_MANGLE_DEFINITION_ID, target::asDefinition, it -> { + final String name = it.definition.getName(); + final int simpleNameBegin = name.lastIndexOf('.'); + return name.substring(simpleNameBegin + 1); + }), + () -> this.mangleIf(EXP_TAR_MANGLE_FUNCTION_ID, target::asFunction, it -> this.mangleFunctionHeader(it.header)), + () -> this.mangleIf(EXP_TAR_MANGLE_GENERIC_ID, target::asGeneric, it -> this.mangleGenericTypeParameter(it.parameter)), + () -> this.mangleIf( + EXP_TAR_MANGLE_GENERIC_MAP_ID, + target::asGenericMap, + it -> this.mangleKv(this.mangleGenericTypeParameter(it.key), this.mangleExpansionTarget(it.value)) + ), + () -> this.mangleIf( + EXP_TAR_MANGLE_ITERATOR_ID, + target, + IteratorTypeID.class, + it -> Arrays.stream(it.iteratorTypes).map(this::mangleExpansionTarget).map("I"::concat).collect(Collectors.joining()) + ), + () -> this.mangleIf(EXP_TAR_MANGLE_OPTIONAL_ID, target::asOptional, it -> this.mangleExpansionTarget(it.baseType)), + () -> this.mangleIf(EXP_TAR_MANGLE_RANGE_ID, target::asRange, it -> this.mangleExpansionTarget(it.baseType)) + ).orElseThrow(() -> new IllegalStateException("Unable to mangle target type " + target)); + } + + private Optional mangleIf(final String type, final TypeID id, final Class clazz, final Function extractor) { + return this.mangleIf(type, () -> Optional.of(id).filter(clazz::isInstance).map(clazz::cast), extractor); + } + + private Optional mangleIf(final String type, final Supplier> supplier, final Function extractor) { + return supplier.get().map(it -> this.mangleExpansionWithType(type, () -> extractor.apply(it))); + } + + private String mangleKv(final String mangledKey, final String mangledValue) { + return 'K' + mangledKey + 'V' + mangledValue; + } + + private String mangleExpansionWithType(final String type, final Supplier inner) { + return type + (inner == null? "" : this.encodeLengthNameFormat(inner.get())); + } + + private String mangleFunctionHeader(final FunctionHeader header) { + final StringBuilder builder = new StringBuilder("t"); + builder.append(header.typeParameters.length); + for (final TypeParameter typeParameter : header.typeParameters) { + builder.append('T').append(this.encodeLengthNameFormat(this.mangleGenericTypeParameter(typeParameter))); + } + builder.append('R'); + builder.append(this.encodeLengthNameFormat(this.mangleExpansionTarget(header.getReturnType()))); + builder.append('p'); + builder.append(header.parameters.length); + for (final FunctionParameter parameter : header.parameters) { + builder.append('P').append(this.encodeLengthNameFormat(this.mangleExpansionTarget(parameter.type))); + } + return builder.toString(); + } + + private String mangleGenericTypeParameter(final TypeParameter parameter) { + return parameter.name; // TODO("Verify") + } + + private String encodeLengthNameFormat(final String string) { + return string.length() + string; + } + + @SafeVarargs // It's private, so it's already final... + @SuppressWarnings("unchecked") + private final Optional oneOf(final Supplier>... suppliers) { + return Arrays.stream(suppliers) + .map(Supplier::get) + .filter(Optional::isPresent) + .findFirst() + .flatMap(it -> (Optional) it); + } +} diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/CompilerUtils.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/CompilerUtils.java index 20a5c6551..0d13b24ac 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/CompilerUtils.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/CompilerUtils.java @@ -12,6 +12,7 @@ import org.openzen.zenscript.codemodel.type.BasicTypeID; import org.openzen.zenscript.codemodel.type.TypeID; import org.openzen.zenscript.javabytecode.JavaBytecodeContext; +import org.openzen.zenscript.javabytecode.JavaMangler; import org.openzen.zenscript.javashared.JavaCompiledModule; import org.openzen.zenscript.javashared.JavaNativeField; import org.openzen.zenscript.javashared.JavaParameterInfo; @@ -131,8 +132,14 @@ public static void tagConstructorParameters(JavaBytecodeContext context, JavaCom */ } - public static void writeDefaultFieldInitializers(JavaBytecodeContext context, JavaWriter constructorWriter, HighLevelDefinition definition, boolean staticFields) { - JavaExpressionVisitor expressionVisitor = new JavaExpressionVisitor(context, context.getJavaModule(definition.module), constructorWriter); + public static void writeDefaultFieldInitializers( + JavaBytecodeContext context, + JavaWriter constructorWriter, + HighLevelDefinition definition, + JavaMangler mangler, + boolean staticFields + ) { + JavaExpressionVisitor expressionVisitor = new JavaExpressionVisitor(context, context.getJavaModule(definition.module), constructorWriter, mangler); for (final IDefinitionMember definitionMember : definition.members) { if (!(definitionMember instanceof FieldMember)) continue; diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaExpressionVisitor.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaExpressionVisitor.java index 715e3d8fd..c43350722 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaExpressionVisitor.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaExpressionVisitor.java @@ -13,19 +13,17 @@ import org.openzen.zenscript.codemodel.identifiers.ModuleSymbol; import org.openzen.zenscript.codemodel.definition.ExpansionDefinition; import org.openzen.zenscript.codemodel.expression.*; -import org.openzen.zenscript.codemodel.expression.switchvalue.VariantOptionSwitchValue; -import org.openzen.zenscript.codemodel.statement.VarStatement; import org.openzen.zenscript.codemodel.type.*; import org.openzen.zenscript.codemodel.type.builtin.BuiltinMethodSymbol; import org.openzen.zenscript.javabytecode.JavaBytecodeContext; import org.openzen.zenscript.javabytecode.JavaLocalVariableInfo; +import org.openzen.zenscript.javabytecode.JavaMangler; import org.openzen.zenscript.javabytecode.compiler.JavaModificationExpressionVisitor.PushOption; import org.openzen.zenscript.javashared.*; import org.openzen.zenscript.javashared.compiling.JavaCompilingMethod; import org.openzen.zenscript.javashared.expressions.JavaFunctionInterfaceCastExpression; import org.openzen.zenscript.javashared.types.JavaFunctionalInterfaceTypeID; -import java.lang.reflect.Array; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; @@ -40,45 +38,24 @@ public class JavaExpressionVisitor implements ExpressionVisitor { final JavaWriter javaWriter; final JavaBytecodeContext context; final JavaCompiledModule module; + private final JavaMangler javaMangler; private final JavaBoxingTypeVisitor boxingTypeVisitor; private final JavaUnboxingTypeVisitor unboxingTypeVisitor; private final JavaCapturedExpressionVisitor capturedExpressionVisitor = new JavaCapturedExpressionVisitor(this); private final JavaFieldBytecodeCompiler fieldCompiler; private final JavaMethodBytecodeCompiler methodCompiler; - public JavaExpressionVisitor(JavaBytecodeContext context, JavaCompiledModule module, JavaWriter javaWriter) { + public JavaExpressionVisitor(JavaBytecodeContext context, JavaCompiledModule module, JavaWriter javaWriter, JavaMangler javaMangler) { this.javaWriter = javaWriter; this.context = context; this.module = module; + this.javaMangler = javaMangler; boxingTypeVisitor = new JavaBoxingTypeVisitor(javaWriter); unboxingTypeVisitor = new JavaUnboxingTypeVisitor(javaWriter); fieldCompiler = new JavaFieldBytecodeCompiler(javaWriter, this, true); methodCompiler = new JavaMethodBytecodeCompiler(javaWriter, this, context, module); } - //TODO replace with visitor? - private static int calculateMemberPosition(GetLocalVariableExpression localVariableExpression, FunctionExpression expression) { - int h = 1;//expression.header.parameters.length; - for (CapturedExpression capture : expression.closure.captures) { - if (capture instanceof CapturedLocalVariableExpression && ((CapturedLocalVariableExpression) capture).variable == localVariableExpression.variable) - return h; - if (capture instanceof CapturedClosureExpression && ((CapturedClosureExpression) capture).value instanceof CapturedLocalVariableExpression && ((CapturedLocalVariableExpression) ((CapturedClosureExpression) capture).value).variable == localVariableExpression.variable) - return h; - h++; - } - throw new RuntimeException(localVariableExpression.position.toString() + ": Captured Statement error"); - } - - private static int calculateMemberPosition(CapturedParameterExpression functionParameterExpression, FunctionExpression expression) { - int h = 1;//expression.header.parameters.length; - for (CapturedExpression capture : expression.closure.captures) { - if (capture instanceof CapturedParameterExpression && ((CapturedParameterExpression) capture).parameter == functionParameterExpression.parameter) - return h; - h++; - } - throw new RuntimeException(functionParameterExpression.position.toString() + ": Captured Statement error"); - } - private static boolean hasNoDefault(MatchExpression switchStatement) { for (MatchExpression.Case switchCase : switchStatement.cases) if (switchCase.key == null) return false; @@ -506,8 +483,7 @@ public Void visitFunction(FunctionExpression expression) { } final JavaNativeMethod methodInfo; - // We don't allow registering classes starting with "java" - final String className = interfaces[0].replace("java", "j").replace("/", "_") + "_" + context.getLambdaCounter(); + final String className = this.javaMangler.mangleGeneratedLambdaName(interfaces[0]); { final JavaNativeMethod m = context.getFunctionalInterface(expression.type); methodInfo = new JavaNativeMethod(m.cls, m.kind, m.name, m.compile, m.descriptor, m.modifiers & ~JavaModifiers.ABSTRACT, m.genericResult, m.typeParameterArguments); @@ -576,13 +552,8 @@ public Void visitFunction(FunctionExpression expression) { for (CapturedExpression capture : expression.closure.captures) { constructorWriter.dup(); Type type = context.getType(capture.type); - String name; - ++i; - if (capture instanceof CapturedThisExpression) { - name = "capturedThis"; - } else { - name = "captured" + i; - } + // TODO("Or maybe split i and ++i?") + String name = this.javaMangler.mangleCapturedParameter(++i, capture instanceof CapturedThisExpression); lambdaCW.visitField(Opcodes.ACC_FINAL | Opcodes.ACC_PRIVATE, name, type.getDescriptor(), null, null).visitEnd(); capture.accept(this); @@ -601,42 +572,9 @@ public Void visitFunction(FunctionExpression expression) { functionWriter.start(); - - final JavaStatementVisitor CSV = new JavaStatementVisitor(context, new JavaExpressionVisitor(context, module, functionWriter) { - @Override - public Void visitGetLocalVariable(GetLocalVariableExpression varExpression) { - final JavaLocalVariableInfo localVariable = functionWriter.tryGetLocalVariable(varExpression.variable.id); - if (localVariable != null) { - final Label label = new Label(); - localVariable.end = label; - functionWriter.label(label); - functionWriter.load(localVariable); - return null; - } - - final int position = calculateMemberPosition(varExpression, expression); - functionWriter.loadObject(0); - functionWriter.getField(className, "captured" + position, context.getDescriptor(varExpression.variable.type)); - return null; - } - - @Override - public Void visitCapturedParameter(CapturedParameterExpression varExpression) { - final int position = calculateMemberPosition(varExpression, expression); - functionWriter.loadObject(0); - functionWriter.getField(className, "captured" + position, context.getDescriptor(varExpression.parameter.type)); - return null; - } - - @Override - public Void visitCapturedThis(CapturedThisExpression expression) { - functionWriter.loadObject(0); - functionWriter.getField(className, "capturedThis", context.getDescriptor(expression.type)); - return null; - } - }); - - expression.body.accept(CSV); + final JavaExpressionVisitor lambdaBodyVisitor = new JavaLambdaBodyCapturingExpressionVisitor(context, module, functionWriter, javaMangler, className, expression); + final JavaStatementVisitor capturedStatementVisitor = new JavaStatementVisitor(context, lambdaBodyVisitor, javaMangler); + expression.body.accept(capturedStatementVisitor); functionWriter.ret(); functionWriter.end(); @@ -1132,9 +1070,8 @@ private void visitFunctionalInterfaceWrapping(JavaFunctionInterfaceCastExpressio } private FunctionCastWrapperClass generateFunctionCastWrapperClass(CodePosition position, FunctionTypeID fromType, FunctionTypeID toType) { - final String lambdaName = "lambda" + context.getLambdaCounter(); - final JavaClass classInfo = new JavaClass("zsynthetic", lambdaName, JavaClass.Kind.CLASS); - final String className = "zsynthetic/" + lambdaName; + final String className = this.javaMangler.mangleGeneratedLambdaName(fromType.header); + final JavaClass classInfo = JavaClass.fromInternalName(className, JavaClass.Kind.CLASS); String[] interfaces; String wrappedFromSignature = context.getDescriptor(fromType); diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaLambdaBodyCapturingExpressionVisitor.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaLambdaBodyCapturingExpressionVisitor.java new file mode 100644 index 000000000..a6e05f0d6 --- /dev/null +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaLambdaBodyCapturingExpressionVisitor.java @@ -0,0 +1,83 @@ +package org.openzen.zenscript.javabytecode.compiler; + +import org.objectweb.asm.Label; +import org.openzen.zenscript.codemodel.expression.*; +import org.openzen.zenscript.javabytecode.JavaBytecodeContext; +import org.openzen.zenscript.javabytecode.JavaLocalVariableInfo; +import org.openzen.zenscript.javabytecode.JavaMangler; +import org.openzen.zenscript.javashared.JavaCompiledModule; + +public class JavaLambdaBodyCapturingExpressionVisitor extends JavaExpressionVisitor { + private final String lambdaClassName; + private final FunctionExpression functionExpression; + private final JavaMangler javaMangler; + + public JavaLambdaBodyCapturingExpressionVisitor( + final JavaBytecodeContext context, + final JavaCompiledModule module, + final JavaWriter javaWriter, + final JavaMangler javaMangler, + final String lambdaClassName, + final FunctionExpression functionExpression + ) { + super(context, module, javaWriter, javaMangler); + this.lambdaClassName = lambdaClassName; + this.functionExpression = functionExpression; + this.javaMangler = javaMangler; + } + + @Override + public Void visitGetLocalVariable(GetLocalVariableExpression varExpression) { + final JavaLocalVariableInfo localVariable = javaWriter.tryGetLocalVariable(varExpression.variable.id); + if (localVariable != null) { + final Label label = new Label(); + localVariable.end = label; + javaWriter.label(label); + javaWriter.load(localVariable); + return null; + } + + final int position = calculateMemberPosition(varExpression, this.functionExpression); + javaWriter.loadObject(0); + javaWriter.getField(lambdaClassName, this.javaMangler.mangleCapturedParameter(position, false), context.getDescriptor(varExpression.variable.type)); + return null; + } + + @Override + public Void visitCapturedParameter(CapturedParameterExpression varExpression) { + final int position = calculateMemberPosition(varExpression, this.functionExpression); + javaWriter.loadObject(0); + javaWriter.getField(lambdaClassName, this.javaMangler.mangleCapturedParameter(position, false), context.getDescriptor(varExpression.parameter.type)); + return null; + } + + @Override + public Void visitCapturedThis(CapturedThisExpression expression) { + javaWriter.loadObject(0); + javaWriter.getField(lambdaClassName, this.javaMangler.mangleCapturedParameter(1, true), context.getDescriptor(expression.type)); + return null; + } + + //TODO replace with visitor? + private static int calculateMemberPosition(GetLocalVariableExpression localVariableExpression, FunctionExpression expression) { + int h = 1;//expression.header.parameters.length; + for (CapturedExpression capture : expression.closure.captures) { + if (capture instanceof CapturedLocalVariableExpression && ((CapturedLocalVariableExpression) capture).variable == localVariableExpression.variable) + return h; + if (capture instanceof CapturedClosureExpression && ((CapturedClosureExpression) capture).value instanceof CapturedLocalVariableExpression && ((CapturedLocalVariableExpression) ((CapturedClosureExpression) capture).value).variable == localVariableExpression.variable) + return h; + h++; + } + throw new RuntimeException(localVariableExpression.position.toString() + ": Captured Statement error"); + } + + private static int calculateMemberPosition(CapturedParameterExpression functionParameterExpression, FunctionExpression expression) { + int h = 1;//expression.header.parameters.length; + for (CapturedExpression capture : expression.closure.captures) { + if (capture instanceof CapturedParameterExpression && ((CapturedParameterExpression) capture).parameter == functionParameterExpression.parameter) + return h; + h++; + } + throw new RuntimeException(functionParameterExpression.position.toString() + ": Captured Statement error"); + } +} diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaNonPushingExpressionVisitor.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaNonPushingExpressionVisitor.java index e37d22bf0..e899e762a 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaNonPushingExpressionVisitor.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaNonPushingExpressionVisitor.java @@ -11,6 +11,7 @@ import org.openzen.zenscript.codemodel.type.builtin.BuiltinMethodSymbol; import org.openzen.zenscript.javabytecode.JavaBytecodeContext; import org.openzen.zenscript.javabytecode.JavaLocalVariableInfo; +import org.openzen.zenscript.javabytecode.JavaMangler; import org.openzen.zenscript.javabytecode.compiler.JavaModificationExpressionVisitor.PushOption; import org.openzen.zenscript.javashared.JavaCompiledModule; import org.openzen.zenscript.javashared.JavaParameterInfo; @@ -25,12 +26,14 @@ public class JavaNonPushingExpressionVisitor implements ExpressionVisitor private final JavaWriter javaWriter; private final JavaExpressionVisitor original; private final JavaFieldBytecodeCompiler fieldCompiler; + private final JavaMangler mangler; - public JavaNonPushingExpressionVisitor(JavaBytecodeContext context, JavaCompiledModule module, JavaWriter javaWriter, JavaExpressionVisitor original) { + public JavaNonPushingExpressionVisitor(JavaBytecodeContext context, JavaCompiledModule module, JavaWriter javaWriter, JavaMangler mangler, JavaExpressionVisitor original) { this.context = context; this.module = module; this.javaWriter = javaWriter; this.original = original; + this.mangler = mangler; fieldCompiler = new JavaFieldBytecodeCompiler(javaWriter, original, false); } @@ -373,7 +376,7 @@ public Void visitConstructorSuperCall(ConstructorSuperCallExpression expression) "", context.getMethodDescriptor(expression.constructor.getHeader().withReturnType(BasicTypeID.VOID))); - CompilerUtils.writeDefaultFieldInitializers(context, javaWriter, javaWriter.forDefinition, false); + CompilerUtils.writeDefaultFieldInitializers(context, javaWriter, javaWriter.forDefinition, mangler, false); return null; } diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaStatementVisitor.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaStatementVisitor.java index 60122670a..2fd1de065 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaStatementVisitor.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaStatementVisitor.java @@ -10,6 +10,7 @@ import org.openzen.zenscript.javabytecode.JavaBytecodeContext; import org.openzen.zenscript.javabytecode.JavaLocalVariableInfo; import org.openzen.zenscript.javashared.JavaBuiltinModule; +import org.openzen.zenscript.javabytecode.JavaMangler; import org.openzen.zenscript.javashared.JavaCompiledModule; import java.util.Arrays; @@ -25,18 +26,15 @@ public class JavaStatementVisitor implements StatementVisitor { /** * @param javaWriter the method writer that compiles the statement */ - public JavaStatementVisitor(JavaBytecodeContext context, JavaCompiledModule module, JavaWriter javaWriter) { - this.javaWriter = javaWriter; - this.context = context; - this.expressionVisitor = new JavaExpressionVisitor(context, module, javaWriter); - this.nonPushingExpressionVisitor = new JavaNonPushingExpressionVisitor(context, module, javaWriter, expressionVisitor); + public JavaStatementVisitor(JavaBytecodeContext context, JavaCompiledModule module, JavaWriter javaWriter, JavaMangler javaMangler) { + this(context, new JavaExpressionVisitor(context, module, javaWriter, javaMangler), javaMangler); } - public JavaStatementVisitor(JavaBytecodeContext context, JavaExpressionVisitor expressionVisitor) { + public JavaStatementVisitor(JavaBytecodeContext context, JavaExpressionVisitor expressionVisitor, JavaMangler javaMangler) { this.javaWriter = expressionVisitor.getJavaWriter(); this.context = context; this.expressionVisitor = expressionVisitor; - this.nonPushingExpressionVisitor = new JavaNonPushingExpressionVisitor(expressionVisitor.context, expressionVisitor.module, expressionVisitor.javaWriter, expressionVisitor); + this.nonPushingExpressionVisitor = new JavaNonPushingExpressionVisitor(expressionVisitor.context, expressionVisitor.module, expressionVisitor.javaWriter, javaMangler, expressionVisitor); } @Override diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaDefinitionVisitor.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaDefinitionVisitor.java index 6d3934492..5f52578c1 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaDefinitionVisitor.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaDefinitionVisitor.java @@ -15,6 +15,7 @@ import org.openzen.zenscript.codemodel.type.TypeID; import org.openzen.zenscript.codemodel.type.builtin.BuiltinMethodSymbol; import org.openzen.zenscript.javabytecode.JavaBytecodeContext; +import org.openzen.zenscript.javabytecode.JavaMangler; import org.openzen.zenscript.javabytecode.compiler.*; import org.openzen.zenscript.javashared.*; import org.openzen.zenscript.javashared.compiling.JavaCompilingClass; @@ -34,12 +35,14 @@ public class JavaDefinitionVisitor implements DefinitionVisitor { private final JavaClassWriter outerWriter; private final JavaBytecodeContext context; private final JavaCompilingModule module; + private final JavaMangler mangler; - public JavaDefinitionVisitor(JavaBytecodeContext context, JavaCompilingModule module, JavaClassWriter outerWriter) { + public JavaDefinitionVisitor(JavaBytecodeContext context, JavaCompilingModule module, JavaClassWriter outerWriter, JavaMangler mangler) { this.context = context; this.module = module; this.outerWriter = outerWriter; this.javaTypeGenericVisitor = new JavaTypeGenericVisitor(context); + this.mangler = mangler; } @Override @@ -92,7 +95,7 @@ public byte[] visitClass(ClassDefinition definition) { ); } - JavaMemberVisitor memberVisitor = new JavaMemberVisitor(context, writer, compilingClass, definition); + JavaMemberVisitor memberVisitor = new JavaMemberVisitor(context, writer, compilingClass, definition, mangler); for (IDefinitionMember member : definition.members) { member.accept(memberVisitor); } @@ -113,7 +116,7 @@ public byte[] visitInterface(InterfaceDefinition definition) { baseInterfaces[i] = context.getInternalName(definition.baseInterfaces.get(i)); writer.visit(Opcodes.V1_8, JavaModifiers.getJavaModifiers(definition.modifiers) | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT, compilingClass.compiled.internalName, signature, "java/lang/Object", baseInterfaces); - JavaMemberVisitor memberVisitor = new JavaMemberVisitor(context, writer, compilingClass, definition); + JavaMemberVisitor memberVisitor = new JavaMemberVisitor(context, writer, compilingClass, definition, mangler); for (IDefinitionMember member : definition.members) { member.accept(memberVisitor); } @@ -136,7 +139,7 @@ public byte[] visitEnum(EnumDefinition definition) { //Enum Stuff(required!) writer.visitField(Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC, "$VALUES", "[L" + class_.getInternalName() + ";", null, null).visitEnd(); - final JavaMemberVisitor visitor = new JavaMemberVisitor(context, writer, class_, definition); + final JavaMemberVisitor visitor = new JavaMemberVisitor(context, writer, class_, definition, mangler); for (IDefinitionMember member : definition.members) { member.accept(visitor); } @@ -208,7 +211,7 @@ public byte[] visitFunction(FunctionDefinition definition) { JavaCompilingMethod method = class_.getMethod(definition.caller); final JavaWriter writer = new JavaWriter(context.logger, definition.position, outerWriter, method, definition); - final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, context.getJavaModule(definition.module), writer); + final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, context.getJavaModule(definition.module), writer, mangler); statementVisitor.start(); boolean returns = definition.caller.body.accept(statementVisitor); if (!returns) { @@ -235,8 +238,8 @@ public byte[] visitExpansion(ExpansionDefinition definition) { final JavaClass expansionClassInfo = context.getJavaModule(definition.module).getExpansionClassInfo(definition); final String internalName = expansionClassInfo.internalName; - writer.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, internalName, null, "java/lang/Object", null); - JavaExpansionMemberVisitor memberVisitor = new JavaExpansionMemberVisitor(context, class_, writer, definition.target, definition); + writer.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, internalName, null, "java/lang/Object", null); + JavaExpansionMemberVisitor memberVisitor = new JavaExpansionMemberVisitor(context, class_, writer, definition.target, definition, mangler); for (IDefinitionMember member : definition.members) { member.accept(memberVisitor); @@ -267,7 +270,7 @@ public byte[] visitVariant(VariantDefinition variant) { writer.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT, class_.getInternalName(), ss, "java/lang/Object", null); writer.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT, "getDenominator", "()I", null, null).visitEnd(); - final JavaMemberVisitor visitor = new JavaMemberVisitor(context, writer, class_, variant); + final JavaMemberVisitor visitor = new JavaMemberVisitor(context, writer, class_, variant, mangler); final List options = variant.options; //Each option is one of the possible child classes diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaExpansionMemberVisitor.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaExpansionMemberVisitor.java index 0d29b10c2..871af7031 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaExpansionMemberVisitor.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaExpansionMemberVisitor.java @@ -11,6 +11,7 @@ import org.openzen.zenscript.codemodel.member.*; import org.openzen.zenscript.codemodel.type.TypeID; import org.openzen.zenscript.javabytecode.JavaBytecodeContext; +import org.openzen.zenscript.javabytecode.JavaMangler; import org.openzen.zenscript.javabytecode.compiler.CompilerUtils; import org.openzen.zenscript.javabytecode.compiler.JavaStatementVisitor; import org.openzen.zenscript.javabytecode.compiler.JavaWriter; @@ -28,23 +29,26 @@ public class JavaExpansionMemberVisitor implements MemberVisitor { private final HighLevelDefinition definition; private final JavaCompiledModule javaModule; private final JavaCompilingClass class_; + private final JavaMangler mangler; private final JavaStatementVisitor clinitStatementVisitor; - public JavaExpansionMemberVisitor(JavaBytecodeContext context, JavaCompilingClass class_, ClassWriter writer, TypeID expandedClass, HighLevelDefinition definition) { + public JavaExpansionMemberVisitor(JavaBytecodeContext context, JavaCompilingClass class_, ClassWriter writer, TypeID expandedClass, HighLevelDefinition definition, JavaMangler mangler) { this.writer = writer; this.class_ = class_; this.expandedClass = expandedClass; this.definition = definition; this.context = context; + this.mangler = mangler; + javaModule = context.getJavaModule(definition.module); JavaNativeMethod clinit = new JavaNativeMethod(context.getJavaClass(definition), JavaNativeMethod.Kind.STATICINIT, "", true, "()V", Opcodes.ACC_STATIC, false); JavaCompilingMethod clinitCompiling = new JavaCompilingMethod(class_.compiled, clinit, "()V"); final JavaWriter javaWriter = new JavaWriter(context.logger, definition.position, writer, clinitCompiling, definition); - this.clinitStatementVisitor = new JavaStatementVisitor(context, javaModule, javaWriter); + this.clinitStatementVisitor = new JavaStatementVisitor(context, javaModule, javaWriter, mangler); this.clinitStatementVisitor.start(); - CompilerUtils.writeDefaultFieldInitializers(context, javaWriter, definition, true); + CompilerUtils.writeDefaultFieldInitializers(context, javaWriter, definition, mangler, true); } public void end() { @@ -114,7 +118,7 @@ public Void visitMethod(MethodMember member) { { - final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter); + final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter, mangler); statementVisitor.start(); member.body.accept(statementVisitor); methodWriter.label(methodEnd); @@ -152,7 +156,7 @@ public Void visitGetter(GetterMember member) { } { - final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter); + final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter, mangler); statementVisitor.start(); member.body.accept(statementVisitor); methodWriter.label(methodEnd); @@ -202,7 +206,7 @@ public Void visitSetter(SetterMember member) { javaModule.setParameterInfo(member.parameter, new JavaParameterInfo(i, context.getDescriptor(setterType))); - final JavaStatementVisitor javaStatementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter); + final JavaStatementVisitor javaStatementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter, mangler); javaStatementVisitor.start(); member.body.accept(javaStatementVisitor); javaStatementVisitor.end(); @@ -245,7 +249,7 @@ public Void visitCaster(CasterMember member) { methodWriter.nameParameter(0, name); } - final JavaStatementVisitor javaStatementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter); + final JavaStatementVisitor javaStatementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter, mangler); javaStatementVisitor.start(); member.body.accept(javaStatementVisitor); javaStatementVisitor.end(); diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaMemberVisitor.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaMemberVisitor.java index 29496452b..2268474fe 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaMemberVisitor.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/definitions/JavaMemberVisitor.java @@ -15,6 +15,7 @@ import org.openzen.zenscript.codemodel.member.*; import org.openzen.zenscript.codemodel.type.DefinitionTypeID; import org.openzen.zenscript.javabytecode.JavaBytecodeContext; +import org.openzen.zenscript.javabytecode.JavaMangler; import org.openzen.zenscript.javabytecode.compiler.*; import org.openzen.zenscript.javashared.*; import org.openzen.zenscript.javashared.compiling.JavaCompilingClass; @@ -29,26 +30,29 @@ public class JavaMemberVisitor implements MemberVisitor { private final HighLevelDefinition definition; private final JavaStatementVisitor clinitStatementVisitor; private final JavaCompiledModule javaModule; + private final JavaMangler mangler; private EnumDefinition enumDefinition = null; public JavaMemberVisitor( JavaBytecodeContext context, ClassWriter writer, JavaCompilingClass class_, - HighLevelDefinition definition + HighLevelDefinition definition, + JavaMangler mangler ) { this.writer = writer; this.class_ = class_; this.definition = definition; this.context = context; + this.mangler = mangler; javaModule = context.getJavaModule(definition.module); JavaNativeMethod clinitMethod = new JavaNativeMethod(class_.compiled, JavaNativeMethod.Kind.STATICINIT, "", true, "()V", Opcodes.ACC_STATIC, false); final JavaCompilingMethod clinitMethodCompiling = new JavaCompilingMethod(class_.compiled, clinitMethod, "()V"); final JavaWriter javaWriter = new JavaWriter(context.logger, definition.position, writer, clinitMethodCompiling, definition); - this.clinitStatementVisitor = new JavaStatementVisitor(context, javaModule, javaWriter); + this.clinitStatementVisitor = new JavaStatementVisitor(context, javaModule, javaWriter, mangler); this.clinitStatementVisitor.start(); - CompilerUtils.writeDefaultFieldInitializers(context, javaWriter, definition, true); + CompilerUtils.writeDefaultFieldInitializers(context, javaWriter, definition, mangler, true); if (definition instanceof EnumDefinition) { this.enumDefinition = (EnumDefinition) definition; @@ -110,7 +114,7 @@ public Void visitConstructor(ConstructorMember member) { context.getType(parameter.type)); } - final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, javaModule, constructorWriter); + final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, javaModule, constructorWriter, mangler); statementVisitor.start(); forwardToSuperConstructorIfNecessary(member, isEnum, constructorWriter, method); @@ -204,7 +208,7 @@ private void visitFunction(FunctionalMember member) { final Label methodStart = new Label(); final Label methodEnd = new Label(); - final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter); + final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter, mangler); statementVisitor.start(); member.body.accept(statementVisitor); @@ -226,7 +230,7 @@ public Void visitGetter(GetterMember member) { final JavaWriter methodWriter = new JavaWriter(context.logger, member.position, this.writer, method, definition); methodWriter.label(methodStart); - final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter); + final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter, mangler); statementVisitor.start(); member.body.accept(statementVisitor); methodWriter.label(methodEnd); @@ -254,7 +258,7 @@ public Void visitSetter(SetterMember member) { javaModule.setParameterInfo(member.parameter, new JavaParameterInfo(localIndex, context.getDescriptor(member.type))); - final JavaStatementVisitor javaStatementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter); + final JavaStatementVisitor javaStatementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter, mangler); javaStatementVisitor.start(); member.body.accept(javaStatementVisitor); javaStatementVisitor.end(); @@ -279,7 +283,7 @@ public Void visitOperator(OperatorMember member) { final JavaWriter destructorWriter = new JavaWriter(context.logger, member.position, writer, method, definition); destructorWriter.label(constructorStart); - final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, javaModule, destructorWriter); + final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(context, javaModule, destructorWriter, mangler); statementVisitor.start(); // TODO: destruction of members (to be done when memory tags are implemented) @@ -321,7 +325,7 @@ public Void visitCaster(CasterMember member) { } if(member.body != null) { - final JavaStatementVisitor javaStatementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter); + final JavaStatementVisitor javaStatementVisitor = new JavaStatementVisitor(context, javaModule, methodWriter, mangler); javaStatementVisitor.start(); member.body.accept(javaStatementVisitor); javaStatementVisitor.end(); diff --git a/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaTypeGenericVisitor.java b/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaTypeGenericVisitor.java index c8330fbd2..ff20ecd2a 100644 --- a/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaTypeGenericVisitor.java +++ b/JavaShared/src/main/java/org/openzen/zenscript/javashared/JavaTypeGenericVisitor.java @@ -155,10 +155,10 @@ public String visitFunction(FunctionTypeID function) { StringBuilder sb = new StringBuilder("L").append(function1.getCls().internalName).append("<"); for (TypeID typeArgument : function1.typeArguments) { final String n = typeArgument instanceof GenericTypeID - ? ((GenericTypeID) typeArgument).parameter.name - : "Ljava/lang/Object"; //Can latter even happen? + ? ('T' + ((GenericTypeID) typeArgument).parameter.name) + : "Ljava/lang/Object"; // Can latter even happen? Yes, it can! - sb.append("T").append(n).append(";"); + sb.append(n).append(";"); } return sb.append(">;").toString(); diff --git a/ScriptingEngineTester/src/main/resources/zencode_tests/classes/class_with_same_name_as_script.zc b/ScriptingEngineTester/src/main/resources/zencode_tests/classes/class_with_same_name_as_script.zc deleted file mode 100644 index 97ff49a65..000000000 --- a/ScriptingEngineTester/src/main/resources/zencode_tests/classes/class_with_same_name_as_script.zc +++ /dev/null @@ -1,9 +0,0 @@ -#output: prints - -class class_with_same_name_as_script { - print(): void { - println("prints"); - } -} - -(new class_with_same_name_as_script()).print(); diff --git a/ScriptingEngineTester/src/main/resources/zencode_tests/lambdas/capturing_lambda_1.zc b/ScriptingEngineTester/src/main/resources/zencode_tests/lambdas/capturing_lambda_1.zc new file mode 100644 index 000000000..863e84eae --- /dev/null +++ b/ScriptingEngineTester/src/main/resources/zencode_tests/lambdas/capturing_lambda_1.zc @@ -0,0 +1,10 @@ +#output: 10 + +function foo(block: function(a as int) as int): void { + println(block(5) as string); +} + +function findMultiplier(): int => 2; + +val multiplier = findMultiplier(); +foo((x) => x * multiplier); diff --git a/ScriptingEngineTester/src/main/resources/zencode_tests/lambdas/capturing_lambda_2.zc b/ScriptingEngineTester/src/main/resources/zencode_tests/lambdas/capturing_lambda_2.zc new file mode 100644 index 000000000..f4c64e6e5 --- /dev/null +++ b/ScriptingEngineTester/src/main/resources/zencode_tests/lambdas/capturing_lambda_2.zc @@ -0,0 +1,33 @@ +#output: 10 + +public class CaptureTest2Foo { + private val field as int : public get; + + public this(field: int) { + this.field = field; + } + + public foo(provider: function() as int): int { + val lambdaHell = this.wrapItAllUp(() => provider() + 1, (p) => new CaptureTest2Bar(p)); + return lambdaHell(); + } + + private wrapItAllUp(provider: function() as int, creator: function(foo as function() as int) as CaptureTest2Bar): function() as int { + return creator(() => provider() * this.field).wrapProvider(); + } +} + +public class CaptureTest2Bar { + private val provider as function() as int : public get; + + public this(provider: function() as int) { + this.provider = provider; + } + + public wrapProvider(): function() as int { + return () => this.provider(); + } +} + +val test = new CaptureTest2Foo(2); +println(test.foo(() => 4) as string); diff --git a/ScriptingEngineTester/src/main/resources/zencode_tests/mangling/function_mangling.zc b/ScriptingEngineTester/src/main/resources/zencode_tests/mangling/function_mangling.zc new file mode 100644 index 000000000..5db25c538 --- /dev/null +++ b/ScriptingEngineTester/src/main/resources/zencode_tests/mangling/function_mangling.zc @@ -0,0 +1,7 @@ +#output: mangled + +function run(): void { + println("mangled"); +} + +run(); diff --git a/ScriptingEngineTester/src/main/resources/zencode_tests/mangling/script_mangling.zc b/ScriptingEngineTester/src/main/resources/zencode_tests/mangling/script_mangling.zc new file mode 100644 index 000000000..0e310b0b3 --- /dev/null +++ b/ScriptingEngineTester/src/main/resources/zencode_tests/mangling/script_mangling.zc @@ -0,0 +1,13 @@ +#output: mangled + +class script_mangling { + print(): void { + println("mangled"); + } +} + +function print(): void { + println("mangling failure"); +} + +(new script_mangling()).print();