From a38bd5d597471e2ee434271fa7a82b835e828062 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sun, 22 Dec 2024 10:36:51 +0000 Subject: Handle params in method references --- .../org/shedlang/compiler/shid/ShidCodeGen.java | 53 ++++++++++++++++++-- .../shid/ShidCodeGenMemberAccessTests.java | 57 +++++++++++++++++++--- 2 files changed, 99 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/main/java/org/shedlang/compiler/shid/ShidCodeGen.java b/src/main/java/org/shedlang/compiler/shid/ShidCodeGen.java index 1fe776d4..d6626b37 100644 --- a/src/main/java/org/shedlang/compiler/shid/ShidCodeGen.java +++ b/src/main/java/org/shedlang/compiler/shid/ShidCodeGen.java @@ -13,6 +13,7 @@ import org.shedlang.compiler.util.P; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; +import java.util.stream.Stream; public class ShidCodeGen { private ShidCodeGen() { @@ -407,6 +408,8 @@ public class ShidCodeGen { case METHOD -> { // TODO: handle not a struct type var structType = ((ShidFieldLoad.Receiver.Struct) receiver).type(); + // TODO: handle not a function type + var methodType = (FunctionType) node.type(); var receiverLocalNameResult = context.generateShidVal("receiver"); var receiverLocalName = receiverLocalNameResult.value(); @@ -416,17 +419,59 @@ public class ShidCodeGen { new ShidLocalStore(receiverLocalName, node.source()) ); - context = context.enterBlock(List.of(), node.source()); + var shedPositionalParamNames = new ArrayList(); + for ( + var positionalParamIndex = 0; + positionalParamIndex < methodType.positionalParams().size(); + positionalParamIndex++ + ) { + shedPositionalParamNames.add("arg" + positionalParamIndex); + } + + var boundVariables = Stream.concat( + shedPositionalParamNames.stream(), + methodType.namedParams().stream() + .map(namedParam -> namedParam.name()) + ) + .map(BoundVariable::param) + .toList(); + + context = context.enterBlock(boundVariables, node.source()); context = context.addInstruction( new ShidMethodLoad(structType, node.memberName(), node.source()) ); + context = context.addInstruction( new ShidLocalLoad(receiverLocalName, node.source()) ); + var shidPositionalParams = new ArrayList(); + for (var positionalParamName : shedPositionalParamNames) { + var shidParamName = context.shedVariableToLocal(positionalParamName); + shidPositionalParams.add(new ShidDefineFunction.Param(shidParamName, node.source())); + context = context.addInstruction( + new ShidLocalLoad(shidParamName, node.source()) + ); + } + + var shidNamedParams = new ArrayList(); + for (var namedParam : methodType.namedParams()) { + var shidParamName = context.shedVariableToLocal(namedParam.name()); + shidNamedParams.add(new ShidDefineFunction.Param(shidParamName, node.source())); + context = context.addInstruction( + new ShidLocalLoad(shidParamName, node.source()) + ); + } + context = context.addInstruction( - new ShidCall(1, List.of(), node.source()) + new ShidCall( + methodType.positionalParams().size() + 1, + methodType.namedParams().stream() + .map(namedParam -> namedParam.name()) + .toList(), + node.source() + ) ); context = context.addInstruction(new ShidReturn(node.source())); @@ -438,8 +483,8 @@ public class ShidCodeGen { yield context.addInstruction( new ShidDefineFunction( node.memberName(), - List.of(), - List.of(), + shidPositionalParams, + shidNamedParams, FreeVariables.builder() .plus(receiverLocalName, node.source()) .build(), diff --git a/src/test/java/org/shedlang/compiler/shid/ShidCodeGenMemberAccessTests.java b/src/test/java/org/shedlang/compiler/shid/ShidCodeGenMemberAccessTests.java index 79453d76..d2a0e5ce 100644 --- a/src/test/java/org/shedlang/compiler/shid/ShidCodeGenMemberAccessTests.java +++ b/src/test/java/org/shedlang/compiler/shid/ShidCodeGenMemberAccessTests.java @@ -5,10 +5,7 @@ import org.shedlang.compiler.ast.typed.Typed; import org.shedlang.compiler.shid.instructions.ShidDefineFunction; import org.shedlang.compiler.shid.instructions.ShidFieldLoad; import org.shedlang.compiler.shid.instructions.ShidMatchers; -import org.shedlang.compiler.types.Effects; -import org.shedlang.compiler.types.NamespaceName; -import org.shedlang.compiler.types.TypeParam; -import org.shedlang.compiler.types.Types; +import org.shedlang.compiler.types.*; import java.util.List; @@ -60,13 +57,15 @@ public class ShidCodeGenMemberAccessTests { } @Test - public void structMethodAccessIsCompiledToDefineFunctionInstruction() { + public void structMethodAccessZeroParamsIsCompiledToDefineFunctionInstruction() { var namespaceName = NamespaceName.of("Example", "Project"); var structType = Types.struct(namespaceName, "User"); var node = Typed.methodAccess( Typed.reference("user", structType), "name", - Types.STRING + FunctionType.builder() + .withReturnType(Types.STRING) + .build() ); var context = ShidCodeGen.Context.EMPTY .addShedVal("user"); @@ -74,7 +73,6 @@ public class ShidCodeGenMemberAccessTests { var result = ShidCodeGen.compileExpression(node, context); // TODO: optimise calls - // TODO: handle params assertThat(result.instructions(), isSequence( isShidLocalLoad("user__0"), isShidLocalStore("receiver__0"), @@ -96,6 +94,51 @@ public class ShidCodeGenMemberAccessTests { )); } + @Test + public void structMethodAccessMultipleParamsIsCompiledToDefineFunctionInstruction() { + var namespaceName = NamespaceName.of("Example", "Project"); + var structType = Types.struct(namespaceName, "User"); + var node = Typed.methodAccess( + Typed.reference("user", structType), + "name", + FunctionType.builder() + .addPositionalParam(Types.BOOL) + .addNamedParam("b", Types.INT) + .withReturnType(Types.STRING) + .build() + ); + var context = ShidCodeGen.Context.EMPTY + .addShedVal("user"); + + var result = ShidCodeGen.compileExpression(node, context); + + assertThat(result.instructions(), isSequence( + isShidLocalLoad("user__0"), + isShidLocalStore("receiver__0"), + instanceOf( + ShidDefineFunction.class, + has("name", x -> x.name(), equalTo("name")), + has("positionalParams", x -> x.positionalParams(), isSequence( + isShidDefineFunctionParam("arg0__0") + )), + has("namedParams", x -> x.namedParams(), isSequence( + isShidDefineFunctionParam("b__0") + )), + has("freeVariables", x -> x.freeVariables(), containsExactly( + has("user", x -> x.name(), equalTo("receiver__0")) + )), + has("body", x -> x.body(), isShidBlock(isSequence( + isShidMethodLoad(structType, "name"), + isShidLocalLoad("receiver__0"), + isShidLocalLoad("arg0__0"), + isShidLocalLoad("b__0"), + isShidCall(2, List.of("b")), + isShidReturn() + ))) + ) + )); + } + @Test public void constructedTypeFieldAccessIsCompiledToFieldLoad() { var structType = Types.struct(NamespaceName.of("Example", "Project"), "Box"); -- cgit v1.2.3