Example #1
0
    def parameter_value(parameter: model.Field, parameter_type: model.Type) -> expr.Expr:
        if isinstance(parameter_type, model.Enumeration):
            if embedded:
                return expr.Call("To_Base_Integer", [expr.Variable(parameter.name)])
            return expr.Call("To_Base_Integer", [expr.Variable("Ctx" * parameter.identifier)])
        if isinstance(parameter_type, model.Scalar):
            if embedded:
                return expr.Variable(parameter.name)
            return expr.Variable("Ctx" * parameter.identifier)

        assert False, f'unexpected type "{type(parameter_type).__name__}"'
Example #2
0
 def field_value(field: model.Field) -> expr.Expr:
     if public:
         return expr.Call(f"Get_{field.name}", [expr.Variable("Ctx")])
     return expr.Selected(
         expr.Indexed(
             expr.Variable(ID("Ctx") * "Cursors" if not embedded else "Cursors"),
             expr.Variable(field.affixed_name),
         ),
         "Value",
     )
Example #3
0
 def valid_predecessors_invariant() -> Expr:
     return AndThen(
         *[
             If(
                 [
                     (
                         Call(
                             "Structural_Valid",
                             [
                                 Indexed(
                                     Variable("Cursors"),
                                     Variable(f.affixed_name),
                                 )
                             ],
                         ),
                         Or(
                             *[
                                 expr.AndThen(
                                     expr.Call(
                                         "Structural_Valid"
                                         if l.source in composite_fields
                                         else "Valid",
                                         [
                                             expr.Indexed(
                                                 expr.Variable("Cursors"),
                                                 expr.Variable(l.source.affixed_name),
                                             )
                                         ],
                                     ),
                                     expr.Equal(
                                         expr.Selected(
                                             expr.Indexed(
                                                 expr.Variable("Cursors"),
                                                 expr.Variable(f.affixed_name),
                                             ),
                                             "Predecessor",
                                         ),
                                         expr.Variable(l.source.affixed_name),
                                     ),
                                     l.condition.substituted(
                                         substitution(message, embedded=True, prefix=prefix)
                                     ),
                                 )
                                 .simplified()
                                 .ada_expr()
                                 for l in message.incoming(f)
                             ]
                         ),
                     )
                 ]
             )
             for f in message.fields
             if f not in message.direct_successors(model.INITIAL)
         ]
     )
Example #4
0
    def field_value(field: model.Field, field_type: model.Type) -> expr.Expr:
        if isinstance(field_type, model.Enumeration):
            if public:
                return expr.Call(
                    "To_Base_Integer", [expr.Call(f"Get_{field.name}", [expr.Variable("Ctx")])]
                )
            return expr.Selected(
                expr.Indexed(cursors, expr.Variable(field.affixed_name)),
                "Value",
            )
        if isinstance(field_type, model.Scalar):
            if public:
                return expr.Call(f"Get_{field.name}", [expr.Variable("Ctx")])
            return expr.Selected(
                expr.Indexed(cursors, expr.Variable(field.affixed_name)),
                "Value",
            )
        if isinstance(field_type, model.Composite):
            return expr.Variable(field.name)

        assert False, f'unexpected type "{type(field_type).__name__}"'
Example #5
0
 def field_size(field: model.Field) -> expr.Expr:
     if public:
         return expr.Call(
             "Field_Size", [expr.Variable("Ctx"), expr.Variable(field.affixed_name)]
         )
     return expr.Add(
         expr.Sub(
             expr.Selected(expr.Indexed(cursors, expr.Variable(field.affixed_name)), "Last"),
             expr.Selected(expr.Indexed(cursors, expr.Variable(field.affixed_name)), "First"),
         ),
         expr.Number(1),
     )
