aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-06-10 20:50:15 +0100
committerMichael Williamson <mike@zwobble.org>2023-06-10 20:50:15 +0100
commit0cf3c519c2b834c1d5709e1e98be54cd98b90eb9 (patch)
tree8c3a56e24d9029c2a2410c00541da05c14457bee /src/main/java
parent4564de5f2b387ce71c906d980eb9d9ef2f5c4390 (diff)
Add serialization for instructions
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/org/shedlang/compiler/stackir/InstructionSerializer.java208
-rw-r--r--src/main/java/org/shedlang/compiler/stackir/instructions/CallInstruction.java4
-rw-r--r--src/main/java/org/shedlang/compiler/util/Action.java6
-rw-r--r--src/main/java/org/shedlang/compiler/util/Iterables.java19
-rw-r--r--src/main/java/org/shedlang/compiler/util/Sets.java18
5 files changed, 253 insertions, 2 deletions
diff --git a/src/main/java/org/shedlang/compiler/stackir/InstructionSerializer.java b/src/main/java/org/shedlang/compiler/stackir/InstructionSerializer.java
new file mode 100644
index 00000000..65f29512
--- /dev/null
+++ b/src/main/java/org/shedlang/compiler/stackir/InstructionSerializer.java
@@ -0,0 +1,208 @@
+package org.shedlang.compiler.stackir;
+
+import org.shedlang.compiler.stackir.instructions.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.shedlang.compiler.util.Iterables.forEachInterspersed;
+
+public class InstructionSerializer {
+ private InstructionSerializer() {
+ }
+
+ public static void serialize(Instruction instruction, StringBuilder builder) {
+ var tree = toTree(instruction);
+ serializeTree(tree, builder, 0);
+ }
+
+ private static Tree toTree(Instruction instruction) {
+ return switch (instruction) {
+ case CallInstruction callInstruction ->
+ treeList(
+ treeIdentifier("call"),
+ treeNamed(
+ "positionalArgCount",
+ treeInt(callInstruction.positionalArgCount())
+ ),
+ treeNamed(
+ "namedArgNames",
+ treeList(
+ callInstruction.namedArgNames().stream()
+ .map(arg -> treeString(arg))
+ .toList()
+ )
+ )
+ );
+
+ case DefineFunctionInstruction defineFunctionInstruction ->
+ treeListIndented(
+ treeIdentifier("define-function"),
+ treeNamed("positionalParams", treeList(
+ defineFunctionInstruction.positionalParams().stream()
+ .map(param -> treeString(param.name()))
+ .toList()
+ )),
+ treeNamed("namedParams", treeList(
+ defineFunctionInstruction.namedParams().stream()
+ .map(param -> treeString(param.name()))
+ .toList()
+ )),
+ treeNamed("freeVariables", treeList(
+ defineFunctionInstruction.freeVariables().stream()
+ .map(freeVariable -> treeString(freeVariable))
+ .toList()
+ )),
+ treeNamed("body", treeListIndented(
+ defineFunctionInstruction.body().stream()
+ .map(bodyInstruction -> toTree(bodyInstruction))
+ .toList()
+ ))
+ );
+
+ case DiscardInstruction discardInstruction ->
+ treeList(
+ treeIdentifier("discard")
+ );
+
+ case LocalLoadInstruction localLoadInstruction ->
+ treeList(
+ treeIdentifier("local-load"),
+ treeString(localLoadInstruction.name())
+ );
+
+ case LocalStoreInstruction localStoreInstruction ->
+ treeList(
+ treeIdentifier("local-store"),
+ treeString(localStoreInstruction.name())
+ );
+
+ case ModuleExportInstruction moduleExportInstruction ->
+ treeList(
+ treeIdentifier("module-export"),
+ treeString(moduleExportInstruction.name())
+ );
+
+ case PushBoolInstruction pushBoolInstruction ->
+ treeList(
+ treeIdentifier("push-bool"),
+ treeIdentifier(Boolean.toString(pushBoolInstruction.value()))
+ );
+
+ case PushIntInstruction pushIntInstruction ->
+ treeList(
+ treeIdentifier("push-int"),
+ treeIdentifier(pushIntInstruction.value().toString())
+ );
+
+ case PushStringInstruction pushStringInstruction ->
+ treeList(
+ treeIdentifier("push-string"),
+ treeString(pushStringInstruction.value())
+ );
+ };
+ }
+
+ private static Tree treeIdentifier(String name) {
+ return new TreeIdentifier(name);
+ }
+
+ private static Tree treeInt(int value) {
+ return new TreeInt(value);
+ }
+
+ private static Tree treeList(List<Tree> children) {
+ return new TreeList(children);
+ }
+
+ private static Tree treeList(Tree... children) {
+ return new TreeList(Arrays.asList(children));
+ }
+
+ private static Tree treeListIndented(List<Tree> children) {
+ return new TreeListIndented(children);
+ }
+
+ private static Tree treeListIndented(Tree... children) {
+ return new TreeListIndented(Arrays.asList(children));
+ }
+
+ private static Tree treeNamed(String name, Tree value) {
+ return new TreeNamed(name, value);
+ }
+
+ private static Tree treeString(String value) {
+ return new TreeString(value);
+ }
+
+ private sealed interface Tree {}
+
+ private record TreeIdentifier(String name) implements Tree {
+ }
+
+ private record TreeInt(int value) implements Tree {
+ }
+
+ private record TreeList(List<Tree> children) implements Tree {
+ }
+
+ private record TreeListIndented(List<Tree> children) implements Tree {
+ }
+
+ private record TreeNamed(String name, Tree value) implements Tree {
+ }
+
+ private record TreeString(String value) implements Tree {
+ }
+
+ private static void serializeTree(Tree tree, StringBuilder builder, int indentation) {
+ switch (tree) {
+ case TreeIdentifier identifier -> {
+ builder.append(identifier.name);
+ }
+ case TreeInt treeInt -> {
+ builder.append(treeInt.value);
+ }
+ case TreeList list -> {
+ builder.append("(");
+ forEachInterspersed(
+ list.children,
+ child -> serializeTree(child, builder, indentation),
+ () -> builder.append(" ")
+ );
+ builder.append(")");
+ }
+ case TreeListIndented list -> {
+ builder.append("(");
+ forEachInterspersed(
+ list.children,
+ child -> {
+ newLine(indentation + 1, builder);
+ serializeTree(child, builder, indentation + 1);
+ },
+ () -> {}
+ );
+ newLine(indentation, builder);
+ builder.append(")");
+ }
+ case TreeNamed named -> {
+ builder.append(named.name);
+ builder.append("=");
+ serializeTree(named.value, builder, indentation);
+ }
+ case TreeString string -> {
+ // TODO: escaping
+ builder.append("\"");
+ builder.append(string.value);
+ builder.append("\"");
+ }
+ }
+ }
+
+ private static void newLine(int indentation, StringBuilder builder) {
+ builder.append("\n");
+ for (var i = 0; i < indentation; i++) {
+ builder.append(" ");
+ }
+ }
+}
diff --git a/src/main/java/org/shedlang/compiler/stackir/instructions/CallInstruction.java b/src/main/java/org/shedlang/compiler/stackir/instructions/CallInstruction.java
index 1cdfa9d5..d1e3c4bb 100644
--- a/src/main/java/org/shedlang/compiler/stackir/instructions/CallInstruction.java
+++ b/src/main/java/org/shedlang/compiler/stackir/instructions/CallInstruction.java
@@ -5,8 +5,8 @@ import org.shedlang.compiler.sources.Source;
import java.util.List;
public record CallInstruction(
- int argCount,
- List<String> namedArgs,
+ int positionalArgCount,
+ List<String> namedArgNames,
Source source
) implements Instruction {
}
diff --git a/src/main/java/org/shedlang/compiler/util/Action.java b/src/main/java/org/shedlang/compiler/util/Action.java
new file mode 100644
index 00000000..67422480
--- /dev/null
+++ b/src/main/java/org/shedlang/compiler/util/Action.java
@@ -0,0 +1,6 @@
+package org.shedlang.compiler.util;
+
+@FunctionalInterface
+public interface Action {
+ void call();
+}
diff --git a/src/main/java/org/shedlang/compiler/util/Iterables.java b/src/main/java/org/shedlang/compiler/util/Iterables.java
new file mode 100644
index 00000000..6fcb02e1
--- /dev/null
+++ b/src/main/java/org/shedlang/compiler/util/Iterables.java
@@ -0,0 +1,19 @@
+package org.shedlang.compiler.util;
+
+import java.util.function.Consumer;
+
+public class Iterables {
+ private Iterables() {
+ }
+
+ public static <T> void forEachInterspersed(Iterable<T> values, Consumer<T> onElement, Action between) {
+ var first = true;
+ for (var value : values) {
+ if (!first) {
+ between.call();
+ }
+ onElement.accept(value);
+ first = false;
+ }
+ }
+}
diff --git a/src/main/java/org/shedlang/compiler/util/Sets.java b/src/main/java/org/shedlang/compiler/util/Sets.java
new file mode 100644
index 00000000..f9bedfaf
--- /dev/null
+++ b/src/main/java/org/shedlang/compiler/util/Sets.java
@@ -0,0 +1,18 @@
+package org.shedlang.compiler.util;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+public class Sets {
+ private Sets() {
+ }
+
+ @SafeVarargs
+ public static <T> Set<T> orderedSetOf(T... values) {
+ var set = new LinkedHashSet<T>(values.length);
+ for (var value : values) {
+ set.add(value);
+ }
+ return set;
+ }
+}