source: rtems-central/rtemsspec/interfacedoc.py @ e49c759

Last change on this file since e49c759 was e49c759, checked in by Sebastian Huber <sebastian.huber@…>, on 07/15/20 at 08:04:25

Rename "rtemsqual" in "rtemsspec"

  • Property mode set to 100644
File size: 8.5 KB
Line 
1# SPDX-License-Identifier: BSD-2-Clause
2"""
3This module provides functions for the generation of interface documentation.
4"""
5
6# Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de)
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27# POSSIBILITY OF SUCH DAMAGE.
28
29import os
30from typing import Any, Callable, Dict, List
31
32from rtemsspec.content import CContent, enabled_by_to_exp, ExpressionMapper
33from rtemsspec.sphinxcontent import get_label, get_reference, SphinxContent, \
34     SphinxMapper
35from rtemsspec.items import Item, ItemCache, ItemGetValueContext, ItemMapper
36
37ItemMap = Dict[str, Item]
38AddDefinition = Callable[[CContent, ItemMapper, Item, Dict[str, Any]], None]
39
40INTERFACE = "Interface"
41
42
43def _forward_declaration(item: Item) -> str:
44    target = next(item.parents("interface-target"))
45    return f"{target['interface-type']} {target['name']}"
46
47
48def _get_reference(name: str) -> str:
49    return get_reference(get_label(f"{INTERFACE}{name}"), f"{name}()")
50
51
52def _get_value_forward_declaration(ctx: ItemGetValueContext) -> Any:
53    return _forward_declaration(ctx.item)
54
55
56class _CodeMapper(ItemMapper):
57    def __init__(self, item: Item):
58        super().__init__(item)
59        self.add_get_value("interface/forward-declaration:/name",
60                           _get_value_forward_declaration)
61
62
63def _get_value_function(ctx: ItemGetValueContext) -> Any:
64    return _get_reference(ctx.value[ctx.key])
65
66
67class _Mapper(SphinxMapper):
68    def __init__(self, item: Item):
69        super().__init__(item)
70        self.add_get_value("interface/function:/name", _get_value_function)
71
72
73def _generate_introduction(target: str, group: Item,
74                           items: List[Item]) -> None:
75    content = SphinxContent()
76    content.register_license_and_copyrights_of_item(group)
77    group_name = group["name"]
78    with content.section("Introduction", get_label(group_name)):
79        content.append("")
80        content.gap = False
81        content.wrap(group["brief"])
82        content.wrap(group["description"])
83        content.paste(f"The directives provided by the {group_name} are:")
84        for item in items:
85            content.register_license_and_copyrights_of_item(item)
86            name = item["name"]
87            brief = item["brief"]
88            if brief:
89                brief = f" - {brief}"
90            else:
91                brief = ""
92            ref = _get_reference(name)
93            content.add_list_item(f"{ref}{brief}")
94    content.add_licence_and_copyrights()
95    content.write(target)
96
97
98def _add_function_definition(content: CContent, mapper: ItemMapper, item: Item,
99                             value: Dict[str, Any]) -> None:
100    name = item["name"]
101    ret = mapper.substitute(value["return"])
102    params = [mapper.substitute(param) for param in value["params"]]
103    content.declare_function(ret, name, params)
104
105
106def _add_definition(content: CContent, mapper: ItemMapper, item: Item,
107                    prefix: str, value: Dict[str, Any],
108                    add_definition: AddDefinition) -> None:
109    # pylint: disable=too-many-arguments
110    assert item["interface-type"] == "function"
111    default = value["default"]
112    variants = value["variants"]
113    if variants:
114        ifelse = "#if "
115        with mapper.prefix(os.path.join(prefix, "variants")):
116            for variant in variants:
117                enabled_by = enabled_by_to_exp(variant["enabled-by"],
118                                               ExpressionMapper())
119                content.append(f"{ifelse}{enabled_by}")
120                with content.indent():
121                    add_definition(content, mapper, item,
122                                   variant["definition"])
123                ifelse = "#elif "
124        if default is not None:
125            content.append("#else")
126            with mapper.prefix(os.path.join(prefix, "default")):
127                with content.indent():
128                    add_definition(content, mapper, item, default)
129        content.append("#endif")
130    else:
131        with mapper.prefix(os.path.join(prefix, "default")):
132            add_definition(content, mapper, item, default)
133
134
135def _generate_directives(target: str, group: Item, items: List[Item]) -> None:
136    content = SphinxContent()
137    content.register_license_and_copyrights_of_item(group)
138    group_name = group["name"]
139    with content.section("Directives", get_label(group_name)):
140        for item in items:
141            content.register_license_and_copyrights_of_item(item)
142            name = item["name"]
143            code_mapper = _CodeMapper(item)
144            mapper = _Mapper(item)
145            with content.section(f"{name}()", "Interface"):
146                content.wrap(item["brief"])
147                with content.definition_item("CALLING SEQUENCE:"):
148                    with content.directive("code-block", "c"):
149                        code = CContent()
150                        _add_definition(code, code_mapper, item, "definition",
151                                        item["definition"],
152                                        _add_function_definition)
153                        content.add(code)
154                if item["params"]:
155                    with content.definition_item("DIRECTIVE PARAMETERS:"):
156                        for param in item["params"]:
157                            content.add_definition_item(
158                                mapper.substitute(param["name"]),
159                                mapper.substitute(
160                                    f"This parameter {param['description']}"),
161                                wrap=True)
162                ret = item["return"]
163                if ret["return"] or ret["return-values"]:
164                    with content.definition_item("DIRECTIVE RETURN VALUES:"):
165                        if ret["return-values"]:
166                            for retval in ret["return-values"]:
167                                content.add_definition_item(
168                                    mapper.substitute(str(retval["value"])),
169                                    mapper.substitute(retval["description"]),
170                                    wrap=True)
171                        content.wrap(mapper.substitute(ret["return"]))
172                content.add_definition_item("DESCRIPTION:",
173                                            mapper.substitute(
174                                                item["description"]),
175                                            wrap=True)
176                content.add_definition_item("NOTES:",
177                                            mapper.substitute(item["notes"]),
178                                            wrap=True)
179    content.add_licence_and_copyrights()
180    content.write(target)
181
182
183def generate(config: list, item_cache: ItemCache) -> None:
184    """
185    Generates interface documentation according to the configuration.
186
187    :param config: A dictionary with configuration entries.
188    :param item_cache: The specification item cache containing the interfaces.
189    """
190    for doc_config in config:
191        items = []  # type: List[Item]
192        group = item_cache[doc_config["group"]]
193        assert group["type"] == "interface"
194        assert group["interface-type"] == "group"
195        for child in group.children("interface-ingroup"):
196            if child["interface-type"] in ["function"]:
197                items.append(child)
198        items.sort(key=lambda x: x["name"])
199        _generate_introduction(doc_config["introduction-target"], group, items)
200        _generate_directives(doc_config["directives-target"], group, items)
Note: See TracBrowser for help on using the repository browser.