diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/ResolvedType.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/ResolvedType.java index 526d1b242..6cd7e2039 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/ResolvedType.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/ResolvedType.java @@ -74,7 +74,7 @@ default boolean canCastImplicitlyTo(TypeID target) { Optional findStaticOperator(OperatorType operator); interface SwitchMember { - SwitchValue toSwitchValue(String[] bindingNames); + SwitchValue toSwitchValue(List bindings); } interface Field { diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/StatementCompiler.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/StatementCompiler.java index 4b1542f64..824e8e19d 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/StatementCompiler.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/StatementCompiler.java @@ -9,10 +9,6 @@ import java.util.Optional; public interface StatementCompiler { - Expression compile(CompilableExpression expression); - - Expression compile(CompilableExpression expression, TypeID type); - ExpressionCompiler expressions(); TypeBuilder types(); diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/impl/compiler/StatementCompilerImpl.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/impl/compiler/StatementCompilerImpl.java index 0efe8c8b1..11e6766db 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/impl/compiler/StatementCompilerImpl.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/compilation/impl/compiler/StatementCompilerImpl.java @@ -31,19 +31,6 @@ public StatementCompilerImpl(CompileContext context, LocalType localType, TypeBu expressionCompiler = new ExpressionCompilerImpl(context, localType, this.types, functionHeader.thrownType, locals, functionHeader); } - @Override - public Expression compile(CompilableExpression expression) { - return expression.compile(expressionCompiler).eval(); - } - - @Override - public Expression compile(CompilableExpression expression, TypeID type) { - return expression - .compile(expressionCompiler) - .cast(CastedEval.implicit(expressionCompiler, expression.getPosition(), type)) - .value; - } - @Override public ExpressionCompiler expressions() { return expressionCompiler; diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/CharSwitchValue.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/CharSwitchValue.java index e4a6eb85e..eee74bc0a 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/CharSwitchValue.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/CharSwitchValue.java @@ -1,5 +1,6 @@ package org.openzen.zenscript.codemodel.expression.switchvalue; +import org.openzen.zenscript.codemodel.VariableDefinition; import org.openzen.zenscript.codemodel.ssa.SSAVariableCollector; import org.openzen.zenscript.codemodel.statement.VarStatement; @@ -14,7 +15,7 @@ public CharSwitchValue(char value) { } @Override - public List getBindings() { + public List getBindings() { return Collections.emptyList(); } diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/EnumConstantSwitchValue.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/EnumConstantSwitchValue.java index 34f5a2fec..fa0d5e6a5 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/EnumConstantSwitchValue.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/EnumConstantSwitchValue.java @@ -1,5 +1,6 @@ package org.openzen.zenscript.codemodel.expression.switchvalue; +import org.openzen.zenscript.codemodel.VariableDefinition; import org.openzen.zenscript.codemodel.member.EnumConstantMember; import org.openzen.zenscript.codemodel.ssa.SSAVariableCollector; import org.openzen.zenscript.codemodel.statement.VarStatement; @@ -15,7 +16,7 @@ public EnumConstantSwitchValue(EnumConstantMember constant) { } @Override - public List getBindings() { + public List getBindings() { return Collections.emptyList(); } diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/ErrorSwitchValue.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/ErrorSwitchValue.java index 89ce943c5..5dd62d6c4 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/ErrorSwitchValue.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/ErrorSwitchValue.java @@ -2,6 +2,7 @@ import org.openzen.zencode.shared.CodePosition; import org.openzen.zencode.shared.CompileError; +import org.openzen.zenscript.codemodel.VariableDefinition; import org.openzen.zenscript.codemodel.ssa.SSAVariableCollector; import org.openzen.zenscript.codemodel.statement.VarStatement; @@ -18,7 +19,7 @@ public ErrorSwitchValue(CodePosition position, CompileError error) { } @Override - public List getBindings() { + public List getBindings() { return Collections.emptyList(); } diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/IntSwitchValue.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/IntSwitchValue.java index 9d124832b..5824f1849 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/IntSwitchValue.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/IntSwitchValue.java @@ -1,5 +1,6 @@ package org.openzen.zenscript.codemodel.expression.switchvalue; +import org.openzen.zenscript.codemodel.VariableDefinition; import org.openzen.zenscript.codemodel.ssa.SSAVariableCollector; import org.openzen.zenscript.codemodel.statement.VarStatement; @@ -14,7 +15,7 @@ public IntSwitchValue(int value) { } @Override - public List getBindings() { + public List getBindings() { return Collections.emptyList(); } diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/StringSwitchValue.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/StringSwitchValue.java index faa8473f9..d6992d202 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/StringSwitchValue.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/StringSwitchValue.java @@ -1,5 +1,6 @@ package org.openzen.zenscript.codemodel.expression.switchvalue; +import org.openzen.zenscript.codemodel.VariableDefinition; import org.openzen.zenscript.codemodel.ssa.SSAVariableCollector; import org.openzen.zenscript.codemodel.statement.VarStatement; @@ -14,7 +15,7 @@ public StringSwitchValue(String value) { } @Override - public List getBindings() { + public List getBindings() { return Collections.emptyList(); } diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/SwitchValue.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/SwitchValue.java index 9da1d6c25..fc6951164 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/SwitchValue.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/SwitchValue.java @@ -1,13 +1,14 @@ package org.openzen.zenscript.codemodel.expression.switchvalue; import org.openzen.zenscript.codemodel.LocalVariable; +import org.openzen.zenscript.codemodel.VariableDefinition; import org.openzen.zenscript.codemodel.ssa.SSAVariableCollector; import org.openzen.zenscript.codemodel.statement.VarStatement; import java.util.List; public interface SwitchValue { - List getBindings(); + List getBindings(); T accept(SwitchValueVisitor visitor); diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/VariantOptionSwitchValue.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/VariantOptionSwitchValue.java index e4cd25e79..26ceb7f83 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/VariantOptionSwitchValue.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/expression/switchvalue/VariantOptionSwitchValue.java @@ -1,6 +1,7 @@ package org.openzen.zenscript.codemodel.expression.switchvalue; import org.openzen.zencode.shared.CodePosition; +import org.openzen.zenscript.codemodel.VariableDefinition; import org.openzen.zenscript.codemodel.member.ref.VariantOptionInstance; import org.openzen.zenscript.codemodel.ssa.SSAVariableCollector; import org.openzen.zenscript.codemodel.statement.VarStatement; @@ -12,25 +13,16 @@ public class VariantOptionSwitchValue implements SwitchValue { public final VariantOptionInstance option; public final String[] parameters; - private final List bindings; + private final List bindings; - public VariantOptionSwitchValue(VariantOptionInstance option, String[] parameters) { + public VariantOptionSwitchValue(VariantOptionInstance option, List bindings) { this.option = option; - this.parameters = parameters; - this.bindings = new ArrayList<>(); - for (int i = 0; i < option.types.length; i++) { - bindings.add(new VarStatement( - CodePosition.UNKNOWN, - new VariableID(), - parameters[i], - option.types[i], - null, - true)); - } + this.parameters = bindings.stream().map(p -> p.name).toArray(String[]::new); + this.bindings = bindings; } @Override - public List getBindings() { + public List getBindings() { return bindings; } @@ -46,6 +38,5 @@ public R accept(C context, SwitchValueVisitorWithContext visitor) { @Override public void collect(SSAVariableCollector collector) { - } } diff --git a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/member/ref/VariantOptionInstance.java b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/member/ref/VariantOptionInstance.java index 225fd5f6a..be9246de2 100644 --- a/CodeModel/src/main/java/org/openzen/zenscript/codemodel/member/ref/VariantOptionInstance.java +++ b/CodeModel/src/main/java/org/openzen/zenscript/codemodel/member/ref/VariantOptionInstance.java @@ -2,6 +2,7 @@ import org.openzen.zencode.shared.CodePosition; import org.openzen.zencode.shared.Tag; +import org.openzen.zenscript.codemodel.VariableDefinition; import org.openzen.zenscript.codemodel.compilation.*; import org.openzen.zenscript.codemodel.compilation.expression.AbstractCompilingExpression; import org.openzen.zenscript.codemodel.definition.VariantDefinition; @@ -14,7 +15,10 @@ import org.openzen.zenscript.codemodel.ssa.SSAVariableCollector; import org.openzen.zenscript.codemodel.type.TypeID; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; public class VariantOptionInstance implements CompilableExpression, ResolvedType.SwitchMember { public final TypeID variant; @@ -78,8 +82,13 @@ public void linkVariables(CodeBlockStatement.VariableLinker linker) {} } @Override - public SwitchValue toSwitchValue(String[] bindingNames) { - return new VariantOptionSwitchValue(this, bindingNames); + public SwitchValue toSwitchValue(List variables) { + List bindings = new ArrayList<>(); + for (int i = 0; i < variables.size(); i++) { + variables.get(i).inferredType = types[i]; + bindings.add(variables.get(i).asType(types[i])); + } + return new VariantOptionSwitchValue(this, bindings); } private static class OptionCallable implements CompilingCallable { diff --git a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaSwitchKeyVariableVisitor.java b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaSwitchKeyVariableVisitor.java index 5989dde77..8f1774e34 100644 --- a/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaSwitchKeyVariableVisitor.java +++ b/JavaBytecodeCompiler/src/main/java/org/openzen/zenscript/javabytecode/compiler/JavaSwitchKeyVariableVisitor.java @@ -1,6 +1,7 @@ package org.openzen.zenscript.javabytecode.compiler; import org.objectweb.asm.Label; +import org.openzen.zenscript.codemodel.VariableDefinition; import org.openzen.zenscript.codemodel.expression.switchvalue.*; import org.openzen.zenscript.codemodel.statement.VarStatement; import org.openzen.zenscript.javabytecode.JavaBytecodeContext; @@ -57,7 +58,7 @@ public Void acceptVariantOption(VariantOptionSwitchValue key) { javaWriter.checkCast(javaVariantOption.variantOptionClass.internalName); int fieldNumber = 0; - for (VarStatement binding : key.getBindings()) { + for (VariableDefinition binding : key.getBindings()) { javaWriter.dup(); javaWriter.getField( javaVariantOption.variantOptionClass.internalName, @@ -71,7 +72,7 @@ public Void acceptVariantOption(VariantOptionSwitchValue key) { binding.name, caseEnd ); - javaWriter.setLocalVariable(binding.variable, javaLocalVariableInfo); + javaWriter.setLocalVariable(binding.id, javaLocalVariableInfo); javaWriter.store(javaLocalVariableInfo); } return null; 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 8a726a3e2..09cd431ea 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 @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.stream.Stream; public class JavaDefinitionVisitor implements DefinitionVisitor { @@ -280,11 +281,12 @@ public byte[] visitVariant(VariantDefinition variant) { { StringBuilder builder = new StringBuilder(); //TODO check if this can be changed to what Stan was up to - builder.append("<"); - for (final TypeID type : option.types) { - builder.append(javaTypeGenericVisitor.getSignatureWithBound(type)); + if (Stream.of(option.types).anyMatch(TypeID::isGeneric)) { + builder.append("<"); + Stream.of(option.types).filter(TypeID::isGeneric) + .forEach(it -> builder.append(javaTypeGenericVisitor.getSignatureWithBound(it))); + builder.append(">"); } - builder.append(">"); builder.append("L").append(class_.getInternalName()).append("<"); for (final TypeParameter genericParameter : variant.typeParameters) { @@ -299,10 +301,8 @@ public byte[] visitVariant(VariantDefinition variant) { } if (t) builder.append(javaTypeGenericVisitor.getGenericBounds(genericParameter.bounds)); - } - signature = builder.append(">;").toString(); } @@ -314,8 +314,8 @@ public byte[] visitVariant(VariantDefinition variant) { for (int i = 0; i < types.length; ++i) { final String descriptor = context.getDescriptor(types[i]); optionInitDescBuilder.append(descriptor); - optionInitSignatureBuilder.append("T").append(((GenericTypeID) types[i]).parameter.name).append(";"); - optionWriter.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, "field" + i, descriptor, "T" + ((GenericTypeID) types[i]).parameter.name + ";", null).visitEnd(); + optionInitSignatureBuilder.append(context.getSignature(types[i])); + optionWriter.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, "field" + i, descriptor, context.getSignature(types[i]), null).visitEnd(); } optionInitDescBuilder.append(")V"); optionInitSignatureBuilder.append(")V"); diff --git a/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionCall.java b/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionCall.java index aae0a8a62..6adf0ce98 100644 --- a/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionCall.java +++ b/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionCall.java @@ -8,8 +8,10 @@ import org.openzen.zenscript.codemodel.expression.switchvalue.SwitchValue; import org.openzen.zenscript.codemodel.ssa.CodeBlockStatement; import org.openzen.zenscript.codemodel.ssa.SSAVariableCollector; +import org.openzen.zenscript.codemodel.statement.VariableID; import org.openzen.zenscript.codemodel.type.TypeID; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -75,26 +77,44 @@ public CompilingSwitchValue compileSwitchValue(ExpressionCompiler compiler) { return type -> new ErrorSwitchValue(position, CompileErrors.invalidSwitchCaseExpression()); } - return type -> { - String name = ((ParsedExpressionVariable) receiver).name; - ResolvedType resolved = compiler.resolve(type); - Optional maybeSwitchMember = resolved.findSwitchMember(name); - if (maybeSwitchMember.isPresent()) { - String[] values = new String[arguments.arguments.size()]; - for (int i = 0; i < values.length; i++) { - CompilableExpression argument = arguments.arguments.get(i); - Optional lambdaHeader = argument.asLambdaHeaderParameter(); - if (lambdaHeader.isPresent()) { - values[i] = lambdaHeader.get().getName(); - } else { - return new ErrorSwitchValue(position, CompileErrors.invalidSwitchCaseExpression()); - } - } - - return maybeSwitchMember.get().toSwitchValue(values); + List bindings = new ArrayList<>(); + for (CompilableExpression argument : arguments.arguments) { + Optional lambdaHeader = argument.asLambdaHeaderParameter(); + if (lambdaHeader.isPresent()) { + bindings.add(new CompilingVariable(new VariableID(), lambdaHeader.get().getName(), null, true)); } else { - return new ErrorSwitchValue(position, CompileErrors.invalidSwitchCaseExpression()); + return type -> new ErrorSwitchValue(position, CompileErrors.invalidSwitchCaseExpression()); } - }; + } + + return new CompilingSwitchValue() { + @Override + public SwitchValue as(TypeID type) { + String name = ((ParsedExpressionVariable) receiver).name; + ResolvedType resolved = compiler.resolve(type); + Optional maybeSwitchMember = resolved.findSwitchMember(name); + if (maybeSwitchMember.isPresent()) { + String[] values = new String[arguments.arguments.size()]; + for (int i = 0; i < values.length; i++) { + CompilableExpression argument = arguments.arguments.get(i); + Optional lambdaHeader = argument.asLambdaHeaderParameter(); + if (lambdaHeader.isPresent()) { + values[i] = lambdaHeader.get().getName(); + } else { + return new ErrorSwitchValue(position, CompileErrors.invalidSwitchCaseExpression()); + } + } + + return maybeSwitchMember.get().toSwitchValue(bindings); + } else { + return new ErrorSwitchValue(position, CompileErrors.invalidSwitchCaseExpression()); + } + } + + @Override + public List getBindings() { + return bindings; + } + }; } } diff --git a/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionVariable.java b/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionVariable.java index 7225de596..bfbeddb2e 100644 --- a/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionVariable.java +++ b/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedExpressionVariable.java @@ -211,7 +211,7 @@ public SwitchValue as(TypeID type) { ResolvedType resolved = compiler.resolve(type); Optional switchMember = resolved.findSwitchMember(name); if (switchMember.isPresent()) { - return switchMember.get().toSwitchValue(new String[0]); + return switchMember.get().toSwitchValue(Collections.emptyList()); } else { return new ErrorSwitchValue(position, CompileErrors.invalidSwitchCaseExpression()); } diff --git a/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedMatchExpression.java b/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedMatchExpression.java index 84afe0759..f5ab0f2a9 100644 --- a/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedMatchExpression.java +++ b/Parser/src/main/java/org/openzen/zenscript/parser/expression/ParsedMatchExpression.java @@ -97,6 +97,9 @@ public void collect(SSAVariableCollector collector) { public void linkVariables(CodeBlockStatement.VariableLinker linker) { value.linkVariables(linker); for (CompilingCase case_ : cases) { + for (CompilingVariable variable : case_.name.getBindings()) { + variable.ssaCompilingVariable = linker.get(variable.id); + } case_.value.linkVariables(linker); } } diff --git a/Parser/src/main/java/org/openzen/zenscript/parser/member/ParsedDefinitionMember.java b/Parser/src/main/java/org/openzen/zenscript/parser/member/ParsedDefinitionMember.java index 290ab3378..16d471e75 100644 --- a/Parser/src/main/java/org/openzen/zenscript/parser/member/ParsedDefinitionMember.java +++ b/Parser/src/main/java/org/openzen/zenscript/parser/member/ParsedDefinitionMember.java @@ -170,15 +170,20 @@ public static ParsedDefinitionMember parse(ZSTokenParser tokens) throws ParseExc } case K_IMPLEMENTS: { tokens.next(); - IParsedType type = IParsedType.parse(tokens); - ParsedImplementation implementation = new ParsedImplementation(start, modifiers, annotations, type); - if (tokens.optional(ZSTokenType.T_SEMICOLON) == null) { - tokens.required(ZSTokenType.T_AOPEN, "{ expected"); - while (tokens.optional(ZSTokenType.T_ACLOSE) == null) { - implementation.addMember(ParsedDefinitionMember.parse(tokens)); + try { + IParsedType type = IParsedType.parse(tokens); + ParsedImplementation implementation = new ParsedImplementation(start, modifiers, annotations, type); + if (tokens.optional(ZSTokenType.T_SEMICOLON) == null) { + tokens.required(ZSTokenType.T_AOPEN, "{ expected"); + while (tokens.optional(ZSTokenType.T_ACLOSE) == null) { + implementation.addMember(ParsedDefinitionMember.parse(tokens)); + } } + return implementation; + } catch (ParseException ex) { + tokens.recoverUntilOnToken(T_ACLOSE); + throw ex; } - return implementation; } case T_BROPEN: { ParsedFunctionHeader header = ParsedFunctionHeader.parse(tokens); diff --git a/Parser/src/main/java/org/openzen/zenscript/parser/statements/ParsedLambdaFunctionBody.java b/Parser/src/main/java/org/openzen/zenscript/parser/statements/ParsedLambdaFunctionBody.java index 223046d82..f8a59a8ea 100644 --- a/Parser/src/main/java/org/openzen/zenscript/parser/statements/ParsedLambdaFunctionBody.java +++ b/Parser/src/main/java/org/openzen/zenscript/parser/statements/ParsedLambdaFunctionBody.java @@ -3,9 +3,13 @@ import org.openzen.zencode.shared.CodePosition; import org.openzen.zenscript.codemodel.FunctionHeader; import org.openzen.zenscript.codemodel.compilation.CompilableExpression; +import org.openzen.zenscript.codemodel.compilation.CompilingExpression; import org.openzen.zenscript.codemodel.compilation.StatementCompiler; +import org.openzen.zenscript.codemodel.compilation.statement.CompilingExpressionCodeStatement; +import org.openzen.zenscript.codemodel.compilation.statement.CompilingStatement; import org.openzen.zenscript.codemodel.expression.Expression; import org.openzen.zenscript.codemodel.ssa.CodeBlock; +import org.openzen.zenscript.codemodel.ssa.SSA; import org.openzen.zenscript.codemodel.statement.ExpressionStatement; import org.openzen.zenscript.codemodel.statement.ReturnStatement; import org.openzen.zenscript.codemodel.statement.Statement; @@ -23,12 +27,19 @@ public ParsedLambdaFunctionBody(CodePosition position, CompilableExpression valu @Override public Statement compile(StatementCompiler compiler) { + CodeBlock initialBlock = new CodeBlock(); + CompilingExpression compiling = value.compile(compiler.expressions()); + initialBlock.add(new CompilingExpressionCodeStatement(compiling)); + + SSA ssa = new SSA(initialBlock); + ssa.compute(); + TypeID returnType = compiler.getFunctionHeader().map(FunctionHeader::getReturnType).orElse(BasicTypeID.VOID); if (returnType == BasicTypeID.VOID) { - Expression value = compiler.compile(this.value); + Expression value = compiling.eval(); return new ExpressionStatement(value.position, value); } else { - Expression returnValue = compiler.compile(value, returnType); + Expression returnValue = compiling.as(returnType); return new ReturnStatement(position, returnValue); } } diff --git a/Parser/src/main/java/org/openzen/zenscript/parser/statements/ParsedStatement.java b/Parser/src/main/java/org/openzen/zenscript/parser/statements/ParsedStatement.java index aabfe4a5d..c36714942 100644 --- a/Parser/src/main/java/org/openzen/zenscript/parser/statements/ParsedStatement.java +++ b/Parser/src/main/java/org/openzen/zenscript/parser/statements/ParsedStatement.java @@ -48,12 +48,23 @@ public static ParsedFunctionBody parseLambdaBody(ZSTokenParser tokens, boolean i } public static ParsedFunctionBody parseFunctionBody(ZSTokenParser tokens) throws ParseException { - if (tokens.optional(T_LAMBDA) != null) - return parseLambdaBody(tokens, false); - else if (tokens.optional(T_SEMICOLON) != null) + if (tokens.optional(T_LAMBDA) != null) { + try { + return parseLambdaBody(tokens, false); + } catch (ParseException ex) { + tokens.recoverUntilOnToken(T_SEMICOLON); + throw ex; + } + } else if (tokens.optional(T_SEMICOLON) != null) { return new ParsedEmptyFunctionBody(tokens.getPosition()); - else - return new ParsedStatementsFunctionBody(parseBlock(tokens, ParsedAnnotation.NONE, true)); + } else { + try { + return new ParsedStatementsFunctionBody(parseBlock(tokens, ParsedAnnotation.NONE, true)); + } catch (ParseException ex) { + tokens.recoverUntilOnToken(T_ACLOSE); + throw ex; + } + } } public static ParsedStatementBlock parseBlock(ZSTokenParser parser, ParsedAnnotation[] annotations, boolean isFirst) throws ParseException { diff --git a/Parser/src/main/java/org/openzen/zenscript/parser/statements/ParsedStatementReturn.java b/Parser/src/main/java/org/openzen/zenscript/parser/statements/ParsedStatementReturn.java index b4312dcc5..61e3f2e58 100644 --- a/Parser/src/main/java/org/openzen/zenscript/parser/statements/ParsedStatementReturn.java +++ b/Parser/src/main/java/org/openzen/zenscript/parser/statements/ParsedStatementReturn.java @@ -7,8 +7,10 @@ import org.openzen.zenscript.codemodel.compilation.CompileErrors; import org.openzen.zenscript.codemodel.compilation.CompilingExpression; import org.openzen.zenscript.codemodel.compilation.StatementCompiler; +import org.openzen.zenscript.codemodel.compilation.statement.CompilingExpressionCodeStatement; import org.openzen.zenscript.codemodel.compilation.statement.CompilingStatement; import org.openzen.zenscript.codemodel.compilation.statement.InvalidCompilingStatement; +import org.openzen.zenscript.codemodel.expression.Expression; import org.openzen.zenscript.codemodel.ssa.CodeBlock; import org.openzen.zenscript.codemodel.statement.ReturnStatement; import org.openzen.zenscript.codemodel.statement.Statement; @@ -49,6 +51,10 @@ public Compiling(StatementCompiler compiler, CompilingExpression value, Function this.value = value; this.functionHeader = functionHeader; this.block = block; + + if (value != null) { + block.add(new CompilingExpressionCodeStatement(value)); + } } @Override diff --git a/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-expect-empty.zc b/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-expect-empty.zc new file mode 100644 index 000000000..26cce4098 --- /dev/null +++ b/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-expect-empty.zc @@ -0,0 +1,16 @@ +#output: Expect called on empty value + +public variant OptionalString { + Present(string), + Empty; + + public expect() as string { + return match this { + Present(value) => value, + Empty() => 'Expect called on empty value' + }; + } +} + +var opt as OptionalString = Empty; +println(opt.expect()); \ No newline at end of file diff --git a/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-expect-present.zc b/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-expect-present.zc new file mode 100644 index 000000000..1e30d292a --- /dev/null +++ b/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-expect-present.zc @@ -0,0 +1,16 @@ +#output: Hello World + +public variant OptionalString { + Present(string), + Empty; + + public expect() as string { + return match this { + Present(value) => value, + Empty() => 'Expect called on empty value' + }; + } +} + +var opt as OptionalString = Present('Hello World'); +println(opt.expect()); diff --git a/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-ifpresent-empty.zc b/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-ifpresent-empty.zc new file mode 100644 index 000000000..438d745d8 --- /dev/null +++ b/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-ifpresent-empty.zc @@ -0,0 +1,27 @@ +#output: Hello world + +public variant Optional { + Present(T), + Empty; + + public expect() as T { + return match this { + Present(value) => value, + Empty() => panic('Expect called on empty value') + }; + } + + public ifPresent(consumer as function(value as T) as void) as void { + if(this.isPresent) { + consumer(this.expect()); + } + } + + public get isPresent as bool => match(this) { + Present(value) => true, + Empty => false + }; +} + +var opt as Optional = Empty; +opt.ifPresent((value) => println(value)); diff --git a/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-ifpresent-generic.zc b/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-ifpresent-generic.zc new file mode 100644 index 000000000..51e7d9249 --- /dev/null +++ b/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-ifpresent-generic.zc @@ -0,0 +1,20 @@ +#output: Hello world + +public variant Optional { + Present(T), + Empty; + + public ifPresent(consumer as function(value as T) as void) as void { + if(this.isPresent) { + consumer(this.expect()); + } + } + + public get isPresent as bool => match(this) { + Present(value) => true, + Empty => false + }; +} + +var opt as Optional = Present('Hello World'); +opt.ifPresent((value) => println(value)); diff --git a/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-ifpresent-simple.zc b/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-ifpresent-simple.zc new file mode 100644 index 000000000..c59979c3b --- /dev/null +++ b/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-ifpresent-simple.zc @@ -0,0 +1,20 @@ +#output: Hello world + +public variant OptionalString { + Present(string), + Empty; + + public ifPresent(consumer as function(value as string) as void) as void { + if(this.isPresent) { + consumer(this.expect()); + } + } + + public get isPresent as bool => match(this) { + Present(value) => true, + Empty => false + }; +} + +var opt as OptionalString = Present('Hello World'); +opt.ifPresent((value) => println(value)); diff --git a/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-ispresent.zc b/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-ispresent.zc new file mode 100644 index 000000000..94c9e3f8c --- /dev/null +++ b/ScriptingEngineTester/src/main/resources/zencode-tests/variants/optional-ispresent.zc @@ -0,0 +1,24 @@ +#output: true +#output: false + +public variant Optional { + Present(T), + Empty; + + public expect() as T { + return match this { + Present(value) => value, + Empty() => panic('Expect called on empty value') + }; + } + + public get isPresent as bool => match(this) { + Present(value) => true, + Empty => false + }; +} + +var opt as Optional = Present('Hello World'); +println(opt.isPresent); +opt = Empty; +println(opt.isPresent); diff --git a/ScriptingExample/src/test/java/org/openzen/zenscript/scriptingexample/tests/actual_test/strings/StdLibFunctions.java b/ScriptingExample/src/test/java/org/openzen/zenscript/scriptingexample/tests/actual_test/strings/StdLibFunctions.java index ecc62a692..ea910a61b 100644 --- a/ScriptingExample/src/test/java/org/openzen/zenscript/scriptingexample/tests/actual_test/strings/StdLibFunctions.java +++ b/ScriptingExample/src/test/java/org/openzen/zenscript/scriptingexample/tests/actual_test/strings/StdLibFunctions.java @@ -9,11 +9,17 @@ import org.openzen.zenscript.scriptingexample.tests.helpers.ZenCodeTest; import java.util.Arrays; +import java.util.Collections; +import java.util.List; import static org.openzen.zencode.shared.StringExpansion.unescape; @Disabled("Required Stdlib") public class StdLibFunctions extends ZenCodeTest { + @Override + public List getRequiredStdLibModules() { + return Collections.singletonList("stdlib"); + } @Test public void fromAsciiBytes() {