예제 #1
0
def public_context_predicate() -> Expr:
    return And(
        GreaterEqual(Call(const.TYPES_TO_INDEX, [Variable("First")]), Variable("Buffer_First")),
        LessEqual(Call(const.TYPES_TO_INDEX, [Variable("Last")]), Variable("Buffer_Last")),
        Less(Variable("Buffer_Last"), Last(const.TYPES_INDEX)),
        LessEqual(Variable("First"), Add(Variable("Last"), Number(1))),
        Less(Variable("Last"), Last(const.TYPES_BIT_INDEX)),
        Equal(Rem(Variable("First"), Size(const.TYPES_BYTE)), Number(1)),
        Equal(Rem(Variable("Last"), Size(const.TYPES_BYTE)), Number(0)),
    )
예제 #2
0
 def _create_ptr_subtypes(self,
                          slots: Sequence[NumberedSlotInfo]) -> UnitPart:
     unit = UnitPart(specification=[
         Subtype(
             self._ptr_type(size),
             const.TYPES_BYTES_PTR,
             aspects=[
                 DynamicPredicate(
                     OrElse(
                         Equal(Variable(self._ptr_type(size)),
                               Variable("null")),
                         AndThen(
                             Equal(First(self._ptr_type(size)),
                                   First(const.TYPES_INDEX)),
                             Equal(
                                 Last(self._ptr_type(size)),
                                 Add(First(const.TYPES_INDEX),
                                     Number(size - 1)),
                             ),
                         ),
                     ))
             ],
         ) for size in sorted({slot.size
                               for slot in slots})
     ])
     self._declaration_context.append(
         WithClause(self._prefix * const.TYPES_PACKAGE))
     self._declaration_context.append(
         UseTypeClause(self._prefix * const.TYPES_INDEX))
     self._declaration_context.append(
         UseTypeClause(self._prefix * const.TYPES_BYTES_PTR))
     return unit
예제 #3
0
    def create_present_function() -> UnitPart:
        specification = FunctionSpecification(
            "Present", "Boolean",
            [Parameter(["Ctx"], "Context"),
             Parameter(["Fld"], "Field")])

        return UnitPart(
            [SubprogramDeclaration(specification)],
            private=[
                ExpressionFunctionDeclaration(
                    specification,
                    AndThen(
                        Call("Structural_Valid", [
                            Indexed(Variable("Ctx.Cursors"), Variable("Fld"))
                        ]),
                        Less(
                            Selected(
                                Indexed(Variable("Ctx.Cursors"),
                                        Variable("Fld")), "First"),
                            Add(
                                Selected(
                                    Indexed(Variable("Ctx.Cursors"),
                                            Variable("Fld")), "Last"),
                                Number(1),
                            ),
                        ),
                    ),
                )
            ],
        )
예제 #4
0
def field_condition_call(
    prefix: str,
    message: model.Message,
    field: model.Field,
    value: Expr = None,
    aggregate: Expr = None,
    size: Expr = None,
) -> Expr:
    package = prefix * message.identifier
    if value is None:
        value = Number(0)
    if aggregate is None:
        aggregate = EMPTY_ARRAY
    if size is None:
        size = Call(
            package * "Field_Size",
            [Variable("Ctx"), Variable(package * field.affixed_name)],
        )
    return Call(
        package * "Field_Condition",
        [
            Variable("Ctx"),
            Variable(package * field.affixed_name),
            *([value] if has_value_dependent_condition(message) else []),
            *([aggregate] if has_aggregate_dependent_condition(message) else []),
            *([size] if has_size_dependent_condition(message, field) else []),
        ],
    )
예제 #5
0
 def _create_memory(slots: Sequence[NumberedSlotInfo]) -> UnitPart:
     return UnitPart([
         RecordType(
             "Memory",
             [
                 Component(
                     f"Slot_{slot.slot_id}",
                     Slice(
                         Variable(const.TYPES_BYTES),
                         First(const.TYPES_INDEX),
                         Add(First(const.TYPES_INDEX),
                             Number(slot.size - 1)),
                     ),
                     NamedAggregate(("others", Number(0))),
                     aliased=True,
                 ) for slot in slots
             ],
         )
     ])
