From 2dba29dfa74c32a3102a9317455e16cd9a5a35a7 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sat, 21 Dec 2024 10:40:28 +0000 Subject: Compile methods into free functions --- .../org/shedlang/compiler/shid/ShidCodeGen.java | 65 +++++++++++++++------- .../shid/instructions/ShidDefineStruct.java | 4 -- .../compiler/shid/ShidCodeGenNamespaceTests.java | 44 +++++++++++++++ .../shid/ShidCodeGenStructDefinitionTests.java | 18 +++--- .../shedlang/compiler/shid/instructions/Shid.java | 1 - 5 files changed, 97 insertions(+), 35 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 b0c33578..280e94b8 100644 --- a/src/main/java/org/shedlang/compiler/shid/ShidCodeGen.java +++ b/src/main/java/org/shedlang/compiler/shid/ShidCodeGen.java @@ -474,6 +474,12 @@ public class ShidCodeGen { for (var statement : statementsAfterHoisting) { context = compileNamespaceStatement(statement, context); } + for (var statement : statementsAfterHoisting) { + if (statement instanceof TypedStructDefinitionNode structDefinitionNode) { + // TODO: test method hoisting + context = compileStructDefinitionMethods(structDefinitionNode, context); + } + } for (var fieldName : node.fieldNames()) { var localName = context.shedVariableToLocal(fieldName); @@ -549,31 +555,11 @@ public class ShidCodeGen { ) { var structType = node.typeOrConstructor().toType(); - var methods = new ArrayList(); - for (var methodNode : node.methods()) { - var shidFunctionName = context.generateLocalNameForVariable( - structType.name() + "__" + methodNode.name() - ); - context = compileFunction( - shidFunctionName, - methodNode.signature().params(), - methodNode.body(), - ShidDefineFunction.Variant.FUNCTION, - methodNode.source(), - context - ); - methods.add(new ShidDefineStruct.Method( - methodNode.name(), - shidFunctionName - )); - } - var defineStructInstruction = new ShidDefineStruct( structType, node.fields().stream() .map(field -> new ShidDefineStruct.Field(field.name(), field.source())) .toList(), - methods, node.source() ); @@ -585,6 +571,45 @@ public class ShidCodeGen { .addInstruction(storeInstruction); } + static Context compileStructDefinitionMethods( + TypedStructDefinitionNode node, + Context context + ) { + var structType = node.typeOrConstructor().toType(); + + for (var methodNode : node.methods()) { + var shidFunctionName = context.generateLocalNameForVariable( + "$methods__" + String.join("_", structType.namespaceName().parts()) + "__" + structType.name() + "__" + methodNode.name() + ); + context = compileFunction( + shidFunctionName, + methodNode.signature().params(), + methodNode.body(), + ShidDefineFunction.Variant.FUNCTION, + methodNode.source(), + context + ); + + context = context.addInstruction( + new ShidLocalStore(shidFunctionName, methodNode.source()) + ); + + context = context.addInstruction( + new ShidLocalLoad(shidFunctionName, methodNode.source()) + ); + + context = context.addInstruction( + new ShidNamespaceFieldStore( + structType.namespaceName(), + shidFunctionName, + methodNode.source() + ) + ); + } + + return context; + } + private static Context compileSumTypeDefinition( TypedSumTypeDefinitionNode node, Context context diff --git a/src/main/java/org/shedlang/compiler/shid/instructions/ShidDefineStruct.java b/src/main/java/org/shedlang/compiler/shid/instructions/ShidDefineStruct.java index c76b4f20..d3ed9e10 100644 --- a/src/main/java/org/shedlang/compiler/shid/instructions/ShidDefineStruct.java +++ b/src/main/java/org/shedlang/compiler/shid/instructions/ShidDefineStruct.java @@ -13,15 +13,11 @@ public record ShidDefineStruct( SimpleStructType type, // TODO: remove fields? We should have fields from the type info. List fields, - List methods, Source source ) implements ShidInstruction { public record Field(String name, Source source) { } - public record Method(String methodName, String shidFunctionName) { - } - @Override public boolean isBlockTerminator() { return false; diff --git a/src/test/java/org/shedlang/compiler/shid/ShidCodeGenNamespaceTests.java b/src/test/java/org/shedlang/compiler/shid/ShidCodeGenNamespaceTests.java index 1e6a1000..e760bdae 100644 --- a/src/test/java/org/shedlang/compiler/shid/ShidCodeGenNamespaceTests.java +++ b/src/test/java/org/shedlang/compiler/shid/ShidCodeGenNamespaceTests.java @@ -7,6 +7,7 @@ import org.shedlang.compiler.types.NamespaceName; import org.shedlang.compiler.types.Types; import java.util.List; +import java.util.Optional; import static org.shedlang.compiler.shid.instructions.ShidMatchers.*; import static org.zwobble.precisely.AssertThat.assertThat; @@ -115,4 +116,47 @@ public class ShidCodeGenNamespaceTests { isShidNamespaceFieldStore(namespaceName, "None") ))); } + + @Test + public void structMethodsAreExported() { + var namespaceName = new NamespaceName(List.of("Example", "Project")); + var structType = Types.struct(namespaceName, "User"); + var node = Typed.namespace( + namespaceName, + List.of( + TypedStructDefinitionNode.builder() + .withType(structType) + .addMethod( + TypedFunctionDefinitionNode.builder() + .withName("name") + .addPositionalParam("this", Optional.empty()) + .build() + ) + .build() + ), + List.of(BoundVariable.val("User")), + List.of() + ); + + var shidNamespace = ShidCodeGen.compileNamespace(node); + + assertThat(shidNamespace.body(), isShidBlock(isSequence( + instanceOf(ShidNamespaceImport.class), + instanceOf(ShidFieldLoad.class), + instanceOf(ShidLocalStore.class), + + instanceOf( + ShidDefineStruct.class, + has("type", x -> x.type(), equalTo(structType)) + ), + isShidLocalStore("User__0"), + instanceOf( + ShidDefineFunction.class, + has("name", x -> x.name(), equalTo("$methods__Example_Project__User__name__0")) + ), + isShidLocalStore("$methods__Example_Project__User__name__0"), + isShidLocalLoad("$methods__Example_Project__User__name__0"), + isShidNamespaceFieldStore(namespaceName, "$methods__Example_Project__User__name__0") + ))); + } } diff --git a/src/test/java/org/shedlang/compiler/shid/ShidCodeGenStructDefinitionTests.java b/src/test/java/org/shedlang/compiler/shid/ShidCodeGenStructDefinitionTests.java index 7db25429..0ffea260 100644 --- a/src/test/java/org/shedlang/compiler/shid/ShidCodeGenStructDefinitionTests.java +++ b/src/test/java/org/shedlang/compiler/shid/ShidCodeGenStructDefinitionTests.java @@ -61,12 +61,12 @@ public class ShidCodeGenStructDefinitionTests { var context = ShidCodeGen.Context.EMPTY .addShedVal("User"); - var result = ShidCodeGen.compileNamespaceStatement(node, context); + var result = ShidCodeGen.compileStructDefinitionMethods(node, context); assertThat(result.instructions(), isSequence( instanceOf( ShidDefineFunction.class, - has("name", x -> x.name(), equalTo("User__name__0")), + has("name", x -> x.name(), equalTo("$methods__Example_Project__User__name__0")), has("positionalParams", x -> x.positionalParams(), isSequence( isShidDefineFunctionParam("this__0"), isShidDefineFunctionParam("a__0") @@ -80,14 +80,12 @@ public class ShidCodeGenStructDefinitionTests { isShidReturn() ))) ), - instanceOf( - ShidDefineStruct.class, - has("type", x -> x.type(), equalTo(structType)), - has("methods", x -> x.methods(), isSequence( - equalTo(new ShidDefineStruct.Method("name", "User__name__0")) - )) - ), - isShidLocalStore("User__0") + isShidLocalStore("$methods__Example_Project__User__name__0"), + isShidLocalLoad("$methods__Example_Project__User__name__0"), + isShidNamespaceFieldStore( + NamespaceName.of("Example", "Project"), + "$methods__Example_Project__User__name__0" + ) )); } } diff --git a/src/test/java/org/shedlang/compiler/shid/instructions/Shid.java b/src/test/java/org/shedlang/compiler/shid/instructions/Shid.java index 1a547eea..ee78a3e3 100644 --- a/src/test/java/org/shedlang/compiler/shid/instructions/Shid.java +++ b/src/test/java/org/shedlang/compiler/shid/instructions/Shid.java @@ -35,7 +35,6 @@ public class Shid { return new ShidDefineStruct( type, fields, - List.of(), Sources.NULL ); } -- cgit v1.2.3