From ecb878e11effdfd91ed1c29f18913e7074a527e4 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Thu, 28 Sep 2023 15:44:28 +0100 Subject: Hoist structs --- examples/15-struct-hoisting/shed.toml | 9 ++++ examples/15-struct-hoisting/src/HelloWorld.shed | 12 ++++++ .../shedlang/compiler/stackir/StackCompiler.java | 13 +++++- .../stackir/StackCompilerNamespaceTests.java | 49 ++++++++++++++++++++-- 4 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 examples/15-struct-hoisting/shed.toml create mode 100644 examples/15-struct-hoisting/src/HelloWorld.shed diff --git a/examples/15-struct-hoisting/shed.toml b/examples/15-struct-hoisting/shed.toml new file mode 100644 index 00000000..156fa7c6 --- /dev/null +++ b/examples/15-struct-hoisting/shed.toml @@ -0,0 +1,9 @@ +[shed] +main = "HelloWorld" + +[[shed.bins]] +name = "hello-world" + +[[shed.examples]] +bin = "hello-world" +expected-output = "hello, world" diff --git a/examples/15-struct-hoisting/src/HelloWorld.shed b/examples/15-struct-hoisting/src/HelloWorld.shed new file mode 100644 index 00000000..d9caa802 --- /dev/null +++ b/examples/15-struct-hoisting/src/HelloWorld.shed @@ -0,0 +1,12 @@ +val messageParts = MessageParts(.part1 = "hello, ", .part2 = "world\n"); + +fun main() ! Io -> Unit { + print!(messageParts.part1); + print!(messageParts.part2); +} + +struct MessageParts( + .part1: String, + .part2: String, +) { +} diff --git a/src/main/java/org/shedlang/compiler/stackir/StackCompiler.java b/src/main/java/org/shedlang/compiler/stackir/StackCompiler.java index dc171e00..cca640b4 100644 --- a/src/main/java/org/shedlang/compiler/stackir/StackCompiler.java +++ b/src/main/java/org/shedlang/compiler/stackir/StackCompiler.java @@ -5,6 +5,7 @@ import org.shedlang.compiler.ShedBuiltins; import org.shedlang.compiler.ast.typed.*; import org.shedlang.compiler.stackir.instructions.*; import org.shedlang.compiler.types.StructType; +import org.shedlang.compiler.util.Iterables; import org.shedlang.compiler.util.P; import java.util.List; @@ -337,7 +338,17 @@ public class StackCompiler { context = context.addShedVariable(boundVariableName); } - for (var statement : node.body()) { + var statementsAfterHoisting = Iterables.sortedBy(node.body(), statement -> switch (statement) { + case TypedAssignNode assign -> + 1; + + case TypedFunctionDefinitionNode functionDefinition -> + 1; + + case TypedStructDefinitionNode structDefinition -> + 0; + }); + for (var statement : statementsAfterHoisting) { context = compileNamespaceStatement(statement, context); } diff --git a/src/test/java/org/shedlang/compiler/stackir/StackCompilerNamespaceTests.java b/src/test/java/org/shedlang/compiler/stackir/StackCompilerNamespaceTests.java index b4524e90..3557ac20 100644 --- a/src/test/java/org/shedlang/compiler/stackir/StackCompilerNamespaceTests.java +++ b/src/test/java/org/shedlang/compiler/stackir/StackCompilerNamespaceTests.java @@ -3,10 +3,8 @@ package org.shedlang.compiler.stackir; import org.junit.jupiter.api.Test; import org.shedlang.compiler.ast.typed.Typed; import org.shedlang.compiler.ast.typed.TypedFunctionDefinitionNode; -import org.shedlang.compiler.stackir.instructions.DefineFunctionInstruction; -import org.shedlang.compiler.stackir.instructions.FieldLoadInstruction; -import org.shedlang.compiler.stackir.instructions.LocalStoreInstruction; -import org.shedlang.compiler.stackir.instructions.NamespaceImportInstruction; +import org.shedlang.compiler.ast.typed.TypedStructDefinitionNode; +import org.shedlang.compiler.stackir.instructions.*; import org.shedlang.compiler.types.NamespaceName; import org.shedlang.compiler.types.Types; @@ -52,4 +50,47 @@ public class StackCompilerNamespaceTests { isNamespaceFieldStore(namespaceName, "f") )); } + + @Test + public void structsAreHoisted() { + var namespaceName = new NamespaceName(List.of("Example")); + var structType = Types.struct(namespaceName, "None"); + var node = Typed.namespace( + namespaceName, + List.of( + TypedFunctionDefinitionNode.builder() + .withName("f") + .build(), + TypedStructDefinitionNode.builder() + .withType(structType) + .build() + ), + List.of("f", "None"), + List.of("f", "None") + ); + + var stackIrNamespace = StackCompiler.compileNamespace(node); + + assertThat(stackIrNamespace.instructions(), isSequence( + // TODO: test the builtin loading properly + instanceOf(NamespaceImportInstruction.class), + instanceOf(FieldLoadInstruction.class), + instanceOf(LocalStoreInstruction.class), + + instanceOf( + DefineStructInstruction.class, + has("type", x -> x.type(), equalTo(structType)) + ), + isLocalStoreInstruction("None__0"), + instanceOf( + DefineFunctionInstruction.class, + has("name", x -> x.name(), equalTo("f")) + ), + isLocalStoreInstruction("f__0"), + isLocalLoadInstruction("f__0"), + isNamespaceFieldStore(namespaceName, "f"), + isLocalLoadInstruction("None__0"), + isNamespaceFieldStore(namespaceName, "None") + )); + } } -- cgit v1.2.3