Example #6
0
 def valid_message_condition(self,
                             message: Message,
                             structural: bool = False) -> Expr:
     return (expr.Or(*[
         expr.AndThen(
             expr.Call(
                 "Structural_Valid" if structural and isinstance(
                     message.field_types[l.source], Composite) else "Valid",
                 [
                     expr.Variable("Ctx"),
                     expr.Variable(l.source.affixed_name, immutable=True),
                 ],
             ),
             l.condition,
         ) for l in message.incoming(FINAL) if l.target == FINAL
     ]).substituted(common.substitution(
         message, self.prefix)).simplified().ada_expr())
Example #7
0
def test_substitution_relation_aggregate(
    relation: Callable[[expr.Expr, expr.Expr], expr.Relation], left: expr.Expr, right: expr.Expr
) -> None:
    equal_call = expr.Call(
        "Equal",
        [
            expr.Variable("Ctx"),
            expr.Variable("F_Value"),
            expr.Aggregate(
                expr.Val(expr.Variable("Types.Byte"), expr.Number(1)),
                expr.Val(expr.Variable("Types.Byte"), expr.Number(2)),
            ),
        ],
    )

    assert_equal(
        relation(left, right).substituted(common.substitution(TLV_MESSAGE)),
        equal_call if relation == expr.Equal else expr.Not(equal_call),
    )
Example #8
0
def test_consistency_specification_parsing_generation(tmp_path: Path) -> None:
    tag = Enumeration(
        "Test::Tag",
        [("Msg_Data", expr.Number(1)), ("Msg_Error", expr.Number(3))],
        expr.Number(8),
        always_valid=False,
    )
    length = ModularInteger("Test::Length",
                            expr.Pow(expr.Number(2), expr.Number(16)))
    message = Message(
        "Test::Message",
        [
            Link(INITIAL, Field("Tag")),
            Link(
                Field("Tag"),
                Field("Length"),
                expr.Equal(expr.Variable("Tag"), expr.Variable("Msg_Data")),
            ),
            Link(Field("Tag"), FINAL,
                 expr.Equal(expr.Variable("Tag"), expr.Variable("Msg_Error"))),
            Link(
                Field("Length"),
                Field("Value"),
                size=expr.Mul(expr.Variable("Length"), expr.Number(8)),
            ),
            Link(Field("Value"), FINAL),
        ],
        {
            Field("Tag"): tag,
            Field("Length"): length,
            Field("Value"): OPAQUE
        },
        skip_proof=True,
    )
    session = Session(
        "Test::Session",
        "A",
        "C",
        [
            State(
                "A",
                declarations=[],
                actions=[stmt.Read("X", expr.Variable("M"))],
                transitions=[
                    Transition("B"),
                ],
            ),
            State(
                "B",
                declarations=[
                    decl.VariableDeclaration("Z", BOOLEAN.identifier,
                                             expr.Variable("Y")),
                ],
                actions=[],
                transitions=[
                    Transition(
                        "C",
                        condition=expr.And(
                            expr.Equal(expr.Variable("Z"), expr.TRUE),
                            expr.Equal(expr.Call("G", [expr.Variable("F")]),
                                       expr.TRUE),
                        ),
                        description="rfc1149.txt+45:4-47:8",
                    ),
                    Transition("A"),
                ],
                description="rfc1149.txt+51:4-52:9",
            ),
            State("C"),
        ],
        [
            decl.VariableDeclaration("M", "Test::Message"),
            decl.VariableDeclaration("Y", BOOLEAN.identifier, expr.FALSE),
        ],
        [
            decl.ChannelDeclaration("X", readable=True, writable=True),
            decl.TypeDeclaration(Private("Test::T")),
            decl.FunctionDeclaration("F", [], "Test::T"),
            decl.FunctionDeclaration("G", [decl.Argument("P", "Test::T")],
                                     BOOLEAN.identifier),
        ],
        [BOOLEAN, OPAQUE, tag, length, message],
    )
    model = Model(types=[BOOLEAN, OPAQUE, tag, length, message],
                  sessions=[session])
    model.write_specification_files(tmp_path)
    p = parser.Parser()
    p.parse(tmp_path / "test.rflx")
    parsed_model = p.create_model()
    assert parsed_model.types == model.types
    assert parsed_model.sessions == model.sessions
    assert parsed_model == model
