Skip to content

Commit

Permalink
Add support for relations with aggregates and variables in pyrflx
Browse files Browse the repository at this point in the history
Ref: #964
  • Loading branch information
rssen committed Apr 7, 2022
1 parent f6fb320 commit 2c34d1b
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 11 deletions.
17 changes: 15 additions & 2 deletions rflx/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -1710,8 +1710,21 @@ def _simplified(self, relation_operator: Callable[[Expr, Expr], bool]) -> Expr:
}
if (relation_operator, left, right) in mapping:
return mapping[(relation_operator, left, right)]
if isinstance(left, Number) and isinstance(right, Number):
return TRUE if relation_operator(left, right) else FALSE
if isinstance(left, (Number, Aggregate)) and isinstance(right, (Number, Aggregate)):
if isinstance(left, Number) and isinstance(right, Number):
return TRUE if relation_operator(left, right) else FALSE
if isinstance(left, Aggregate) and isinstance(right, Aggregate):
return TRUE if left.elements == right.elements else FALSE
aggregate = left if isinstance(left, Aggregate) else right
number = left if isinstance(left, Number) else right
assert isinstance(aggregate, Aggregate)
assert isinstance(number, Number)
if relation_operator is operator.eq and number in aggregate.elements:
return TRUE
if relation_operator is operator.ne and number not in aggregate.elements:
return TRUE
return FALSE

return self.__class__(left, right)

@property
Expand Down
13 changes: 5 additions & 8 deletions rflx/pyrflx/typevalue.py
Original file line number Diff line number Diff line change
Expand Up @@ -1153,14 +1153,6 @@ def _calculate_checksum(self, checksum: "MessageValue.Checksum") -> int:
expr_tuple.evaluated_expression.lower.value,
expr_tuple.evaluated_expression.upper.value,
)
elif isinstance(expr_tuple.evaluated_expression, Variable):
assert (
expr_tuple.evaluated_expression.name in self.fields
and self._fields[expr_tuple.evaluated_expression.name].set
)
val = self._fields[expr_tuple.evaluated_expression.name].typeval.value
assert isinstance(val, bytes)
arguments[str(expr_tuple.expression)] = val
else:
assert isinstance(expr_tuple.evaluated_expression, Number)
arguments[str(expr_tuple.expression)] = expr_tuple.evaluated_expression.value
Expand Down Expand Up @@ -1356,6 +1348,11 @@ def subst(expression: Expr) -> Expr:
if expression in self._parameters:
assert isinstance(expression, Name)
return self._parameters[expression]
if isinstance(expression, Variable) and expression.name in self.fields:
if self._fields[expression.identifier.flat].set:
exp_value = self._fields[expression.identifier.flat].typeval.value
assert isinstance(exp_value, bytes)
return Number(int.from_bytes(exp_value, "big"))
return expression

return expr.substituted(func=subst).substituted(func=subst).simplified()
Expand Down
8 changes: 7 additions & 1 deletion tests/data/fixtures/pyrflx.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def fixture_pyrflx() -> pyrflx.PyRFLX:
f"{SPEC_DIR}/parameterized.rflx",
f"{SPEC_DIR}/endianness.rflx",
f"{SPEC_DIR}/low_order.rflx",
f"{SPEC_DIR}/aggregate_in_relation.rflx",
],
skip_model_verification=True,
)
Expand Down Expand Up @@ -235,5 +236,10 @@ def fixture_endianness_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:


@pytest.fixture(name="low_order_package", scope="session")
def fixure_low_order_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
def fixture_low_order_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
return pyrflx_.package("Low_Order")


@pytest.fixture(name="aggregate_in_relation_package", scope="session")
def fixture_aggregate_in_relation_package(pyrflx_: pyrflx.PyRFLX) -> pyrflx.Package:
return pyrflx_.package("Aggregate_In_Relation")
24 changes: 24 additions & 0 deletions tests/data/specs/aggregate_in_relation.rflx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package Aggregate_In_Relation is

type B is mod 2 ** 8;
type C is mod 2 ** 8;
type D is mod 2 ** 8;

type Aggregate_In_Relation_Msg is
message
Fld_A : Opaque
with Size => 16
then Fld_B
if Fld_A /= [16#01#, 16#02#]
then null
if [16#01#, 16#02#] = Fld_A;
Fld_B : B
then Fld_C
if [16#01#, 16#02#] = [16#01#, 16#02#];
Fld_C : C
then Fld_D
if Fld_C = Fld_B;
Fld_D : D;
end message;

end Aggregate_In_Relation;
37 changes: 37 additions & 0 deletions tests/unit/expression_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1081,6 +1081,37 @@ def test_relation_simplified() -> None:
Equal(Add(Number(1), Number(1)), Add(Number(1), Number(1))).simplified(),
TRUE,
)

assert_equal(Equal(String("Foo Bar"), String("Foo Bar")).simplified(), TRUE)

assert_equal(
Equal(String("Foo"), Aggregate(Number(70), Number(111), Number(111))).simplified(), TRUE
)

assert_equal(
Equal(
Aggregate(Number(0), Number(1), Number(2)), Aggregate(Number(0), Number(1), Number(2))
).simplified(),
TRUE,
)

assert_equal(
Equal(
Aggregate(Number(1), Number(2), Number(3)), Aggregate(Number(4), Number(5), Number(6))
).simplified(),
FALSE,
)

assert_equal(Equal(Number(0), Aggregate(Number(0), Number(1), Number(2))).simplified(), TRUE)

assert_equal(Equal(Aggregate(Number(0), Number(1), Number(2)), Number(0)).simplified(), TRUE)

assert_equal(NotEqual(Number(4), Aggregate(Number(0), Number(1), Number(2))).simplified(), TRUE)

assert_equal(
NotEqual(Number(0), Aggregate(Number(0), Number(1), Number(2))).simplified(), FALSE
)

assert Equal(TRUE, TRUE).simplified() == TRUE
assert Equal(TRUE, FALSE).simplified() == FALSE
assert NotEqual(TRUE, TRUE).simplified() == FALSE
Expand Down Expand Up @@ -1573,6 +1604,12 @@ def test_string_simplified() -> None:
assert String("Test").simplified() == String("Test")


def test_string_substituted() -> None:
assert String("Test").substituted(
lambda x: String("TestSub") if x == String("Test") else x
) == String("TestSub")


def test_string_elements() -> None:
assert String("Test").elements == [Number(84), Number(101), Number(115), Number(116)]

Expand Down
21 changes: 21 additions & 0 deletions tests/unit/pyrflx_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ def test_pyrflx_iterator(pyrflx_: PyRFLX) -> None:
"Message_Type_Size_Condition",
"Always_Valid_Aspect",
"Low_Order",
"Aggregate_In_Relation",
}


Expand Down Expand Up @@ -1515,3 +1516,23 @@ def test_low_order(low_order_package: Package) -> None:

assert m1.valid_message
assert m1.bytestring == b"\x01\x00"


def test_aggregate_in_relation(aggregate_in_relation_package: Package) -> None:
msg = aggregate_in_relation_package.new_message("Aggregate_In_Relation_Msg")
with pytest.raises(
PyRFLXError,
match=(
"^"
"pyrflx: error: Bitstring representing the message is too short"
" - stopped while parsing field: Fld_B"
"$"
),
):
msg.parse(b"\x00\x03")

msg.parse(b"\x00\x02")
assert msg.valid_message

msg.parse(b"\x00\x03\x00\x00\x01")
assert msg.valid_message

0 comments on commit 2c34d1b

Please sign in to comment.