VHDLDomain
Summary
- Doc-string:
documented
File |
Expected |
Covered |
Uncovered |
Coverage |
|---|---|---|---|---|
__init__.py |
35 |
34 |
1 |
97.1% |
Overall (6 files) |
157 |
154 |
3 |
98.1% |
Modules
Module |
Expected |
Covered |
Uncovered |
Coverage |
|---|---|---|---|---|
42 |
41 |
1 |
97.6% |
|
25 |
24 |
1 |
96.0% |
|
16 |
16 |
0 |
100.0% |
|
24 |
24 |
0 |
100.0% |
|
15 |
15 |
0 |
100.0% |
Source
VHDLDomain/__init__.pydocumentedundocumentedignoredexcludednot counted
32"""
33**A Sphinx domain providing VHDL language support.**
34
35The domain ``vhdl`` documents VHDL designs from their model, a :class:`pyVHDLModel.Design`. The designs are declared
36in :file:`conf.py` (see :mod:`VHDLDomain.Frontend`) and read when the builder is initialized; a directive describes a
37design, a library or a design unit from the model, and a role refers to what a directive described.
38
39.. code-block:: rst
40
41 .. vhdl:design:: StopWatch
42
43 .. vhdl:library:: lib_StopWatch
44
45 The entity :vhdl:ent:`Counter` counts clock cycles.
46
47.. rubric:: What it registers
48
49* Directives: ``vhdl:design``, ``vhdl:library``, ``vhdl:context``, ``vhdl:entity``, ``vhdl:package``,
50 ``vhdl:configuration``
51* Roles: ``:vhdl:design:``, ``:vhdl:lib:``, ``:vhdl:ctx:``, ``:vhdl:ent:``, ``:vhdl:arch:``, ``:vhdl:pack:``,
52 ``:vhdl:config:``, ``:vhdl:type:``, ``:vhdl:const:``, ``:vhdl:func:``, ``:vhdl:proc:``, ``:vhdl:generic:``,
53 ``:vhdl:port:``
54* Indices: ``vhdl-entities``, ``vhdl-packages``, ``vhdl-subprograms``, ``vhdl-types``
55* Configuration value ``vhdl_designs``
56* Generated pages per library and design unit, for a design declared with ``pages`` (see :mod:`VHDLDomain.Pages`)
57
58.. rubric:: Names
59
60An object's qualified name starts with its design and library, e.g. ``StopWatch.lib_StopWatch.Counter``; a reference
61names it by the qualified name, or by a part of it ending with the object's name, e.g. ``lib_StopWatch.Counter`` or
62``Counter``. A subprogram's name may end in its signature, the type marks of its parameters, e.g.
63``Utilities.to_index(natural, positive)``. A name matching several objects - also a subprogram's overloads without a
64signature - is resolved in the design and library of the last ``vhdl:design`` and ``vhdl:library`` before the
65reference, otherwise it is warned about. VHDL identifiers are case-insensitive, so are the names.
66
67.. admonition:: Copyright Information
68
69 :copyright: Copyright 2017-2026 Patrick Lehmann - Bötzingen, Germany
70 :copyright: Copyright 2016-2017 Patrick Lehmann - Dresden, Germany
71 :license: Apache License, Version 2.0
72"""
...
74
75__author__ = "Patrick Lehmann"
76__email__ = "Paebbels@gmail.com"
77__copyright__ = "2016-2026, Patrick Lehmann"
78__license__ = "Apache License, Version 2.0"
79__version__ = "0.2.0rc1"
80
...
106
108__all__ = ["OBJECT_TYPES", "ROLES"]
109
110_logger = getLogger(__name__)
111
112#: The object types: their display names, by object type.
113OBJECT_TYPES: dict[str, str] = {
114 "design": "design",
115 "library": "library",
116 "context": "context",
117 "entity": "entity",
118 "architecture": "architecture",
119 "package": "package",
120 "configuration": "configuration",
121 "type": "type",
122 "subtype": "subtype",
123 "constant": "constant",
124 "function": "function",
125 "procedure": "procedure",
126 "generic": "generic",
127 "port": "port",
128}
129
130#: The roles: the object types each refers to, by role name.
131ROLES: dict[str, tuple[str, ...]] = {
132 "design": ("design", ),
133 "lib": ("library", ),
134 "ctx": ("context", ),
135 "ent": ("entity", ),
136 "arch": ("architecture", ),
137 "pack": ("package", ),
138 "config": ("configuration", ),
139 "type": ("type", "subtype"),
140 "const": ("constant", ),
141 "func": ("function", ),
142 "proc": ("procedure", ),
143 "generic": ("generic", ),
144 "port": ("port", ),
145}
146
148@export
149def normalizeName(name: str) -> str:
150 """
151 Normalize an object's name for comparison: lower case, without white space.
152
153 VHDL identifiers are case-insensitive; white space may separate the type marks of a subprogram's signature.
154
155 :param name: The name.
156 :returns: The normalized name.
157 """
...
159
161@export
162class VHDLXRefRole(XRefRole):
163 """
164 A role of domain ``vhdl``, referring to an object a directive described.
165
166 The reference remembers the design and library current where it is written - set by ``vhdl:design`` and
167 ``vhdl:library`` -, so an ambiguous name is resolved in them. A leading ``~`` shows only the object's name, the last
168 part of the target.
169 """
170
171 def process_link(
172 self,
173 env: BuildEnvironment,
174 refnode: Element,
175 has_explicit_title: bool,
176 title: str,
177 target: str
178 ) -> tuple[str, str]:
179 """
180 Remember the current design and library on the reference, and shorten the title for a leading ``~``.
181
182 :param env: The build environment.
183 :param refnode: The reference node.
184 :param has_explicit_title: ``True``, if the role was written with a title, as ``text <target>``.
185 :param title: The title.
186 :param target: The target.
187 :returns: The title and the target.
188 """
...
196
198@export
199class VHDLDomain(Domain):
200 """
201 The Sphinx domain ``vhdl``, documenting VHDL designs from their model.
202
203 Its objects are keyed by object type and normalized qualified name - ``("entity", "stopwatch.lib_stopwatch.counter")``
204 - and located by document and anchor. The designs are no domain data, as the environment pickles the data: they are
205 read again by every build, and handed to the domain by :meth:`AddDesign`.
206 """
207
208 name = "vhdl" #: Name of the domain, the prefix of its directives and roles.
209 label = "VHDL" #: Name of the domain, as displayed.
210 data_version = 1 #: Version of the data layout; a change discards pickled environments.
211
212 object_types: ClassVar[dict[str, ObjType]] = {
213 objectType: ObjType(displayName, *[roleName for roleName, types in ROLES.items() if objectType in types])
214 for objectType, displayName in OBJECT_TYPES.items()
215 } #: The object types, each with the roles referring to it.
216
217 directives: ClassVar[dict[str, type]] = {
218 "design": DesignDirective,
219 "library": LibraryDirective,
220 "context": ContextDirective,
221 "entity": EntityDirective,
222 "package": PackageDirective,
223 "configuration": ConfigurationDirective,
224 } #: The directives, by name.
225
226 roles: ClassVar[dict[str, XRefRole]] = { # type: ignore[assignment]
227 roleName: VHDLXRefRole(innernodeclass=nodes.literal, warn_dangling=True) for roleName in ROLES
228 } #: The roles, by name.
229
230 indices: ClassVar[list[type[Index]]] = [
231 EntityIndex,
232 PackageIndex,
233 SubprogramIndex,
234 TypeIndex,
235 ] #: The indices, each a page ``vhdl-<name>``, e.g. ``vhdl-entities``.
236
237 dangling_warnings: ClassVar[dict[str, str]] = {
238 roleName: f"VHDL {' or '.join(OBJECT_TYPES[objectType] for objectType in types)} '%(target)s' not found"
239 for roleName, types in ROLES.items()
240 } #: The warning for a reference to an undocumented object, per role.
241
242 initial_data: ClassVar[dict[str, Any]] = {
243 "objects": {},
244 } #: The domain's data: ``objects`` maps (object type, normalized name) to (document, anchor, qualified name).
245
246 #: The configuration values the domain adds to :file:`conf.py`, as ``name: (default, rebuild, types)``. Each is
247 #: registered with the domain's name as prefix, e.g. ``vhdl_designs``.
248 #:
249 #: ``designs``
250 #: The designs to read, by name: the directory of the source files and the libraries' files, see
251 #: :mod:`VHDLDomain.Frontend`.
252 configValues: ClassVar[dict[str, tuple[Any, str, Any]]] = {
253 "designs": ({}, "env", dict),
254 }
255
256 _designs: dict[str, Design] #: The designs read by this build, by name.
257 _lookup: Nullable[dict[tuple[str, str], list[tuple[str, str]]]] #: Object keys by (object type, last name part).
258
259 def __init__(self, env: BuildEnvironment) -> None:
260 """
261 Initializes the domain.
262
263 :param env: The build environment.
264 """
...
269
270 @readonly
271 def Objects(self) -> dict[tuple[str, str], tuple[str, str, str]]:
272 """
273 Read-only property to return the documented objects.
274
275 :returns: A mapping of (object type, normalized qualified name) to (document, anchor, qualified name).
276 """
...
278
279 @readonly
280 def Designs(self) -> dict[str, Design]:
281 """
282 Read-only property to access the designs read by this build (:attr:`_designs`).
283
284 :returns: Dictionary of the designs, indexed by design name.
285 """
...
287
288 def AddDesign(self, name: str, design: Design, pages: Nullable[str] = None, source: Nullable[Path] = None) -> None:
289 """
290 Add a design, which the directives can describe, and generate its pages.
291
292 Besides the designs of ``vhdl_designs``, a design read by another frontend can be added, by a handler of Sphinx'
293 ``builder-inited`` event in :file:`conf.py`.
294
295 :param name: The design's name, as directives and roles name it.
296 :param design: The design.
297 :param pages: Optional, document name the design's pages are generated below. Default: ``None``,
298 no pages.
299 :param source: Optional, the file or directory Sphinx regards as the pages' source. Default:
300 ``None``, the Sphinx source directory.
301 :raises ValueError: If parameter 'name' is ``None`` or empty.
302 :raises TypeError: If parameter 'name' is not of type :class:`str`.
303 :raises ValueError: If parameter 'design' is ``None``.
304 :raises TypeError: If parameter 'design' is not of type :class:`~pyVHDLModel.Design`.
305 :raises VHDLDomainException: If a design of that name was added already.
306 """
...
330
331 def GetDesign(self, name: str) -> Nullable[Design]:
332 """
333 Return a design by name.
334
335 :param name: The design's name; case-insensitive.
336 :returns: The design, or ``None`` if no design of that name was added.
337 """
...
339
340 def NoteObject(self, objectType: str, qualifiedName: str, nodeID: str, location: Nullable[Node] = None) -> None:
341 """
342 Register a documented object.
343
344 An object described twice - e.g. by two directives - is warned about; the later description wins.
345
346 :param objectType: The object type, as ``entity``.
347 :param qualifiedName: The object's qualified name, as ``StopWatch.lib_StopWatch.Counter``.
348 :param nodeID: The anchor of the object's node.
349 :param location: Optional, the node a duplicate is reported at. Default: ``None``.
350 :raises ValueError: If parameter 'objectType' is not an object type of the domain.
351 """
...
368
369 def FindObjects(
370 self,
371 objectTypes: Iterable[str],
372 target: str,
373 design: Nullable[str] = None,
374 library: Nullable[str] = None
375 ) -> list[tuple[str, str]]:
376 """
377 Find the objects a reference's target names.
378
379 The target names an object by its qualified name or by a part of it ending with the object's name; it may end
380 in a subprogram's signature, which must match then: the same number of type marks, each a type mark of the
381 object's signature or a part of it ending with the type's name (``unsigned`` matches ``ieee.numeric_std.unsigned``).
382 A qualified name equal to the target wins over the others. Of several matches, those in the given design - and
383 then those in the given library - win.
384
385 :param objectTypes: The object types the reference's role refers to.
386 :param target: The reference's target.
387 :param design: Optional, the design current at the reference. Default: ``None``.
388 :param library: Optional, the library current at the reference. Default: ``None``.
389 :returns: The keys of the matching objects: none, one, or several if the name is ambiguous.
390 """
391 def signatureMatches(objectSignature: str, targetSignature: str) -> bool:
392 """
393 Nested function checking whether a target's signature names an object's signature, type mark by type mark.
394
395 :param objectSignature: The object's normalized signature, without the opening parenthesis.
396 :param targetSignature: The target's normalized signature, without the opening parenthesis.
397 :returns: ``True``, if every type mark of the target names the object's type mark at its position.
398 """
...
408
...
444
445 def clear_doc(self, docname: str) -> None:
446 """
447 Remove the objects of a document, before it is read again.
448
449 :param docname: The document.
450 """
...
456
457 def merge_domaindata(self, docnames: Iterable[str], otherdata: dict[str, Any]) -> None:
458 """
459 Merge the objects a parallel reader collected for its documents.
460
461 :param docnames: The documents the other reader read.
462 :param otherdata: The other reader's data.
463 """
...
471
472 def resolve_xref(
473 self,
474 env: BuildEnvironment,
475 fromdocname: str,
476 builder: Builder,
477 typ: str,
478 target: str,
479 node: addnodes.pending_xref,
480 contnode: Element
481 ) -> Nullable[Element]:
482 """
483 Resolve a reference by one of the domain's roles.
484
485 :param env: The build environment.
486 :param fromdocname: The document containing the reference.
487 :param builder: The builder.
488 :param typ: The role's name, as ``ent``.
489 :param target: The target, as ``lib_StopWatch.Counter``.
490 :param node: The pending reference.
491 :param contnode: The node rendering the reference's title.
492 :returns: The reference, the title if the name is ambiguous, or ``None`` if the target isn't documented.
493 """
...
510
511 def resolve_any_xref(
512 self,
513 env: BuildEnvironment,
514 fromdocname: str,
515 builder: Builder,
516 target: str,
517 node: addnodes.pending_xref,
518 contnode: Element
519 ) -> list[tuple[str, nodes.reference]]:
520 """
521 Resolve a reference by the ``:any:`` role, trying every role with an unambiguous match.
522
523 :param env: The build environment.
524 :param fromdocname: The document containing the reference.
525 :param builder: The builder.
526 :param target: The target.
527 :param node: The pending reference.
528 :param contnode: The node rendering the reference's title.
529 :returns: A pair of role and reference per role the target resolves for.
530 """
...
540
541 def get_objects(self) -> Iterator[tuple[str, str, str, str, str, int]]:
542 """
543 Iterate the documented objects, for the search index and the inventory.
544
545 :returns: An iterator of (name, display name, type, document, anchor, priority).
546 """
...
550
552@export
553def readDesigns(sphinx: Sphinx) -> None:
554 """
555 Call-back for Sphinx' ``builder-inited`` event, reading the designs of ``vhdl_designs`` into the domain.
556
557 A design, which can't be read, is logged as an error rather than stopping the build; a directive describing it warns
558 on its own.
559
560 :param sphinx: The Sphinx application.
561 """
...
571
573@export
574def setup(sphinx: Sphinx) -> dict[str, Any]:
575 """
576 Register the domain ``vhdl`` and its configuration values with Sphinx.
577
578 :param sphinx: The Sphinx application to register with.
579 :returns: The extension's metadata.
580 """
...