package org.shedlang.compiler.patio.serialization; import org.junit.jupiter.api.Test; import org.shedlang.compiler.patio.*; import org.shedlang.compiler.patio.instructions.Patio; import org.shedlang.compiler.patio.instructions.PatioInstruction; import org.shedlang.compiler.patio.operands.PatioOperand; import org.shedlang.compiler.patio.types.*; import org.shedlang.compiler.patio.values.PatioDataPtrValue; import org.shedlang.compiler.patio.values.PatioIntValue; import java.io.IOException; import java.util.List; import java.util.Optional; import static org.zwobble.precisely.AssertThat.assertThat; import static org.zwobble.precisely.Matchers.equalTo; public abstract class PatioSerializationTests { // == Compilation unit == protected abstract PatioCompilationUnit deserializeCompilationUnit(byte[] buffer) throws IOException; protected abstract byte[] serializeCompilationUnit(PatioCompilationUnit value) throws IOException; @Test public void canSerializeCompilationUnit() throws IOException { var element = PatioFunctionDefinition.builder() .withName("f") .build(); var compilationUnit = Patio.compilationUnit(List.of(element)); var deserializedCompilationUnit = deserializeCompilationUnit( serializeCompilationUnit(compilationUnit) ); assertThat(deserializedCompilationUnit, equalTo(compilationUnit)); } // == Compilation unit elements == protected abstract PatioCompilationUnitElement deserializeCompilationUnitElement(byte[] buffer) throws IOException; protected abstract byte[] serializeCompilationUnitElement(PatioCompilationUnitElement value) throws IOException; @Test public void canSerializeDataElementImmutableDefinition() throws IOException { var element = Patio.dataElementImmutableDefinition( "x", PatioVisibility.PRIVATE, PatioDataValues.array( PatioDataLayouts.BYTE, List.of(PatioDataValues.byte_(0x01), PatioDataValues.byte_(0x02)) ) ); var deserializedElement = deserializeCompilationUnitElement( serializeCompilationUnitElement(element) ); assertThat(deserializedElement, equalTo(element)); } @Test public void canSerializeDataElementMutableDeclaration() throws IOException { var element = Patio.dataElementMutableDeclaration( "x", PatioDataLayouts.INT ); var deserializedElement = deserializeCompilationUnitElement( serializeCompilationUnitElement(element) ); assertThat(deserializedElement, equalTo(element)); } @Test public void canSerializeDataElementMutableDefinition() throws IOException { var element = Patio.dataElementMutableDefinition( "x", PatioVisibility.PRIVATE, PatioDataValues.int_(42) ); var deserializedElement = deserializeCompilationUnitElement( serializeCompilationUnitElement(element) ); assertThat(deserializedElement, equalTo(element)); } @Test public void canSerializeExceptionTypeDefinition() throws IOException { var element = Patio.exceptionTypeDefinition("Error", PatioTypes.INT); var deserializedElement = deserializeCompilationUnitElement( serializeCompilationUnitElement(element) ); assertThat(deserializedElement, equalTo(element)); } @Test public void canSerializeFunctionDeclaration() throws IOException { var element = PatioFunctionDeclaration.builder() .withName("f") .addParam(Patio.param("param1", PatioTypes.INT)) .addParam(Patio.param("param2", PatioTypes.DATA_PTR)) .addReturnType(PatioTypes.INT32) .build(); var deserializedElement = deserializeCompilationUnitElement( serializeCompilationUnitElement(element) ); assertThat(deserializedElement, equalTo(element)); } @Test public void canSerializeFunctionDefinition() throws IOException { var element = PatioFunctionDefinition.builder() .withName("f") .withVisibility(PatioVisibility.PRIVATE) .addLocal(Patio.param("param1", PatioTypes.INT)) .addLocal(Patio.param("param2", PatioTypes.DATA_PTR)) .addLocal(Patio.val("local1", PatioTypes.FUNCTION_PTR)) .addLocal(Patio.val("local2", PatioTypes.INT)) .addReturnType(PatioTypes.INT32) .addBodyInstruction(Patio.localStore(Patio.localRef("local2"), Patio.intConst(2))) .build(); var deserializedElement = deserializeCompilationUnitElement( serializeCompilationUnitElement(element) ); assertThat(deserializedElement, equalTo(element)); } // == Instructions == protected abstract PatioInstruction deserializeInstruction(byte[] buffer) throws IOException; protected abstract byte[] serializeInstruction(PatioInstruction value) throws IOException; @Test public void canSerializeBlock() throws IOException { var instruction = Patio.block( List.of( Patio.localStore(Patio.localRef("x1"), Patio.intConst(1)), Patio.localStore(Patio.localRef("y1"), Patio.intConst(2)) ), List.of( Patio.localRef("x1"), Patio.localRef("y1") ) ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeBoolToInt() throws IOException { var instruction = Patio.boolToInt(Patio.localRef("destination"), Patio.localRef("value")); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeCallWithoutDestination() throws IOException { var instruction = Patio.call( Optional.empty(), "f", List.of(Patio.localRef("a"), Patio.localRef("b"), Patio.localRef("c")) ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeCallWithDestination() throws IOException { var instruction = Patio.call( Optional.of(Patio.localRef("destination")), "f", List.of(Patio.localRef("a"), Patio.localRef("b"), Patio.localRef("c")) ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeCallPointer() throws IOException { var instruction = Patio.callPointer( Patio.localRef("destination"), Patio.localRef("f"), List.of(Patio.localRef("a"), Patio.localRef("b"), Patio.localRef("c")) ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeDataPtrToInt() throws IOException { var instruction = Patio.dataPtrToInt(Patio.localRef("destination"), Patio.localRef("value")); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeIf() throws IOException { var instruction = Patio.if_( List.of( Patio.localRef("x"), Patio.localRef("y") ), Patio.localRef("condition"), Patio.block( List.of( Patio.localStore(Patio.localRef("x1"), Patio.intConst(1)), Patio.localStore(Patio.localRef("y1"), Patio.intConst(2)) ), List.of( Patio.localRef("x1"), Patio.localRef("y1") ) ), Patio.block( List.of( Patio.localStore(Patio.localRef("x2"), Patio.intConst(11)), Patio.localStore(Patio.localRef("y2"), Patio.intConst(12)) ), List.of( Patio.localRef("x2"), Patio.localRef("y2") ) ) ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeIntAdd() throws IOException { var instruction = Patio.intAdd( Patio.localRef("destination"), Patio.localRef("left"), Patio.localRef("right") ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeIntEquals() throws IOException { var instruction = Patio.intEquals( Patio.localRef("destination"), Patio.localRef("left"), Patio.localRef("right") ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeIntNotEqual() throws IOException { var instruction = Patio.intNotEqual( Patio.localRef("destination"), Patio.localRef("left"), Patio.localRef("right") ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeIntSub() throws IOException { var instruction = Patio.intSub( Patio.localRef("destination"), Patio.localRef("left"), Patio.localRef("right") ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeIntToBool() throws IOException { var instruction = Patio.intToBool(Patio.localRef("destination"), Patio.localRef("value")); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeIntToDataPtr() throws IOException { var instruction = Patio.intToDataPtr( Patio.localRef("destination"), Patio.localRef("value") ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeLocalStore() throws IOException { var instruction = Patio.localStore( Patio.localRef("destination"), Patio.localRef("x") ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeLoop() throws IOException { var instruction = Patio.loop( List.of( Patio.localStore(Patio.localRef("x"), Patio.intConst(1)) ) ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeLoopBreak() throws IOException { var instruction = Patio.loopBreak(); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeLoopContinue() throws IOException { var instruction = Patio.loopContinue(); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeMemoryLoad() throws IOException { var instruction = Patio.memoryLoad( Patio.localRef("destination"), Patio.localRef("pointer"), PatioDataLayouts.struct(List.of(PatioDataLayouts.INT, PatioDataLayouts.INT, PatioDataLayouts.BYTE)), List.of(1) ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeMemoryStore() throws IOException { var instruction = Patio.memoryStore( Patio.localRef("pointer"), PatioDataLayouts.struct(List.of(PatioDataLayouts.INT, PatioDataLayouts.INT, PatioDataLayouts.BYTE)), List.of(1), Patio.localRef("value") ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeReturn() throws IOException { var instruction = Patio.return_(Patio.localRef("value")); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeReturnVoid() throws IOException { var instruction = Patio.returnVoid(); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeSwitch() throws IOException { var instruction = Patio.switch_( List.of( Patio.localRef("x"), Patio.localRef("y") ), Patio.localRef("value"), List.of( Patio.switchCase( 1, Patio.block( List.of( Patio.localStore(Patio.localRef("x1"), Patio.intConst(11)), Patio.localStore(Patio.localRef("y1"), Patio.intConst(12)) ), List.of( Patio.localRef("x1"), Patio.localRef("y1") ) ) ), Patio.switchCase( 2, Patio.block( List.of( Patio.localStore(Patio.localRef("x2"), Patio.intConst(21)), Patio.localStore(Patio.localRef("y2"), Patio.intConst(22)) ), List.of( Patio.localRef("x2"), Patio.localRef("y2") ) ) ) ), Patio.block( List.of( Patio.localStore(Patio.localRef("x3"), Patio.intConst(31)), Patio.localStore(Patio.localRef("y3"), Patio.intConst(32)) ), List.of( Patio.localRef("x3"), Patio.localRef("y3") ) ) ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeThrow() throws IOException { var instruction = Patio.throw_("Error", Patio.localRef("value")); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeTry() throws IOException { var instruction = Patio.try_( List.of(Patio.localRef("x"), Patio.localRef("y")), List.of( Patio.catchClause( "Error1", Patio.localRef("a1"), Patio.block( List.of( Patio.localStore(Patio.localRef("xCatch1"), Patio.intConst(11)), Patio.localStore(Patio.localRef("yCatch1"), Patio.intConst(12)) ), List.of(Patio.localRef("xCatch1"), Patio.localRef("yCatch1")) ) ), Patio.catchClause( "Error2", Patio.localRef("a2"), Patio.block( List.of( Patio.localStore(Patio.localRef("xCatch2"), Patio.intConst(21)), Patio.localStore(Patio.localRef("yCatch2"), Patio.intConst(22)) ), List.of(Patio.localRef("xCatch2"), Patio.localRef("yCatch2")) ) ) ), Patio.block( List.of( Patio.localStore(Patio.localRef("xTry"), Patio.intConst(31)), Patio.localStore(Patio.localRef("yTry"), Patio.intConst(32)) ), List.of(Patio.localRef("xTry"), Patio.localRef("yTry")) ) ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeUnreachable() throws IOException { var instruction = Patio.unreachable(); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeVarLoad() throws IOException { var instruction = Patio.varLoad( Patio.localRef("destination"), Patio.localRef("v") ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } @Test public void canSerializeVarStore() throws IOException { var instruction = Patio.varStore( Patio.localRef("destination"), Patio.localRef("value") ); var deserializedInstruction = deserializeInstruction( serializeInstruction(instruction) ); assertThat(deserializedInstruction, equalTo(instruction)); } // == Operands == protected abstract PatioOperand deserializeOperand(byte[] buffer) throws IOException; protected abstract byte[] serializeOperand(PatioOperand value) throws IOException; @Test public void canSerializeBoolConst() throws IOException { var operand = Patio.boolConst(true); var deserializedOperand = deserializeOperand( serializeOperand(operand) ); assertThat(deserializedOperand, equalTo(operand)); } @Test public void canSerializeByteConst() throws IOException { var operand = Patio.byteConst((byte) 42); var deserializedOperand = deserializeOperand( serializeOperand(operand) ); assertThat(deserializedOperand, equalTo(operand)); } @Test public void canSerializeDataPtrConst() throws IOException { var operand = Patio.dataPtrConst("x"); var deserializedOperand = deserializeOperand( serializeOperand(operand) ); assertThat(deserializedOperand, equalTo(operand)); } @Test public void canSerializeFunctionPtrConst() throws IOException { var operand = Patio.functionPtrConst("x"); var deserializedOperand = deserializeOperand( serializeOperand(operand) ); assertThat(deserializedOperand, equalTo(operand)); } @Test public void canSerializeIntConst() throws IOException { var operand = Patio.intConst(42); var deserializedOperand = deserializeOperand( serializeOperand(operand) ); assertThat(deserializedOperand, equalTo(operand)); } @Test public void canSerializeInt32Const() throws IOException { var operand = Patio.int32Const(42); var deserializedOperand = deserializeOperand( serializeOperand(operand) ); assertThat(deserializedOperand, equalTo(operand)); } @Test public void canSerializeLocalRef() throws IOException { var operand = Patio.localRef("x"); var deserializedOperand = deserializeOperand( serializeOperand(operand) ); assertThat(deserializedOperand, equalTo(operand)); } // == Data ptr values == protected abstract PatioDataPtrValue deserializeDataPtrValue(byte[] buffer) throws IOException; protected abstract byte[] serializeDataPtrValue(PatioDataPtrValue value) throws IOException; @Test public void canSerializeDataPtrValueDataElement() throws IOException { var dataPtrValue = Patio.dataPtrValueDataElement("string"); var deserializedDataPtrValue = deserializeDataPtrValue( serializeDataPtrValue(dataPtrValue) ); assertThat(deserializedDataPtrValue, equalTo(dataPtrValue)); } @Test public void canSerializeDataPtrValueNull() throws IOException { var dataPtrValue = Patio.dataPtrValueNull(); var deserializedDataPtrValue = deserializeDataPtrValue( serializeDataPtrValue(dataPtrValue) ); assertThat(deserializedDataPtrValue, equalTo(dataPtrValue)); } // == Int values == protected abstract PatioIntValue deserializeIntValue(byte[] buffer) throws IOException; protected abstract byte[] serializeIntValue(PatioIntValue value) throws IOException; @Test public void canSerializeIntValueByteOffsetOf() throws IOException { var intValue = Patio.intValueByteOffsetOf( PatioDataLayouts.struct(List.of( PatioDataLayouts.INT, PatioDataLayouts.BYTE )), List.of(1, 2) ); var deserializedIntValue = deserializeIntValue( serializeIntValue(intValue) ); assertThat(deserializedIntValue, equalTo(intValue)); } @Test public void canSerializeIntValueByteSizeOf() throws IOException { var intValue = Patio.intValueByteSizeOf( PatioDataLayouts.struct(List.of( PatioDataLayouts.INT, PatioDataLayouts.BYTE )) ); var deserializedIntValue = deserializeIntValue( serializeIntValue(intValue) ); assertThat(deserializedIntValue, equalTo(intValue)); } @Test public void canSerializeIntValueLiteral() throws IOException { var intValue = Patio.intValueLiteral(42); var deserializedIntValue = deserializeIntValue( serializeIntValue(intValue) ); assertThat(deserializedIntValue, equalTo(intValue)); } // == Types == protected abstract PatioType deserializeType(byte[] buffer) throws IOException; protected abstract byte[] serializeType(PatioType value) throws IOException; @Test public void canSerializeBoolType() throws IOException { var type = PatioTypes.BOOL; var deserializedType = deserializeType( serializeType(type) ); assertThat(deserializedType, equalTo(type)); } @Test public void canSerializeByteType() throws IOException { var type = PatioTypes.BYTE; var deserializedType = deserializeType( serializeType(type) ); assertThat(deserializedType, equalTo(type)); } @Test public void canSerializeDataPtrType() throws IOException { var type = PatioTypes.DATA_PTR; var deserializedType = deserializeType( serializeType(type) ); assertThat(deserializedType, equalTo(type)); } @Test public void canSerializeFunctionPtrType() throws IOException { var type = PatioTypes.FUNCTION_PTR; var deserializedType = deserializeType( serializeType(type) ); assertThat(deserializedType, equalTo(type)); } @Test public void canSerializeIntType() throws IOException { var type = PatioTypes.INT; var deserializedType = deserializeType( serializeType(type) ); assertThat(deserializedType, equalTo(type)); } @Test public void canSerializeInt32Type() throws IOException { var type = PatioTypes.INT32; var deserializedType = deserializeType( serializeType(type) ); assertThat(deserializedType, equalTo(type)); } // == Data layouts == protected abstract PatioDataLayout deserializeDataLayout(byte[] buffer) throws IOException; protected abstract byte[] serializeDataLayout(PatioDataLayout value) throws IOException; @Test public void canSerializeDataLayoutArray() throws IOException { var layout = PatioDataLayouts.array(PatioDataLayouts.INT, 4); var deserializedLayout = deserializeDataLayout( serializeDataLayout(layout) ); assertThat(deserializedLayout, equalTo(layout)); } @Test public void canSerializeDataLayoutBool() throws IOException { var layout = PatioDataLayouts.BOOL; var deserializedLayout = deserializeDataLayout( serializeDataLayout(layout) ); assertThat(deserializedLayout, equalTo(layout)); } @Test public void canSerializeDataLayoutByte() throws IOException { var layout = PatioDataLayouts.BYTE; var deserializedLayout = deserializeDataLayout( serializeDataLayout(layout) ); assertThat(deserializedLayout, equalTo(layout)); } @Test public void canSerializeDataLayoutDataPtr() throws IOException { var layout = PatioDataLayouts.DATA_PTR; var deserializedLayout = deserializeDataLayout( serializeDataLayout(layout) ); assertThat(deserializedLayout, equalTo(layout)); } @Test public void canSerializeDataLayoutFunctionPtr() throws IOException { var layout = PatioDataLayouts.FUNCTION_PTR; var deserializedLayout = deserializeDataLayout( serializeDataLayout(layout) ); assertThat(deserializedLayout, equalTo(layout)); } @Test public void canSerializeDataLayoutInt() throws IOException { var layout = PatioDataLayouts.INT; var deserializedLayout = deserializeDataLayout( serializeDataLayout(layout) ); assertThat(deserializedLayout, equalTo(layout)); } @Test public void canSerializeDataLayoutInt32() throws IOException { var layout = PatioDataLayouts.INT32; var deserializedLayout = deserializeDataLayout( serializeDataLayout(layout) ); assertThat(deserializedLayout, equalTo(layout)); } @Test public void canSerializeDataLayoutStruct() throws IOException { var layout = PatioDataLayouts.struct(List.of(PatioDataLayouts.INT, PatioDataLayouts.INT, PatioDataLayouts.BYTE)); var deserializedLayout = deserializeDataLayout( serializeDataLayout(layout) ); assertThat(deserializedLayout, equalTo(layout)); } // == Data values == protected abstract PatioDataValue deserializeDataValue(byte[] buffer) throws IOException; protected abstract byte[] serializeDataValue(PatioDataValue value) throws IOException; @Test public void canSerializeDataValueArray() throws IOException { var value = PatioDataValues.array( PatioDataLayouts.BYTE, List.of( PatioDataValues.byte_(0x01), PatioDataValues.byte_(0x02), PatioDataValues.byte_(0x03) ) ); var deserializedValue = deserializeDataValue( serializeDataValue(value) ); assertThat(deserializedValue, equalTo(value)); } @Test public void canSerializeDataValueBool() throws IOException { var value = PatioDataValues.bool(true); var deserializedValue = deserializeDataValue( serializeDataValue(value) ); assertThat(deserializedValue, equalTo(value)); } @Test public void canSerializeDataValueByte() throws IOException { var value = PatioDataValues.byte_(0xc8); var deserializedValue = deserializeDataValue( serializeDataValue(value) ); assertThat(deserializedValue, equalTo(value)); } @Test public void canSerializeDataValueDataPtr() throws IOException { var value = PatioDataValues.dataPtrNull(); var deserializedValue = deserializeDataValue( serializeDataValue(value) ); assertThat(deserializedValue, equalTo(value)); } @Test public void canSerializeDataValueInt() throws IOException { var value = PatioDataValues.int_(42); var deserializedValue = deserializeDataValue( serializeDataValue(value) ); assertThat(deserializedValue, equalTo(value)); } @Test public void canSerializeDataValueInt32() throws IOException { var value = PatioDataValues.int32(42); var deserializedValue = deserializeDataValue( serializeDataValue(value) ); assertThat(deserializedValue, equalTo(value)); } @Test public void canSerializeDataValueStruct() throws IOException { var value = PatioDataValues.struct(List.of( PatioDataValues.byte_(0x01), PatioDataValues.byte_(0x02), PatioDataValues.byte_(0x03) )); var deserializedValue = deserializeDataValue( serializeDataValue(value) ); assertThat(deserializedValue, equalTo(value)); } }