Example #1
0
def fixture_icmp_checksum_message_first(icmp_message: model.Message) -> pyrflx.MessageValue:
    return pyrflx.MessageValue(
        icmp_message.copy(
            structure=[
                model.Link(
                    l.source,
                    l.target,
                    condition=expr.And(l.condition, expr.ValidChecksum("Checksum")),
                )
                if l.target == model.FINAL
                else l
                for l in icmp_message.structure
            ],
            checksums={
                ID("Checksum"): [
                    expr.ValueRange(
                        expr.First("Message"), expr.Sub(expr.First("Checksum"), expr.Number(1))
                    ),
                    expr.Size("Checksum"),
                    expr.ValueRange(
                        expr.Add(expr.Last("Checksum"), expr.Number(1)), expr.Last("Message")
                    ),
                ]
            },
        )
    )
Example #2
0
    def constraints(self,
                    name: str,
                    proof: bool = False,
                    same_package: bool = True) -> ty.Sequence[expr.Expr]:
        if proof:
            prefixed_literals = {
                self.package * l: v
                for l, v in self.literals.items()
            }
            if self.package == const.BUILTINS_PACKAGE:
                literals = self.literals
            elif same_package:
                literals = {**self.literals, **prefixed_literals}
            else:
                literals = prefixed_literals
            result: ty.List[expr.Expr] = [
                expr.Or(
                    *[
                        expr.Equal(expr.Variable(name), expr.Literal(l),
                                   self.location) for l in literals
                    ],
                    location=self.location,
                )
            ]
            result.extend([
                expr.Equal(expr.Literal(l), v, self.location)
                for l, v in literals.items()
            ])
            result.append(expr.Equal(expr.Size(name), self.size,
                                     self.location))
            return result

        raise NotImplementedError
Example #3
0
def has_size_dependent_condition(message: model.Message, field: model.Field = None) -> bool:
    field_sizes = {expr.Size(f.name) for f in message.fields}
    links = message.outgoing(field) if field else message.structure
    return any(
        size in field_sizes
        for link in links
        for size in link.condition.findall(lambda x: isinstance(x, expr.Size))
    )
Example #4
0
    def constraints(self,
                    name: str,
                    proof: bool = False,
                    same_package: bool = True) -> ty.Sequence[expr.Expr]:
        if proof:
            return [
                expr.GreaterEqual(expr.Variable(name),
                                  self.first,
                                  location=self.location),
                expr.LessEqual(expr.Variable(name),
                               self.last,
                               location=self.location),
                expr.Equal(expr.Size(name), self.size, location=self.location),
            ]

        raise NotImplementedError
Example #5
0
@pytest.mark.parametrize(
    "string,expected", [("X", expr.Variable("X")), ("X::Y", expr.Variable("X::Y"))]
)
def test_variable(string: str, expected: decl.Declaration) -> None:
    actual = parse_expression(string, lang.GrammarRule.variable_rule)
    assert actual == expected
    assert actual.location


@pytest.mark.parametrize(
    "string,expected",
    [
        ("X'First", expr.First(expr.Variable("X"))),
        ("X'Last", expr.Last(expr.Variable("X"))),
        ("X'Size", expr.Size(expr.Variable("X"))),
        ("X'Head", expr.Head(expr.Variable("X"))),
        ("X'Opaque", expr.Opaque(expr.Variable("X"))),
        ("X'Present", expr.Present(expr.Variable("X"))),
        ("X'Valid", expr.Valid(expr.Variable("X"))),
        ("X'Valid_Checksum", expr.ValidChecksum(expr.Variable("X"))),
        ("X'Has_Data", expr.HasData(expr.Variable("X"))),
        ("X where X = 42", expr.Binding(expr.Variable("X"), {ID("X"): expr.Number(42)})),
        ("X'Head.Y", expr.Selected(expr.Head(expr.Variable("X")), "Y")),
    ],
)
def test_expression_suffix(string: str, expected: expr.Expr) -> None:
    actual = parse_expression(string, lang.GrammarRule.extended_expression_rule)
    assert actual == expected
    assert actual.location
Example #6
0
 def element_size(self) -> expr.Expr:
     return expr.Size(self.element_type.name)
Example #7
0
    def __init__(self,
                 identifier: StrID,
                 element_type: Type,
                 location: Location = None) -> None:
        super().__init__(identifier, location)
        self.element_type = element_type

        if not isinstance(element_type, Scalar) and not isinstance(
                element_type, message.Message):
            self.error.extend([
                (
                    f'invalid element type of sequence "{self.name}"',
                    Subsystem.MODEL,
                    Severity.ERROR,
                    location,
                ),
                (
                    f'type "{element_type.name}" must be scalar or message',
                    Subsystem.MODEL,
                    Severity.INFO,
                    element_type.location,
                ),
            ], )

        if isinstance(element_type, Scalar):
            element_type_size = element_type.size.simplified()
            if not isinstance(element_type_size,
                              expr.Number) or int(element_type_size) % 8 != 0:
                self.error.extend([
                    (
                        f'unsupported element type size of sequence "{self.name}"',
                        Subsystem.MODEL,
                        Severity.ERROR,
                        location,
                    ),
                    (
                        f'type "{element_type.name}" has size {element_type_size},'
                        r" must be multiple of 8",
                        Subsystem.MODEL,
                        Severity.INFO,
                        element_type.location,
                    ),
                ], )

        if isinstance(element_type, message.Message):
            error = (
                f'invalid element type of sequence "{self.name}"',
                Subsystem.MODEL,
                Severity.ERROR,
                location,
            )

            if not element_type.structure:
                self.error.extend([
                    error,
                    (
                        "null messages must not be used as sequence element",
                        Subsystem.MODEL,
                        Severity.INFO,
                        element_type.location,
                    ),
                ], )

            if any(
                    bool(
                        e.findall(lambda x: x in
                                  [expr.Size("Message"),
                                   expr.Last("Message")]))
                    for l in element_type.structure
                    for e in [l.condition, l.size]):
                self.error.extend([
                    error,
                    (
                        "messages used as sequence element must not depend"
                        ' on "Message\'Size" or "Message\'Last"',
                        Subsystem.MODEL,
                        Severity.INFO,
                        element_type.location,
                    ),
                ], )
Example #8
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},
    }