diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2023-05-05 14:41:20 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2023-05-08 21:58:56 +0200 |
commit | 7d0fb472cce3077f6f99f4ce6e37b5fd0a1624f4 (patch) | |
tree | 388846aaf3464307d65808b7652c47a9d136346c | |
parent | validation: Add group for performance measurements (diff) | |
download | rtems-central-7d0fb472cce3077f6f99f4ce6e37b5fd0a1624f4.tar.bz2 |
interface: Discard non-options in enabled-by
-rw-r--r-- | rtemsspec/interface.py | 109 | ||||
-rw-r--r-- | rtemsspec/tests/spec-interface/h.yml | 26 | ||||
-rw-r--r-- | rtemsspec/tests/spec-interface/h9.yml | 13 | ||||
-rw-r--r-- | rtemsspec/tests/test_interface.py | 4 |
4 files changed, 117 insertions, 35 deletions
diff --git a/rtemsspec/interface.py b/rtemsspec/interface.py index d5ed395d..6a11f1c3 100644 --- a/rtemsspec/interface.py +++ b/rtemsspec/interface.py @@ -128,7 +128,7 @@ class _InterfaceMapper(ItemMapper): Maps an item-level enabled-by attribute value to the corresponding defined expression. """ - return self._node.header_file.enabled_by_defined[enabled_by] + return self._node.header_file.options[enabled_by] class _InterfaceExpressionMapper(ExpressionMapper): @@ -142,6 +142,47 @@ class _InterfaceExpressionMapper(ExpressionMapper): return self._mapper.substitute(symbol) +def _filter_op_binary(op_name: str, options: Dict[str, str], + enabled_by: Any) -> Any: + new_enabled_by = [] + for next_enabled_by in enabled_by: + exp = _discard_non_options(options, next_enabled_by) + if exp is not None: + new_enabled_by.append(exp) + if len(new_enabled_by) == 0: + return None + if len(new_enabled_by) == 1: + return new_enabled_by[0] + return {op_name: new_enabled_by} + + +def _filter_op_not(options: Dict[str, str], enabled_by: Any) -> Any: + exp = _discard_non_options(options, enabled_by) + if exp is None: + return None + return {"not": exp} + + +_FILTER_OP = { + "and": functools.partial(_filter_op_binary, "and"), + "not": _filter_op_not, + "or": functools.partial(_filter_op_binary, "or") +} + + +def _discard_non_options(options: Dict[str, str], enabled_by: Any) -> Any: + if isinstance(enabled_by, bool): + return enabled_by + if isinstance(enabled_by, list): + return _filter_op_binary("or", options, enabled_by) + if isinstance(enabled_by, dict): + key, value = next(iter(enabled_by.items())) + return _FILTER_OP[key](options, value) # type: ignore + if enabled_by in options: + return enabled_by + return None + + class _ItemLevelExpressionMapper(ExpressionMapper): def __init__(self, mapper: _InterfaceMapper): @@ -156,13 +197,13 @@ class _ItemLevelExpressionMapper(ExpressionMapper): class _HeaderExpressionMapper(ExpressionMapper): - def __init__(self, item: Item, enabled_by_defined: Dict[str, str]): + def __init__(self, item: Item, options: Dict[str, str]): super().__init__() self._mapper = ItemMapper(item) - self._enabled_by_defined = enabled_by_defined + self._options = options def map_symbol(self, symbol: str) -> str: - return self._mapper.substitute(self._enabled_by_defined[symbol]) + return self._mapper.substitute(self._options[symbol]) def _add_definition(node: "Node", item: Item, prefix: str, @@ -283,8 +324,10 @@ class Node: def generate(self) -> None: """ Generates a node to generate the node content. """ - enabled_by = self.item["enabled-by"] - if not isinstance(enabled_by, bool) or not enabled_by: + enabled_by = _discard_non_options(self.header_file.options, + self.item["enabled-by"]) + if enabled_by is not None and (not isinstance(enabled_by, bool) + or not enabled_by): mapper = _ItemLevelExpressionMapper(self.mapper) self.content.add(f"#if {enabled_by_to_exp(enabled_by, mapper)}") with self.content.indent(): @@ -723,9 +766,9 @@ def _bubble_sort(nodes: List[Node]) -> List[Node]: return nodes -def _merge_enabled_by(link: Link) -> Any: - enabled_by = link["enabled-by"] - enabled_by_2 = link.item["enabled-by"] +def _merge_enabled_by(options: Dict[str, str], link: Link) -> Any: + enabled_by = _discard_non_options(options, link["enabled-by"]) + enabled_by_2 = _discard_non_options(options, link.item["enabled-by"]) if enabled_by == enabled_by_2: return enabled_by if isinstance(enabled_by, bool): @@ -739,16 +782,10 @@ def _merge_enabled_by(link: Link) -> Any: return {"and": [enabled_by, enabled_by_2]} -def _combine_enabled_by(item: Item, enabled_by: Any) -> Any: - if enabled_by == item["enabled-by"]: - return True - return enabled_by - - class _HeaderFile: """ A header file. """ - def __init__(self, item: Item, enabled_by_defined: Dict[str, str], + def __init__(self, item: Item, options: Dict[str, str], enabled: List[str]): self._item = item self._content = CContent() @@ -756,7 +793,7 @@ class _HeaderFile: self._ingroups = _get_ingroups(item) self._includes: List[Item] = [] self._nodes: Dict[str, Node] = {} - self.enabled_by_defined = enabled_by_defined + self.options = options self.enabled = enabled def add_includes(self, item: Item) -> None: @@ -826,6 +863,13 @@ class _HeaderFile: return _bubble_sort(nodes_in_dependency_order) + def _combine_enabled_by(self, enabled_by: Any) -> Any: + enabled_by_2 = _discard_non_options(self.options, + self._item["enabled-by"]) + if enabled_by == enabled_by_2 or enabled_by is None: + return True + return enabled_by + def finalize(self) -> None: """ Finalizes the header file. """ self._content.prepend_spdx_license_identifier() @@ -836,13 +880,14 @@ class _HeaderFile: self._content.add_automatically_generated_warning() self._content.add(f"/* Generated from spec:{self._item.uid} */") with self._content.header_guard(self._item["path"]): - exp_mapper = _HeaderExpressionMapper(self._item, - self.enabled_by_defined) + exp_mapper = _HeaderExpressionMapper(self._item, self.options) includes = [ CInclude( item["path"], enabled_by_to_exp( - _combine_enabled_by(self._item, item["enabled-by"]), + self._combine_enabled_by( + _discard_non_options(self.options, + item["enabled-by"])), exp_mapper)) for item in self._includes if item != self._item ] @@ -850,8 +895,8 @@ class _HeaderFile: CInclude( link.item["path"], enabled_by_to_exp( - _combine_enabled_by(self._item, - _merge_enabled_by(link)), + self._combine_enabled_by( + _merge_enabled_by(self.options, link)), exp_mapper)) for link in self._item.links_to_parents("interface-include") ]) @@ -868,28 +913,27 @@ class _HeaderFile: def _generate_header_file(item: Item, domains: Dict[str, str], - enabled_by_defined: Dict[str, str], - enabled: List[str]) -> None: + options: Dict[str, str], enabled: List[str]) -> None: domain = item.parent("interface-placement") assert domain["interface-type"] == "domain" domain_path = domains.get(domain.uid, None) if domain_path is None: return - header_file = _HeaderFile(item, enabled_by_defined, enabled) + header_file = _HeaderFile(item, options, enabled) header_file.generate_nodes() header_file.finalize() header_file.write(domain_path) -def _gather_enabled_by_defined(item_level_interfaces: List[str], - item_cache: ItemCache) -> Dict[str, str]: - enabled_by_defined: Dict[str, str] = {} +def _gather_options(item_level_interfaces: List[str], + item_cache: ItemCache) -> Dict[str, str]: + options: Dict[str, str] = {} for uid in item_level_interfaces: for child in item_cache[uid].children("interface-ingroup"): if child.type == "interface/unspecified-define": define = f"defined(${{{child.uid}:/name}})" - enabled_by_defined[child["name"]] = define - return enabled_by_defined + options[child["name"]] = define + return options def generate(config: dict, item_cache: ItemCache) -> None: @@ -901,7 +945,6 @@ def generate(config: dict, item_cache: ItemCache) -> None: """ domains = config["domains"] enabled = config["enabled"] - enabled_by_defined = _gather_enabled_by_defined( - config["item-level-interfaces"], item_cache) + options = _gather_options(config["item-level-interfaces"], item_cache) for item in item_cache.items_by_type.get("interface/header-file", []): - _generate_header_file(item, domains, enabled_by_defined, enabled) + _generate_header_file(item, domains, options, enabled) diff --git a/rtemsspec/tests/spec-interface/h.yml b/rtemsspec/tests/spec-interface/h.yml index 01118207..ec273a6b 100644 --- a/rtemsspec/tests/spec-interface/h.yml +++ b/rtemsspec/tests/spec-interface/h.yml @@ -2,11 +2,27 @@ SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause brief: This header file defines X. copyrights: - Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) -enabled-by: RTEMS_SMP +enabled-by: +- and: + - RTEMS_SMP + - blub +- foobar +- not: + and: + - foo + - bar index-entries: [] interface-type: header-file links: -- enabled-by: RTEMS_SMP +- enabled-by: + - and: + - RTEMS_SMP + - blub + - foobar + - not: + and: + - foo + - bar role: interface-include uid: h2 - enabled-by: [] @@ -35,6 +51,12 @@ links: - enabled-by: ASM role: interface-include uid: h8 +- enabled-by: + - not: ASM + - RTEMS_SMP + - blub + role: interface-include + uid: h9 - role: interface-placement uid: domain-abc - role: interface-ingroup diff --git a/rtemsspec/tests/spec-interface/h9.yml b/rtemsspec/tests/spec-interface/h9.yml new file mode 100644 index 00000000..7b23ca37 --- /dev/null +++ b/rtemsspec/tests/spec-interface/h9.yml @@ -0,0 +1,13 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +brief: H9. +copyrights: +- Copyright (C) 2023 embedded brains GmbH & Co. KG +enabled-by: true +index-entries: [] +interface-type: header-file +links: +- role: interface-placement + uid: domain-abc +path: h9.h +prefix: include +type: interface diff --git a/rtemsspec/tests/test_interface.py b/rtemsspec/tests/test_interface.py index 5a4d972e..f1131784 100644 --- a/rtemsspec/tests/test_interface.py +++ b/rtemsspec/tests/test_interface.py @@ -114,6 +114,10 @@ def test_interface(tmpdir): #include <math.h> #include <stdint.h> +#if !defined(ASM) || defined(RTEMS_SMP) + #include <h9.h> +#endif + #if 0 #include <h5.h> #include <h6.h> |