Example #9
0
        ("X and Y", expr.And(expr.Variable("X"), expr.Variable("Y"))),
        ("X or Y", expr.Or(expr.Variable("X"), expr.Variable("Y"))),
        ("((X or Y))", expr.Or(expr.Variable("X"), expr.Variable("Y"))),
    ],
)
def test_expression_boolean(string: str, expected: expr.Expr) -> None:
    actual = parse_bool_expression(string, extended=False)
    assert actual == expected
    assert actual.location


@pytest.mark.parametrize(
    "string,expected",
    [
        ("X + Y", expr.Add(expr.Variable("X"), expr.Variable("Y"))),
        ("X + Y (Z)", expr.Add(expr.Variable("X"), expr.Call("Y", [expr.Variable("Z")]))),
    ],
)
def test_mathematical_expression(string: str, expected: expr.Expr) -> None:
    actual = parse_math_expression(string, extended=True)
    assert actual == expected
    assert actual.location


@pytest.mark.parametrize(
    "string,error",
    [
        ("42 > X", "Invalid math BinOp OpGt.*"),
        ("X and Y", "Invalid math BinOp OpAnd.*"),
    ],
)
Example #10
0
            ),
        ],
    )

    assert_equal(
        relation(left, right).substituted(common.substitution(TLV_MESSAGE)),
        equal_call if relation == expr.Equal else expr.Not(equal_call),
    )


