[rtems-central commit] items: Enable custom get value for lists

Sebastian Huber sebh at rtems.org
Tue Dec 1 13:38:26 UTC 2020


Module:    rtems-central
Branch:    master
Commit:    e165b7d684ec73f1010be3c53d73dbf990f9ac4e
Changeset: http://git.rtems.org/rtems-central/commit/?id=e165b7d684ec73f1010be3c53d73dbf990f9ac4e

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Tue Dec  1 12:07:29 2020 +0100

items: Enable custom get value for lists

---

 rtemsspec/applconfig.py                 | 34 +++++++++---------------
 rtemsspec/interface.py                  | 41 ++++++++++++++---------------
 rtemsspec/items.py                      | 46 +++++++++++++++------------------
 rtemsspec/tests/test_items_itemcache.py | 11 ++++----
 4 files changed, 59 insertions(+), 73 deletions(-)

diff --git a/rtemsspec/applconfig.py b/rtemsspec/applconfig.py
index 51f5736..6e3691c 100644
--- a/rtemsspec/applconfig.py
+++ b/rtemsspec/applconfig.py
@@ -321,10 +321,6 @@ def _generate(group: Item, options: ItemMap, content: _ContentAdaptor) -> None:
     content.add_licence_and_copyrights()
 
 
-def _get_value_none(_ctx: ItemGetValueContext) -> Any:
-    return None
-
-
 def _sphinx_ref(ref: str) -> str:
     return f":ref:`{ref}`"
 
@@ -354,17 +350,14 @@ _SPHINX_DOC_REFS = {
 }
 
 
-def _get_value_sphinx_reference(ctx: ItemGetValueContext) -> Any:
-    return _SPHINX_DOC_REFS[ctx.key]
+def _get_value_sphinx_reference(_ctx: ItemGetValueContext) -> Any:
+    return _SPHINX_DOC_REFS
 
 
 def _add_sphinx_get_values(mapper: ItemMapper) -> None:
-    for key in _SPHINX_DOC_REFS:
-        for opt in ["feature-enable", "feature", "initializer", "integer"]:
-            doc_ref = f"interface/appl-config-option/{opt}:/document-reference"
-            mapper.add_get_value(doc_ref, _get_value_none)
-            mapper.add_get_value(f"{doc_ref}/{key}",
-                                 _get_value_sphinx_reference)
+    for opt in ["feature-enable", "feature", "initializer", "integer"]:
+        doc_ref = f"interface/appl-config-option/{opt}:/document-reference"
+        mapper.add_get_value(doc_ref, _get_value_sphinx_reference)
 
 
 def _c_user_ref(ref: str, name: str) -> str:
@@ -427,8 +420,8 @@ _DOXYGEN_DOC_REFS = {
 }
 
 
-def _get_value_doxygen_reference(ctx: ItemGetValueContext) -> Any:
-    return _DOXYGEN_DOC_REFS[ctx.key]
+def _get_value_doxygen_reference(_ctx: ItemGetValueContext) -> Any:
+    return _DOXYGEN_DOC_REFS
 
 
 def _get_value_doxygen_url(ctx: ItemGetValueContext) -> Any:
@@ -448,14 +441,11 @@ def _get_value_doxygen_unspecfied_type(ctx: ItemGetValueContext) -> Any:
 
 
 def _add_doxygen_get_values(mapper: ItemMapper) -> None:
-    for key in _DOXYGEN_DOC_REFS:
-        for opt in ["feature-enable", "feature", "initializer", "integer"]:
-            doc_ref = f"interface/appl-config-option/{opt}:/document-reference"
-            mapper.add_get_value(doc_ref, _get_value_none)
-            mapper.add_get_value(f"{doc_ref}/{key}",
-                                 _get_value_doxygen_reference)
-            name = f"interface/appl-config-option/{opt}:/name"
-            mapper.add_get_value(name, get_value_hash)
+    for opt in ["feature-enable", "feature", "initializer", "integer"]:
+        doc_ref = f"interface/appl-config-option/{opt}:/document-reference"
+        mapper.add_get_value(doc_ref, _get_value_doxygen_reference)
+        name = f"interface/appl-config-option/{opt}:/name"
+        mapper.add_get_value(name, get_value_hash)
     mapper.add_get_value("interface/define:/name", get_value_hash)
     mapper.add_get_value("interface/function:/name",
                          get_value_doxygen_function)
diff --git a/rtemsspec/interface.py b/rtemsspec/interface.py
index 87e6f8b..0453623 100644
--- a/rtemsspec/interface.py
+++ b/rtemsspec/interface.py
@@ -31,7 +31,8 @@ from typing import Any, Callable, Dict, Iterator, List, Union, Set
 from rtemsspec.content import CContent, CInclude, enabled_by_to_exp, \
     ExpressionMapper, get_value_double_colon, get_value_doxygen_function, \
     get_value_hash
