-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Detect duplicate messages and channels aspects #930
Conversation
This commit introduces extra checks to avoid duplicate aspects for messages and channels. Closes #714
@@ -533,10 +533,23 @@ def create_channel_decl( | |||
filename: Path, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please also have a look at other uses of aspects. For example, messages can have
Checksum
aspects and transitions in sessions can haveDesc
aspects. Maybe we have the same issue there.
See #714 (comment).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about the Desc aspect mentioned above? Please add a unit test, even if a duplicate aspect is already detected (even as a syntax error).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't do anything for Desc as I think the code doesn't allow more than one Desc anyway, so I don't think it is necessary to add a test for this as I didn't implement it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if it is not possible to have duplicate Desc aspects at the moment, this doesn't mean that this cannot be the case in the future. Unit test are used to prevent regressions. That is why it still makes sense to add a unit test, even if you did not change anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test added.
006fab2
to
fcb9cd0
Compare
def test_parse_error_duplicate_channel_aspect_readable() -> None: | ||
assert_error_string( | ||
""" | ||
package Test is | ||
|
||
type M is | ||
message | ||
B : Opaque | ||
with Size => 8; | ||
end message; | ||
|
||
generic | ||
Channel : Channel with Readable, Writable, Readable; | ||
session Session with | ||
Initial => Start, | ||
Final => Terminated | ||
is | ||
Message : M; | ||
begin | ||
state Start is | ||
begin | ||
Channel'Read (Message); | ||
transition | ||
goto Reply | ||
if Message'Valid | ||
goto Terminated | ||
end Start; | ||
|
||
state Reply is | ||
begin | ||
Channel'Write (Message); | ||
transition | ||
goto Terminated | ||
end Reply; | ||
|
||
state Terminated is null state; | ||
end Session; | ||
|
||
end Test; | ||
""", | ||
r'^<stdin>:11:62: parser: error: duplicate aspect "Readable"', | ||
) | ||
|
||
|
||
def test_parse_error_duplicate_channel_aspect_writable() -> None: | ||
assert_error_string( | ||
""" | ||
package Test is | ||
|
||
type M is | ||
message | ||
B : Opaque | ||
with Size => 8; | ||
end message; | ||
|
||
generic | ||
Channel : Channel with Readable, Writable, Writable; | ||
session Session with | ||
Initial => Start, | ||
Final => Terminated | ||
is | ||
Message : M; | ||
begin | ||
state Start is | ||
begin | ||
Channel'Read (Message); | ||
transition | ||
goto Reply | ||
if Message'Valid | ||
goto Terminated | ||
end Start; | ||
|
||
state Reply is | ||
begin | ||
Channel'Write (Message); | ||
transition | ||
goto Terminated | ||
end Reply; | ||
|
||
state Terminated is null state; | ||
end Session; | ||
|
||
end Test; | ||
""", | ||
r'^<stdin>:11:62: parser: error: duplicate aspect "Writable"', | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate code can be avoided by using @pytest.mark.parametrize.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
Byte_Order => Low_Order_First, | ||
Byte_Order => Low_Order_First; | ||
end Test; | ||
""", | ||
r'^<stdin>:18:27: parser: error: duplicate aspect "ByteOrderAspect"', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The aspect is called Byte_Order
, not ByteOrderAspect
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what the error message generates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then the error message needs to be changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That means changing aspect.kind_name, if you don't like the message I suggest you open a ticket to change the attribute _kind_name of the class ByteOrderAspect from librflxlang.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing kind_name
is not possible. Please find another solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case I think the error message should stay the same to keep the code consistent then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error messages are intended for users of the tool. Having a error message mentioning "ByteOrderAspect", while the aspect is actually called "Byte_Order" in the specification, is confusing. Keeping the code as it as, just because it is easier, is no option here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First, I don't think ByteOrderAspect is confusing, it literally literally has Byte Order and Aspect in it. and I already proposed a solution to change kind_name if you don't like the exact wording. I don't see another way to do it.
rflx/specification/parser.py
Outdated
@@ -218,9 +219,10 @@ def create_session( | |||
session: lang.SessionDecl, | |||
package: ID, | |||
filename: Path, | |||
error: RecordFluxError, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All create_*
functions, which had an error
parameter before, had this as the first parameter. Could you please make that consistent to the existing code? A consistent order of parameters is especially relevant when function pointers are used, which is done in several cases here. I also would like to prevent confusions in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
rflx/specification/parser.py
Outdated
checksum_parsed = False | ||
checksum_result = {} | ||
byte_order_parsed = False | ||
byte_order_result = None | ||
for aspect in aspects: | ||
if isinstance(aspect, lang.ChecksumAspect): | ||
if (isinstance(aspect, lang.ChecksumAspect) and checksum_parsed) or ( | ||
isinstance(aspect, lang.ByteOrderAspect) and byte_order_parsed | ||
): | ||
error.extend( | ||
[ | ||
( | ||
f'duplicate aspect "{aspect.kind_name}"', | ||
Subsystem.PARSER, | ||
Severity.ERROR, | ||
node_location(aspect, filename), | ||
) | ||
], | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are checksum_parsed
and byte_order_parsed
required? Couldn't just checksum_result
and byte_order_result
be used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really, fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using checksum_result is causing mypy to raise typing errors, I am putting checksum_parsed back
rflx/specification/parser.py
Outdated
raise NotImplementedError( | ||
f"Enumeration kind {enumeration.f_elements.kind_name} unsupported" | ||
) | ||
raise NotImplementedError(f"Enmeration kind {enumeration.f_elements.kind_name} unsupported") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A typo is added here: Enmeration
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
def parse_formal_declaration(data: str) -> decl.Declaration: | ||
parser_declaration, filename = parse(data, lang.GrammarRule.session_parameter_rule) | ||
assert isinstance(parser_declaration, lang.FormalDecl) | ||
declaration = create_formal_declaration(parser_declaration, ID("Package"), filename) | ||
error = RecordFluxError() | ||
declaration = create_formal_declaration(parser_declaration, ID("Package"), filename, error) | ||
assert isinstance(declaration, decl.Declaration) | ||
return declaration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
error.propagate()
should be called after create_*
, otherwise any error in create_*
will be just ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
if diagnostics_to_error(unit.diagnostics, error, STDIN): | ||
error.propagate() | ||
assert isinstance(unit.root, lang.SessionDecl) | ||
return create_session(unit.root, ID("Package"), Path("<stdin>")) | ||
return create_session(unit.root, ID("Package"), Path("<stdin>"), error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
error.propagate()
should be called after create_*
, otherwise any error in create_*
will be just ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
@@ -73,7 +74,7 @@ def parse_unproven_session(string: str) -> model.UnprovenSession: | |||
if diagnostics_to_error(unit.diagnostics, error, STDIN): | |||
error.propagate() | |||
assert isinstance(unit.root, lang.SessionDecl) | |||
return create_unproven_session(unit.root, ID("Package"), Path("<stdin>")) | |||
return create_unproven_session(unit.root, ID("Package"), Path("<stdin>"), error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
error.propagate()
should be called after create_*
, otherwise any error in create_*
will be just ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
def test_parse_error_duplicate_size_aspect() -> None: | ||
assert_error_string( | ||
""" | ||
package Test is | ||
type T is (A, B) with Size => 12, Size => 10; | ||
end Test; | ||
""", | ||
r'^<stdin>:3:50: parser: error: duplicate aspect "Size"', | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are duplicate Size aspects also detected for range integers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic of detecting duplicate Size aspects doesn't care about the format of the expression given to the aspect Size, so the answer to your question is Yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a regression test nevertheless.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wouldn't be code duplication as well?
210d1c2
to
4adca2e
Compare
xCloses #714