예제 #6
0
def byte_aligned_field(prefix: str, message: model.Message, field: model.Field) -> Expr:
    return Equal(
        Rem(
            Call(
                prefix * message.identifier * "Field_First",
                [
                    Variable("Ctx"),
                    Variable(prefix * message.identifier * field.affixed_name),
                ],
            ),
            Size(const.TYPES_BYTE),
        ),
        Number(1),
    )
예제 #7
0
 def cursors_invariant() -> Expr:
     return ForAllIn(
         "F",
         Variable("Field"),
         If(
             [
                 (
                     Call(
                         "Structural_Valid",
                         [Indexed(Variable("Cursors"), Variable("F"))],
                     ),
                     And(
                         GreaterEqual(
                             Selected(Indexed(Variable("Cursors"), Variable("F")), "First"),
                             Variable("First"),
                         ),
                         LessEqual(
                             Selected(Indexed(Variable("Cursors"), Variable("F")), "Last"),
                             Variable("Verified_Last"),
                         ),
                         LessEqual(
                             Selected(Indexed(Variable("Cursors"), Variable("F")), "First"),
                             Add(
                                 Selected(
                                     Indexed(Variable("Cursors"), Variable("F")),
                                     "Last",
                                 ),
                                 Number(1),
                             ),
                         ),
                         Call(
                             "Valid_Value",
                             [
                                 Variable("F"),
                                 Selected(
                                     Indexed(Variable("Cursors"), Variable("F")),
                                     "Value",
                                 ),
                             ],
                         ),
                     ),
                 )
             ]
         ),
     )