-from rtemsspec.items import Item, ItemCache, ItemGetValueContext, ItemMapper
+from rtemsspec.items import Item, ItemCache, ItemGetValueContext, \
+    ItemGetValueMap, ItemMapper
 
 ItemMap = Dict[str, Item]
 Lines = Union[str, List[str]]
@@ -63,25 +64,25 @@ class _InterfaceMapper(ItemMapper):
         super().__init__(node.item)
         self._node = node
         self._code_or_doc = "doc"
-        self.add_get_value("interface/forward-declaration:code:/name",
+        self.add_get_value("interface/forward-declaration/code:/name",
                            _get_value_forward_declaration)
-        self.add_get_value("interface/forward-declaration:doc:/name",
+        self.add_get_value("interface/forward-declaration/doc:/name",
                            _get_value_forward_declaration)
-        self.add_get_value("interface/function:doc:/name",
+        self.add_get_value("interface/function/doc:/name",
                            get_value_doxygen_function)
-        self.add_get_value("interface/enumerator:doc:/name",
+        self.add_get_value("interface/enumerator/doc:/name",
                            get_value_double_colon)
-        self.add_get_value("interface/typedef:doc:/name",
+        self.add_get_value("interface/typedef/doc:/name",
                            get_value_double_colon)
-        self.add_get_value("interface/define:doc:/name", get_value_hash)
-        self.add_get_value("interface/enum:doc:/name", get_value_hash)
-        self.add_get_value("interface/macro:doc:/name",
+        self.add_get_value("interface/define/doc:/name", get_value_hash)
+        self.add_get_value("interface/enum/doc:/name", get_value_hash)
+        self.add_get_value("interface/macro/doc:/name",
                            get_value_doxygen_function)
-        self.add_get_value("interface/variable:doc:/name", get_value_hash)
+        self.add_get_value("interface/variable/doc:/name", get_value_hash)
         for opt in ["feature-enable", "feature", "initializer", "integer"]:
-            name = f"interface/appl-config-option/{opt}:doc:/name"
+            name = f"interface/appl-config-option/{opt}/doc:/name"
             self.add_get_value(name, get_value_hash)
-        self.add_get_value("interface/unspecified-function:doc:/name",
+        self.add_get_value("interface/unspecified-function/doc:/name",
                            get_value_doxygen_function)
 
     @contextmanager
@@ -92,19 +93,17 @@ class _InterfaceMapper(ItemMapper):
         yield
         self._code_or_doc = code_or_doc
 
-    def get_value(self, ctx: ItemGetValueContext) -> Any:
-        if self._code_or_doc == "code" and ctx.item["type"] == "interface":
+    def get_value_map(self, item: Item) -> ItemGetValueMap:
+        if self._code_or_doc == "code" and item["type"] == "interface":
             node = self._node
             header_file = node.header_file
-            if ctx.item["interface-type"] == "enumerator":
-                for child in ctx.item.children("interface-enumerator"):
+            if item["interface-type"] == "enumerator":
+                for child in item.children("interface-enumerator"):
                     header_file.add_includes(child)
             else:
-                header_file.add_includes(ctx.item)
-            header_file.add_dependency(node, ctx.item)
-        return super().get_value(
-            ItemGetValueContext(ctx.item, f"{self._code_or_doc}:{ctx.path}",
-                                ctx.value, ctx.key, ctx.index))
+                header_file.add_includes(item)
+            header_file.add_dependency(node, item)
+        return self._get_value_map.get(f"{item.type}/{self._code_or_doc}", {})
 
     def enabled_by_to_defined(self, enabled_by: str) -> str:
         """
diff --git a/rtemsspec/items.py b/rtemsspec/items.py
index 5b7a95a..12ecfb4 100644
--- a/rtemsspec/items.py
+++ b/rtemsspec/items.py
@@ -42,14 +42,10 @@ class ItemGetValueContext(NamedTuple):
     key: str
     index: Any  # should be int, but this triggers a mypy error
 
-    @property
-    def type_path_key(self) -> str:
-        """ Returns the item type followed the path to the key. """
-        return f"{self.item.type}:{os.path.join(self.path, self.key)}"
-
 
 ItemMap = Dict[str, "Item"]
 ItemGetValue = Callable[[ItemGetValueContext], Any]
+ItemGetValueMap = Dict[str, Tuple[ItemGetValue, Any]]
 
 
 def _is_enabled_op_and(enabled: List[str], enabled_by: Any) -> bool:
@@ -185,10 +181,8 @@ class Item:
         """
         return self._data.get(key, default)
 
-    def get_by_normalized_key_path(
-            self,
-            normalized_key_path: str,
-            get_value: ItemGetValue = _get_value) -> Any:
+    def get_by_normalized_key_path(self, normalized_key_path: str,
+                                   get_value_map: ItemGetValueMap) -> Any:
         """
         Gets the attribute value corresponding to the normalized key path.
         """
@@ -201,20 +195,16 @@ class Item:
             except IndexError:
                 index = -1
             ctx = ItemGetValueContext(self, path, value, parts[0], index)
-            try:
-                value = get_value(ctx)
-            except KeyError:
-                value = _get_value(ctx)
+            get_value, get_value_map = get_value_map.get(
+                parts[0], (_get_value, {}))
+            value = get_value(ctx)
             path = os.path.join(path, key)
         return value
 
-    def get_by_key_path(self,
-                        key_path: str,
-                        prefix: str = "",
-                        get_value: ItemGetValue = _get_value) -> Any:
+    def get_by_key_path(self, key_path: str, prefix: str = "") -> Any:
         """ Gets the attribute value corresponding to the key path. """
         return self.get_by_normalized_key_path(
-            normalize_key_path(key_path, prefix), get_value)
+            normalize_key_path(key_path, prefix), {})
 
     @property
     def uid(self) -> str:
@@ -378,7 +368,7 @@ class ItemMapper(Mapping[str, object]):
         self._item = item
         self._recursive = recursive
         self._prefix = [""]
-        self._get_value = {}  # type: Dict[str, ItemGetValue]
+        self._get_value_map = {}  # type: Dict[str, ItemGetValueMap]
 
     @property
     def item(self) -> Item:
@@ -395,7 +385,12 @@ class ItemMapper(Mapping[str, object]):
         """
         Adds a get value for the specified type and key path.
         """
-        self._get_value[type_path_key] = get_value
+        type_name, path_key = type_path_key.split(":")
+        keys = path_key.strip("/").split("/")
+        get_value_map = self._get_value_map.setdefault(type_name, {})
+        for key in keys[:-1]:
+            _, get_value_map = get_value_map.setdefault(key, (_get_value, {}))
+        get_value_map[keys[-1]] = (get_value, {})
 
     def push_prefix(self, prefix: str) -> None:
         """ Pushes a key path prefix. """
@@ -412,6 +407,10 @@ class ItemMapper(Mapping[str, object]):
         yield
         self.pop_prefix()
 
+    def get_value_map(self, item: Item) -> ItemGetValueMap:
+        """ Returns the get value map for the item. """
+        return self._get_value_map.get(item.type, {})
+
     def map(self, identifier: str) -> Tuple[Item, str, Any]:
         """
         Maps an identifier to the corresponding item and attribute value.
@@ -429,7 +428,8 @@ class ItemMapper(Mapping[str, object]):
             item = self._item.map(uid)
             prefix = ""
         key_path = normalize_key_path(key_path, prefix)
-        value = item.get_by_normalized_key_path(key_path, self.get_value)
+        value = item.get_by_normalized_key_path(key_path,
+                                                self.get_value_map(item))
         for func in pipes:
             value = getattr(self, func)(value)
         return item, key_path, value
@@ -472,10 +472,6 @@ class ItemMapper(Mapping[str, object]):
         with self.prefix(prefix):
             return ItemTemplate(text).substitute(self)
 
-    def get_value(self, ctx: ItemGetValueContext) -> Any:
-        """ Gets a value by key and optional index. """
-        return self._get_value[ctx.type_path_key](ctx)
-
 
 class _SpecType(NamedTuple):
     key: str
diff --git a/rtemsspec/tests/test_items_itemcache.py b/rtemsspec/tests/test_items_itemcache.py
index 05affc2..4331b33 100644
--- a/rtemsspec/tests/test_items_itemcache.py
+++ b/rtemsspec/tests/test_items_itemcache.py
@@ -96,6 +96,11 @@ expected <block end>, but found ':'
         ItemCache(config)
 
 
+def get_x_to_b_value(ctx):
+    assert ctx.key == "x-to-b"
+    return ctx.value["b"]
+
+
 class Mapper(ItemMapper):
     def __init__(self, item):
         super().__init__(item)
@@ -109,11 +114,6 @@ class Mapper(ItemMapper):
     def dup(self, value):
         return value + value
 
-    def get_value(self, ctx):
-        if ctx.key == "x-to-b":
-            return ctx.value["b"]
-        raise KeyError
-
 
 def test_item_mapper(tmpdir):
     config = create_item_cache_config_and_copy_spec(tmpdir, "spec-item-cache")
@@ -141,6 +141,7 @@ def test_item_mapper(tmpdir):
     assert mapper["d/c:v"] == "c"
     assert mapper["d/c:a/b"] == "e"
     assert mapper["d/c:a/b|u"] == "ue"
+    mapper.add_get_value(":/a/x-to-b", get_x_to_b_value)
     assert mapper["d/c:a/x-to-b|u|v"] == "vue"
     assert mapper["d/c:a/f[1]"] == 2
     assert mapper["d/c:a/../a/f[3]/g[0]|dup"] == 8



More information about the vc mailing list