diff options
| author | Michael Williamson <mike@zwobble.org> | 2023-06-10 20:50:15 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2023-06-10 20:50:15 +0100 |
| commit | 0cf3c519c2b834c1d5709e1e98be54cd98b90eb9 (patch) | |
| tree | 8c3a56e24d9029c2a2410c00541da05c14457bee /src/main/java | |
| parent | 4564de5f2b387ce71c906d980eb9d9ef2f5c4390 (diff) | |
Add serialization for instructions
Diffstat (limited to 'src/main/java')
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; + } +} |
