def test_while_str() -> None: assert_equal( str(ada.While( ada.Variable("X"), [ada.NullStatement()], )), multilinestr("""while X loop null; end loop;"""), ) assert_equal( str( ada.While( ada.And( ada.Variable("X"), ada.Variable("Y"), ), [ada.NullStatement()], )), multilinestr("""while X and Y loop null; end loop;"""), )
def test_case_str() -> None: assert_equal( str( ada.Case( ada.Variable("X"), [ (ada.Variable("Y"), ada.Number(1)), (ada.Variable("Z"), ada.Number(1)), (ada.Variable("others"), ada.Number(2)), ], )), multilinestr("""(case X is when Y | Z => 1, when others => 2)"""), )
def test_named_aggregate_rflx_expr() -> None: assert ada.NamedAggregate( ("X", ada.Number(1)), (ada.ValueRange(ada.Number(2), ada.Number(3)), ada.Variable("Y")), ).rflx_expr() == expr.NamedAggregate( ("X", expr.Number(1)), (expr.ValueRange(expr.Number(2), expr.Number(3)), expr.Variable("Y")), )
def test_call_statement_str() -> None: assert str(ada.CallStatement("A", [])) == "A;" assert str(ada.CallStatement( "A", [ada.Variable("B"), ada.Variable("C")])) == "A (B, C);" assert (str( ada.CallStatement("A", [], { ID("B"): ada.Number(1), ID("C"): ada.Number(2) })) == "A (B => 1, C => 2);") assert (str( ada.CallStatement( "A", [ada.Variable("B"), ada.Variable("C")], { ID("D"): ada.Number(1), ID("E"): ada.Number(2) }, )) == "A (B, C, D => 1, E => 2);")
def test_call_str() -> None: assert str(ada.Call("A", [])) == "A" assert str(ada.Call( "A", [ada.Variable("B"), ada.Variable("C")])) == "A (B, C)" assert (str( ada.Call("A", [], { ID("B"): ada.Number(1), ID("C"): ada.Number(2) })) == "A (B => 1, C => 2)") assert (str( ada.Call( "A", [ada.Variable("B"), ada.Variable("C")], { ID("D"): ada.Number(1), ID("E"): ada.Number(2) }, )) == "A (B, C, D => 1, E => 2)") assert str(-ada.Call("A", [])) == "(-A)"
def test_quantified_expression_str() -> None: assert (str( ada.ForAllOf("X", ada.Variable("Y"), ada.Variable("Z"))) == "(for all X of Y =>\n Z)") assert (str( ada.ForAllIn("X", ada.Variable("Y"), ada.Variable("Z"))) == "(for all X in Y =>\n Z)") assert (str( ada.ForSomeIn("X", ada.Variable("Y"), ada.Variable("Z"))) == "(for some X in Y =>\n Z)")
def test_bool_expr_str() -> None: assert_equal( str( ada.And(ada.Variable("A"), ada.Or(ada.Variable("B"), ada.Variable("C")), ada.Variable("D"))), multilinestr("""A and (B or C) and D"""), ) assert_equal( str( ada.AndThen( ada.Variable("A"), ada.OrElse(ada.Variable("B"), ada.Variable("C")), ada.Variable("D"), )), multilinestr("""A and then (B or else C) and then D"""), )
def test_if_str() -> None: assert_equal( str( ada.If( [ (ada.Variable("X"), ada.Number(1)), (ada.Variable("Y"), ada.Number(2)), ], ada.Number(3), )), "(if X then 1 elsif Y then 2 else 3)", ) assert_equal( str( ada.If( [ ( ada.Variable("Some_Complex_Condition"), ada.Variable("Some_Complex_Expression"), ), ( ada.Variable("Another_Complex_Condition"), ada.Variable("Another_Complex_Expression"), ), ], ada.Variable("Some_Complex_Expression"), )), multilinestr("""(if Some_Complex_Condition then Some_Complex_Expression elsif Another_Complex_Condition then Another_Complex_Expression else Some_Complex_Expression)"""), )
def test_qualified_expr() -> None: assert str(ada.QualifiedExpr("T", ada.Variable("A"))) == "T'(A)"
def test_not_in_str() -> None: assert str(ada.NotIn(ada.Variable("X"), ada.Variable("Y"))) == "X not in Y"
def test_exit_statement_str() -> None: assert str(ada.ExitStatement(ada.Variable("A"))) == "exit when A;"
def test_quantified_expression_rflx_expr( expression: Callable[[str, ada.Expr, ada.Expr], ada.Expr]) -> None: result = expression("X", ada.Variable("Y"), ada.Variable("Z")).rflx_expr() expected = getattr(expr, expression.__name__)("X", expr.Variable("Y"), expr.Variable("Z")) assert result == expected
def test_access_parameter() -> None: assert str(ada.AccessParameter("A", "B")) == "A : access B" assert str(ada.AccessParameter("A", "B", ada.Variable("C"))) == "A : access B := C" assert str(ada.AccessParameter("A", "B", constant=True)) == "A : access constant B"
def session_main( input_channels: dict[str, Sequence[tuple[int, ...]]] = None, output_channels: Sequence[str] = None, context: Sequence[ada.ContextItem] = None, subprograms: Sequence[ada.SubprogramBody] = None, session_package: StrID = "RFLX.Test.Session", ) -> Mapping[str, str]: input_channels = input_channels or {} output_channels = output_channels or [] context = context or [] subprograms = subprograms or [] session_package = ID(session_package) run_procedure_spec = ada.ProcedureSpecification("Run") run_procedure_decl = ada.SubprogramDeclaration(run_procedure_spec) run_procedure_body = ada.SubprogramBody( run_procedure_spec, [ ada.ObjectDeclaration(["Ctx"], "Session.Context"), ], [ ada.CallStatement(session_package * "Initialize", [ada.Variable("Ctx")]), ada.While( ada.Call(session_package * "Active", [ada.Variable("Ctx")]), [ ada.PragmaStatement( "Loop_Invariant", [ ada.Call(session_package * "Initialized", [ada.Variable("Ctx")]) ], ), *([ ada.ForIn( "C", ada.Range(session_package * "Channel"), [ ada.PragmaStatement( "Loop_Invariant", [ ada.Call( session_package * "Initialized", [ada.Variable("Ctx")], ) ], ), *([ ada.IfStatement([( ada.Call( session_package * "Has_Data", [ ada.Variable("Ctx"), ada.Variable("C"), ], ), [ ada.CallStatement( "Read", [ ada.Variable("Ctx"), ada.Variable("C"), ], ), ], )]) ] if output_channels else []), *([ ada.IfStatement([( ada.Call( session_package * "Needs_Data", [ ada.Variable("Ctx"), ada.Variable("C"), ], ), [ ada.CallStatement( "Write", [ ada.Variable("Ctx"), ada.Variable("C"), ], ), ], )]) ] if input_channels else []), ], ) ] if input_channels or output_channels else []), ada.CallStatement(session_package * "Run", [ada.Variable("Ctx")]), ], ), ada.PragmaStatement( "Warnings", [ada.Variable("Off"), ada.String("statement has no effect")], ), ada.PragmaStatement( "Warnings", [ ada.Variable("Off"), ada.String( '"Ctx" is set by "Finalize" but not used after the call' ), ], ), ada.CallStatement(session_package * "Finalize", [ada.Variable("Ctx")]), ada.PragmaStatement( "Warnings", [ada.Variable("On"), ada.String("statement has no effect")], ), ada.PragmaStatement( "Warnings", [ ada.Variable("On"), ada.String( '"Ctx" is set by "Finalize" but not used after the call' ), ], ), ], ) print_procedure = ada.SubprogramBody( ada.ProcedureSpecification( "Print", [ ada.Parameter(["Prefix"], "String"), ada.Parameter(["Chan"], session_package * "Channel"), ada.Parameter(["Buffer"], "RFLX" * const.TYPES_BYTES), ], ), [], [ ada.CallStatement( "Ada.Text_IO.Put", [ ada.Concatenation( ada.Variable("Prefix"), ada.String(" "), ada.Case( ada.Variable("Chan"), [( ada.Variable(session_package * f"C_{channel}"), ada.String(channel), ) for channel in sorted( {*input_channels.keys(), *output_channels})], ), ada.String(":"), ) ], ), ada.ForOf( "B", ada.Variable("Buffer"), [ ada.CallStatement("Ada.Text_IO.Put", [ada.Variable("B'Image")]), ], ), ada.CallStatement("Ada.Text_IO.New_Line"), ], aspects=[ ada.Precondition( ada.AndThen( ada.Equal(ada.First("Prefix"), ada.Number(1)), ada.LessEqual(ada.Length("Prefix"), ada.Number(1000)), )) ], ) read_procedure = ada.SubprogramBody( ada.ProcedureSpecification( "Read", [ ada.Parameter(["Ctx"], "Session.Context"), ada.Parameter(["Chan"], session_package * "Channel"), ], ), [ ada.UseTypeClause("RFLX" * const.TYPES_INDEX), ada.UseTypeClause("RFLX" * const.TYPES_LENGTH), ada.ObjectDeclaration( ["Buffer"], ada.Slice( ada.Variable("RFLX" * const.TYPES_BYTES), ada.First("RFLX" * const.TYPES_INDEX), ada.Add(ada.First("RFLX" * const.TYPES_INDEX), ada.Number(4095)), ), ada.NamedAggregate(("others", ada.Number(0))), ), ada.ObjectDeclaration( ["Size"], "RFLX" * const.TYPES_LENGTH, ada.Call( session_package * "Read_Buffer_Size", [ ada.Variable("Ctx"), ada.Variable("Chan"), ], ), constant=True, ), ], [ ada.IfStatement([ ( ada.Equal(ada.Variable("Size"), ada.Number(0)), [ ada.CallStatement( "Ada.Text_IO.Put_Line", [ ada.Concatenation( ada.String("Read "), ada.Image("Chan"), ada.String(": read buffer size is 0"), ) ], ), ada.ReturnStatement(), ], ), ]), ada.IfStatement([ ( ada.Less(ada.Length("Buffer"), ada.Variable("Size")), [ ada.CallStatement( "Ada.Text_IO.Put_Line", [ ada.Concatenation( ada.String("Read "), ada.Image("Chan"), ada.String(": read buffer size too small"), ) ], ), ada.ReturnStatement(), ], ), ], ), ada.CallStatement( session_package * "Read", [ ada.Variable("Ctx"), ada.Variable("Chan"), ada.Slice( ada.Variable("Buffer"), ada.First("Buffer"), ada.Add( ada.First("Buffer"), -ada.Number(2), ada.Call( "RFLX" * const.TYPES_INDEX, [ada.Add(ada.Variable("Size"), ada.Number(1))], ), ), ), ], ), ada.CallStatement( "Print", [ ada.String("Read"), ada.Variable("Chan"), ada.Slice( ada.Variable("Buffer"), ada.First("Buffer"), ada.Add( ada.First("Buffer"), -ada.Number(2), ada.Call( "RFLX" * const.TYPES_INDEX, [ada.Add(ada.Variable("Size"), ada.Number(1))], ), ), ), ], ), ], aspects=[ ada.Precondition( ada.AndThen( ada.Call(session_package * "Initialized", [ada.Variable("Ctx")]), ada.Call(session_package * "Has_Data", [ada.Variable("Ctx"), ada.Variable("Chan")]), ), ), ada.Postcondition( ada.Call(session_package * "Initialized", [ada.Variable("Ctx")])), ], ) write_procedure = ada.SubprogramBody( ada.ProcedureSpecification( "Write", [ ada.InOutParameter(["Ctx"], "Session.Context"), ada.Parameter(["Chan"], session_package * "Channel"), ], ), [ ada.UseTypeClause("RFLX" * const.TYPES_LENGTH), *([ada.UseTypeClause(session_package * "Channel")] if len(input_channels) > 1 else []), ada.ObjectDeclaration( ["None"], ada.Slice( ada.Variable("RFLX" * const.TYPES_BYTES), ada.Number(1), ada.Number(0), ), ada.NamedAggregate(("others", ada.Number(0))), constant=True, ), ada.ObjectDeclaration( ["Message"], "RFLX" * const.TYPES_BYTES, ada.If( [( ada.And( *([ ada.Equal( ada.Variable("Chan"), ada.Variable(session_package * f"C_{channel}"), ) ] if len(input_channels) > 1 else []), ada.Equal( ada.Call("Written_Messages", [ada.Variable("Chan")]), ada.Number(i), ), ), ada.Aggregate(*[ada.Number(b) for b in message]) if len(message) > 1 else ada.NamedAggregate(*[( ada.First("RFLX" * const.TYPES_INDEX), ada.Number(message[0]), )]), ) for channel, messages in input_channels.items() for i, message in enumerate(messages)], ada.Variable("None"), ), constant=True, ), ], [ ada.IfStatement([( ada.And( ada.Greater( ada.Length("Message"), ada.Number(0), ), ada.LessEqual( ada.Length("Message"), ada.Call( session_package * "Write_Buffer_Size", [ada.Variable("Ctx"), ada.Variable("Chan")], ), ), ), [ ada.CallStatement( "Print", [ ada.String("Write"), ada.Variable("Chan"), ada.Variable("Message"), ], ), ada.CallStatement( session_package * "Write", [ ada.Variable("Ctx"), ada.Variable("Chan"), ada.Variable("Message"), ], ), ada.IfStatement([( ada.Less( ada.Call("Written_Messages", [ada.Variable("Chan")]), ada.Last("Natural"), ), [ ada.Assignment( ada.Call("Written_Messages", [ada.Variable("Chan")]), ada.Add( ada.Call("Written_Messages", [ada.Variable("Chan")]), ada.Number(1), ), ) ], )]), ], )], ) ], aspects=[ ada.Precondition( ada.AndThen( ada.Call(session_package * "Initialized", [ada.Variable("Ctx")]), ada.Call(session_package * "Needs_Data", [ada.Variable("Ctx"), ada.Variable("Chan")]), ), ), ada.Postcondition( ada.Call(session_package * "Initialized", [ada.Variable("Ctx")])), ], ) lib_unit = ada.PackageUnit( [ *const.CONFIGURATION_PRAGMAS, *context, ], ada.PackageDeclaration( "Lib", [ run_procedure_decl, ], aspects=[ada.SparkMode()], ), [ *const.CONFIGURATION_PRAGMAS, *([ ada.WithClause("Ada.Text_IO"), ada.WithClause("RFLX" * const.TYPES), ] if input_channels or output_channels else []), ada.WithClause(session_package), ada.WithClause("Session"), ], ada.PackageBody( "Lib", [ *([print_procedure] if input_channels or output_channels else []), *([read_procedure] if output_channels else []), *([ ada.ArrayType("Number_Per_Channel", session_package * "Channel", "Natural"), ada.ObjectDeclaration( ["Written_Messages"], "Number_Per_Channel", ada.NamedAggregate(("others", ada.Number(0))), ), write_procedure, ] if input_channels else []), run_procedure_body, *[ ada.SubprogramBody(s.specification, s.declarations, s.statements) for s in subprograms ], ], aspects=[ada.SparkMode()], ), ) session_unit = ada.PackageUnit( [ *const.CONFIGURATION_PRAGMAS, ada.WithClause(session_package), ], ada.PackageDeclaration( "Session", [ ada.DerivedType("Context", session_package * "Context", []), ], aspects=[ ada.SparkMode(), ], ), [], ada.PackageBody("Session"), ) return { f"{session_unit.name}.ads": session_unit.ads, f"{lib_unit.name}.ads": lib_unit.ads, f"{lib_unit.name}.adb": lib_unit.adb, "main.adb": """with Lib; procedure Main with SPARK_Mode is begin Lib.Run; end Main; """, }
def test_and_then_str() -> None: assert str(ada.AndThen(ada.Variable("X"), ada.Variable("Y"))) == "X\nand then Y"
def test_expr_str() -> None: assert_equal( str( ada.If( [ ( ada.Or( ada.And(ada.Variable("X"), ada.Variable("Y")), ada.Variable("Z"), ), ada.Number(1), ), (ada.Variable("Y"), ada.Number(2)), ], ada.Div(ada.Mul(ada.Variable("A"), ada.Number(3)), ada.Number(8)), )), "(if (X and Y) or Z then 1 elsif Y then 2 else (A * 3) / 8)", ) assert_equal( str( ada.If( [ ( ada.Or( ada.And(ada.Variable("Variable_X"), ada.Variable("Variable_Y")), ada.Variable("Variable_Z"), ), ada.Number(1), ), (ada.Variable("Variable_Y"), ada.Number(2)), ], ada.Div(ada.Mul(ada.Variable("Variable_A"), ada.Number(3)), ada.Number(8)), )), multilinestr("""(if (Variable_X and Variable_Y) or Variable_Z then 1 elsif Variable_Y then 2 else (Variable_A * 3) / 8)"""), ) assert_equal( str( ada.And( ada.If( [ ( ada.Or( ada.And( ada.Variable("Variable_X"), ada.Variable("Variable_Y"), ), ada.Variable("Variable_Z"), ), ada.Number(1), ), (ada.Variable("Variable_Y"), ada.Number(2)), ], ada.Div( ada.Mul(ada.Variable("Variable_A"), ada.Number(3)), ada.Number(8), ), ), ada.Variable("A"), ada.Or(ada.Variable("B"), ada.Variable("C")), ada.Variable("D"), )), multilinestr("""(if (Variable_X and Variable_Y) or Variable_Z then 1 elsif Variable_Y then 2 else (Variable_A * 3) / 8) and A and (B or C) and D"""), ) assert_equal( str( ada.ForAllOf( "X", ada.Variable("Z"), ada.If( [ ( ada.Or( ada.And( ada.Variable("Variable_X"), ada.Variable("Variable_Y"), ), ada.Variable("Variable_Z"), ), ada.Number(1), ), (ada.Variable("Variable_Y"), ada.Number(2)), ], ada.Div( ada.Mul(ada.Variable("Variable_A"), ada.Number(3)), ada.Number(8), ), ), )), multilinestr("""(for all X of Z => (if (Variable_X and Variable_Y) or Variable_Z then 1 elsif Variable_Y then 2 else (Variable_A * 3) / 8))"""), ) assert str(ada.Equal(ada.String("S"), ada.Variable("X"))) == '"S" = X'
def test_or_else_str() -> None: assert str(ada.OrElse(ada.Variable("X"), ada.Variable("Y"))) == "X\nor else Y"
def test_if_expr_rflx_expr() -> None: assert ada.IfExpr([(ada.Variable("X"), ada.Variable("Y"))], ada.Variable("Z")).rflx_expr() == expr.IfExpr( [(expr.Variable("X"), expr.Variable("Y"))], expr.Variable("Z"))
def test_not_rflx_expr() -> None: assert ada.Not(ada.Variable("X")).rflx_expr() == expr.Not( expr.Variable("X"))
def test_named_aggregate_str() -> None: assert (str( ada.NamedAggregate( ("X", ada.Number(1)), (ada.ValueRange(ada.Number(2), ada.Number(3)), ada.Variable("Y")), )) == "(X => 1, 2 .. 3 => Y)")
def test_qualified_expr_rflx_expr() -> None: assert ada.QualifiedExpr( "X", ada.Variable("Y")).rflx_expr() == expr.QualifiedExpr( "X", expr.Variable("Y"))
def test_in_str() -> None: assert str(ada.In(ada.Variable("X"), ada.Variable("Y"))) == "X in Y"
def test_and_str() -> None: assert str(ada.And(ada.Variable("X"), ada.Variable("Y"))) == "X\nand Y"
def test_conversion_rflx_expr() -> None: assert ada.Conversion("X", ada.Variable("Y")).rflx_expr() == expr.Conversion( "X", expr.Variable("Y"))
def test_or_str() -> None: assert str(ada.Or(ada.Variable("X"), ada.Variable("Y"))) == "X\nor Y"
def test_value_range_rflx_expr() -> None: assert ada.ValueRange(ada.Variable("X"), ada.Variable("Y")).rflx_expr() == expr.ValueRange( expr.Variable("X"), expr.Variable("Y"))
def test_math_expr_ada_expr( expression: Callable[[ada.Expr, ada.Expr], ada.Expr]) -> None: result = expression(ada.Variable("X"), ada.Variable("Y")).rflx_expr() expected = getattr(expr, expression.__name__)(expr.Variable("X"), expr.Variable("Y")) assert result == expected
def test_conversion_str() -> None: assert str(ada.Conversion("A", ada.Variable("B"))) == "A (B)" assert str(ada.Not(ada.Conversion("A", ada.Variable("B")))) == "not A (B)"
TEMPLATE_DIR = ("rflx", "templates/") TYPES = TYPES_PACKAGE TYPES_BYTE = TYPES * "Byte" TYPES_BYTES = TYPES * "Bytes" TYPES_BYTES_PTR = TYPES * "Bytes_Ptr" TYPES_INDEX = TYPES * "Index" TYPES_LENGTH = TYPES * "Length" TYPES_BIT_INDEX = TYPES * "Bit_Index" TYPES_BIT_LENGTH = TYPES * "Bit_Length" TYPES_TO_INDEX = TYPES * "To_Index" TYPES_TO_LENGTH = TYPES * "To_Length" TYPES_TO_BIT_LENGTH = TYPES * "To_Bit_Length" TYPES_TO_FIRST_BIT_INDEX = TYPES * "To_First_Bit_Index" TYPES_TO_LAST_BIT_INDEX = TYPES * "To_Last_Bit_Index" TYPES_OFFSET = TYPES * "Offset" TYPES_U64 = TYPES * "U64" TYPES_BASE_INT = TYPES * "Base_Integer" TYPES_BYTE_ORDER = TYPES * "Byte_Order" TYPES_HIGH_ORDER_FIRST = TYPES * "High_Order_First" TYPES_LOW_ORDER_FIRST = TYPES * "Low_Order_First" UNREACHABLE = ada.Call(TYPES * "Unreachable") CONFIGURATION_PRAGMAS = [ ada.Pragma("Style_Checks", [ada.String("N3aAbcdefhiIklnOprStux")]), # https://github.com/Componolit/RecordFlux/issues/508 ada.Pragma("Warnings", [ada.Variable("Off"), ada.String("redundant conversion")]), ]
def test_slice_rflx_expr() -> None: assert ada.Slice(ada.Variable("X"), ada.Variable("Y"), ada.Variable("Z")).rflx_expr() == expr.Slice( expr.Variable("X"), expr.Variable("Y"), expr.Variable("Z"))