Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion rosidl_parser/rosidl_parser/definition.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,40 @@ def has_annotations(self, name: str) -> bool:
return bool(annotations)


class Enumerator(Annotatable):
"""An enumerator in an enum."""

__slots__ = ('name')

def __init__(self, name: str):
"""
Create an Enumerator.

:param name: the name of the enumerator
"""
super().__init__()
self.name = name


class Enum(Annotatable):
"""An enum type containing a list of enumerators."""

__slots__ = ('namespaced_type', 'enumerators')

def __init__(self, namespaced_type: NamespacedType,
enumerators: Optional[List['Enumerator']] = None) -> None:
"""
Create an Enum.

:param namespaced_type: the namespaced type identifying the enum
:param list enumerators: the enumerators of the enum
"""
super().__init__()
assert isinstance(namespaced_type, NamespacedType)
self.namespaced_type = namespaced_type
self.enumerators = enumerators or []


class Member(Annotatable):
"""A member of a structure."""

Expand Down Expand Up @@ -819,7 +853,7 @@ def get_absolute_path(self) -> pathlib.Path:
return self.basepath / self.relative_path


IdlContentElement: 'TypeAlias' = Union[Include, Message, Service, Action]
IdlContentElement: 'TypeAlias' = Union[Include, Message, Service, Action, Enum]
IdlContentElementT = TypeVar('IdlContentElementT', bound=IdlContentElement)


Expand Down
29 changes: 29 additions & 0 deletions rosidl_parser/rosidl_parser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
from rosidl_parser.definition import BoundedWString
from rosidl_parser.definition import Constant
from rosidl_parser.definition import CONSTANT_MODULE_SUFFIX
from rosidl_parser.definition import Enum
from rosidl_parser.definition import Enumerator
from rosidl_parser.definition import IdlContent
from rosidl_parser.definition import IdlFile
from rosidl_parser.definition import IdlLocator
Expand Down Expand Up @@ -146,6 +148,33 @@ def extract_content_from_ast(tree: 'ParseTree') -> IdlContent:
module_comments.append(constant)

typedefs: Dict[Any, Union[Array, AbstractTypeAlias]] = {}
enum_dcls = tree.find_data('enum_dcl')
for enum_dcl in enum_dcls:
annotations = get_annotations(enum_dcl)
module_identifiers = get_module_identifier_values(tree, enum_dcl)
enum_name = get_child_identifier_value(enum_dcl)

enumerators = []
enumerator_nodes = enum_dcl.find_data('enumerator')
for enumerator_node in enumerator_nodes:
enumerator_name = get_child_identifier_value(enumerator_node)
enumerator_annotations = get_annotations(enumerator_node)

enumerator = Enumerator(enumerator_name)
enumerator.annotations = enumerator_annotations
enumerators.append(enumerator)

enum_obj = Enum(
NamespacedType(
namespaces=module_identifiers,
name=enum_name
),
enumerators=enumerators
)
enum_obj.annotations = annotations
content.elements.append(enum_obj)
typedefs[enum_name] = enum_obj

typedef_dcls = tree.find_data('typedef_dcl')
for typedef_dcl in typedef_dcls:
assert len(typedef_dcl.children) == 1
Expand Down
10 changes: 10 additions & 0 deletions rosidl_parser/test/msg/MyMessage.idl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ module rosidl_parser {
const string EMPTY_STRING_CONSTANT = "";
};

@verbatim ( language="comment", text="Documentation of MyEnum." "Define an enum." )
enum MyEnum {
FIRST_ENUM,
SECOND_ENUM,
THIRD_ENUM
};

@verbatim ( language="comment", text="Documentation of MyMessage." "Adjacent string literal." )
@transfer_mode(SHMEM_REF)
struct MyMessage {
Expand Down Expand Up @@ -85,6 +92,9 @@ module rosidl_parser {
// Optional test
@optional
int32 optional_int;

// Enum field usage
MyEnum my_enum;
};
};
};
26 changes: 25 additions & 1 deletion rosidl_parser/test/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from rosidl_parser.definition import BoundedSequence
from rosidl_parser.definition import BoundedString
from rosidl_parser.definition import BoundedWString
from rosidl_parser.definition import Enum
from rosidl_parser.definition import IdlFile
from rosidl_parser.definition import IdlLocator
from rosidl_parser.definition import Include
Expand Down Expand Up @@ -92,6 +93,21 @@ def test_message_parser_includes(message_idl_file: IdlFile) -> None:
assert includes[1].locator == 'pkgname/msg/OtherMessage.idl'


def test_message_parser_enums(message_idl_file: IdlFile) -> None:
enums = message_idl_file.content.get_elements_of_type(Enum)
assert len(enums) == 1
assert enums[0].namespaced_type.name == 'MyEnum'
assert len(enums[0].annotations) == 1
assert enums[0].annotations[0].name == 'verbatim'
assert enums[0].annotations[0].value['language'] == 'comment'
text = enums[0].annotations[0].value['text']
assert text == 'Documentation of MyEnum.Define an enum.'
assert len(enums[0].enumerators) == 3
assert enums[0].enumerators[0].name == 'FIRST_ENUM'
assert enums[0].enumerators[1].name == 'SECOND_ENUM'
assert enums[0].enumerators[2].name == 'THIRD_ENUM'


def test_message_parser_structure(message_idl_file: IdlFile) -> None:
messages = message_idl_file.content.get_elements_of_type(Message)
assert len(messages) == 1
Expand Down Expand Up @@ -134,7 +150,7 @@ def test_message_parser_structure(message_idl_file: IdlFile) -> None:
structure = messages[0].structure
assert structure.namespaced_type.namespaces == ['rosidl_parser', 'msg']
assert structure.namespaced_type.name == 'MyMessage'
assert len(structure.members) == 46
assert len(structure.members) == 47

assert isinstance(structure.members[0].type, BasicType)
assert structure.members[0].type.typename == 'int16'
Expand Down Expand Up @@ -310,6 +326,14 @@ def test_message_parser_annotations(message_idl_file: IdlFile) -> None:
assert len(structure.members[45].annotations) == 1
assert structure.members[45].annotations[0].name == 'optional'

assert isinstance(structure.members[46].type, Enum)
assert structure.members[46].name == 'my_enum'
assert structure.members[46].type.namespaced_type.name == 'MyEnum'
assert len(structure.members[46].type.enumerators) == 3
assert structure.members[46].type.enumerators[0].name == 'FIRST_ENUM'
assert structure.members[46].type.enumerators[1].name == 'SECOND_ENUM'
assert structure.members[46].type.enumerators[2].name == 'THIRD_ENUM'


@pytest.fixture(scope='module')
def service_idl_file() -> IdlFile:
Expand Down