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

DesignUnit

42

41

1

97.6%

Directive

25

24

1

96.0%

Frontend

16

16

0

100.0%

Index

24

24

0

100.0%

Pages

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	"""
	...