From 2cefa82d059dfd16d224b16f92fd69104beb24a2 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sat, 10 Jun 2023 11:52:04 +0100 Subject: Compile calls to stack instructions --- .../shedlang/compiler/stackir/StackCompiler.java | 48 ++++++++++++++++------ .../stackir/instructions/CallInstruction.java | 12 ++++++ .../compiler/stackir/instructions/Instruction.java | 3 +- src/main/java/org/shedlang/compiler/util/P.java | 8 ++++ .../org/shedlang/compiler/ast/typed/Typed.java | 19 +++++++++ .../org/shedlang/compiler/ast/untyped/Untyped.java | 40 +++++++++--------- .../compiler/stackir/StackCompilerCallTests.java | 39 ++++++++++++++++++ .../stackir/instructions/InstructionMatchers.java | 9 ++++ 8 files changed, 145 insertions(+), 33 deletions(-) create mode 100644 src/main/java/org/shedlang/compiler/stackir/instructions/CallInstruction.java create mode 100644 src/test/java/org/shedlang/compiler/stackir/StackCompilerCallTests.java (limited to 'src') diff --git a/src/main/java/org/shedlang/compiler/stackir/StackCompiler.java b/src/main/java/org/shedlang/compiler/stackir/StackCompiler.java index 1d6b0a88..c16674e0 100644 --- a/src/main/java/org/shedlang/compiler/stackir/StackCompiler.java +++ b/src/main/java/org/shedlang/compiler/stackir/StackCompiler.java @@ -1,25 +1,49 @@ package org.shedlang.compiler.stackir; +import org.pcollections.PVector; import org.shedlang.compiler.ast.typed.*; import org.shedlang.compiler.stackir.instructions.*; - -import java.util.List; +import org.shedlang.compiler.util.P; public class StackCompiler { private StackCompiler() { } - private static List compileBoolLiteral(TypedBoolLiteralNode node) { - return List.of(new PushBoolInstruction(node.value(), node.source())); + private static PVector compileBoolLiteral(TypedBoolLiteralNode node) { + return P.vector(new PushBoolInstruction(node.value(), node.source())); + } + + private static PVector compileCall(TypedCallNode node) { + var instructions = compileExpression(node.receiver()); + + instructions = node.args().positional().stream() + .map(arg -> compileExpression(arg)) + .reduce(instructions, PVector::plusAll); + + instructions = node.args().named().stream() + .map(arg -> compileExpression(arg.expression())) + .reduce(instructions, PVector::plusAll); + + var callInstruction = new CallInstruction( + node.args().positional().size(), + node.args().named().stream() + .map(arg -> arg.name()) + .toList(), + node.source() + ); + + instructions = instructions.plus(callInstruction); + + return instructions; } - public static List compileExpression(TypedExpressionNode node) { + public static PVector compileExpression(TypedExpressionNode node) { return switch (node) { case TypedBoolLiteralNode typedBoolLiteralNode -> compileBoolLiteral(typedBoolLiteralNode); case TypedCallNode typedCallNode -> - throw new UnsupportedOperationException("TODO"); + compileCall(typedCallNode); case TypedIntLiteralNode typedIntLiteralNode -> compileIntLiteral(typedIntLiteralNode); @@ -32,15 +56,15 @@ public class StackCompiler { }; } - private static List compileIntLiteral(TypedIntLiteralNode node) { - return List.of(new PushIntInstruction(node.value(), node.source())); + private static PVector compileIntLiteral(TypedIntLiteralNode node) { + return P.vector(new PushIntInstruction(node.value(), node.source())); } - private static List compileReference(TypedReferenceNode node) { - return List.of(new LocalLoadInstruction(node.name(), node.source())); + private static PVector compileReference(TypedReferenceNode node) { + return P.vector(new LocalLoadInstruction(node.name(), node.source())); } - private static List compileStringLiteral(TypedStringLiteralNode node) { - return List.of(new PushStringInstruction(node.value(), node.source())); + private static PVector compileStringLiteral(TypedStringLiteralNode node) { + return P.vector(new PushStringInstruction(node.value(), node.source())); } } diff --git a/src/main/java/org/shedlang/compiler/stackir/instructions/CallInstruction.java b/src/main/java/org/shedlang/compiler/stackir/instructions/CallInstruction.java new file mode 100644 index 00000000..1cdfa9d5 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/stackir/instructions/CallInstruction.java @@ -0,0 +1,12 @@ +package org.shedlang.compiler.stackir.instructions; + +import org.shedlang.compiler.sources.Source; + +import java.util.List; + +public record CallInstruction( + int argCount, + List namedArgs, + Source source +) implements Instruction { +} diff --git a/src/main/java/org/shedlang/compiler/stackir/instructions/Instruction.java b/src/main/java/org/shedlang/compiler/stackir/instructions/Instruction.java index 59af2b9b..33007bf2 100644 --- a/src/main/java/org/shedlang/compiler/stackir/instructions/Instruction.java +++ b/src/main/java/org/shedlang/compiler/stackir/instructions/Instruction.java @@ -1,4 +1,5 @@ package org.shedlang.compiler.stackir.instructions; -public sealed interface Instruction permits LocalLoadInstruction, LocalStoreInstruction, PushBoolInstruction, PushIntInstruction, PushStringInstruction { +public sealed interface Instruction + permits CallInstruction, LocalLoadInstruction, LocalStoreInstruction, PushBoolInstruction, PushIntInstruction, PushStringInstruction { } diff --git a/src/main/java/org/shedlang/compiler/util/P.java b/src/main/java/org/shedlang/compiler/util/P.java index 7ce8232c..a09d7940 100644 --- a/src/main/java/org/shedlang/compiler/util/P.java +++ b/src/main/java/org/shedlang/compiler/util/P.java @@ -2,7 +2,10 @@ package org.shedlang.compiler.util; import org.pcollections.HashTreePMap; import org.pcollections.PMap; +import org.pcollections.PVector; +import org.pcollections.TreePVector; +import java.util.Arrays; import java.util.Map; public class P { @@ -17,4 +20,9 @@ public class P { } return map; } + + @SafeVarargs + public static PVector vector(T... values) { + return TreePVector.from(Arrays.asList(values)); + } } diff --git a/src/test/java/org/shedlang/compiler/ast/typed/Typed.java b/src/test/java/org/shedlang/compiler/ast/typed/Typed.java index 75f54d36..ed58b4d4 100644 --- a/src/test/java/org/shedlang/compiler/ast/typed/Typed.java +++ b/src/test/java/org/shedlang/compiler/ast/typed/Typed.java @@ -5,6 +5,7 @@ import org.shedlang.compiler.types.Type; import org.shedlang.compiler.types.Types; import java.math.BigInteger; +import java.util.List; public class Typed { private Typed() { @@ -14,10 +15,28 @@ public class Typed { return new TypedBoolLiteralNode(value, Sources.NULL); } + public static TypedCallNode call( + TypedExpressionNode receiver, + List positionalArgs, + List namedArgs + ) { + return new TypedCallNode( + receiver, + new TypedArgsNode(positionalArgs, namedArgs, Sources.NULL), + false, + Types.UNIT, + Sources.NULL + ); + } + public static TypedIntLiteralNode intLiteral(int value) { return new TypedIntLiteralNode(BigInteger.valueOf(value), Sources.NULL); } + public static TypedNamedArgNode namedArg(String name, TypedExpressionNode expression) { + return new TypedNamedArgNode(name, expression, Sources.NULL); + } + public static TypedStringLiteralNode stringLiteral(String value) { return new TypedStringLiteralNode(value, Sources.NULL); } diff --git a/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java b/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java index 11e7b38f..5cc0ce85 100644 --- a/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java +++ b/src/test/java/org/shedlang/compiler/ast/untyped/Untyped.java @@ -13,26 +13,6 @@ public class Untyped { return new UntypedBoolLiteralNode(value, Sources.NULL); } - public static UntypedIntLiteralNode intLiteral(int value) { - return new UntypedIntLiteralNode(BigInteger.valueOf(value), Sources.NULL); - } - - public static UntypedIntLiteralNode intLiteral(BigInteger value) { - return new UntypedIntLiteralNode(value, Sources.NULL); - } - - public static UntypedNamedArgNode namedArg(String name, UntypedExpressionNode expression) { - return new UntypedNamedArgNode(name, expression, Sources.NULL); - } - - public static UntypedReferenceNode reference(String name) { - return new UntypedReferenceNode(name, Sources.NULL); - } - - public static UntypedStringLiteralNode stringLiteral(String value) { - return new UntypedStringLiteralNode(value, Sources.NULL); - } - public static UntypedCallNode call( UntypedExpressionNode receiver, List positionalArgs @@ -52,4 +32,24 @@ public class Untyped { Sources.NULL ); } + + public static UntypedIntLiteralNode intLiteral(int value) { + return new UntypedIntLiteralNode(BigInteger.valueOf(value), Sources.NULL); + } + + public static UntypedIntLiteralNode intLiteral(BigInteger value) { + return new UntypedIntLiteralNode(value, Sources.NULL); + } + + public static UntypedNamedArgNode namedArg(String name, UntypedExpressionNode expression) { + return new UntypedNamedArgNode(name, expression, Sources.NULL); + } + + public static UntypedReferenceNode reference(String name) { + return new UntypedReferenceNode(name, Sources.NULL); + } + + public static UntypedStringLiteralNode stringLiteral(String value) { + return new UntypedStringLiteralNode(value, Sources.NULL); + } } diff --git a/src/test/java/org/shedlang/compiler/stackir/StackCompilerCallTests.java b/src/test/java/org/shedlang/compiler/stackir/StackCompilerCallTests.java new file mode 100644 index 00000000..f4a2f229 --- /dev/null +++ b/src/test/java/org/shedlang/compiler/stackir/StackCompilerCallTests.java @@ -0,0 +1,39 @@ +package org.shedlang.compiler.stackir; + +import org.junit.jupiter.api.Test; +import org.shedlang.compiler.ast.typed.Typed; + +import java.util.List; + +import static org.shedlang.compiler.stackir.instructions.InstructionMatchers.*; +import static org.zwobble.precisely.AssertThat.assertThat; +import static org.zwobble.precisely.Matchers.isSequence; + +public class StackCompilerCallTests { + @Test + public void callIsCompiledToInstructionsForOperandThenCall() { + var node = Typed.call( + Typed.reference("f"), + List.of( + Typed.stringLiteral("p1"), + Typed.stringLiteral("p2") + + ), + List.of( + Typed.namedArg("x2", Typed.stringLiteral("n2")), + Typed.namedArg("x1", Typed.stringLiteral("n1")) + ) + ); + + var instructions = StackCompiler.compileExpression(node); + + assertThat(instructions, isSequence( + isLocalLoadInstruction("f"), + isPushStringInstruction("p1"), + isPushStringInstruction("p2"), + isPushStringInstruction("n2"), + isPushStringInstruction("n1"), + isCallInstruction(2, List.of("x2", "x1")) + )); + } +} diff --git a/src/test/java/org/shedlang/compiler/stackir/instructions/InstructionMatchers.java b/src/test/java/org/shedlang/compiler/stackir/instructions/InstructionMatchers.java index 2fc1aa21..c9cd8621 100644 --- a/src/test/java/org/shedlang/compiler/stackir/instructions/InstructionMatchers.java +++ b/src/test/java/org/shedlang/compiler/stackir/instructions/InstructionMatchers.java @@ -3,6 +3,7 @@ package org.shedlang.compiler.stackir.instructions; import org.zwobble.precisely.Matcher; import java.math.BigInteger; +import java.util.List; import static org.zwobble.precisely.Matchers.*; @@ -10,6 +11,14 @@ public class InstructionMatchers { private InstructionMatchers() { } + public static Matcher isCallInstruction(int argCount, List namedArgs) { + return instanceOf( + CallInstruction.class, + has("argCount", x -> x.argCount(), equalTo(argCount)), + has("namedArgs", x -> x.namedArgs(), equalTo(namedArgs)) + ); + } + public static Matcher isLocalLoadInstruction(String name) { return instanceOf( LocalLoadInstruction.class, -- cgit v1.2.3