specware 1.3.6__tar.gz → 1.3.8__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.8
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.8"
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,34 @@ 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 _is_hosted_in_second_domain(item: Item) -> bool:
82
+ return any(True for _ in item.links_to_children("interface-host")) or (
83
+ bool(get_register_block_hosts(item))
84
+ and any(True for _ in item.parents("interface-placement")))
85
+
86
+
87
+ def _get_ingroups_of_node(item: Item, domain: Item) -> _ItemMap:
88
+ ingroups = _get_ingroups(item)
89
+ if _is_hosted_in_second_domain(item):
90
+ return {
91
+ uid: group
92
+ for uid, group in ingroups.items()
93
+ if domain.uid in _get_domains(group)
94
+ }
95
+ return ingroups
96
+
97
+
70
98
  def _get_group_identifier(item: Item) -> str:
71
99
  if item.type == "interface/register-block":
72
100
  return get_register_block_identifier(item)
@@ -525,7 +553,7 @@ class _Node:
525
553
  self.header_file = header_file
526
554
  self.item = item
527
555
  self.host = host
528
- self.ingroups = _get_ingroups(item)
556
+ self.ingroups = _get_ingroups_of_node(item, header_file.domain)
529
557
  self.dependents: set[_Node] = set()
530
558
  self.depends_on: set[_Node] = set()
531
559
  self.content = header_file.content.fragment()
@@ -678,7 +706,10 @@ class _Node:
678
706
  ctx.regs[name] = {}
679
707
  ctx.regs[name]["size"] = link.item["register-block-size"]
680
708
  ctx.regs[name]["type"] = link.item["name"]
681
- ctx.regs[name]["group"] = get_register_block_identifier(link.item)
709
+ host = self.header_file.get_host(
710
+ link.item) if _is_hosted_in_second_domain(link.item) else None
711
+ ctx.regs[name]["group"] = get_register_block_identifier(
712
+ link.item, host)
682
713
 
683
714
  def _get_register_member_info(self, ctx: _RegisterMemberContext) -> None:
684
715
  offset = -1
@@ -1236,6 +1267,11 @@ class _HeaderFile:
1236
1267
  self.register_bit_macros = register_bit_macros
1237
1268
  self._option_expressions = option_expressions
1238
1269
 
1270
+ @property
1271
+ def domain(self) -> Item:
1272
+ """ Is the domain of the header file. """
1273
+ return self._item.parent("interface-placement")
1274
+
1239
1275
  def option_expression(self, option: str) -> str:
1240
1276
  """ Get the expression which tests the option in the header file. """
1241
1277
  return self._option_expressions.get_expression(self._item, option)
@@ -1245,18 +1281,32 @@ class _HeaderFile:
1245
1281
  Add the includes of the item to the header file includes.
1246
1282
 
1247
1283
  A register block which header files host adds the host of the domain
1248
- of this header file.
1284
+ of this header file, unless a header file of this domain places the
1285
+ register block.
1249
1286
  """
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)
1287
+ host = self.get_host(item)
1288
+ if host is None:
1289
+ self._includes.extend(
1290
+ parent for parent in item.parents("interface-placement")
1291
+ if parent.type in
1292
+ ["interface/header-file", "interface/unspecified-header-file"])
1293
+ else:
1294
+ self._includes.append(host.item)
1295
+
1296
+ def get_host(self, item: Item) -> Optional[Link]:
1297
+ """
1298
+ Get the link of the header file of the domain of this header file
1299
+ which hosts the item.
1300
+
1301
+ Returns None, if no header file hosts the item or a header file of the
1302
+ domain places it.
1303
+ """
1304
+ domain = self.domain
1305
+ if not get_register_block_hosts(item) or any(
1306
+ parent.parent("interface-placement") == domain
1307
+ for parent in item.parents("interface-placement")):
1308
+ return None
1309
+ return get_register_block_host_of_domain(item, domain)
1260
1310
 
1261
1311
  def add_node(self, item: Item) -> None:
1262
1312
  """ Add a node for the item. """
@@ -1268,15 +1318,26 @@ class _HeaderFile:
1268
1318
  if item.type != "interface/register-block":
1269
1319
  raise ValueError(f"header file '{self._item.uid}' hosts "
1270
1320
  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"))
1321
+ self._check_hosted_item(item)
1277
1322
  node_type = _ZephyrNode if link["style"] == "zephyr" else _Node
1278
1323
  self._nodes[item.uid] = node_type(self, item, link)
1279
1324
 
1325
+ def add_hosted_interface(self, link: Link) -> None:
1326
+ """ Add a node for the interface of the host link. """
1327
+ self._check_hosted_item(link.item)
1328
+ self.add_node(link.item)
1329
+
1330
+ def _check_hosted_item(self, item: Item) -> None:
1331
+ domain = self.domain
1332
+ if any(
1333
+ parent.parent("interface-placement") == domain
1334
+ for parent in item.parents("interface-placement")):
1335
+ kind = item["interface-type"].replace("-", " ")
1336
+ raise ValueError(f"{kind} '{item.uid}' has an interface "
1337
+ "placement in the domain of header file "
1338
+ f"'{self._item.uid}' which hosts it")
1339
+ get_register_block_host_of_domain(item, domain)
1340
+
1280
1341
  def add_dependency(self, node: _Node, item: Item) -> None:
1281
1342
  """