@pytest.mark.parametrize(
    "expressions,expected",
    [
        (
            (expr.Variable("Length"), expr.Number(1)),
            (expr.Call("Get_Length", [expr.Variable("Ctx")]), expr.Number(1)),
        ),
        (
            (expr.Number(1), expr.Variable("Length")),
            (expr.Number(1), expr.Call("Get_Length", [expr.Variable("Ctx")])),
        ),
        ((expr.Number(1), expr.Variable("Unknown")), (expr.Number(1), expr.Variable("Unknown"))),
    ],
)
@pytest.mark.parametrize(
    "relation",
    [expr.Less, expr.LessEqual, expr.Equal, expr.GreaterEqual, expr.Greater, expr.NotEqual],
)
def test_substitution_relation_scalar(
    relation: Callable[[expr.Expr, expr.Expr], expr.Relation],
    expressions: Tuple[expr.Expr, expr.Expr],
Example #11
0
    def func(expression: expr.Expr) -> expr.Expr:  # pylint: disable = too-many-branches
        def byte_aggregate(aggregate: expr.Aggregate) -> expr.Aggregate:
            return expr.Aggregate(*[expr.Val(const.TYPES_BYTE, e) for e in aggregate.elements])

        if isinstance(expression, expr.Name) and expression in facts:
            return facts[expression]

        if isinstance(expression, expr.String):
            return expr.Aggregate(*expression.elements)

        if isinstance(expression, (expr.Equal, expr.NotEqual)):
            field = None
            aggregate = None
            if isinstance(expression.left, expr.Variable) and isinstance(
                expression.right, expr.Aggregate
            ):
                field = model.Field(expression.left.name)
                aggregate = byte_aggregate(expression.right)
            elif isinstance(expression.left, expr.Aggregate) and isinstance(
                expression.right, expr.Variable
            ):
                field = model.Field(expression.right.name)
                aggregate = byte_aggregate(expression.left)
            if field and field in message.fields and len(field.identifier.parts) == 1 and aggregate:
                if embedded:
                    return expression.__class__(
                        expr.Indexed(
                            expr.Variable(ID("Buffer") * "all"),
                            expr.ValueRange(
                                expr.Call(
                                    const.TYPES_TO_INDEX,
                                    [
                                        expr.Selected(
                                            expr.Indexed(
                                                expr.Variable("Cursors"),
                                                expr.Variable(field.affixed_name),
                                            ),
                                            "First",
                                        )
                                    ],
                                ),
                                expr.Call(
                                    const.TYPES_TO_INDEX,
                                    [
                                        expr.Selected(
                                            expr.Indexed(
                                                expr.Variable("Cursors"),
                                                expr.Variable(field.affixed_name),
                                            ),
                                            "Last",
                                        )
                                    ],
                                ),
                            ),
                        ),
                        aggregate,
                    )
                equal_call = expr.Call(
                    "Equal",
                    [expr.Variable("Ctx"), expr.Variable(field.affixed_name), aggregate],
                )
                return equal_call if isinstance(expression, expr.Equal) else expr.Not(equal_call)

            boolean_literal = None
            other = None
            if (
                isinstance(expression.left, expr.Literal)
                and expression.left.identifier in model.BOOLEAN.literals
            ):
                boolean_literal = expression.left
                other = expression.right
            if (
                isinstance(expression.right, expr.Literal)
                and expression.right.identifier in model.BOOLEAN.literals
            ):
                boolean_literal = expression.right
                other = expression.left
            if boolean_literal and other:
                return expression.__class__(
                    other, type_conversion(expr.Call("To_Base_Integer", [boolean_literal]))
                )

        def field_value(field: model.Field) -> expr.Expr:
            if public:
                return expr.Call(f"Get_{field.name}", [expr.Variable("Ctx")])
            return expr.Selected(
                expr.Indexed(
                    expr.Variable(ID("Ctx") * "Cursors" if not embedded else "Cursors"),
                    expr.Variable(field.affixed_name),
                ),
                "Value",
            )

        if isinstance(expression, expr.Relation):
            if (
                isinstance(expression.left, expr.Variable)
                and model.Field(expression.left.name) in message.fields
                and isinstance(expression.right, expr.Number)
            ):
                return expression.__class__(
                    field_value(model.Field(expression.left.name)), expression.right
                )
            if (
                isinstance(expression.right, expr.Variable)
                and model.Field(expression.right.name) in message.fields
                and isinstance(expression.left, expr.Number)
            ):
                return expression.__class__(
                    expression.left, field_value(model.Field(expression.right.name))
                )

        return expression
Example #12
0
 def type_conversion(expression: expr.Expr) -> expr.Expr:
     return expr.Call(target_type, [expression]) if target_type else expression
Example #13
0
 def field_last(field: model.Field) -> expr.Expr:
     if public:
         return expr.Call(
             "Field_Last", [expr.Variable("Ctx"), expr.Variable(field.affixed_name)]
         )
     return expr.Selected(expr.Indexed(cursors, expr.Variable(field.affixed_name)), "Last")
Example #14
0
def substitution_facts(
    message: model.Message,
    prefix: str,
    embedded: bool = False,
    public: bool = False,
    target_type: Optional[ID] = const.TYPES_BASE_INT,
) -> Mapping[expr.Name, expr.Expr]:
    def prefixed(name: str) -> expr.Expr:
        return expr.Variable(ID("Ctx") * name) if not embedded else expr.Variable(name)

    first = prefixed("First")
    last = expr.Call("Written_Last", [expr.Variable("Ctx")]) if public else prefixed("Written_Last")
    cursors = prefixed("Cursors")

    def field_first(field: model.Field) -> expr.Expr:
        if public:
            return expr.Call(
                "Field_First", [expr.Variable("Ctx"), expr.Variable(field.affixed_name)]
            )
        return expr.Selected(expr.Indexed(cursors, expr.Variable(field.affixed_name)), "First")

    def field_last(field: model.Field) -> expr.Expr:
        if public:
            return expr.Call(
                "Field_Last", [expr.Variable("Ctx"), expr.Variable(field.affixed_name)]
            )
        return expr.Selected(expr.Indexed(cursors, expr.Variable(field.affixed_name)), "Last")

    def field_size(field: model.Field) -> expr.Expr:
        if public:
            return expr.Call(
                "Field_Size", [expr.Variable("Ctx"), expr.Variable(field.affixed_name)]
            )
        return expr.Add(
            expr.Sub(
                expr.Selected(expr.Indexed(cursors, expr.Variable(field.affixed_name)), "Last"),
                expr.Selected(expr.Indexed(cursors, expr.Variable(field.affixed_name)), "First"),
            ),
            expr.Number(1),
        )

    def parameter_value(parameter: model.Field, parameter_type: model.Type) -> expr.Expr:
        if isinstance(parameter_type, model.Enumeration):
            if embedded:
                return expr.Call("To_Base_Integer", [expr.Variable(parameter.name)])
            return expr.Call("To_Base_Integer", [expr.Variable("Ctx" * parameter.identifier)])
        if isinstance(parameter_type, model.Scalar):
            if embedded:
                return expr.Variable(parameter.name)
            return expr.Variable("Ctx" * parameter.identifier)

        assert False, f'unexpected type "{type(parameter_type).__name__}"'

    def field_value(field: model.Field, field_type: model.Type) -> expr.Expr:
        if isinstance(field_type, model.Enumeration):
            if public:
                return expr.Call(
                    "To_Base_Integer", [expr.Call(f"Get_{field.name}", [expr.Variable("Ctx")])]
                )
            return expr.Selected(
                expr.Indexed(cursors, expr.Variable(field.affixed_name)),
                "Value",
            )
        if isinstance(field_type, model.Scalar):
            if public:
                return expr.Call(f"Get_{field.name}", [expr.Variable("Ctx")])
            return expr.Selected(
                expr.Indexed(cursors, expr.Variable(field.affixed_name)),
                "Value",
            )
        if isinstance(field_type, model.Composite):
            return expr.Variable(field.name)

        assert False, f'unexpected type "{type(field_type).__name__}"'

    def type_conversion(expression: expr.Expr) -> expr.Expr:
        return expr.Call(target_type, [expression]) if target_type else expression

    return {
        **{expr.First("Message"): type_conversion(first)},
        **{expr.Last("Message"): type_conversion(last)},
        **{expr.Size("Message"): type_conversion(expr.Add(last, -first, expr.Number(1)))},
        **{expr.First(f.name): type_conversion(field_first(f)) for f in message.fields},
        **{expr.Last(f.name): type_conversion(field_last(f)) for f in message.fields},
        **{expr.Size(f.name): type_conversion(field_size(f)) for f in message.fields},
        **{
            expr.Variable(p.identifier): type_conversion(parameter_value(p, t))
            for p, t in message.parameter_types.items()
        },
        **{
            expr.Variable(f.name): type_conversion(field_value(f, t))
            for f, t in message.field_types.items()
        },
        **{
            expr.Literal(l): type_conversion(expr.Call("To_Base_Integer", [expr.Variable(l)]))
            for t in message.types.values()
            if isinstance(t, model.Enumeration) and t != model.BOOLEAN
            for l in t.literals.keys()
        },
        **{
            expr.Literal(t.package * l): type_conversion(
                expr.Call("To_Base_Integer", [expr.Variable(prefix * t.package * l)])
            )
            for t in message.types.values()
            if isinstance(t, model.Enumeration) and t != model.BOOLEAN
            for l in t.literals.keys()
        },
        # https://github.com/Componolit/RecordFlux/issues/276
        **{expr.ValidChecksum(f): expr.TRUE for f in message.checksums},
    }
Example #15
0
def test_call_rflx_expr() -> None:
    assert ada.Call(
        "X", [ada.Variable("Y"), ada.Variable("Z")]).rflx_expr() == expr.Call(
            "X", [expr.Variable("Y"), expr.Variable("Z")])