aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2026-03-22 10:59:03 +0000
committerMichael Williamson <mike@zwobble.org>2026-03-22 10:59:03 +0000
commitd8e89e31a95b7f435b07a5756368e5b39e063c6c (patch)
tree34a78709d64c1d146363acf6035606c98f8abb5a
parent0d83766cdb08286adf64c54d82ef2a78755f4c1e (diff)
Add serialization of sources to flatbuffers
-rw-r--r--flatbuffers/sources.fbs6
-rw-r--r--src/main/java/org/shedlang/compiler/sources/serialization/SourceToFlatbuffers.java141
-rw-r--r--src/test/java/org/shedlang/compiler/sources/serialization/SourceToFlatbuffersTests.java27
3 files changed, 173 insertions, 1 deletions
diff --git a/flatbuffers/sources.fbs b/flatbuffers/sources.fbs
index 9253bf6f..3b797d71 100644
--- a/flatbuffers/sources.fbs
+++ b/flatbuffers/sources.fbs
@@ -1,11 +1,15 @@
namespace Sources;
-union Source {
+union SourceValue {
NullSource,
RuntimeSource,
FileFragmentSource,
}
+table Source {
+ value:SourceValue (required);
+}
+
table NullSource {
}
diff --git a/src/main/java/org/shedlang/compiler/sources/serialization/SourceToFlatbuffers.java b/src/main/java/org/shedlang/compiler/sources/serialization/SourceToFlatbuffers.java
new file mode 100644
index 00000000..7c1bb074
--- /dev/null
+++ b/src/main/java/org/shedlang/compiler/sources/serialization/SourceToFlatbuffers.java
@@ -0,0 +1,141 @@
+package org.shedlang.compiler.sources.serialization;
+
+import com.google.flatbuffers.FlatBufferBuilder;
+import org.shedlang.compiler.sources.*;
+import org.shedlang.compiler.sources.flatbuffers.*;
+import org.zwobble.sourcetext.SourcePosition;
+import org.zwobble.sourcetext.SourceRange;
+import org.zwobble.sourcetext.SourceText;
+
+import java.util.Optional;
+
+public class SourceToFlatbuffers {
+ private SourceToFlatbuffers() {
+ }
+
+ public static int serializeSource(
+ FlatBufferBuilder builder,
+ Source source,
+ Source parentSource
+ ) {
+ return serializeSource(builder, source, Optional.of(parentSource));
+ }
+
+ public static int serializeSource(
+ FlatBufferBuilder builder,
+ Source source,
+ Optional<Source> parentSource
+ ) {
+ switch (source) {
+ case NullSource nullSource -> {
+ NullSourceFbs.startNullSourceFbs(builder);
+ var nullSourceFbs = NullSourceFbs.endNullSourceFbs(builder);
+
+ SourceFbs.startSourceFbs(builder);
+ SourceFbs.addValueType(builder, SourceValueFbs.NullSourceFbs);
+ SourceFbs.addValue(builder, nullSourceFbs);
+ return SourceFbs.endSourceFbs(builder);
+ }
+ case RuntimeSource runtimeSource -> {
+ RuntimeSourceFbs.startRuntimeSourceFbs(builder);
+ var runtimeSourceFbs = RuntimeSourceFbs.endRuntimeSourceFbs(builder);
+
+ SourceFbs.startSourceFbs(builder);
+ SourceFbs.addValueType(builder, SourceValueFbs.RuntimeSourceFbs);
+ SourceFbs.addValue(builder, runtimeSourceFbs);
+ return SourceFbs.endSourceFbs(builder);
+ }
+ case FileFragmentSource fileFragmentSource -> {
+ var fileFragmentSourceFbs = serializeFileFragmentSource(builder, fileFragmentSource, parentSource);
+
+ SourceFbs.startSourceFbs(builder);
+ SourceFbs.addValueType(builder, SourceValueFbs.FileFragmentSourceFbs);
+ SourceFbs.addValue(
+ builder,
+ fileFragmentSourceFbs
+ );
+ return SourceFbs.endSourceFbs(builder);
+ }
+ default -> {
+ throw new UnsupportedOperationException("Unhandled source: " + source);
+ }
+ }
+ }
+
+ public static Source deserializeSource(
+ SourceFbs sourceFbs,
+ Source parentSource
+ ) {
+ return deserializeSource(sourceFbs, Optional.of(parentSource));
+ }
+
+ public static Source deserializeSource(
+ SourceFbs sourceFbs,
+ Optional<Source> parentSource
+ ) {
+ return switch (sourceFbs.valueType()) {
+ case SourceValueFbs.NullSourceFbs ->
+ Sources.NULL;
+
+ case SourceValueFbs.RuntimeSourceFbs ->
+ Sources.RUNTIME;
+
+ case SourceValueFbs.FileFragmentSourceFbs ->
+ deserializeFileFragmentSource(
+ (FileFragmentSourceFbs) sourceFbs.value(new FileFragmentSourceFbs()),
+ parentSource
+ );
+
+ default -> {
+ throw new UnsupportedOperationException("TODO");
+ }
+ };
+ }
+
+ private static int serializeFileFragmentSource(
+ FlatBufferBuilder builder,
+ FileFragmentSource source,
+ Optional<Source> parentSource
+ ) {
+ var sourceTextName = source.sourceRange().sourceText().name();
+ if (!(
+ parentSource.isPresent() &&
+ parentSource.get() instanceof FileFragmentSource(
+ SourceRange parentSourceRange) &&
+ parentSourceRange.sourceText().name().equals(sourceTextName)
+ )) {
+ var sourceTextNameFbs = builder.createString(sourceTextName);
+ var sourceTextContentsFbs = builder.createString(source.sourceRange().sourceText().charSequence());
+ var sourceTextFbs = SourceTextFbs.createSourceTextFbs(builder, sourceTextNameFbs, sourceTextContentsFbs);
+ FileFragmentSourceFbs.startFileFragmentSourceFbs(builder);
+ FileFragmentSourceFbs.addSourceText(builder, sourceTextFbs);
+ } else {
+ FileFragmentSourceFbs.startFileFragmentSourceFbs(builder);
+ }
+
+ FileFragmentSourceFbs.addStartCharacterIndex(builder, source.sourceRange().start().characterIndex());
+ FileFragmentSourceFbs.addEndCharacterIndex(builder, source.sourceRange().end().characterIndex());
+
+ return FileFragmentSourceFbs.endFileFragmentSourceFbs(builder);
+ }
+
+ private static FileFragmentSource deserializeFileFragmentSource(
+ FileFragmentSourceFbs sourceFbs,
+ Optional<Source> parentSource
+ ) {
+ SourceText sourceText;
+ if (sourceFbs.sourceText() != null) {
+ sourceText = SourceText.fromString(
+ sourceFbs.sourceText().name(),
+ sourceFbs.sourceText().contents()
+ );
+ } else {
+ // TODO: handle missing parent
+ sourceText = ((FileFragmentSource) parentSource.orElseThrow()).sourceRange().sourceText();
+ }
+
+ var start = new SourcePosition(sourceText, (int) sourceFbs.startCharacterIndex());
+ var end = new SourcePosition(sourceText, (int) sourceFbs.endCharacterIndex());
+ return new FileFragmentSource(new SourceRange(sourceText, start, end));
+ }
+}
diff --git a/src/test/java/org/shedlang/compiler/sources/serialization/SourceToFlatbuffersTests.java b/src/test/java/org/shedlang/compiler/sources/serialization/SourceToFlatbuffersTests.java
new file mode 100644
index 00000000..31d20149
--- /dev/null
+++ b/src/test/java/org/shedlang/compiler/sources/serialization/SourceToFlatbuffersTests.java
@@ -0,0 +1,27 @@
+package org.shedlang.compiler.sources.serialization;
+
+import com.google.flatbuffers.FlatBufferBuilder;
+import com.google.protobuf.InvalidProtocolBufferException;
+import org.shedlang.compiler.sources.SourceSerializationTests;
+import org.shedlang.compiler.sources.flatbuffers.SourceFbs;
+import org.shedlang.compiler.sources.protobuf.SourcesProtobuf;
+
+import java.nio.ByteBuffer;
+
+public class SourceToFlatbuffersTests extends SourceSerializationTests {
+ public SourceToFlatbuffersTests() {
+ super(
+ (source, parentSource) -> {
+ var builder = new FlatBufferBuilder();
+ var sourceFbs = SourceToFlatbuffers.serializeSource(builder, source, parentSource);
+ builder.finish(sourceFbs);
+ return builder.sizedByteArray();
+ },
+
+ (serializedSource, parentSource) -> {
+ var sourceFbs = SourceFbs.getRootAsSourceFbs(ByteBuffer.wrap(serializedSource));
+ return SourceToFlatbuffers.deserializeSource(sourceFbs, parentSource);
+ }
+ );
+ }
+}