Support relative type references in msg files

This commit is contained in:
Marko Durkovic 2021-07-08 09:18:54 +02:00
parent 3d694b20f6
commit 117a4f6348
4 changed files with 57 additions and 10 deletions

View File

@ -253,6 +253,11 @@ class VisitorIDL(Visitor): # pylint: disable=too-many-public-methods
RULES = parse_grammar(GRAMMAR_IDL)
def __init__(self):
"""Initialize."""
super().__init__()
self.typedefs = {}
def visit_specification(self, children: Any) -> Typesdict:
"""Process start symbol, return only children of modules."""
children = [x[0] for x in children if x is not None]

View File

@ -89,10 +89,11 @@ def normalize_msgtype(name: str) -> str:
return str(path)
def normalize_fieldtype(field: Any, names: List[str]):
def normalize_fieldtype(typename: str, field: Any, names: List[str]):
"""Normalize field typename.
Args:
typename: Type name of field owner.
field: Field definition.
names: Valid message names.
@ -111,9 +112,12 @@ def normalize_fieldtype(field: Any, names: List[str]):
else:
if name in dct:
name = dct[name]
elif name == 'Header':
name = 'std_msgs/msg/Header'
elif '/' not in name:
name = str(Path(typename).parent / name)
elif '/msg/' not in name:
ptype = Path(name)
name = str(ptype.parent / 'msg' / ptype.name)
name = str((path := Path(name)).parent / 'msg' / path.name)
inamedef = (Nodetype.NAME, name)
if namedef[0] == Nodetype.NAME:
@ -159,9 +163,9 @@ class VisitorMSG(Visitor):
typelist = [children[0], *[x[1] for x in children[1]]]
typedict = dict(typelist)
names = list(typedict.keys())
for _, fields in typedict.items():
for name, fields in typedict.items():
for field in fields:
normalize_fieldtype(field, names)
normalize_fieldtype(name, field, names)
return typedict
def visit_msgdef(self, children: Any) -> Any:

View File

@ -58,10 +58,22 @@ class Rule:
class RuleLiteral(Rule):
"""Rule to match string literal."""
def __init__(self, value: Any, rules: Dict[str, Rule], name: Optional[str] = None):
"""Initialize.
Args:
value: Value of this rule.
rules: Grammar containing all rules.
name: Name of this rule.
"""
super().__init__(value, rules, name)
self.value = value[1:-1].replace('\\\'', '\'')
def parse(self, text: str, pos: int) -> Tuple[int, Any]:
"""Apply rule at position."""
value: str = self.value[1:-1].replace('\\\'', '\'')
if text[pos:].startswith(value):
value = self.value
if text[pos:pos + len(value)] == value:
npos = pos + len(value)
npos = self.skip_ws(text, npos)
return npos, (self.LIT, value)
@ -71,10 +83,21 @@ class RuleLiteral(Rule):
class RuleRegex(Rule):
"""Rule to match regular expression."""
def __init__(self, value: Any, rules: Dict[str, Rule], name: Optional[str] = None):
"""Initialize.
Args:
value: Value of this rule.
rules: Grammar containing all rules.
name: Name of this rule.
"""
super().__init__(value, rules, name)
self.value = re.compile(value[2:-1], re.M | re.S)
def parse(self, text: str, pos: int) -> Tuple[int, Any]:
"""Apply rule at position."""
pattern = re.compile(self.value[2:-1], re.M | re.S)
match = pattern.match(text, pos)
match = self.value.match(text, pos)
if not match:
return -1, []
npos = self.skip_ws(text, match.span()[1])
@ -171,7 +194,6 @@ class Visitor: # pylint: disable=too-few-public-methods
def __init__(self):
"""Initialize."""
self.typedefs = {}
def visit(self, tree: Any) -> Any:
"""Visit all nodes in parse tree."""

View File

@ -37,6 +37,11 @@ MSG: test_msgs/Other
uint64[3] Header
"""
RELSIBLING_MSG = """
Header header
Other other
"""
IDL_LANG = """
// assign different literals and expressions
@ -122,6 +127,17 @@ def test_parse_multi_msg():
assert ret['test_msgs/msg/Foo'][2][0][1] == 'uint8'
def test_parse_relative_siblings_msg():
"""Test relative siblings with msg parser."""
ret = get_types_from_msg(RELSIBLING_MSG, 'test_msgs/msg/Foo')
assert ret['test_msgs/msg/Foo'][0][0][1] == 'std_msgs/msg/Header'
assert ret['test_msgs/msg/Foo'][1][0][1] == 'test_msgs/msg/Other'
ret = get_types_from_msg(RELSIBLING_MSG, 'rel_msgs/msg/Foo')
assert ret['rel_msgs/msg/Foo'][0][0][1] == 'std_msgs/msg/Header'
assert ret['rel_msgs/msg/Foo'][1][0][1] == 'rel_msgs/msg/Other'
def test_parse_idl():
"""Test idl parser."""
ret = get_types_from_idl(IDL_LANG)