예제 #8
0
    def create_verify_procedure(
        self,
        message: Message,
        scalar_fields: Mapping[Field, Scalar],
        composite_fields: Sequence[Field],
    ) -> UnitPart:
        specification = ProcedureSpecification(
            "Verify",
            [InOutParameter(["Ctx"], "Context"),
             Parameter(["Fld"], "Field")])

        valid_field_condition = AndThen(
            Call(
                "Valid_Value",
                [Variable("Fld"), Variable("Value")],
            ),
            Call(
                "Field_Condition",
                [
                    Variable("Ctx"),
                    Variable("Fld"),
                    *([Variable("Value")] if
                      common.has_value_dependent_condition(message) else []),
                    *([
                        Slice(
                            Variable("Ctx.Buffer.all"),
                            Call(
                                const.TYPES_TO_INDEX,
                                [
                                    Call("Field_First",
                                         [Variable("Ctx"),
                                          Variable("Fld")])
                                ],
                            ),
                            Call(
                                const.TYPES_TO_INDEX,
                                [
                                    Call("Field_Last",
                                         [Variable("Ctx"),
                                          Variable("Fld")])
                                ],
                            ),
                        )
                    ] if common.has_aggregate_dependent_condition(message) else
                      []),
                    *([Call("Field_Size",
                            [Variable("Ctx"), Variable("Fld")])]
                      if common.has_size_dependent_condition(message) else []),
                ],
            ),
        )

        last = Mul(
            Div(
                Add(
                    Call("Field_Last",
                         [Variable("Ctx"), Variable("Fld")]),
                    Size(const.TYPES_BYTE),
                    -Number(1),
                ),
                Size(const.TYPES_BYTE),
            ),
            Size(const.TYPES_BYTE),
        )
        set_cursors_statements = [
            *([
                PragmaStatement(
                    "Assert",
                    [
                        If([(
                            Or(*[
                                Equal(Variable("Fld"), Variable(
                                    f.affixed_name))
                                for f in message.direct_predecessors(FINAL)
                            ]),
                            Equal(
                                Mod(
                                    Call("Field_Last",
                                         [Variable("Ctx"),
                                          Variable("Fld")]),
                                    Size(const.TYPES_BYTE),
                                ),
                                Number(0),
                            ),
                        )])
                    ],
                )
            ] if len(message.fields) > 1 else []),
            # Improve provability of context predicate
            PragmaStatement(
                "Assert",
                [Equal(Mod(last, Size(const.TYPES_BYTE)), Number(0))]),
            Assignment(Variable("Ctx.Verified_Last"), last),
            PragmaStatement(
                "Assert",
                [
                    LessEqual(
                        Call("Field_Last", [Variable("Ctx"),
                                            Variable("Fld")]),
                        Variable("Ctx.Verified_Last"),
                    )
                ],
            ),
            IfStatement(
                [(
                    Call("Composite_Field", [Variable("Fld")]),
                    [set_context_cursor_composite_field("Fld")],
                )],
                [set_context_cursor_scalar()],
            ) if scalar_fields and composite_fields else
            set_context_cursor_scalar()
            if scalar_fields and not composite_fields else
            set_context_cursor_composite_field("Fld"),
            *([
                # https://github.com/Componolit/RecordFlux/issues/664
                # The provability of the context predicate is increased by splitting the
                # assignment into multiple statements.
                Assignment(
                    Indexed(
                        Variable("Ctx.Cursors"),
                        Call(
                            "Successor",
                            [Variable("Ctx"), Variable("Fld")],
                        ),
                    ),
                    NamedAggregate(
                        ("State", Variable("S_Invalid")),
                        ("Predecessor", Variable("Fld")),
                    ),
                )
            ] if len(message.fields) > 1 else []),
        ]

        return UnitPart(
            [
                SubprogramDeclaration(
                    specification,
                    [
                        Precondition(
                            Call(
                                self.prefix * message.identifier *
                                "Has_Buffer",
                                [Variable("Ctx")],
                            )),
                        Postcondition(
                            And(
                                Call("Has_Buffer", [Variable("Ctx")]),
                                *common.context_invariant(message),
                            )),
                    ],
                )
            ],
            [
                SubprogramBody(
                    specification,
                    [ObjectDeclaration(["Value"], const.TYPES_BASE_INT)],
                    [
                        IfStatement([(
                            AndThen(
                                Call(
                                    "Invalid",
                                    [
                                        Indexed(Variable("Ctx.Cursors"),
                                                Variable("Fld"))
                                    ],
                                ),
                                Call("Valid_Predecessor",
                                     [Variable("Ctx"),
                                      Variable("Fld")]),
                                Call("Path_Condition",
                                     [Variable("Ctx"),
                                      Variable("Fld")]),
                            ),
                            [
                                IfStatement(
                                    [(
                                        Call(
                                            "Sufficient_Buffer_Length",
                                            [Variable("Ctx"),
                                             Variable("Fld")],
                                        ),
                                        [
                                            Assignment(
                                                "Value",
                                                If(
                                                    [(
                                                        Call(
                                                            "Composite_Field",
                                                            [
                                                                Variable(
                                                                    "Fld"),
                                                            ],
                                                        ),
                                                        Number(0),
                                                    )],
                                                    Call(
                                                        "Get",
                                                        [
                                                            Variable("Ctx"),
                                                            Variable("Fld"),
                                                        ],
                                                    ),
                                                ) if scalar_fields
                                                and composite_fields else Call(
                                                    "Get",
                                                    [
                                                        Variable("Ctx"),
                                                        Variable("Fld"),
                                                    ],
                                                ) if scalar_fields else
                                                Number(0),
                                            ),
                                            IfStatement(
                                                [(
                                                    valid_field_condition,
                                                    set_cursors_statements,
                                                )],
                                                [
                                                    Assignment(
                                                        Indexed(
                                                            Variable(
                                                                "Ctx.Cursors"),
                                                            Variable("Fld"),
                                                        ),
                                                        NamedAggregate(
                                                            (
                                                                "State",
                                                                Variable(
                                                                    "S_Invalid"
                                                                ),
                                                            ),
                                                            (
                                                                "Predecessor",
                                                                Variable(
                                                                    FINAL.
                                                                    affixed_name,
                                                                ),
                                                            ),
                                                        ),
                                                    )
                                                ],
                                            ),
                                        ],
                                    )],
                                    [
                                        Assignment(
                                            Indexed(Variable("Ctx.Cursors"),
                                                    Variable("Fld")),
                                            NamedAggregate(
                                                ("State",
                                                 Variable("S_Incomplete")),
                                                (
                                                    "Predecessor",
                                                    Variable(
                                                        FINAL.affixed_name),
                                                ),
                                            ),
                                        )
                                    ],
                                )
                            ],
                        )], )
                    ],
                )
            ],
        )
