package org.shedlang.compiler.patio; import org.junit.jupiter.api.Test; import org.shedlang.compiler.patio.instructions.Patio; import org.shedlang.compiler.patio.types.PatioDataLayouts; import org.shedlang.compiler.patio.types.PatioDataValues; import org.shedlang.compiler.patio.types.PatioTypes; import java.util.List; import java.util.Optional; import static org.zwobble.precisely.AssertThat.assertThat; import static org.zwobble.precisely.Matchers.equalTo; public class PatioSerializerTests { // == Compilation unit == @Test public void canSerializeCompilationUnit() { var element = PatioFunctionDefinition.builder() .withName("f") .build(); var compilationUnit = Patio.compilationUnit(List.of(element)); var string = PatioTesting.serializeCompilationUnit(compilationUnit); assertThat(string, equalTo(""" ( ( function "f" visibility=private locals=() return-types=() body=( ) ) )""" )); } // == Compilation unit elements == @Test public void canSerializeDataElementImmutableDefinition() { var element = Patio.dataElementImmutableDefinition( "x", PatioVisibility.PRIVATE, PatioDataValues.array( PatioDataLayouts.BYTE, List.of(PatioDataValues.byte_(0x01), PatioDataValues.byte_(0x02)) ) ); var string = PatioTesting.serializeCompilationUnitElement(element); assertThat(string, equalTo(""" (data-immutable "x" private (array byte ((byte 0x01) (byte 0x02))))""" )); } @Test public void canSerializeDataElementMutableDeclaration() { var element = Patio.dataElementMutableDeclaration( "x", PatioDataLayouts.INT ); var string = PatioTesting.serializeCompilationUnitElement(element); assertThat(string, equalTo(""" (data-mutable-decl "x" int)""" )); } @Test public void canSerializeDataElementMutableDefinition() { var element = Patio.dataElementMutableDefinition( "x", PatioVisibility.PRIVATE, PatioDataValues.int_(42) ); var string = PatioTesting.serializeCompilationUnitElement(element); assertThat(string, equalTo(""" (data-mutable "x" private (int 42))""" )); } @Test public void canSerializeExceptionTypeDefinition() { var element = Patio.exceptionTypeDefinition("Error", PatioTypes.INT); var string = PatioTesting.serializeCompilationUnitElement(element); assertThat(string, equalTo(""" (exception-type "Error" int)""" )); } @Test public void canSerializeFunctionDeclaration() { var element = PatioFunctionDeclaration.builder() .withName("f") .addParam(Patio.param("param1", PatioTypes.INT)) .addParam(Patio.param("param2", PatioTypes.DATA_PTR)) .addReturnType(PatioTypes.INT32) .build(); var string = PatioTesting.serializeCompilationUnitElement(element); assertThat(string, equalTo(""" ( function-decl "f" params=((param "param1" int) (param "param2" data-ptr)) return-types=(int32) )""" )); } @Test public void canSerializeFunctionDefinition() { 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 string = PatioTesting.serializeCompilationUnitElement(element); assertThat(string, equalTo(""" ( function "f" visibility=private locals=((param "param1" int) (param "param2" data-ptr) (val "local1" function-ptr) (val "local2" int)) return-types=(int32) body=( (local-store (local "local2") (int-const 2)) ) )""" )); } // == Instructions == @Test public void canSerializeBlock() { 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 string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" ( block ( (local-store (local "x1") (int-const 1)) (local-store (local "y1") (int-const 2)) ) results=((local "x1") (local "y1")) )""")); } @Test public void canSerializeBoolToInt() { var instruction = Patio.boolToInt(Patio.localRef("destination"), Patio.localRef("value")); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo("(bool-to-int (local \"destination\") (local \"value\"))")); } @Test public void canSerializeCallWithoutTarget() { var instruction = Patio.call( Optional.empty(), "f", List.of(Patio.localRef("a"), Patio.localRef("b"), Patio.localRef("c")) ); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" (call () "f" ((local "a") (local "b") (local "c")))""" )); } @Test public void canSerializeCallWithTarget() { var instruction = Patio.call( Optional.of(Patio.localRef("destination")), "f", List.of(Patio.localRef("a"), Patio.localRef("b"), Patio.localRef("c")) ); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" (call ((local "destination")) "f" ((local "a") (local "b") (local "c")))""" )); } @Test public void canSerializeCallPointer() { var instruction = Patio.callPointer( Patio.localRef("destination"), Patio.localRef("f"), List.of(Patio.localRef("a"), Patio.localRef("b"), Patio.localRef("c")) ); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" (call-pointer ((local "destination")) (local "f") ((local "a") (local "b") (local "c")))""" )); } @Test public void canSerializeDataPtrToInt() { var instruction = Patio.dataPtrToInt(Patio.localRef("destination"), Patio.localRef("value")); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" (data-ptr-to-int (local "destination") (local "value"))""" )); } @Test public void canSerializeIf() { 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 string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" ( if ((local "x") (local "y")) (local "condition") ( block ( (local-store (local "x1") (int-const 1)) (local-store (local "y1") (int-const 2)) ) results=((local "x1") (local "y1")) ) ( block ( (local-store (local "x2") (int-const 11)) (local-store (local "y2") (int-const 12)) ) results=((local "x2") (local "y2")) ) )""")); } @Test public void canSerializeIntAdd() { var instruction = Patio.intAdd( Patio.localRef("destination"), Patio.localRef("left"), Patio.localRef("right") ); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" (int-add (local "destination") (local "left") (local "right"))""" )); } @Test public void canSerializeIntEquals() { var instruction = Patio.intEquals( Patio.localRef("destination"), Patio.localRef("left"), Patio.localRef("right") ); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" (int-eq (local "destination") (local "left") (local "right"))""" )); } @Test public void canSerializeIntNotEqual() { var instruction = Patio.intNotEqual( Patio.localRef("destination"), Patio.localRef("left"), Patio.localRef("right") ); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" (int-ne (local "destination") (local "left") (local "right"))""" )); } @Test public void canSerializeIntSub() { var instruction = Patio.intSub( Patio.localRef("destination"), Patio.localRef("left"), Patio.localRef("right") ); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" (int-sub (local "destination") (local "left") (local "right"))""" )); } @Test public void canSerializeIntToBool() { var instruction = Patio.intToBool(Patio.localRef("destination"), Patio.localRef("value")); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo("(int-to-bool (local \"destination\") (local \"value\"))")); } @Test public void canSerializeIntToDataPtr() { var instruction = Patio.intToDataPtr( Patio.localRef("destination"), Patio.localRef("value") ); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo("(int-to-data-ptr (local \"destination\") (local \"value\"))")); } @Test public void canSerializeLocalStore() { var instruction = Patio.localStore( Patio.localRef("destination"), Patio.localRef("x") ); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo("(local-store (local \"destination\") (local \"x\"))")); } @Test public void canSerializeLoop() { var instruction = Patio.loop( List.of( Patio.localStore(Patio.localRef("x"), Patio.intConst(1)) ) ); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" ( loop ( (local-store (local "x") (int-const 1)) ) )""")); } @Test public void canSerializeLoopBreak() { var instruction = Patio.loopBreak(); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo("(break)")); } @Test public void canSerializeLoopContinue() { var instruction = Patio.loopContinue(); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo("(continue)")); } @Test public void canSerializeMemoryLoad() { var instruction = Patio.memoryLoad( Patio.localRef("destination"), Patio.localRef("pointer"), PatioDataLayouts.struct(List.of(PatioDataLayouts.INT, PatioDataLayouts.INT, PatioDataLayouts.BYTE)), List.of(1) ); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" ( memory-load (local "destination") pointer=(local "pointer") layout=(struct (int int byte)) element-offsets=(1) )""" )); } @Test public void canSerializeMemoryStore() { var instruction = Patio.memoryStore( Patio.localRef("pointer"), PatioDataLayouts.struct(List.of(PatioDataLayouts.INT, PatioDataLayouts.INT, PatioDataLayouts.BYTE)), List.of(1), Patio.localRef("value") ); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" ( memory-store pointer=(local "pointer") layout=(struct (int int byte)) element-offsets=(1) value=(local "value") )""" )); } @Test public void canSerializeReturn() { var instruction = Patio.return_(Patio.localRef("value")); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo("(return ((local \"value\")))")); } @Test public void canSerializeSwitch() { 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 string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" ( switch ((local "x") (local "y")) (local "value") ( ( case 1 ( block ( (local-store (local "x1") (int-const 11)) (local-store (local "y1") (int-const 12)) ) results=((local "x1") (local "y1")) ) ) ( case 2 ( block ( (local-store (local "x2") (int-const 21)) (local-store (local "y2") (int-const 22)) ) results=((local "x2") (local "y2")) ) ) ) ( block ( (local-store (local "x3") (int-const 31)) (local-store (local "y3") (int-const 32)) ) results=((local "x3") (local "y3")) ) )""")); } @Test public void canSerializeThrow() { var instruction = Patio.throw_("Error", Patio.localRef("value")); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" (throw "Error" (local "value"))""")); } @Test public void canSerializeTry() { 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 string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo(""" ( try ((local "x") (local "y")) ( ( catch "Error1" (local "a1") ( block ( (local-store (local "xCatch1") (int-const 11)) (local-store (local "yCatch1") (int-const 12)) ) results=((local "xCatch1") (local "yCatch1")) ) ) ( catch "Error2" (local "a2") ( block ( (local-store (local "xCatch2") (int-const 21)) (local-store (local "yCatch2") (int-const 22)) ) results=((local "xCatch2") (local "yCatch2")) ) ) ) ( block ( (local-store (local "xTry") (int-const 31)) (local-store (local "yTry") (int-const 32)) ) results=((local "xTry") (local "yTry")) ) )""")); } @Test public void canSerializeUnreachable() { var instruction = Patio.unreachable(); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo("(unreachable)")); } @Test public void canSerializeVarLoad() { var instruction = Patio.varLoad( Patio.localRef("destination"), Patio.localRef("v") ); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo("(var-load (local \"destination\") (local \"v\"))")); } @Test public void canSerializeVarStore() { var instruction = Patio.varStore( Patio.localRef("destination"), Patio.localRef("value") ); var string = PatioTesting.serializeInstruction(instruction); assertThat(string, equalTo("(var-store (local \"destination\") (local \"value\"))")); } // == Operands == @Test public void canSerializeBoolConst() { var operand = Patio.boolConst(true); var string = PatioTesting.serializeOperand(operand); assertThat(string, equalTo("(bool-const true)")); } @Test public void canSerializeByteConst() { var operand = Patio.byteConst((byte) 42); var string = PatioTesting.serializeOperand(operand); assertThat(string, equalTo("(byte-const 42)")); } @Test public void canSerializeDataPtrConst() { var operand = Patio.dataPtrConst("x"); var string = PatioTesting.serializeOperand(operand); assertThat(string, equalTo("(data-ptr-const \"x\")")); } @Test public void canSerializeFunctionPtrConst() { var operand = Patio.functionPtrConst("x"); var string = PatioTesting.serializeOperand(operand); assertThat(string, equalTo("(function-ptr-const \"x\")")); } @Test public void canSerializeIntConst() { var operand = Patio.intConst(42); var string = PatioTesting.serializeOperand(operand); assertThat(string, equalTo("(int-const 42)")); } @Test public void canSerializeInt32Const() { var operand = Patio.int32Const(42); var string = PatioTesting.serializeOperand(operand); assertThat(string, equalTo("(int32-const 42)")); } @Test public void canSerializeLocalRef() { var operand = Patio.localRef("x"); var string = PatioTesting.serializeOperand(operand); assertThat(string, equalTo("(local \"x\")")); } // == Data ptr values == @Test public void canSerializeDataPtrValueDataElement() { var dataPtrValue = Patio.dataPtrValueDataElement("string"); var string = PatioTesting.serializeDataPtrValue(dataPtrValue); assertThat(string, equalTo("\"string\"")); } @Test public void canSerializeDataPtrValueNull() { var dataPtrValue = Patio.dataPtrValueNull(); var string = PatioTesting.serializeDataPtrValue(dataPtrValue); assertThat(string, equalTo("null")); } // == Int values == @Test public void canSerializeIntValueByteOffsetOf() { var intValue = Patio.intValueByteOffsetOf( PatioDataLayouts.struct(List.of( PatioDataLayouts.INT, PatioDataLayouts.BYTE )), List.of(1, 2) ); var string = PatioTesting.serializeIntValue(intValue); assertThat(string, equalTo("(byte-offset-of (struct (int byte)) (1 2))")); } @Test public void canSerializeIntValueByteSizeOf() { var intValue = Patio.intValueByteSizeOf( PatioDataLayouts.struct(List.of( PatioDataLayouts.INT, PatioDataLayouts.BYTE )) ); var string = PatioTesting.serializeIntValue(intValue); assertThat(string, equalTo("(byte-size-of (struct (int byte)))")); } @Test public void canSerializeIntValueLiteral() { var intValue = Patio.intValueLiteral(42); var string = PatioTesting.serializeIntValue(intValue); assertThat(string, equalTo("42")); } // == Types == @Test public void canSerializeBoolType() { var type = PatioTypes.BOOL; var string = PatioTesting.serializeType(type); assertThat(string, equalTo("bool")); } @Test public void canSerializeByteType() { var type = PatioTypes.BYTE; var string = PatioTesting.serializeType(type); assertThat(string, equalTo("byte")); } @Test public void canSerializeDataPtrType() { var type = PatioTypes.DATA_PTR; var string = PatioTesting.serializeType(type); assertThat(string, equalTo("data-ptr")); } @Test public void canSerializeFunctionPtrType() { var type = PatioTypes.FUNCTION_PTR; var string = PatioTesting.serializeType(type); assertThat(string, equalTo("function-ptr")); } @Test public void canSerializeIntType() { var type = PatioTypes.INT; var string = PatioTesting.serializeType(type); assertThat(string, equalTo("int")); } @Test public void canSerializeInt32Type() { var type = PatioTypes.INT32; var string = PatioTesting.serializeType(type); assertThat(string, equalTo("int32")); } // == Data layouts == @Test public void canSerializeDataLayoutArray() { var layout = PatioDataLayouts.array(PatioDataLayouts.INT, 4); var string = PatioTesting.serializeDataLayout(layout); assertThat(string, equalTo("(array int 4)")); } @Test public void canSerializeDataLayoutBool() { var layout = PatioDataLayouts.BOOL; var string = PatioTesting.serializeDataLayout(layout); assertThat(string, equalTo("bool")); } @Test public void canSerializeDataLayoutByte() { var layout = PatioDataLayouts.BYTE; var string = PatioTesting.serializeDataLayout(layout); assertThat(string, equalTo("byte")); } @Test public void canSerializeDataLayoutDataPtr() { var layout = PatioDataLayouts.DATA_PTR; var string = PatioTesting.serializeDataLayout(layout); assertThat(string, equalTo("data-ptr")); } @Test public void canSerializeDataLayoutFunctionPtr() { var layout = PatioDataLayouts.FUNCTION_PTR; var string = PatioTesting.serializeDataLayout(layout); assertThat(string, equalTo("function-ptr")); } @Test public void canSerializeDataLayoutInt() { var layout = PatioDataLayouts.INT; var string = PatioTesting.serializeDataLayout(layout); assertThat(string, equalTo("int")); } @Test public void canSerializeDataLayoutInt32() { var layout = PatioDataLayouts.INT32; var string = PatioTesting.serializeDataLayout(layout); assertThat(string, equalTo("int32")); } @Test public void canSerializeDataLayoutStruct() { var layout = PatioDataLayouts.struct(List.of(PatioDataLayouts.INT, PatioDataLayouts.INT, PatioDataLayouts.BYTE)); var string = PatioTesting.serializeDataLayout(layout); assertThat(string, equalTo(""" (struct (int int byte))""" )); } // == Data values == @Test public void canSerializeDataValueArray() { var value = PatioDataValues.array( PatioDataLayouts.BYTE, List.of( PatioDataValues.byte_(0x01), PatioDataValues.byte_(0x02), PatioDataValues.byte_(0x03) ) ); var string = PatioTesting.serializeDataValue(value); assertThat(string, equalTo("(array byte ((byte 0x01) (byte 0x02) (byte 0x03)))")); } @Test public void canSerializeDataValueBool() { var value = PatioDataValues.bool(true); var string = PatioTesting.serializeDataValue(value); assertThat(string, equalTo("(bool true)")); } @Test public void canSerializeDataValueByte() { var value = PatioDataValues.byte_(0xc8); var string = PatioTesting.serializeDataValue(value); assertThat(string, equalTo("(byte 0xc8)")); } @Test public void canSerializeDataValueDataPtr() { var value = PatioDataValues.dataPtrNull(); var string = PatioTesting.serializeDataValue(value); assertThat(string, equalTo("(data-ptr null)")); } @Test public void canSerializeDataValueInt() { var value = PatioDataValues.int_(42); var string = PatioTesting.serializeDataValue(value); assertThat(string, equalTo("(int 42)")); } @Test public void canSerializeDataValueInt32() { var value = PatioDataValues.int32(42); var string = PatioTesting.serializeDataValue(value); assertThat(string, equalTo("(int32 42)")); } @Test public void canSerializeDataValueStruct() { var value = PatioDataValues.struct(List.of( PatioDataValues.byte_(0x01), PatioDataValues.byte_(0x02), PatioDataValues.byte_(0x03) )); var string = PatioTesting.serializeDataValue(value); assertThat(string, equalTo("(struct ((byte 0x01) (byte 0x02) (byte 0x03)))")); } }