Skip to content

Commit

Permalink
Don't depend on known field_size in _field_constraints method
Browse files Browse the repository at this point in the history
We replace the use of `_target_size` by a similar `_target_size_opt`
function, which returns None if the size of the link target can't be
computed. In this case, no constraints need to be added to the
constraints computed by `_field_constraints`. We do the same for
`_target_last_opt`.

Also add unit test for new `_target_last_opt` function

For eng/recordflux/recordflux#1480
  • Loading branch information
kanigsson committed Dec 8, 2023
1 parent bc8ae3d commit 4bfe83e
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 8 deletions.
43 changes: 35 additions & 8 deletions rflx/model/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -875,7 +875,7 @@ def _validate_types(
parameters = type_fields - structure_fields - {INITIAL, FINAL}

for f, t in types.items():
if f in structure_fields and not isinstance(t, (mty.Scalar, mty.Composite)):
if f in structure_fields and not isinstance(t, (mty.Scalar, mty.Composite, Message)):
self.error.extend(
[
(
Expand Down Expand Up @@ -2035,33 +2035,60 @@ def _target_size(self, link: Link) -> expr.Expr:
return link.size
return self.field_size(link.target)

def _target_size_opt(self, link: Link) -> Optional[expr.Expr]:
if link.size != expr.UNDEFINED:
return link.size
return self.field_size_opt(link.target)

def _target_last(self, link: Link) -> expr.Expr:
return expr.Sub(
expr.Add(self._target_first(link), self._target_size(link)),
expr.Number(1),
link.target.identifier.location,
)

def _target_last_opt(self, link: Link) -> Optional[expr.Expr]:
size = self._target_size_opt(link)
if not size:
return None
return expr.Sub(
expr.Add(self._target_first(link), size),
expr.Number(1),
link.target.identifier.location,
)

def _link_size_constraints(
self,
link: Link,
ignore_implicit_sizes: bool = False,
) -> list[expr.Expr]:
name = link.target.name
target_first = self._target_first(link)
target_size = self._target_size(link)
target_last = self._target_last(link)
target_size = self._target_size_opt(link)
target_last = self._target_last_opt(link)
include_sizes = not (
ignore_implicit_sizes
and target_size
and (expr.Size("Message") in target_size or expr.Last("Message") in target_size)
)
return [
expr.Equal(expr.First(name), target_first, target_first.location or self.location),
*(
[
expr.Equal(expr.Size(name), target_size, target_size.location or self.location),
expr.Equal(
expr.Size(name),
target_size,
target_size.location or self.location,
),
]
if include_sizes and target_size
else []
),
*(
[
expr.Equal(expr.Last(name), target_last, target_last.location or self.location),
]
if not (
ignore_implicit_sizes
and (expr.Size("Message") in target_size or expr.Last("Message") in target_size)
)
if include_sizes and target_last
else []
),
expr.GreaterEqual(expr.First("Message"), expr.Number(0), self.location),
Expand Down
21 changes: 21 additions & 0 deletions tests/unit/model/message_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2765,6 +2765,27 @@ def test_field_size() -> None:
message.field_size(Field("X"))


def test_target_last_opt() -> None:
link_ia = Link(INITIAL, Field("A"))
link_ab = Link(Field("A"), Field("B"), size=Mul(Size("A"), Number(8)))
link_bc = Link(Field("B"), Field("C"))
message = Message(
"P::M",
[link_ia, link_ab, link_bc, Link(Field("C"), FINAL)],
{Field("A"): models.integer(), Field("B"): OPAQUE, Field("C"): OPAQUE},
location=Location((30, 10)),
)
assert message._target_last_opt(link_ia) == Sub( # noqa: SLF001
Add(First("Message"), Number(8)),
Number(1),
)
assert message._target_last_opt(link_ab) == Sub( # noqa: SLF001
Add(Add(Last("A"), Number(1)), Mul(Size("A"), Number(8))),
Number(1),
)
assert message._target_last_opt(link_bc) is None # noqa: SLF001


def test_copy() -> None:
message = Message(
"P::M",
Expand Down

0 comments on commit 4bfe83e

Please sign in to comment.