예제 #9
0
def initialize_field_statements(
    field: model.Field, reset_written_last: bool = False
) -> Sequence[Statement]:
    return [
        CallStatement(
            "Reset_Dependent_Fields",
            [Variable("Ctx"), Variable(field.affixed_name)],
        ),
        # https://github.com/Componolit/RecordFlux/issues/868
        PragmaStatement(
            "Warnings",
            [
                Variable("Off"),
                String("attribute Update is an obsolescent feature"),
            ],
        ),
        Assignment(
            "Ctx",
            Update(
                "Ctx",
                ("Verified_Last", Variable("Last")),
                (
                    "Written_Last",
                    Variable("Last")
                    if reset_written_last
                    else Max(
                        const.TYPES_BIT_LENGTH,
                        Variable("Ctx.Written_Last"),
                        Variable("Last"),
                    ),
                ),
            ),
        ),
        PragmaStatement(
            "Warnings",
            [
                Variable("On"),
                String("attribute Update is an obsolescent feature"),
            ],
        ),
        Assignment(
            Indexed(Variable("Ctx.Cursors"), Variable(field.affixed_name)),
            NamedAggregate(
                ("State", Variable("S_Structural_Valid")),
                ("First", Variable("First")),
                ("Last", Variable("Last")),
                ("Value", Number(0)),
                (
                    "Predecessor",
                    Selected(
                        Indexed(
                            Variable("Ctx.Cursors"),
                            Variable(field.affixed_name),
                        ),
                        "Predecessor",
                    ),
                ),
            ),
        ),
        Assignment(
            Indexed(
                Variable("Ctx.Cursors"),
                Call(
                    "Successor",
                    [Variable("Ctx"), Variable(field.affixed_name)],
                ),
            ),
            NamedAggregate(
                ("State", Variable("S_Invalid")),
                ("Predecessor", Variable(field.affixed_name)),
            ),
        ),
    ]
예제 #10
0
def context_predicate(
    message: model.Message, composite_fields: Sequence[model.Field], prefix: str
) -> Expr:
    def cursors_invariant() -> Expr:
        return ForAllIn(
            "F",
            Variable("Field"),
            If(
                [
                    (
                        Call(
                            "Structural_Valid",
                            [Indexed(Variable("Cursors"), Variable("F"))],
                        ),
                        And(
                            GreaterEqual(
                                Selected(Indexed(Variable("Cursors"), Variable("F")), "First"),
                                Variable("First"),
                            ),
                            LessEqual(
                                Selected(Indexed(Variable("Cursors"), Variable("F")), "Last"),
                                Variable("Verified_Last"),
                            ),
                            LessEqual(
                                Selected(Indexed(Variable("Cursors"), Variable("F")), "First"),
                                Add(
                                    Selected(
                                        Indexed(Variable("Cursors"), Variable("F")),
                                        "Last",
                                    ),
                                    Number(1),
                                ),
                            ),
                            Call(
                                "Valid_Value",
                                [
                                    Variable("F"),
                                    Selected(
                                        Indexed(Variable("Cursors"), Variable("F")),
                                        "Value",
                                    ),
                                ],
                            ),
                        ),
                    )
                ]
            ),
        )

    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)
            ]
        )

    def invalid_successors_invariant() -> Expr:
        return AndThen(
            *[
                If(
                    [
                        (
                            AndThen(
                                *[
                                    Call(
                                        "Invalid",
                                        [
                                            Indexed(
                                                Variable("Cursors"),
                                                Variable(p.affixed_name),
                                            )
                                        ],
                                    )
                                    for p in message.direct_predecessors(f)
                                ]
                            ),
                            Call(
                                "Invalid",
                                [
                                    Indexed(
                                        Variable("Cursors"),
                                        Variable(f.affixed_name),
                                    )
                                ],
                            ),
                        )
                    ]
                )
                for f in message.fields
                if f not in message.direct_successors(model.INITIAL)
            ]
        )

    return AndThen(
        If(
            [
                (
                    NotEqual(Variable("Buffer"), Variable("null")),
                    And(
                        Equal(First("Buffer"), Variable("Buffer_First")),
                        Equal(Last("Buffer"), Variable("Buffer_Last")),
                    ),
                )
            ]
        ),
        public_context_predicate(),
        LessEqual(Sub(Variable("First"), Number(1)), Variable("Verified_Last")),
        LessEqual(Sub(Variable("First"), Number(1)), Variable("Written_Last")),
        LessEqual(Variable("Verified_Last"), Variable("Written_Last")),
        LessEqual(Variable("Written_Last"), Variable("Last")),
        Equal(Rem(Variable("First"), Size(const.TYPES_BYTE)), Number(1)),
        Equal(Rem(Variable("Last"), Size(const.TYPES_BYTE)), Number(0)),
        Equal(Rem(Variable("Verified_Last"), Size(const.TYPES_BYTE)), Number(0)),
        Equal(Rem(Variable("Written_Last"), Size(const.TYPES_BYTE)), Number(0)),
        cursors_invariant(),
        valid_predecessors_invariant(),
        invalid_successors_invariant(),
        message_structure_invariant(message, prefix, embedded=True),
    )
