Coverage for pyVHDLModel/Base.py: 98%
422 statements
« prev ^ index » next coverage.py v7.17.0, created at 2026-10-25 10:05 +0000
« prev ^ index » next coverage.py v7.17.0, created at 2026-10-25 10:05 +0000
1# ==================================================================================================================== #
2# __ ___ _ ____ _ __ __ _ _ #
3# _ __ _ \ \ / / | | | _ \| | | \/ | ___ __| | ___| | #
4# | '_ \| | | \ \ / /| |_| | | | | | | |\/| |/ _ \ / _` |/ _ \ | #
5# | |_) | |_| |\ V / | _ | |_| | |___| | | | (_) | (_| | __/ | #
6# | .__/ \__, | \_/ |_| |_|____/|_____|_| |_|\___/ \__,_|\___|_| #
7# |_| |___/ #
8# ==================================================================================================================== #
9# Authors: #
10# Patrick Lehmann #
11# #
12# License: #
13# ==================================================================================================================== #
14# Copyright 2017-2026 Patrick Lehmann - Boetzingen, Germany #
15# Copyright 2016-2017 Patrick Lehmann - Dresden, Germany #
16# #
17# Licensed under the Apache License, Version 2.0 (the "License"); #
18# you may not use this file except in compliance with the License. #
19# You may obtain a copy of the License at #
20# #
21# http://www.apache.org/licenses/LICENSE-2.0 #
22# #
23# Unless required by applicable law or agreed to in writing, software #
24# distributed under the License is distributed on an "AS IS" BASIS, #
25# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
26# See the License for the specific language governing permissions and #
27# limitations under the License. #
28# #
29# SPDX-License-Identifier: Apache-2.0 #
30# ==================================================================================================================== #
31#
32"""
33This module contains parts of an abstract document language model for VHDL.
35Base-classes for the VHDL language model.
36"""
37from __future__ import annotations
39from enum import unique, Enum
40from typing import TYPE_CHECKING, ClassVar, Type, Iterable, Optional as Nullable, Union, cast, Self
42from pyTooling.Common import StringEnum, getFullyQualifiedName
43from pyTooling.Decorators import export, notimplemented, readonly
44from pyTooling.MetaClasses import ExtendedType, abstractclass
45if TYPE_CHECKING: 45 ↛ 46line 45 didn't jump to line 46 because the condition on line 45 was never true
46 from pyVHDLModel.Symbol import Symbol
47 from pyVHDLModel.Visitor import Visitor
50__all__ = ["ExpressionUnion", "ModelElementUnion"]
53ExpressionUnion = Union[
54 'BaseExpression',
55 'QualifiedExpression',
56 'FunctionCall',
57 'TypeConversion',
58 # ConstantOrSymbol, TODO: ObjectSymbol
59 'Literal',
60]
62ModelElementUnion = Union['ModelEntity', 'Symbol']
63"""
64A model element a visitor walks or the VHDL writer writes: a :class:`ModelEntity` or a
65:class:`~pyVHDLModel.Symbol.Symbol`.
66"""
69@export
70@unique
71class ReservedWord(StringEnum):
72 """
73 A ``ReservedWord`` is an enumeration of VHDL's reserved words (IEEE Std 1076-2019, 15.10).
75 A member is a :class:`str`: its value is the reserved word in lower case, e.g. ``ReservedWord.DownTo == "downto"``.
76 The VHDL writer (:mod:`pyVHDLModel.Formatting.VHDL`) applies the configured keyword case to it.
78 Each member states the revision of IEEE Std 1076 that first reserved it. Earlier revisions reserved words, which
79 VHDL-2019 doesn't: ``procedural`` and ``reference`` (VHDL-2000 and VHDL-2002), ``assume_guarantee`` and
80 ``restrict_guarantee`` (VHDL-2008).
81 """
83 Abs = "abs" #: Reserved word since VHDL-87.
84 Access = "access" #: Reserved word since VHDL-87.
85 After = "after" #: Reserved word since VHDL-87.
86 Alias = "alias" #: Reserved word since VHDL-87.
87 All = "all" #: Reserved word since VHDL-87.
88 And = "and" #: Reserved word since VHDL-87.
89 Architecture = "architecture" #: Reserved word since VHDL-87.
90 Array = "array" #: Reserved word since VHDL-87.
91 Assert = "assert" #: Reserved word since VHDL-87.
92 Assume = "assume" #: Reserved word since VHDL-2008.
93 Attribute = "attribute" #: Reserved word since VHDL-87.
94 Begin = "begin" #: Reserved word since VHDL-87.
95 Block = "block" #: Reserved word since VHDL-87.
96 Body = "body" #: Reserved word since VHDL-87.
97 Buffer = "buffer" #: Reserved word since VHDL-87.
98 Bus = "bus" #: Reserved word since VHDL-87.
99 Case = "case" #: Reserved word since VHDL-87.
100 Component = "component" #: Reserved word since VHDL-87.
101 Configuration = "configuration" #: Reserved word since VHDL-87.
102 Constant = "constant" #: Reserved word since VHDL-87.
103 Context = "context" #: Reserved word since VHDL-2008.
104 Cover = "cover" #: Reserved word since VHDL-2008.
105 Default = "default" #: Reserved word since VHDL-2008.
106 Disconnect = "disconnect" #: Reserved word since VHDL-87.
107 DownTo = "downto" #: Reserved word since VHDL-87.
108 Else = "else" #: Reserved word since VHDL-87.
109 ElsIf = "elsif" #: Reserved word since VHDL-87.
110 End = "end" #: Reserved word since VHDL-87.
111 Entity = "entity" #: Reserved word since VHDL-87.
112 Exit = "exit" #: Reserved word since VHDL-87.
113 Fairness = "fairness" #: Reserved word since VHDL-2008.
114 File = "file" #: Reserved word since VHDL-87.
115 For = "for" #: Reserved word since VHDL-87.
116 Force = "force" #: Reserved word since VHDL-2008.
117 Function = "function" #: Reserved word since VHDL-87.
118 Generate = "generate" #: Reserved word since VHDL-87.
119 Generic = "generic" #: Reserved word since VHDL-87.
120 Group = "group" #: Reserved word since VHDL-93.
121 Guarded = "guarded" #: Reserved word since VHDL-87.
122 If = "if" #: Reserved word since VHDL-87.
123 Impure = "impure" #: Reserved word since VHDL-93.
124 In = "in" #: Reserved word since VHDL-87.
125 Inertial = "inertial" #: Reserved word since VHDL-93.
126 InOut = "inout" #: Reserved word since VHDL-87.
127 Is = "is" #: Reserved word since VHDL-87.
128 Label = "label" #: Reserved word since VHDL-87.
129 Library = "library" #: Reserved word since VHDL-87.
130 Linkage = "linkage" #: Reserved word since VHDL-87.
131 Literal = "literal" #: Reserved word since VHDL-93.
132 Loop = "loop" #: Reserved word since VHDL-87.
133 Map = "map" #: Reserved word since VHDL-87.
134 Mod = "mod" #: Reserved word since VHDL-87.
135 Nand = "nand" #: Reserved word since VHDL-87.
136 New = "new" #: Reserved word since VHDL-87.
137 Next = "next" #: Reserved word since VHDL-87.
138 Nor = "nor" #: Reserved word since VHDL-87.
139 Not = "not" #: Reserved word since VHDL-87.
140 Null = "null" #: Reserved word since VHDL-87.
141 Of = "of" #: Reserved word since VHDL-87.
142 On = "on" #: Reserved word since VHDL-87.
143 Open = "open" #: Reserved word since VHDL-87.
144 Or = "or" #: Reserved word since VHDL-87.
145 Others = "others" #: Reserved word since VHDL-87.
146 Out = "out" #: Reserved word since VHDL-87.
147 Package = "package" #: Reserved word since VHDL-87.
148 Parameter = "parameter" #: Reserved word since VHDL-2008.
149 Port = "port" #: Reserved word since VHDL-87.
150 Postponed = "postponed" #: Reserved word since VHDL-93.
151 Private = "private" #: Reserved word since VHDL-2019.
152 Procedure = "procedure" #: Reserved word since VHDL-87.
153 Process = "process" #: Reserved word since VHDL-87.
154 Property = "property" #: Reserved word since VHDL-2008.
155 Protected = "protected" #: Reserved word since VHDL-2000.
156 Pure = "pure" #: Reserved word since VHDL-93.
157 Range = "range" #: Reserved word since VHDL-87.
158 Record = "record" #: Reserved word since VHDL-87.
159 Register = "register" #: Reserved word since VHDL-87.
160 Reject = "reject" #: Reserved word since VHDL-93.
161 Release = "release" #: Reserved word since VHDL-2008.
162 Rem = "rem" #: Reserved word since VHDL-87.
163 Report = "report" #: Reserved word since VHDL-87.
164 Restrict = "restrict" #: Reserved word since VHDL-2008.
165 Return = "return" #: Reserved word since VHDL-87.
166 Rol = "rol" #: Reserved word since VHDL-93.
167 Ror = "ror" #: Reserved word since VHDL-93.
168 Select = "select" #: Reserved word since VHDL-87.
169 Sequence = "sequence" #: Reserved word since VHDL-2008.
170 Severity = "severity" #: Reserved word since VHDL-87.
171 Shared = "shared" #: Reserved word since VHDL-93.
172 Signal = "signal" #: Reserved word since VHDL-87.
173 Sla = "sla" #: Reserved word since VHDL-93.
174 Sll = "sll" #: Reserved word since VHDL-93.
175 Sra = "sra" #: Reserved word since VHDL-93.
176 Srl = "srl" #: Reserved word since VHDL-93.
177 Strong = "strong" #: Reserved word since VHDL-2008.
178 Subtype = "subtype" #: Reserved word since VHDL-87.
179 Then = "then" #: Reserved word since VHDL-87.
180 To = "to" #: Reserved word since VHDL-87.
181 Transport = "transport" #: Reserved word since VHDL-87.
182 Type = "type" #: Reserved word since VHDL-87.
183 Unaffected = "unaffected" #: Reserved word since VHDL-93.
184 Units = "units" #: Reserved word since VHDL-87.
185 Until = "until" #: Reserved word since VHDL-87.
186 Use = "use" #: Reserved word since VHDL-87.
187 Variable = "variable" #: Reserved word since VHDL-87.
188 View = "view" #: Reserved word since VHDL-2019.
189 VMode = "vmode" #: Reserved word since VHDL-2008.
190 VPkg = "vpkg" #: Reserved word since VHDL-2019.
191 VProp = "vprop" #: Reserved word since VHDL-2008.
192 VUnit = "vunit" #: Reserved word since VHDL-2008.
193 Wait = "wait" #: Reserved word since VHDL-87.
194 When = "when" #: Reserved word since VHDL-87.
195 While = "while" #: Reserved word since VHDL-87.
196 With = "with" #: Reserved word since VHDL-87.
197 Xnor = "xnor" #: Reserved word since VHDL-93.
198 Xor = "xor" #: Reserved word since VHDL-87.
201_ReservedWord = ReservedWord #: Alias of :class:`ReservedWord` for annotations in classes with a property of that name.
204@export
205@unique
206class Direction(Enum):
207 """An enumeration representing a direction in a range (``to`` or ``downto``)."""
209 To = 0 #: Ascending direction
210 DownTo = 1 #: Descending direction
212 __RESERVED_WORDS: ClassVar[dict[int, _ReservedWord]] = {
213 0: _ReservedWord.To,
214 1: _ReservedWord.DownTo
215 } #: The reserved word of each direction, by value.
217 @readonly
218 def ReservedWord(self) -> _ReservedWord:
219 """
220 Read-only property to return the reserved word of the direction.
222 :returns: The reserved word, ``to`` or ``downto``.
223 """
224 return self.__RESERVED_WORDS[self.value]
226 def __str__(self) -> str:
227 """
228 Formats the direction to ``to`` or ``downto``.
230 :returns: Formatted direction.
231 """
232 return ("to", "downto")[cast(int, self.value)] # TODO: check performance
235@export
236@unique
237class Mode(Enum):
238 """
239 A ``Mode`` is an enumeration. It represents the direction of data exchange (``in``, ``out``, ...) for objects in
240 generic, port or parameter lists.
242 In case no *mode* is defined, ``Default`` is used, so the *mode* is inferred from context.
243 """
245 Default = 0 #: Mode not defined, thus it's context dependent.
246 In = 1 #: Input
247 Out = 2 #: Output
248 InOut = 3 #: Bi-directional
249 Buffer = 4 #: Buffered output
250 Linkage = 5 #: undocumented
252 __RESERVED_WORDS: ClassVar[dict[int, _ReservedWord]] = {
253 1: _ReservedWord.In,
254 2: _ReservedWord.Out,
255 3: _ReservedWord.InOut,
256 4: _ReservedWord.Buffer,
257 5: _ReservedWord.Linkage
258 } #: The reserved word of each mode, by value; ``Default`` has none.
260 @readonly
261 def ReservedWord(self) -> Nullable[_ReservedWord]:
262 """
263 Read-only property to return the reserved word of the mode.
265 :returns: The reserved word, or ``None`` for ``Mode.Default``.
266 """
267 return self.__RESERVED_WORDS.get(self.value, None)
269 def __str__(self) -> str:
270 """
271 Formats the mode.
273 :returns: Formatted mode.
274 """
275 return ("", "in", "out", "inout", "buffer", "linkage")[cast(int, self.value)] # TODO: check performance
278@export
279@abstractclass
280class ModelEntity(metaclass=ExtendedType, slots=True):
281 """
282 ``ModelEntity`` is the base-class for all classes in the VHDL language model, except for mixin classes (see multiple
283 inheritance) and enumerations.
285 Each entity in this model has a reference to its parent entity. Therefore, a protected variable :attr:`_parent` is
286 available and a readonly property :attr:`Parent`.
287 """
289 _parent: ModelEntity #: Reference to a parent entity in the logical model hierarchy.
291 def __init__(self, parent: Nullable[ModelEntity] = None) -> None:
292 """
293 Initializes a VHDL model entity.
295 :param parent: The parent model entity of this entity.
296 """
297 self._parent = parent
299 @property
300 def Parent(self) -> ModelEntity:
301 """
302 Property to access the model entity's parent element reference in a logical hierarchy (:attr:`_parent`).
304 :returns: Reference to the parent entity.
305 """
306 return self._parent
308 @Parent.setter
309 def Parent(self, parent: ModelEntity) -> None:
310 if parent is None:
311 raise ValueError("Parameter 'parent' is None.")
313 self._parent = parent
315 def GetAncestor(self, type: Type) -> ModelEntity:
316 """
317 Return the closest ancestor of the given ``type`` found by walking the parent chain upwards.
319 Iterates the parent chain - starting at this model entity - upwards (toward the root of the model) until an
320 ancestor of the requested type is found.
322 :param type: Class (type) of the ancestor to find.
323 :returns: The closest ancestor of the requested type.
324 :raises VHDLModelException: If the root of the model is reached without finding an ancestor of the requested
325 type.
326 """
327 # Deferred import to avoid a circular import: Base -> Exception -> Symbol -> Base.
328 from pyVHDLModel.Exception import VHDLModelException
330 parent = self._parent
331 while parent is not None:
332 if isinstance(parent, type):
333 break
335 parent = parent._parent
336 else:
337 raise VHDLModelException(f"No ancestor of type '{type.__name__}' found for {self!r}.")
339 return parent
341 @notimplemented("Model element has no walk for a visitor.")
342 def Visit(self, visitor: Visitor) -> None:
343 """
344 Walk this model element with a visitor.
346 A model class implements its walk; a class without one raises.
348 :param visitor: The visitor receiving the events.
349 :raises NotImplementedError: Always, because the element's class has no walk of its own.
350 """
353@export
354class NamedEntityMixin(metaclass=ExtendedType, mixin=True):
355 """
356 A ``NamedEntityMixin`` is a mixin class for all VHDL entities that have an identifier.
358 Protected variables :attr:`_identifier` and :attr:`_normalizedIdentifier` are available to derived classes as well as
359 two readonly properties :attr:`Identifier` and :attr:`NormalizedIdentifier` for public access.
361 .. seealso::
363 * :class:`Attribute <pyVHDLModel.Declaration.Attribute>`
364 * :class:`Alias <pyVHDLModel.Declaration.Alias>`
365 * :class:`Design unit <pyVHDLModel.DesignUnit.DesignUnit>`
366 * :class:`Component <pyVHDLModel.DesignUnit.Component>`
367 * :class:`Mode view declaration <pyVHDLModel.Interface.ModeViewDeclaration>`
368 * :class:`Interface package <pyVHDLModel.Interface.InterfacePackage>`
369 * :class:`Default clock <pyVHDLModel.PSLModel.DefaultClock>`
370 * :class:`Subprogram <pyVHDLModel.Subprogram.Subprogram>`
371 * :class:`Base type <pyVHDLModel.Type.BaseType>`
372 * :class:`Library <pyVHDLModel.Library>`
373 """
375 _identifier: str #: The identifier of a model entity.
376 _normalizedIdentifier: str #: The normalized (lower case) identifier of a model entity.
378 def __init__(self, identifier: str) -> None:
379 """
380 Initializes a named entity.
382 :param identifier: Identifier (name) of the model entity.
383 """
384 self._identifier = identifier
385 self._normalizedIdentifier = identifier.lower()
387 @readonly
388 def Identifier(self) -> str:
389 """
390 Read-only property to access the model entity's identifier (:attr:`_identifier`).
392 :returns: Name of a model entity.
393 """
394 return self._identifier
396 @readonly
397 def NormalizedIdentifier(self) -> str:
398 """
399 Read-only property to access the model entity's normalized identifier (:attr:`_normalizedIdentifier`).
401 :returns: Normalized name of a model entity.
402 """
403 return self._normalizedIdentifier
406@export
407class OptionallyNamedEntityMixin(metaclass=ExtendedType, mixin=True):
408 """
409 A ``OptionallyNamedEntityMixin`` is a mixin class for all VHDL entities that have an optional identifier.
411 Protected variables :attr:`_identifier` and :attr:`_normalizedIdentifier` are available to derived classes as well as
412 two readonly properties :attr:`Identifier` and :attr:`NormalizedIdentifier` for public access.
414 .. seealso::
416 * :class:`Interface group <pyVHDLModel.Interface.InterfaceGroup>`
417 """
419 _identifier: Nullable[str] #: The identifier of a model entity.
420 _normalizedIdentifier: Nullable[str] #: The normalized (lower case) identifier of a model entity.
422 def __init__(self, identifier: Nullable[str]) -> None:
423 """
424 Initializes a named entity.
426 :param identifier: Identifier (name) of the model entity.
427 """
428 self._identifier = identifier
429 self._normalizedIdentifier = identifier.lower() if identifier is not None else None
431 @readonly
432 def Identifier(self) -> Nullable[str]:
433 """
434 Read-only property to access the model entity's optional identifier (:attr:`_identifier`).
436 :returns: Name of a model entity, or ``None`` if unnamed.
437 """
438 return self._identifier
440 @readonly
441 def NormalizedIdentifier(self) -> Nullable[str]:
442 """
443 Read-only property to access the model entity's optional normalized identifier (:attr:`_normalizedIdentifier`).
445 :returns: Normalized name of a model entity, or ``None`` if unnamed.
446 """
447 return self._normalizedIdentifier
450@export
451class MultipleNamedEntityMixin(metaclass=ExtendedType, mixin=True):
452 """
453 A ``MultipleNamedEntityMixin`` is a mixin class for all VHDL entities that declare multiple instances at once by
454 defining multiple identifiers.
456 Protected variables :attr:`_identifiers` and :attr:`_normalizedIdentifiers` are available to derived classes as well
457 as two readonly properties :attr:`Identifiers` and :attr:`NormalizedIdentifiers` for public access.
459 .. seealso::
461 * :class:`Mode view element <pyVHDLModel.Interface.ModeViewElement>`
462 * :class:`Obj <pyVHDLModel.Object.Obj>`
463 * :class:`Record type element <pyVHDLModel.Type.RecordTypeElement>`
464 """
466 _identifiers: tuple[str] #: A list of identifiers.
467 _normalizedIdentifiers: tuple[str] #: A list of normalized (lower case) identifiers.
469 def __init__(self, identifiers: Iterable[str]) -> None:
470 """
471 Initializes a multiple-named entity.
473 :param identifiers: Sequence of identifiers (names) of the model entity.
474 """
475 self._identifiers = tuple(identifiers)
476 self._normalizedIdentifiers = tuple([identifier.lower() for identifier in self._identifiers])
478 @readonly
479 def Identifiers(self) -> tuple[str]:
480 """
481 Read-only property to access the model entity's identifiers (:attr:`_identifiers`).
483 :returns: Tuple of identifiers.
484 """
485 return self._identifiers
487 @readonly
488 def NormalizedIdentifiers(self) -> tuple[str]:
489 """
490 Read-only property to access the model entity's normalized identifiers (:attr:`_normalizedIdentifiers`).
492 :returns: Tuple of normalized identifiers.
493 """
494 return self._normalizedIdentifiers
497@export
498def identifiersOf(item) -> tuple[str, ...]:
499 """
500 Return an item's identifier(s), regardless of how many names its declaration carries.
502 VHDL entities come in two shapes: singularly named ones deriving from :class:`NamedEntityMixin`
503 (``generic (type T)``, ``GenericProcedureInterfaceItem``, ...) and plurally named ones deriving from
504 :class:`MultipleNamedEntityMixin`, where one declaration names several items at once
505 (``port (p1, p2 : in bit)``, and every ``Constant``/``Signal``/``Variable``/``File``-derived item).
507 :param item: A singularly or plurally named entity.
508 :returns: The item's identifiers.
509 :raises TypeError: If the item is neither singularly nor plurally named.
511 .. seealso::
513 :func:`normalizedIdentifiersOf`
514 The same, but normalized (lower case) - use that for dictionary keys and name resolution.
515 """
516 if isinstance(item, MultipleNamedEntityMixin):
517 return item._identifiers
518 elif isinstance(item, NamedEntityMixin): 518 ↛ 521line 518 didn't jump to line 521 because the condition on line 518 was always true
519 return (item._identifier, )
521 ex = TypeError(f"Item '{item}' is neither a NamedEntityMixin nor a MultipleNamedEntityMixin.")
522 ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.")
523 raise ex
526@export
527def normalizedIdentifiersOf(item) -> tuple[str, ...]:
528 """
529 Return an item's normalized (lower case) identifier(s).
531 This is the form used as dictionary keys and for name resolution, because VHDL identifiers are
532 case-insensitive.
534 :param item: A singularly or plurally named entity.
535 :returns: The item's normalized identifiers.
536 :raises TypeError: If the item is neither singularly nor plurally named.
538 .. seealso::
540 :func:`identifiersOf`
541 The same, but as written in the source - use that for rendering.
542 """
543 if isinstance(item, MultipleNamedEntityMixin):
544 return item._normalizedIdentifiers
545 elif isinstance(item, NamedEntityMixin): 545 ↛ 548line 545 didn't jump to line 548 because the condition on line 545 was always true
546 return (item._normalizedIdentifier, )
548 ex = TypeError(f"Item '{item}' is neither a NamedEntityMixin nor a MultipleNamedEntityMixin.")
549 ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.")
550 raise ex
553@export
554def normalizedDeclaredNamesOf(item: ModelEntity) -> tuple[str, ...]:
555 """
556 Return the normalized (lower case) names an item declares in its declarative region.
558 A declaration declares its identifiers. A statement label is declared implicitly in the declarative region enclosing
559 the statement, so a labeled statement declares its label.
561 :param item: A model entity.
562 :returns: The normalized identifiers of a singularly or plurally named entity, the normalized label of a labeled
563 entity, or an empty tuple.
565 .. seealso::
567 :func:`normalizedIdentifiersOf`
568 The normalized identifiers of a singularly or plurally named entity.
569 """
570 if isinstance(item, (NamedEntityMixin, MultipleNamedEntityMixin)):
571 return normalizedIdentifiersOf(item)
572 elif isinstance(item, LabeledEntityMixin) and item._normalizedLabel is not None:
573 return (item._normalizedLabel, )
575 return ()
578@export
579class LabeledEntityMixin(metaclass=ExtendedType, mixin=True):
580 """
581 A ``LabeledEntityMixin`` is a mixin class for all VHDL entities that can have labels.
583 protected variables :attr:`_label` and :attr:`_normalizedLabel` are available to derived classes as well as two
584 readonly properties :attr:`Label` and :attr:`NormalizedLabel` for public access.
586 .. seealso::
588 * :class:`Statement <pyVHDLModel.Common.Statement>`
589 * :class:`Concurrent block statement <pyVHDLModel.Concurrent.ConcurrentBlockStatement>`
590 * :class:`Concurrent case <pyVHDLModel.Concurrent.ConcurrentCase>`
591 """
592 _label: Nullable[str] #: The label of a model entity.
593 _normalizedLabel: Nullable[str] #: The normalized (lower case) label of a model entity.
595 def __init__(self, label: Nullable[str]) -> None:
596 """
597 Initializes a labeled entity.
599 :param label: Label of the model entity.
600 """
601 self._label = label
602 self._normalizedLabel = label.lower() if label is not None else None
604 @readonly
605 def Label(self) -> Nullable[str]:
606 """
607 Read-only property to access the model entity's label (:attr:`_label`).
609 :returns: Label of a model entity.
610 """
611 return self._label
613 @readonly
614 def NormalizedLabel(self) -> Nullable[str]:
615 """
616 Read-only property to access the model entity's normalized label (:attr:`_normalizedLabel`).
618 :returns: Normalized label of a model entity.
619 """
620 return self._normalizedLabel
623@export
624class DocumentedEntityMixin(metaclass=ExtendedType, mixin=True):
625 """
626 A ``DocumentedEntityMixin`` is a mixin class for all VHDL entities that can have an associated documentation.
628 A protected variable :attr:`_documentation` is available to derived classes as well as a readonly property
629 :attr:`Documentation` for public access.
630 """
632 _documentation: Nullable[str] #: The associated documentation of a model entity.
634 def __init__(self, documentation: Nullable[str]) -> None:
635 """
636 Initializes a documented entity.
638 :param documentation: Documentation of a model entity.
639 """
640 self._documentation = documentation
642 @readonly
643 def Documentation(self) -> Nullable[str]:
644 """
645 Read-only property to access the model entity's documentation (:attr:`_documentation`).
647 :returns: Associated documentation of a model entity.
648 """
649 return self._documentation
652@export
653class ConditionalMixin(metaclass=ExtendedType, mixin=True):
654 """
655 A ``ConditionalMixin`` is a mixin-class for all statements with a condition.
657 .. seealso::
659 * :class:`Conditional branch mixin <pyVHDLModel.Base.ConditionalBranchMixin>`
660 * :class:`Assert statement mixin <pyVHDLModel.Base.AssertStatementMixin>`
661 * :class:`Conditional waveform <pyVHDLModel.Common.ConditionalWaveform>`
662 * :class:`Conditional expression <pyVHDLModel.Common.ConditionalExpression>`
663 * :class:`While loop statement <pyVHDLModel.Sequential.WhileLoopStatement>`
664 * :class:`Loop control statement <pyVHDLModel.Sequential.LoopControlStatement>`
665 * :class:`Wait statement <pyVHDLModel.Sequential.WaitStatement>`
666 """
668 _condition: ExpressionUnion #: The condition guarding this statement.
670 def __init__(self, condition: Nullable[ExpressionUnion] = None) -> None:
671 """
672 Initializes a statement with a condition.
674 When the condition is not None, the condition's parent reference is set to this statement.
676 :param condition: The expression representing the condition.
677 """
678 self._condition = condition
679 if condition is not None:
680 condition.Parent = self
682 @readonly
683 def Condition(self) -> ExpressionUnion:
684 """
685 Read-only property to access the condition of a statement (:attr:`_condition`).
687 :returns: The expression representing the condition of a statement.
688 """
689 return self._condition
692@export
693class BranchMixin(metaclass=ExtendedType, mixin=True):
694 """
695 A ``BranchMixin`` is a mixin-class for all statements with branches.
697 .. seealso::
699 * :class:`Conditional branch mixin <pyVHDLModel.Base.ConditionalBranchMixin>`
700 * :class:`Else branch mixin <pyVHDLModel.Base.ElseBranchMixin>`
701 """
703 def __init__(self) -> None:
704 """
705 Initializes a branch.
706 """
707 pass
710@export
711class ConditionalBranchMixin(BranchMixin, ConditionalMixin, mixin=True):
712 """
713 A ``BaseBranch`` is a mixin-class for all branch statements with a condition.
715 .. seealso::
717 * :class:`If branch mixin <pyVHDLModel.Base.IfBranchMixin>`
718 * :class:`Elsif branch mixin <pyVHDLModel.Base.ElsifBranchMixin>`
719 """
720 def __init__(self, condition: ExpressionUnion) -> None:
721 """
722 Initializes a conditional branch.
724 :param condition: The condition guarding this statement.
725 """
726 super().__init__()
727 ConditionalMixin.__init__(self, condition)
730@export
731class IfBranchMixin(ConditionalBranchMixin, mixin=True):
732 """
733 A ``BaseIfBranch`` is a mixin-class for all if-branches.
735 .. seealso::
737 * :class:`If generate branch <pyVHDLModel.Concurrent.IfGenerateBranch>`
738 * :class:`If branch <pyVHDLModel.Sequential.IfBranch>`
739 """
742@export
743class ElsifBranchMixin(ConditionalBranchMixin, mixin=True):
744 """
745 A ``BaseElsifBranch`` is a mixin-class for all elsif-branches.
747 .. seealso::
749 * :class:`Elsif generate branch <pyVHDLModel.Concurrent.ElsifGenerateBranch>`
750 * :class:`Elsif branch <pyVHDLModel.Sequential.ElsifBranch>`
751 """
754@export
755class ElseBranchMixin(BranchMixin, mixin=True):
756 """
757 A ``BaseElseBranch`` is a mixin-class for all else-branches.
759 .. seealso::
761 * :class:`Else generate branch <pyVHDLModel.Concurrent.ElseGenerateBranch>`
762 * :class:`Else branch <pyVHDLModel.Sequential.ElseBranch>`
763 """
766@export
767class ReportStatementMixin(metaclass=ExtendedType, mixin=True):
768 """
769 A ``MixinReportStatement`` is a mixin-class for all report and assert statements.
771 .. seealso::
773 * :class:`Assert statement mixin <pyVHDLModel.Base.AssertStatementMixin>`
774 * :class:`Sequential report statement <pyVHDLModel.Sequential.SequentialReportStatement>`
775 """
777 _message: Nullable[ExpressionUnion] #: The reported message, or ``None`` if none was given.
778 _severity: Nullable[ExpressionUnion] #: The reported severity level, or ``None`` if none was given.
780 def __init__(self, message: Nullable[ExpressionUnion] = None, severity: Nullable[ExpressionUnion] = None) -> None:
781 """
782 Initializes a report statement.
784 :param message: The reported message, or ``None`` if none was given.
785 :param severity: The reported severity level, or ``None`` if none was given.
786 """
787 self._message = message
788 if message is not None:
789 message.Parent = self
791 self._severity = severity
792 if severity is not None:
793 severity.Parent = self
795 def _VisitReportAndSeverity(self, visitor: Visitor) -> None:
796 """
797 Walk the message and the severity, if given, each after its reserved word, with a visitor.
799 :param visitor: The visitor receiving the events.
800 """
801 if self._message is not None:
802 visitor.VisitReport(self)
803 self._message.Visit(visitor)
805 if self._severity is not None:
806 visitor.VisitSeverity(self)
807 self._severity.Visit(visitor)
809 @readonly
810 def Message(self) -> Nullable[ExpressionUnion]:
811 """
812 Read-only property to access the message (:attr:`_message`).
814 :returns: The message, or ``None`` if not set.
815 """
816 return self._message
818 @readonly
819 def Severity(self) -> Nullable[ExpressionUnion]:
820 """
821 Read-only property to access the severity (:attr:`_severity`).
823 :returns: The severity, or ``None`` if not set.
824 """
825 return self._severity
828@export
829class AssertStatementMixin(ReportStatementMixin, ConditionalMixin, mixin=True):
830 """
831 A ``MixinAssertStatement`` is a mixin-class for all assert statements.
833 .. seealso::
835 * :class:`Concurrent assert statement <pyVHDLModel.Concurrent.ConcurrentAssertStatement>`
836 * :class:`Sequential assert statement <pyVHDLModel.Sequential.SequentialAssertStatement>`
837 """
839 def __init__(self, condition: ExpressionUnion, message: Nullable[ExpressionUnion] = None, severity: Nullable[ExpressionUnion] = None) -> None:
840 """
841 Initializes an assert statement.
843 :param condition: The condition guarding this statement.
844 :param message: The reported message, or ``None`` if none was given.
845 :param severity: The reported severity level, or ``None`` if none was given.
846 """
847 super().__init__(message, severity)
848 ConditionalMixin.__init__(self, condition)
850 def _VisitAssertion(self, visitor: Visitor) -> None:
851 """
852 Walk the condition, the message and the severity of an assertion with a visitor.
854 :param visitor: The visitor receiving the events.
855 """
856 self._condition.Visit(visitor)
857 self._VisitReportAndSeverity(visitor)
860class BlockStatementMixin(metaclass=ExtendedType, mixin=True):
861 """
862 A ``BlockStatement`` is a mixin-class for all block statements.
864 .. seealso::
866 * :class:`Concurrent block statement <pyVHDLModel.Concurrent.ConcurrentBlockStatement>`
867 """
869 def __init__(self) -> None:
870 """
871 Initializes a block statement.
872 """
873 pass
876@export
877@abstractclass
878class BaseChoice(ModelEntity):
879 """
880 A ``Choice`` is a base-class for all choices.
882 .. seealso::
884 * :class:`Concurrent choice <pyVHDLModel.Concurrent.ConcurrentChoice>`
885 * :class:`Sequential choice <pyVHDLModel.Sequential.SequentialChoice>`
886 """
889@export
890@abstractclass
891class BaseCase(ModelEntity):
892 """
893 A ``Case`` is a base-class for all cases.
895 .. seealso::
897 * :class:`Selected waveform <pyVHDLModel.Common.SelectedWaveform>`
898 * :class:`Others selected waveform <pyVHDLModel.Common.OthersSelectedWaveform>`
899 * :class:`Selected expression <pyVHDLModel.Common.SelectedExpression>`
900 * :class:`Others selected expression <pyVHDLModel.Common.OthersSelectedExpression>`
901 * :class:`Concurrent case <pyVHDLModel.Concurrent.ConcurrentCase>`
902 * :class:`Sequential case <pyVHDLModel.Sequential.SequentialCase>`
903 """
906@export
907class ChoicesMixin(metaclass=ExtendedType, mixin=True):
908 """
909 A mixin-class for all statements/entities holding a list of :class:`BaseChoice`.
911 .. seealso::
913 * :class:`Selected waveform <pyVHDLModel.Common.SelectedWaveform>`
914 * :class:`Selected expression <pyVHDLModel.Common.SelectedExpression>`
915 * :class:`Concurrent case <pyVHDLModel.Concurrent.ConcurrentCase>`
916 * :class:`Sequential case <pyVHDLModel.Sequential.SequentialCase>`
917 """
919 _choices: list[BaseChoice] #: List of all choices selecting this alternative.
921 def __init__(self, choices: Nullable[Iterable[BaseChoice]] = None) -> None:
922 """
923 Initializes choices.
925 :param choices: List of all choices selecting this alternative.
926 """
927 self._choices = choiceList = []
928 if choices is not None:
929 for choice in choices:
930 choiceList.append(choice)
931 choice.Parent = self
933 @readonly
934 def Choices(self) -> list[BaseChoice]:
935 """
936 Read-only property to access the choices (:attr:`_choices`).
938 :returns: List of choices.
939 """
940 return self._choices
943@export
944class Range(ModelEntity):
945 """
946 Base-class for all ranges.
948 VHDL's ``range`` rule offers a range denoted by a name (:class:`RangeFromName`) as well as a range
949 given by explicit bounds (:class:`SimpleRange`).
951 .. seealso::
953 * :class:`Simple range <pyVHDLModel.Base.SimpleRange>`
954 * :class:`Range from name <pyVHDLModel.Base.RangeFromName>`
955 """
958@export
959class SimpleRange(Range):
960 """
961 A range with both bounds given as expressions.
963 ``0 to 7`` is such a range.
964 """
966 _leftBound: ExpressionUnion #: The range's left bound.
967 _rightBound: ExpressionUnion #: The range's right bound.
968 _direction: Direction #: The range's direction, either ascending (``to``) or descending (``downto``).
970 def __init__(self, leftBound: ExpressionUnion, rightBound: ExpressionUnion, direction: Direction, parent: Nullable[ModelEntity] = None) -> None:
971 """
972 Initialize a simple range.
974 :param leftBound: The range's left bound.
975 :param rightBound: The range's right bound.
976 :param direction: The range's direction (``to`` or ``downto``).
977 :param parent: The parent model entity.
978 """
979 super().__init__(parent)
981 self._leftBound = leftBound
982 leftBound.Parent = self
984 self._rightBound = rightBound
985 rightBound.Parent = self
987 self._direction = direction
989 @readonly
990 def LeftBound(self) -> ExpressionUnion:
991 """
992 Read-only property to access the range's left bound (:attr:`_leftBound`).
994 :returns: The left bound.
995 """
996 return self._leftBound
998 @readonly
999 def RightBound(self) -> ExpressionUnion:
1000 """
1001 Read-only property to access the range's right bound (:attr:`_rightBound`).
1003 :returns: The right bound.
1004 """
1005 return self._rightBound
1007 @readonly
1008 def Direction(self) -> Direction:
1009 """
1010 Read-only property to access the range's direction (:attr:`_direction`).
1012 :returns: The direction.
1013 """
1014 return self._direction
1016 def Copy(self) -> Self:
1017 """
1018 Create a copy of this simple range.
1020 The copy has no parent. Its bounds are copies of this range's bounds.
1022 :returns: The new simple range.
1023 """
1024 return self.__class__(self._leftBound.Copy(), self._rightBound.Copy(), self._direction)
1026 def Visit(self, visitor: Visitor) -> None:
1027 """
1028 Walk this range, its left bound and its right bound with a visitor.
1030 :param visitor: The visitor receiving the events.
1031 """
1032 visitor.VisitSimpleRange(self)
1033 self._leftBound.Visit(visitor)
1034 visitor.VisitDirection(self)
1035 self._rightBound.Visit(visitor)
1036 visitor.DepartSimpleRange(self)
1038 def __str__(self) -> str:
1039 """
1040 Formats the simple range.
1042 **Format:** ``0 to 7``
1044 :returns: Formatted simple range.
1045 """
1046 return f"{self._leftBound!s} {self._direction!s} {self._rightBound!s}"
1049@export
1050class RangeFromName(Range):
1051 """
1052 A range denoted by a name, so its bounds are inferred from whatever that name references.
1054 The name is represented by a :class:`~pyVHDLModel.Symbol.Symbol`, so the bounds become available once
1055 that symbol is resolved. A constrained subtype indication keeps its type mark *and* its range
1056 constraint, because it's carried by a :class:`~pyVHDLModel.Symbol.ConstrainedScalarSubtypeSymbol`.
1058 .. note::
1060 Two forms reach this class, because a parser can't tell them apart beyond "a name, optionally with
1061 a range constraint":
1063 * a range attribute like ``vector'range``, and
1064 * a discrete subtype indication like ``bit`` or ``integer range 0 to 7``.
1066 VHDL's grammar puts the latter one level up (``discrete_range ::= discrete_subtype_indication |
1067 range``), so representing both as a range deviates from the rule split deliberately.
1068 """
1070 _symbol: Symbol #: Reference to the name the range's bounds are inferred from.
1072 def __init__(self, symbol: Symbol, parent: Nullable[ModelEntity] = None) -> None:
1073 """
1074 Initialize a range denoted by a name.
1076 :param symbol: The symbol referencing the range attribute or discrete subtype.
1077 :param parent: The parent model entity.
1078 """
1079 super().__init__(parent)
1081 self._symbol = symbol
1082 symbol.Parent = self
1084 @readonly
1085 def Symbol(self) -> Symbol:
1086 """
1087 Read-only property to access the referenced symbol (:attr:`_symbol`).
1089 :returns: The symbol.
1090 """
1091 return self._symbol
1093 def Copy(self) -> Self:
1094 """
1095 Create a copy of this range denoted by a name.
1097 The copy has no parent. Its symbol is a copy of this range's symbol.
1099 :returns: The new range denoted by a name.
1100 """
1101 return self.__class__(self._symbol.Copy())
1103 def Visit(self, visitor: Visitor) -> None:
1104 """
1105 Walk this range and its name with a visitor.
1107 :param visitor: The visitor receiving the events.
1108 """
1109 visitor.VisitRangeFromName(self)
1110 self._symbol.Visit(visitor)
1111 visitor.DepartRangeFromName(self)
1113 def __str__(self) -> str:
1114 """
1115 Formats the range denoted by a name.
1117 **Format:** ``v'range``
1119 :returns: Formatted range denoted by a name.
1120 """
1121 return f"{self._symbol!s}"
1124@export
1125class WaveformElement(ModelEntity):
1126 """
1127 Represents one element of a waveform in a signal assignment.
1129 A waveform element assigns a value (:data:`Expression`) after an optional delay (:data:`After`).
1131 .. admonition:: Example
1133 .. code-block:: VHDL
1135 s <= '1' after 5 ns;
1136 -- ^^^ <- Expression
1137 -- ^^^^ <- After
1139 .. seealso::
1141 * :class:`Waveform of a simple assignment <pyVHDLModel.Common.WaveformMixin>`
1142 * :class:`Waveform of one conditional branch <pyVHDLModel.Common.ConditionalWaveform>`
1143 * :class:`Waveform of one selected alternative <pyVHDLModel.Common.SelectedWaveform>`
1144 """
1145 _expression: ExpressionUnion #: The value this waveform element assigns.
1146 _after: ExpressionUnion #: The delay after which the value is assigned, or ``None`` if none was given.
1148 def __init__(self, expression: ExpressionUnion, after: Nullable[ExpressionUnion] = None, parent: Nullable[ModelEntity] = None) -> None:
1149 """
1150 Initializes a waveform element.
1152 :param expression: The value this waveform element assigns.
1153 :param after: The delay after which the value is assigned, or ``None`` if none was given.
1154 :param parent: The parent model entity of this entity.
1155 """
1156 super().__init__(parent)
1158 self._expression = expression
1159 expression.Parent = self
1161 self._after = after
1162 if after is not None:
1163 after.Parent = self
1165 def Visit(self, visitor: Visitor) -> None:
1166 """
1167 Walk this waveform element, its value and its delay (if any) with a visitor.
1169 :param visitor: The visitor receiving the events.
1170 """
1171 visitor.VisitWaveformElement(self)
1172 self._expression.Visit(visitor)
1173 if self._after is not None:
1174 visitor.VisitAfter(self)
1175 self._after.Visit(visitor)
1177 visitor.DepartWaveformElement(self)
1179 @readonly
1180 def Expression(self) -> ExpressionUnion:
1181 """
1182 Read-only property to access the expression (:attr:`_expression`).
1184 :returns: The expression.
1185 """
1186 return self._expression
1188 @readonly
1189 def After(self) -> Expression:
1190 """
1191 Read-only property to access the waveform element's delay (:attr:`_after`).
1193 :returns: The after.
1194 """
1195 return self._after