1282
1343
  Add a dependency from a node to another node identified by an item if
@@ -1295,6 +1356,9 @@ class _HeaderFile:
1295
1356
  for link in self._item.links_to_parents("register-block-host"):
1296
1357
  self.add_hosted_node(link)
1297
1358
  self.content.register_license_and_copyrights_of_item(link.item)
1359
+ for link in self._item.links_to_parents("interface-host"):
1360
+ self.add_hosted_interface(link)
1361
+ self.content.register_license_and_copyrights_of_item(link.item)
1298
1362
  for node in self._nodes.values():
1299
1363
  node.generate()
1300
1364
 
@@ -1356,7 +1420,8 @@ class _HeaderFile:
1356
1420
  def finalize(self) -> None:
1357
1421
  """ Finalize the header file. """
1358
1422
  self.add_prologue()
1359
- with self.content.header_guard(self._item["path"]):
1423
+ with self.content.header_guard(self._item["path"],
1424
+ self.get_header_guard()):
1360
1425
  exp_mapper = OptionExpressionMapper(self._option_expressions,
1361
1426
  self._item)
1362
1427
  includes = [
@@ -1383,6 +1448,16 @@ class _HeaderFile:
1383
1448
  for node in self._get_nodes_in_dependency_order():
1384
1449
  self.content.add(node.content)
1385
1450
 
1451
+ def get_header_guard(self) -> Optional[str]:
1452
+ """
1453
+ Get the header guard of the header file.
1454
+
1455
+ The ``header-guard`` attribute of the placement link of the header file
1456
+ states the guard. Returns None, if the guard is derived from the path.
1457
+ """
1458
+ link = next(self._item.links_to_parents("interface-placement"))
1459
+ return link.data.get("header-guard", None)
1460
+
1386
1461
  def write(self, domain_path: Optional[str],
1387
1462
  file_path: Optional[str]) -> None:
1388
1463
  """ 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,9 @@ _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")
57
58
 
58
59
 
59
60
  def recursive_is_enabled(enabled_set: EnabledSet, item: Item) -> bool:
@@ -141,7 +142,8 @@ _VALIDATION_PARENT_ROLES = _PARENT_ROLES + ("interface-group-member", )
141
142
  _VISIT_CHILD_ROLES = _CHILD_ROLES + ("appl-config-group-member",
142
143
  "interface-placement")
143
144
 
144
- _VISIT_PARENT_ROLES = _VALIDATION_PARENT_ROLES + ("register-block-host", )
145
+ _VISIT_PARENT_ROLES = _VALIDATION_PARENT_ROLES + ("interface-host",
146
+ "register-block-host")
145
147
 
146
148
 
147
149
  def _visit_tree(item: Item, related_items: set[Item]) -> None:
@@ -171,8 +173,8 @@ _EXPORT_CHILD_ROLES = ("interface-function", "interface-placement",
171
173
  "test-case", "validation")
172
174
 
173
175
  _EXPORT_PARENT_ROLES = _PARENT_ROLES + (
174
- "constraint", "errno", "register-block-base", "register-block-host",
175
- "register-block-include")
176
+ "constraint", "interface-host", "errno", "register-block-base",
177
+ "register-block-host", "register-block-include")
176
178
 
177
179
  # Items reached through the shallow roles contribute to the generated content
178
180
  # 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