예제 #11
0
def message_structure_invariant(
    message: model.Message, prefix: str, link: model.Link = None, embedded: bool = False
) -> Expr:
    def prefixed(name: str) -> expr.Expr:
        return expr.Selected(expr.Variable("Ctx"), name) if not embedded else expr.Variable(name)

    if not link:
        return message_structure_invariant(
            message, prefix, message.outgoing(model.INITIAL)[0], embedded
        )

    source = link.source
    target = link.target

    if target == model.FINAL:
        return TRUE

    field_type = message.types[target]
    condition = link.condition.substituted(substitution(message, prefix, embedded)).simplified()
    size = (
        field_type.size
        if isinstance(field_type, model.Scalar)
        else link.size.substituted(
            substitution(message, prefix, embedded, target_type=const.TYPES_BIT_LENGTH)
        ).simplified()
    )
    first = (
        prefixed("First")
        if source == model.INITIAL
        else link.first.substituted(
            substitution(message, prefix, embedded, target_type=const.TYPES_BIT_INDEX)
        )
        .substituted(
            mapping={
                expr.UNDEFINED: expr.Add(
                    expr.Selected(
                        expr.Indexed(prefixed("Cursors"), expr.Variable(source.affixed_name)),
                        "Last",
                    ),
                    expr.Number(1),
                )
            }
        )
        .simplified()
    )
    invariant = [
        message_structure_invariant(message, prefix, l, embedded) for l in message.outgoing(target)
    ]

    return If(
        [
            (
                AndThen(
                    Call(
                        "Structural_Valid",
                        [Indexed(prefixed("Cursors").ada_expr(), Variable(target.affixed_name))],
                    ),
                    *([condition.ada_expr()] if condition != expr.TRUE else []),
                ),
                AndThen(
                    Equal(
                        Add(
                            Sub(
                                Selected(
                                    Indexed(
                                        prefixed("Cursors").ada_expr(),
                                        Variable(target.affixed_name),
                                    ),
                                    "Last",
                                ),
                                Selected(
                                    Indexed(
                                        prefixed("Cursors").ada_expr(),
                                        Variable(target.affixed_name),
                                    ),
                                    "First",
                                ),
                            ),
                            Number(1),
                        ),
                        size.ada_expr(),
                    ),
                    Equal(
                        Selected(
                            Indexed(
                                prefixed("Cursors").ada_expr(),
                                Variable(target.affixed_name),
                            ),
                            "Predecessor",
                        ),
                        Variable(source.affixed_name),
                    ),
                    Equal(
                        Selected(
                            Indexed(
                                prefixed("Cursors").ada_expr(),
                                Variable(target.affixed_name),
                            ),
                            "First",
                        ),
                        first.ada_expr(),
                    ),
                    *[i for i in invariant if i != TRUE],
                ),
            )
        ]
    )
예제 #12
0
    Selected,
    Size,
    Statement,
    String,
    Sub,
    Update,
    ValueRange,
    Variable,
    WithClause,
)
from rflx.const import BUILTINS_PACKAGE
from rflx.identifier import ID

from . import const

EMPTY_ARRAY = NamedAggregate((ValueRange(Number(1), Number(0)), Number(0)))


class Debug(enum.Enum):
    NONE = enum.auto()
    BUILTIN = enum.auto()
    EXTERNAL = enum.auto()


def substitution(
    message: model.Message,
    prefix: str,
    embedded: bool = False,
    public: bool = False,
    target_type: Optional[ID] = const.TYPES_BASE_INT,
) -> Callable[[expr.Expr], expr.Expr]: