specware 1.3.6__tar.gz → 1.3.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specware
3
- Version: 1.3.6
3
+ Version: 1.3.7
4
4
  Summary: Provides utilities to specify software.
5
5
  Keywords: certification,documentation,markdown,qualification,requirements-management,traceability
6
6
  Author: The specware Authors
@@ -4,7 +4,7 @@
4
4
 
5
5
  [project]
6
6
  name = "specware"
7
- version = "1.3.6"
7
+ version = "1.3.7"
8
8
  description = "Provides utilities to specify software."
9
9
  authors = [
10
10
  {name = "The specware Authors", email = "specthings@embedded-brains.de"}
@@ -60,6 +60,24 @@ _PARENT_ROLES = [
60
60
  "test-timeouts", "verification-provider"
61
61
  ]
62
62
 
63
+ # The interface group membership and the interface placement are each defined
64
+ # by a pair of link roles which relate the items in opposite directions. The
65
+ # view lists the items of a pair in the order of their UIDs, so the choice of
66
+ # the role does not change the tree.
67
+ _MEMBER_CHILD_ROLES = ["interface-ingroup", "interface-ingroup-hidden"]
68
+
69
+ _VIEW_CHILD_ROLES = [
70
+ role for role in _CHILD_ROLES if role not in _MEMBER_CHILD_ROLES
71
+ ]
72
+
73
+ _VIEW_PARENT_ROLES = [
74
+ role for role in _PARENT_ROLES if role != "interface-group-member"
75
+ ]
76
+
77
+
78
+ def _sorted_links(links: Iterable[Link]) -> list[Link]:
79
+ return sorted(links, key=lambda link: link.item.uid)
80
+
63
81
 
64
82
  def _get_value_dummy(_ctx: ItemGetValueContext) -> Any:
65
83
  return ""
@@ -122,8 +140,11 @@ def _visit_item(item: Item, mapper: ItemMapper, level: int,
122
140
 
123
141
  def _view_interface_placment(item: Item, mapper: ItemMapper, level: int,
124
142
  validated_filter: str) -> None:
125
- for link in itertools.chain(item.links_to_children("interface-placement"),
126
- item.links_to_parents("register-block-host")):
143
+ for link in _sorted_links(
144
+ itertools.chain(
145
+ item.links_to_children("interface-placement"),
146
+ item.links_to_parents(
147
+ ["interface-host", "register-block-host"]))):
127
148
  if _visit_item(link.item, mapper, level, link, validated_filter):
128
149
  _view_interface_placment(link.item, mapper, level + 1,
129
150
  validated_filter)
@@ -146,9 +167,13 @@ def _view(item: Item, mapper: ItemMapper, level: int, link: Optional[Link],
146
167
  for link_2 in item.links_to_parents("reference"):
147
168
  _visit_item(link_2.item, mapper, level + 1, link_2, validated_filter)
148
169
  _view_interface_placment(item, mapper, level + 1, validated_filter)
149
- for link_2 in item.links_to_children(_CHILD_ROLES):
150
- _view(link_2.item, mapper, level + 1, link_2, validated_filter)
151
- for link_2 in item.links_to_parents(_PARENT_ROLES):
170
+ for link_2 in itertools.chain(
171
+ item.links_to_children(_VIEW_CHILD_ROLES),
172
+ _sorted_links(
173
+ itertools.chain(
174
+ item.links_to_children(_MEMBER_CHILD_ROLES),
175
+ item.links_to_parents("interface-group-member"))),
176
+ item.links_to_parents(_VIEW_PARENT_ROLES)):
152
177
  _view(link_2.item, mapper, level + 1, link_2, validated_filter)
153
178
 
154
179
 
@@ -577,9 +602,11 @@ def _register_blocks(item: Item, blocks: list[Item],
577
602
  return
578
603
  for link in itertools.chain(
579
604
  item.links_to_children(is_link_enabled=_any_link),
580
- item.links_to_parents(
581
- ["interface-group-member", "register-block-host"],
582
- is_link_enabled=_any_link)):
605
+ item.links_to_parents([
606
+ "interface-group-member", "interface-host",
607
+ "register-block-host"
608
+ ],
609
+ is_link_enabled=_any_link)):
583
610
  _register_blocks(link.item, blocks, visited)
584
611
 
585
612
 
@@ -524,9 +524,16 @@ class CContent(Content):
524
524
  self.wrap(description)
525
525
 
526
526
  @contextmanager
527
- def header_guard(self, filename: str) -> Iterator[None]:
528
- """ Open a header guard context. """
529
- guard = "_" + _NOT_ALPHANUM.sub("_", filename).upper()
527
+ def header_guard(self,
528
+ filename: str,
529
+ guard: Optional[str] = None) -> Iterator[None]:
530
+ """
531
+ Open a header guard context.
532
+
533
+ Without a guard, the guard is derived from the file name.
534
+ """
535
+ if guard is None:
536
+ guard = "_" + _NOT_ALPHANUM.sub("_", filename).upper()
530
537
  self.add([f"#ifndef {guard}", f"#define {guard}"])
531
538
  yield
532
539
  self.add(f"#endif /* {guard} */")
@@ -67,6 +67,28 @@ def _get_ingroups(item: Item) -> _ItemMap:
67
67
  return ingroups
68
68
 
69
69
 
70
+ def _get_domains(item: Item) -> set[str]:
71
+ if item["interface-type"] == "domain":
72
+ return {item.uid}
73
+ containers = list(item.parents("interface-placement"))
74
+ containers.extend(link.item for link in get_register_block_hosts(item))
75
+ domains: set[str] = set()
76
+ for container in containers:
77
+ domains.update(_get_domains(container))
78
+ return domains
79
+
80
+
81
+ def _get_ingroups_of_node(item: Item, domain: Item) -> _ItemMap:
82
+ ingroups = _get_ingroups(item)
83
+ if get_register_block_hosts(item):
84
+ return {
85
+ uid: group
86
+ for uid, group in ingroups.items()
87
+ if domain.uid in _get_domains(group)
88
+ }
89
+ return ingroups
90
+
91
+
70
92
  def _get_group_identifier(item: Item) -> str:
71
93
  if item.type == "interface/register-block":
72
94
  return get_register_block_identifier(item)
@@ -525,7 +547,7 @@ class _Node:
525
547
  self.header_file = header_file
526
548
  self.item = item
527
549
  self.host = host
528
- self.ingroups = _get_ingroups(item)
550
+ self.ingroups = _get_ingroups_of_node(item, header_file.domain)
529
551
  self.dependents: set[_Node] = set()
530
552
  self.depends_on: set[_Node] = set()
531
553
  self.content = header_file.content.fragment()
@@ -678,7 +700,8 @@ class _Node:
678
700
  ctx.regs[name] = {}
679
701
  ctx.regs[name]["size"] = link.item["register-block-size"]
680
702
  ctx.regs[name]["type"] = link.item["name"]
681
- ctx.regs[name]["group"] = get_register_block_identifier(link.item)
703
+ ctx.regs[name]["group"] = get_register_block_identifier(
704
+ link.item, self.header_file.get_host(link.item))
682
705
 
683
706
  def _get_register_member_info(self, ctx: _RegisterMemberContext) -> None:
684
707
  offset = -1
@@ -1236,6 +1259,11 @@ class _HeaderFile:
1236
1259
  self.register_bit_macros = register_bit_macros
1237
1260
  self._option_expressions = option_expressions
1238
1261
 
1262
+ @property
1263
+ def domain(self) -> Item:
1264
+ """ Is the domain of the header file. """
1265
+ return self._item.parent("interface-placement")
1266
+
1239
1267
  def option_expression(self, option: str) -> str:
1240
1268
  """ Get the expression which tests the option in the header file. """
1241
1269
  return self._option_expressions.get_expression(self._item, option)
@@ -1245,18 +1273,32 @@ class _HeaderFile:
1245
1273
  Add the includes of the item to the header file includes.
1246
1274
 
1247
1275
  A register block which header files host adds the host of the domain
1248
- of this header file.
1276
+ of this header file, unless a header file of this domain places the
1277
+ register block.
1249
1278
  """
1250
- for parent in item.parents("interface-placement"):
1251
- if parent.type in [
1252
- "interface/header-file",
1253
- "interface/unspecified-header-file"
1254
- ]:
1255
- self._includes.append(parent)
1256
- if get_register_block_hosts(item):
1257
- self._includes.append(
1258
- get_register_block_host_of_domain(
1259
- item, self._item.parent("interface-placement")).item)
1279
+ host = self.get_host(item)
1280
+ if host is None:
1281
+ self._includes.extend(
1282
+ parent for parent in item.parents("interface-placement")
1283
+ if parent.type in
1284
+ ["interface/header-file", "interface/unspecified-header-file"])
1285
+ else:
1286
+ self._includes.append(host.item)
1287
+
1288
+ def get_host(self, item: Item) -> Optional[Link]:
1289
+ """
1290
+ Get the link of the header file of the domain of this header file
1291
+ which hosts the item.
1292
+
1293
+ Returns None, if no header file hosts the item or a header file of the
1294
+ domain places it.
1295
+ """
1296
+ domain = self.domain
1297
+ if not get_register_block_hosts(item) or any(
1298
+ parent.parent("interface-placement") == domain
1299
+ for parent in item.parents("interface-placement")):
1300
+ return None
1301
+ return get_register_block_host_of_domain(item, domain)
1260
1302
 
1261
1303
  def add_node(self, item: Item) -> None:
1262
1304
  """ Add a node for the item. """
@@ -1268,15 +1310,26 @@ class _HeaderFile:
1268
1310
  if item.type != "interface/register-block":
1269
1311
  raise ValueError(f"header file '{self._item.uid}' hosts "
1270
1312
  f"'{item.uid}' which is no register block")
1271
- if any(True for _ in item.parents("interface-placement")):
1272
- raise ValueError(f"register block '{item.uid}' has an interface "
1273
- "placement and header file "
1274
- f"'{self._item.uid}' hosts it")
1275
- get_register_block_host_of_domain(
1276
- item, self._item.parent("interface-placement"))
1313
+ self._check_hosted_item(item)
1277
1314
  node_type = _ZephyrNode if link["style"] == "zephyr" else _Node
1278
1315
  self._nodes[item.uid] = node_type(self, item, link)
1279
1316
 
1317
+ def add_hosted_interface(self, link: Link) -> None:
1318
+ """ Add a node for the interface of the host link. """
1319
+ self._check_hosted_item(link.item)
1320
+ self.add_node(link.item)
1321
+
1322
+ def _check_hosted_item(self, item: Item) -> None:
1323
+ domain = self.domain
1324
+ if any(
1325
+ parent.parent("interface-placement") == domain
1326
+ for parent in item.parents("interface-placement")):
1327
+ kind = item["interface-type"].replace("-", " ")
1328
+ raise ValueError(f"{kind} '{item.uid}' has an interface "
1329
+ "placement in the domain of header file "
1330
+ f"'{self._item.uid}' which hosts it")
1331
+ get_register_block_host_of_domain(item, domain)
1332
+
1280
1333
  def add_dependency(self, node: _Node, item: Item) -> None:
1281
1334
  """
1282
1335
  Add a dependency from a node to another node identified by an item if
@@ -1295,6 +1348,9 @@ class _HeaderFile:
1295
1348
  for link in self._item.links_to_parents("register-block-host"):
1296
1349
  self.add_hosted_node(link)
1297
1350
  self.content.register_license_and_copyrights_of_item(link.item)
1351
+ for link in self._item.links_to_parents("interface-host"):
1352
+ self.add_hosted_interface(link)
1353
+ self.content.register_license_and_copyrights_of_item(link.item)
1298
1354
  for node in self._nodes.values():
1299
1355
  node.generate()
1300
1356
 
@@ -1356,7 +1412,8 @@ class _HeaderFile:
1356
1412
  def finalize(self) -> None:
1357
1413
  """ Finalize the header file. """
1358
1414
  self.add_prologue()
1359
- with self.content.header_guard(self._item["path"]):
1415
+ with self.content.header_guard(self._item["path"],
1416
+ self.get_header_guard()):
1360
1417
  exp_mapper = OptionExpressionMapper(self._option_expressions,
1361
1418
  self._item)
1362
1419
  includes = [
@@ -1383,6 +1440,16 @@ class _HeaderFile:
1383
1440
  for node in self._get_nodes_in_dependency_order():
1384
1441
  self.content.add(node.content)
1385
1442
 
1443
+ def get_header_guard(self) -> Optional[str]:
1444
+ """
1445
+ Get the header guard of the header file.
1446
+
1447
+ The ``header-guard`` attribute of the placement link of the header file
1448
+ states the guard. Returns None, if the guard is derived from the path.
1449
+ """
1450
+ link = next(self._item.links_to_parents("interface-placement"))
1451
+ return link.data.get("header-guard", None)
1452
+
1386
1453
  def write(self, domain_path: Optional[str],
1387
1454
  file_path: Optional[str]) -> None:
1388
1455
  """ Write the header file. """
@@ -35,6 +35,7 @@ from .contentc import (CContent, DEFAULT_ITEM_MARKER, add_item_marker,
35
35
  get_value_compound, get_value_forward_declaration,
36
36
  get_value_unspecified_type)
37
37
  from .interfacemapper import sanitize_name
38
+ from .registerblock import get_interface_members
38
39
 
39
40
 
40
41
  def _get_code_param(ctx: ItemGetValueContext) -> Any:
@@ -309,10 +310,10 @@ _TYPE_GENERATORS = {
309
310
  }
310
311
 
311
312
 
312
- def _gather_types(item: Item, types: list[Item]) -> None:
313
- for child in item.children("interface-placement"):
313
+ def _gather_types(item: Item, types: dict[str, Item]) -> None:
314
+ for child in get_interface_members(item):
314
315
  if child.type in _TYPE_GENERATORS:
315
- types.append(child)
316
+ types[child.uid] = child
316
317
  _gather_types(child, types)
317
318
 
318
319
 
@@ -325,7 +326,7 @@ def _is_opaque_type(item: Item) -> Optional[Item]:
325
326
 
326
327
  def _generate_types(content: TextContent, mapper: ItemMapper, config: dict,
327
328
  item_cache: ItemCache, item_marker: str) -> None:
328
- types: list[Item] = []
329
+ types: dict[str, Item] = {}
329
330
  for domain in config["domains"]:
330
331
  _gather_types(item_cache[domain], types)
331
332
  content.add_automatically_generated_warning()
@@ -341,7 +342,7 @@ for more information about the usage of the various data types.""")
341
342
  content.wrap(
342
343
  "The following is a complete list of the RTEMS primitive data "
343
344
  "types in alphabetical order:")
344
- for item in sorted(types, key=lambda x: x["name"]):
345
+ for item in sorted(types.values(), key=lambda x: x["name"]):
345
346
  content.register_license_and_copyrights_of_item(item)
346
347
  add_item_marker(content, item_marker, item)
347
348
  name = item["name"]
@@ -37,23 +37,28 @@ __all__ = [
37
37
  "get_register_block_prefixes"
38
38
  ]
39
39
 
40
+ _HOST_ROLES = ("interface-host", "register-block-host")
41
+
40
42
 
41
43
  def get_register_block_hosts(item: Item) -> list[Link]:
42
44
  """
43
- Get the links of the header files which host the register block.
45
+ Get the links of the header files which host the interface.
44
46
 
45
47
  Each link is a link from the header file to the register block, so
46
48
  ``link.item`` is the header file. The links are sorted by the UID of the
47
49
  header file.
48
50
  """
49
- return sorted(item.links_to_children("register-block-host"),
51
+ return sorted(item.links_to_children(_HOST_ROLES),
50
52
  key=lambda link: link.item.uid)
51
53
 
52
54
 
55
+ def _get_kind(item: Item) -> str:
56
+ return item["interface-type"].replace("-", " ")
57
+
58
+
53
59
  def get_register_block_host_of_domain(item: Item, domain: Item) -> Link:
54
60
  """
55
- Get the link of the header file of the domain which hosts the register
56
- block.
61
+ Get the link of the header file of the domain which hosts the interface.
57
62
 
58
63
  Raises:
59
64
  ValueError: No header file or more than one header file of the domain
@@ -65,10 +70,11 @@ def get_register_block_host_of_domain(item: Item, domain: Item) -> Link:
65
70
  ]
66
71
  if not hosts:
67
72
  raise ValueError(f"no header file of domain '{domain.uid}' hosts "
68
- f"register block '{item.uid}'")
73
+ f"{_get_kind(item)} '{item.uid}'")
69
74
  if len(hosts) > 1:
70
75
  raise ValueError(f"more than one header file of domain "
71
- f"'{domain.uid}' hosts register block '{item.uid}': "
76
+ f"'{domain.uid}' hosts {_get_kind(item)} "
77
+ f"'{item.uid}': "
72
78
  f"{', '.join(link.item.uid for link in hosts)}")
73
79
  return hosts[0]
74
80
 
@@ -78,10 +84,11 @@ def get_interface_members(item: Item) -> list[Item]:
78
84
  Get the interfaces which the interface container places.
79
85
 
80
86
  These are the children of the ``interface-placement`` links and the
81
- register blocks of the ``register-block-host`` links of the container.
87
+ interfaces of the ``register-block-host`` and ``interface-host`` links of
88
+ the container.
82
89
  """
83
90
  return list(item.children("interface-placement")) + list(
84
- item.parents("register-block-host"))
91
+ item.parents(_HOST_ROLES))
85
92
 
86
93
 
87
94
  def get_interface_groups(item: Item) -> list[Item]:
@@ -141,7 +148,7 @@ def _get_block_value(item: Item, host: Optional[Link], key: str) -> Any:
141
148
  value = host.data.get(key, None)
142
149
  if value is not None:
143
150
  return value
144
- else:
151
+ elif not any(True for _ in item.parents("interface-placement")):
145
152
  values = set(link.data[key] for link in get_register_block_hosts(item)
146
153
  if link.data.get(key, None) is not None)
147
154
  if len(values) > 1:
@@ -164,7 +171,7 @@ def get_register_block_identifier(item: Item,
164
171
 
165
172
  The value of the host link takes precedence over the value of the block.
166
173
  Without a host link, the value of the host links of the block takes
167
- precedence.
174
+ precedence, unless the block has an interface placement.
168
175
  """
169
176
  return _get_block_value(item, host, "identifier")
170
177
 
@@ -175,7 +182,7 @@ def get_register_block_group(item: Item, host: Optional[Link] = None) -> str:
175
182
 
176
183
  The value of the host link takes precedence over the value of the block.
177
184
  Without a host link, the value of the host links of the block takes
178
- precedence.
185
+ precedence, unless the block has an interface placement.
179
186
  """
180
187
  return _get_block_value(item, host, "register-block-group")
181
188
 
@@ -52,8 +52,15 @@ _ENABLEMENT_ROLES = ("interface-function", "interface-ingroup",
52
52
  "validation")
53
53
 
54
54
  # An item is enabled through the items which link to it by these roles.
55
- _ENABLEMENT_CHILD_ROLES = ("interface-group-member", "register-block-base",
56
- "register-block-host", "register-block-include")
55
+ _ENABLEMENT_CHILD_ROLES = ("interface-host", "interface-group-member",
56
+ "register-block-base", "register-block-host",
57
+ "register-block-include")
58
+
59
+ # A host of an interface with a placement does not decide its enablement. The
60
+ # placement serves the domain of the placement whatever the hosts are.
61
+ _ENABLEMENT_PLACED_CHILD_ROLES = tuple(role for role in _ENABLEMENT_CHILD_ROLES
62
+ if role not in ("interface-host",
63
+ "register-block-host"))
57
64
 
58
65
 
59
66
  def recursive_is_enabled(enabled_set: EnabledSet, item: Item) -> bool:
@@ -64,10 +71,13 @@ def recursive_is_enabled(enabled_set: EnabledSet, item: Item) -> bool:
64
71
  if not item.is_enabled(enabled_set):
65
72
  return False
66
73
  result = True
74
+ if any(True for _ in item.parents("interface-placement")):
75
+ child_roles = _ENABLEMENT_PLACED_CHILD_ROLES
76
+ else:
77
+ child_roles = _ENABLEMENT_CHILD_ROLES
67
78
  for parent in itertools.chain(
68
79
  item.parents(_ENABLEMENT_ROLES, is_link_enabled=link_is_enabled),
69
- item.children(_ENABLEMENT_CHILD_ROLES,
70
- is_link_enabled=link_is_enabled)):
80
+ item.children(child_roles, is_link_enabled=link_is_enabled)):
71
81
  if recursive_is_enabled(enabled_set, parent):
72
82
  return True
73
83
  result = False
@@ -141,7 +151,8 @@ _VALIDATION_PARENT_ROLES = _PARENT_ROLES + ("interface-group-member", )
141
151
  _VISIT_CHILD_ROLES = _CHILD_ROLES + ("appl-config-group-member",
142
152
  "interface-placement")
143
153
 
144
- _VISIT_PARENT_ROLES = _VALIDATION_PARENT_ROLES + ("register-block-host", )
154
+ _VISIT_PARENT_ROLES = _VALIDATION_PARENT_ROLES + ("interface-host",
155
+ "register-block-host")
145
156
 
146
157
 
147
158
  def _visit_tree(item: Item, related_items: set[Item]) -> None:
@@ -171,8 +182,8 @@ _EXPORT_CHILD_ROLES = ("interface-function", "interface-placement",
171
182
  "test-case", "validation")
172
183
 
173
184
  _EXPORT_PARENT_ROLES = _PARENT_ROLES + (
174
- "constraint", "errno", "register-block-base", "register-block-host",
175
- "register-block-include")
185
+ "constraint", "interface-host", "errno", "register-block-base",
186
+ "register-block-host", "register-block-include")
176
187
 
177
188
  # Items reached through the shallow roles contribute to the generated content
178
189
  # of the visiting item, however, the items related to them do not. Expanding
index 51e706e..779a5d0 100644
Binary file
File without changes
File without changes
File without changes
File without changes