Coverage for pyVHDLModel/Base.py: 96%
225 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-11 23:50 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-11 23:50 +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 enum import unique, Enum
38from typing import Type, Tuple, List, Iterable, Optional as Nullable, Union, cast
40from pyTooling.Common import getFullyQualifiedName
41from pyTooling.Decorators import export, readonly
42from pyTooling.MetaClasses import ExtendedType
45__all__ = ["ExpressionUnion"]
48ExpressionUnion = Union[
49 'BaseExpression',
50 'QualifiedExpression',
51 'FunctionCall',
52 'TypeConversion',
53 # ConstantOrSymbol, TODO: ObjectSymbol
54 'Literal',
55]
58@export
59@unique
60class Direction(Enum):
61 """An enumeration representing a direction in a range (``to`` or ``downto``)."""
63 To = 0 #: Ascending direction
64 DownTo = 1 #: Descending direction
66 def __str__(self) -> str:
67 """
68 Formats the direction to ``to`` or ``downto``.
70 :returns: Formatted direction.
71 """
72 return ("to", "downto")[cast(int, self.value)] # TODO: check performance
75@export
76@unique
77class Mode(Enum):
78 """
79 A ``Mode`` is an enumeration. It represents the direction of data exchange (``in``, ``out``, ...) for objects in
80 generic, port or parameter lists.
82 In case no *mode* is defined, ``Default`` is used, so the *mode* is inferred from context.
83 """
85 Default = 0 #: Mode not defined, thus it's context dependent.
86 In = 1 #: Input
87 Out = 2 #: Output
88 InOut = 3 #: Bi-directional
89 Buffer = 4 #: Buffered output
90 Linkage = 5 #: undocumented
92 def __str__(self) -> str:
93 """
94 Formats the mode.
96 :returns: Formatted mode.
97 """
98 return ("", "in", "out", "inout", "buffer", "linkage")[cast(int, self.value)] # TODO: check performance
101@export
102class ModelEntity(metaclass=ExtendedType, slots=True):
103 """
104 ``ModelEntity`` is the base-class for all classes in the VHDL language model, except for mixin classes (see multiple
105 inheritance) and enumerations.
107 Each entity in this model has a reference to its parent entity. Therefore, a protected variable :attr:`_parent` is
108 available and a readonly property :attr:`Parent`.
109 """
111 _parent: 'ModelEntity' #: Reference to a parent entity in the logical model hierarchy.
113 def __init__(self, parent: Nullable["ModelEntity"] = None) -> None:
114 """
115 Initializes a VHDL model entity.
117 :param parent: The parent model entity of this entity.
118 """
119 self._parent = parent
121 @property
122 def Parent(self) -> 'ModelEntity':
123 """
124 Property to access the model entity's parent element reference in a logical hierarchy (:attr:`_parent`).
126 :returns: Reference to the parent entity.
127 """
128 return self._parent
130 @Parent.setter
131 def Parent(self, parent: 'ModelEntity') -> None:
132 if parent is None:
133 raise ValueError("Parameter 'parent' is None.")
135 self._parent = parent
137 def GetAncestor(self, type: Type) -> 'ModelEntity':
138 """
139 Return the closest ancestor of the given ``type`` found by walking the parent chain upwards.
141 Iterates the parent chain - starting at this model entity - upwards (toward the root of the model) until an
142 ancestor of the requested type is found.
144 :param type: Class (type) of the ancestor to find.
145 :returns: The closest ancestor of the requested type.
146 :raises VHDLModelException: If the root of the model is reached without finding an ancestor of the requested
147 type.
148 """
149 # Deferred import to avoid a circular import: Base -> Exception -> Symbol -> Base.
150 from pyVHDLModel.Exception import VHDLModelException
152 parent = self._parent
153 while parent is not None:
154 if isinstance(parent, type):
155 break
157 parent = parent._parent
158 else:
159 raise VHDLModelException(f"No ancestor of type '{type.__name__}' found for {self!r}.")
161 return parent
164@export
165class NamedEntityMixin(metaclass=ExtendedType, mixin=True):
166 """
167 A ``NamedEntityMixin`` is a mixin class for all VHDL entities that have an identifier.
169 Protected variables :attr:`_identifier` and :attr:`_normalizedIdentifier` are available to derived classes as well as
170 two readonly properties :attr:`Identifier` and :attr:`NormalizedIdentifier` for public access.
172 .. seealso::
174 * :class:`Attribute <pyVHDLModel.Declaration.Attribute>`
175 * :class:`Alias <pyVHDLModel.Declaration.Alias>`
176 * :class:`Design unit <pyVHDLModel.DesignUnit.DesignUnit>`
177 * :class:`Component <pyVHDLModel.DesignUnit.Component>`
178 * :class:`Mode view declaration <pyVHDLModel.Interface.ModeViewDeclaration>`
179 * :class:`Interface package <pyVHDLModel.Interface.InterfacePackage>`
180 * :class:`Default clock <pyVHDLModel.PSLModel.DefaultClock>`
181 * :class:`Subprogram <pyVHDLModel.Subprogram.Subprogram>`
182 * :class:`Base type <pyVHDLModel.Type.BaseType>`
183 * :class:`Library <pyVHDLModel.Library>`
184 """
186 _identifier: str #: The identifier of a model entity.
187 _normalizedIdentifier: str #: The normalized (lower case) identifier of a model entity.
189 def __init__(self, identifier: str) -> None:
190 """
191 Initializes a named entity.
193 :param identifier: Identifier (name) of the model entity.
194 """
195 self._identifier = identifier
196 self._normalizedIdentifier = identifier.lower()
198 @readonly
199 def Identifier(self) -> str:
200 """
201 Read-only property to access the model entity's identifier (:attr:`_identifier`).
203 :returns: Name of a model entity.
204 """
205 return self._identifier
207 @readonly
208 def NormalizedIdentifier(self) -> str:
209 """
210 Read-only property to access the model entity's normalized identifier (:attr:`_normalizedIdentifier`).
212 :returns: Normalized name of a model entity.
213 """
214 return self._normalizedIdentifier
217@export
218class OptionallyNamedEntityMixin(metaclass=ExtendedType, mixin=True):
219 """
220 A ``OptionallyNamedEntityMixin`` is a mixin class for all VHDL entities that have an optional identifier.
222 Protected variables :attr:`_identifier` and :attr:`_normalizedIdentifier` are available to derived classes as well as
223 two readonly properties :attr:`Identifier` and :attr:`NormalizedIdentifier` for public access.
225 .. seealso::
227 * :class:`Interface group <pyVHDLModel.Interface.InterfaceGroup>`
228 """
230 _identifier: Nullable[str] #: The identifier of a model entity.
231 _normalizedIdentifier: Nullable[str] #: The normalized (lower case) identifier of a model entity.
233 def __init__(self, identifier: Nullable[str]) -> None:
234 """
235 Initializes a named entity.
237 :param identifier: Identifier (name) of the model entity.
238 """
239 self._identifier = identifier
240 self._normalizedIdentifier = identifier.lower() if identifier is not None else None
242 @readonly
243 def Identifier(self) -> Nullable[str]:
244 """
245 Read-only property to access the model entity's optional identifier (:attr:`_identifier`).
247 :returns: Name of a model entity, or ``None`` if unnamed.
248 """
249 return self._identifier
251 @readonly
252 def NormalizedIdentifier(self) -> Nullable[str]:
253 """
254 Read-only property to access the model entity's optional normalized identifier (:attr:`_normalizedIdentifier`).
256 :returns: Normalized name of a model entity, or ``None`` if unnamed.
257 """
258 return self._normalizedIdentifier
261@export
262class MultipleNamedEntityMixin(metaclass=ExtendedType, mixin=True):
263 """
264 A ``MultipleNamedEntityMixin`` is a mixin class for all VHDL entities that declare multiple instances at once by
265 defining multiple identifiers.
267 Protected variables :attr:`_identifiers` and :attr:`_normalizedIdentifiers` are available to derived classes as well
268 as two readonly properties :attr:`Identifiers` and :attr:`NormalizedIdentifiers` for public access.
270 .. seealso::
272 * :class:`Mode view element <pyVHDLModel.Interface.ModeViewElement>`
273 * :class:`Obj <pyVHDLModel.Object.Obj>`
274 * :class:`Record type element <pyVHDLModel.Type.RecordTypeElement>`
275 """
277 _identifiers: Tuple[str] #: A list of identifiers.
278 _normalizedIdentifiers: Tuple[str] #: A list of normalized (lower case) identifiers.
280 def __init__(self, identifiers: Iterable[str]) -> None:
281 """
282 Initializes a multiple-named entity.
284 :param identifiers: Sequence of identifiers (names) of the model entity.
285 """
286 self._identifiers = tuple(identifiers)
287 self._normalizedIdentifiers = tuple([identifier.lower() for identifier in identifiers])
289 @readonly
290 def Identifiers(self) -> Tuple[str]:
291 """
292 Read-only property to access the model entity's identifiers (:attr:`_identifiers`).
294 :returns: Tuple of identifiers.
295 """
296 return self._identifiers
298 @readonly
299 def NormalizedIdentifiers(self) -> Tuple[str]:
300 """
301 Read-only property to access the model entity's normalized identifiers (:attr:`_normalizedIdentifiers`).
303 :returns: Tuple of normalized identifiers.
304 """
305 return self._normalizedIdentifiers
308@export
309def identifiersOf(item) -> Tuple[str, ...]:
310 """
311 Return an item's identifier(s), regardless of how many names its declaration carries.
313 VHDL entities come in two shapes: singularly named ones deriving from :class:`NamedEntityMixin`
314 (``generic (type T)``, ``GenericProcedureInterfaceItem``, ...) and plurally named ones deriving from
315 :class:`MultipleNamedEntityMixin`, where one declaration names several items at once
316 (``port (p1, p2 : in bit)``, and every ``Constant``/``Signal``/``Variable``/``File``-derived item).
318 :param item: A singularly or plurally named entity.
319 :returns: The item's identifiers.
320 :raises TypeError: If the item is neither singularly nor plurally named.
322 .. seealso::
324 :func:`normalizedIdentifiersOf`
325 The same, but normalized (lower case) - use that for dictionary keys and name resolution.
326 """
327 if isinstance(item, MultipleNamedEntityMixin):
328 return item._identifiers
329 elif isinstance(item, NamedEntityMixin): 329 ↛ 332line 329 didn't jump to line 332 because the condition on line 329 was always true
330 return (item._identifier, )
332 ex = TypeError(f"Item '{item}' is neither a NamedEntityMixin nor a MultipleNamedEntityMixin.")
333 ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.")
334 raise ex
337@export
338def normalizedIdentifiersOf(item) -> Tuple[str, ...]:
339 """
340 Return an item's normalized (lower case) identifier(s).
342 This is the form used as dictionary keys and for name resolution, because VHDL identifiers are
343 case-insensitive.
345 :param item: A singularly or plurally named entity.
346 :returns: The item's normalized identifiers.
347 :raises TypeError: If the item is neither singularly nor plurally named.
349 .. seealso::
351 :func:`identifiersOf`
352 The same, but as written in the source - use that for rendering.
353 """
354 if isinstance(item, MultipleNamedEntityMixin):
355 return item._normalizedIdentifiers
356 elif isinstance(item, NamedEntityMixin): 356 ↛ 359line 356 didn't jump to line 359 because the condition on line 356 was always true
357 return (item._normalizedIdentifier, )
359 ex = TypeError(f"Item '{item}' is neither a NamedEntityMixin nor a MultipleNamedEntityMixin.")
360 ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.")
361 raise ex
364@export
365class LabeledEntityMixin(metaclass=ExtendedType, mixin=True):
366 """
367 A ``LabeledEntityMixin`` is a mixin class for all VHDL entities that can have labels.
369 protected variables :attr:`_label` and :attr:`_normalizedLabel` are available to derived classes as well as two
370 readonly properties :attr:`Label` and :attr:`NormalizedLabel` for public access.
372 .. seealso::
374 * :class:`Statement <pyVHDLModel.Common.Statement>`
375 * :class:`Concurrent block statement <pyVHDLModel.Concurrent.ConcurrentBlockStatement>`
376 * :class:`Concurrent case <pyVHDLModel.Concurrent.ConcurrentCase>`
377 """
378 _label: Nullable[str] #: The label of a model entity.
379 _normalizedLabel: Nullable[str] #: The normalized (lower case) label of a model entity.
381 def __init__(self, label: Nullable[str]) -> None:
382 """
383 Initializes a labeled entity.
385 :param label: Label of the model entity.
386 """
387 self._label = label
388 self._normalizedLabel = label.lower() if label is not None else None
390 @readonly
391 def Label(self) -> Nullable[str]:
392 """
393 Read-only property to access the model entity's label (:attr:`_label`).
395 :returns: Label of a model entity.
396 """
397 return self._label
399 @readonly
400 def NormalizedLabel(self) -> Nullable[str]:
401 """
402 Read-only property to access the model entity's normalized label (:attr:`_normalizedLabel`).
404 :returns: Normalized label of a model entity.
405 """
406 return self._normalizedLabel
409@export
410class DocumentedEntityMixin(metaclass=ExtendedType, mixin=True):
411 """
412 A ``DocumentedEntityMixin`` is a mixin class for all VHDL entities that can have an associated documentation.
414 A protected variable :attr:`_documentation` is available to derived classes as well as a readonly property
415 :attr:`Documentation` for public access.
416 """
418 _documentation: Nullable[str] #: The associated documentation of a model entity.
420 def __init__(self, documentation: Nullable[str]) -> None:
421 """
422 Initializes a documented entity.
424 :param documentation: Documentation of a model entity.
425 """
426 self._documentation = documentation
428 @readonly
429 def Documentation(self) -> Nullable[str]:
430 """
431 Read-only property to access the model entity's documentation (:attr:`_documentation`).
433 :returns: Associated documentation of a model entity.
434 """
435 return self._documentation
438@export
439class ConditionalMixin(metaclass=ExtendedType, mixin=True):
440 """
441 A ``ConditionalMixin`` is a mixin-class for all statements with a condition.
443 .. seealso::
445 * :class:`Conditional branch mixin <pyVHDLModel.Base.ConditionalBranchMixin>`
446 * :class:`Assert statement mixin <pyVHDLModel.Base.AssertStatementMixin>`
447 * :class:`Conditional waveform <pyVHDLModel.Common.ConditionalWaveform>`
448 * :class:`Conditional expression <pyVHDLModel.Common.ConditionalExpression>`
449 * :class:`While loop statement <pyVHDLModel.Sequential.WhileLoopStatement>`
450 * :class:`Loop control statement <pyVHDLModel.Sequential.LoopControlStatement>`
451 * :class:`Wait statement <pyVHDLModel.Sequential.WaitStatement>`
452 """
454 _condition: ExpressionUnion #: The condition guarding this statement.
456 def __init__(self, condition: Nullable[ExpressionUnion] = None) -> None:
457 """
458 Initializes a statement with a condition.
460 When the condition is not None, the condition's parent reference is set to this statement.
462 :param condition: The expression representing the condition.
463 """
464 self._condition = condition
465 if condition is not None:
466 condition.Parent = self
468 @readonly
469 def Condition(self) -> ExpressionUnion:
470 """
471 Read-only property to access the condition of a statement (:attr:`_condition`).
473 :returns: The expression representing the condition of a statement.
474 """
475 return self._condition
478@export
479class BranchMixin(metaclass=ExtendedType, mixin=True):
480 """
481 A ``BranchMixin`` is a mixin-class for all statements with branches.
483 .. seealso::
485 * :class:`Conditional branch mixin <pyVHDLModel.Base.ConditionalBranchMixin>`
486 * :class:`Else branch mixin <pyVHDLModel.Base.ElseBranchMixin>`
487 """
489 def __init__(self) -> None:
490 """
491 Initializes a branch.
492 """
493 pass
496@export
497class ConditionalBranchMixin(BranchMixin, ConditionalMixin, mixin=True):
498 """
499 A ``BaseBranch`` is a mixin-class for all branch statements with a condition.
501 .. seealso::
503 * :class:`If branch mixin <pyVHDLModel.Base.IfBranchMixin>`
504 * :class:`Elsif branch mixin <pyVHDLModel.Base.ElsifBranchMixin>`
505 """
506 def __init__(self, condition: ExpressionUnion) -> None:
507 """
508 Initializes a conditional branch.
510 :param condition: The condition guarding this statement.
511 """
512 super().__init__()
513 ConditionalMixin.__init__(self, condition)
516@export
517class IfBranchMixin(ConditionalBranchMixin, mixin=True):
518 """
519 A ``BaseIfBranch`` is a mixin-class for all if-branches.
521 .. seealso::
523 * :class:`If generate branch <pyVHDLModel.Concurrent.IfGenerateBranch>`
524 * :class:`If branch <pyVHDLModel.Sequential.IfBranch>`
525 """
528@export
529class ElsifBranchMixin(ConditionalBranchMixin, mixin=True):
530 """
531 A ``BaseElsifBranch`` is a mixin-class for all elsif-branches.
533 .. seealso::
535 * :class:`Elsif generate branch <pyVHDLModel.Concurrent.ElsifGenerateBranch>`
536 * :class:`Elsif branch <pyVHDLModel.Sequential.ElsifBranch>`
537 """
540@export
541class ElseBranchMixin(BranchMixin, mixin=True):
542 """
543 A ``BaseElseBranch`` is a mixin-class for all else-branches.
545 .. seealso::
547 * :class:`Else generate branch <pyVHDLModel.Concurrent.ElseGenerateBranch>`
548 * :class:`Else branch <pyVHDLModel.Sequential.ElseBranch>`
549 """
552@export
553class ReportStatementMixin(metaclass=ExtendedType, mixin=True):
554 """
555 A ``MixinReportStatement`` is a mixin-class for all report and assert statements.
557 .. seealso::
559 * :class:`Assert statement mixin <pyVHDLModel.Base.AssertStatementMixin>`
560 * :class:`Sequential report statement <pyVHDLModel.Sequential.SequentialReportStatement>`
561 """
563 _message: Nullable[ExpressionUnion] #: The reported message, or ``None`` if none was given.
564 _severity: Nullable[ExpressionUnion] #: The reported severity level, or ``None`` if none was given.
566 def __init__(self, message: Nullable[ExpressionUnion] = None, severity: Nullable[ExpressionUnion] = None) -> None:
567 """
568 Initializes a report statement.
570 :param message: The reported message, or ``None`` if none was given.
571 :param severity: The reported severity level, or ``None`` if none was given.
572 """
573 self._message = message
574 if message is not None: 574 ↛ 577line 574 didn't jump to line 577 because the condition on line 574 was always true
575 message.Parent = self
577 self._severity = severity
578 if severity is not None:
579 severity.Parent = self
581 @readonly
582 def Message(self) -> Nullable[ExpressionUnion]:
583 """
584 Read-only property to access the message (:attr:`_message`).
586 :returns: The message, or ``None`` if not set.
587 """
588 return self._message
590 @readonly
591 def Severity(self) -> Nullable[ExpressionUnion]:
592 """
593 Read-only property to access the severity (:attr:`_severity`).
595 :returns: The severity, or ``None`` if not set.
596 """
597 return self._severity
600@export
601class AssertStatementMixin(ReportStatementMixin, ConditionalMixin, mixin=True):
602 """
603 A ``MixinAssertStatement`` is a mixin-class for all assert statements.
605 .. seealso::
607 * :class:`Concurrent assert statement <pyVHDLModel.Concurrent.ConcurrentAssertStatement>`
608 * :class:`Sequential assert statement <pyVHDLModel.Sequential.SequentialAssertStatement>`
609 """
611 def __init__(self, condition: ExpressionUnion, message: Nullable[ExpressionUnion] = None, severity: Nullable[ExpressionUnion] = None) -> None:
612 """
613 Initializes an assert statement.
615 :param condition: The condition guarding this statement.
616 :param message: The reported message, or ``None`` if none was given.
617 :param severity: The reported severity level, or ``None`` if none was given.
618 """
619 super().__init__(message, severity)
620 ConditionalMixin.__init__(self, condition)
623class BlockStatementMixin(metaclass=ExtendedType, mixin=True):
624 """
625 A ``BlockStatement`` is a mixin-class for all block statements.
627 .. seealso::
629 * :class:`Concurrent block statement <pyVHDLModel.Concurrent.ConcurrentBlockStatement>`
630 """
632 def __init__(self) -> None:
633 """
634 Initializes a block statement.
635 """
636 pass
639@export
640class BaseChoice(ModelEntity):
641 """
642 A ``Choice`` is a base-class for all choices.
644 .. seealso::
646 * :class:`Concurrent choice <pyVHDLModel.Concurrent.ConcurrentChoice>`
647 * :class:`Sequential choice <pyVHDLModel.Sequential.SequentialChoice>`
648 """
651@export
652class BaseCase(ModelEntity):
653 """
654 A ``Case`` is a base-class for all cases.
656 .. seealso::
658 * :class:`Selected waveform <pyVHDLModel.Common.SelectedWaveform>`
659 * :class:`Others selected waveform <pyVHDLModel.Common.OthersSelectedWaveform>`
660 * :class:`Selected expression <pyVHDLModel.Common.SelectedExpression>`
661 * :class:`Others selected expression <pyVHDLModel.Common.OthersSelectedExpression>`
662 * :class:`Concurrent case <pyVHDLModel.Concurrent.ConcurrentCase>`
663 * :class:`Sequential case <pyVHDLModel.Sequential.SequentialCase>`
664 """
667@export
668class ChoicesMixin(metaclass=ExtendedType, mixin=True):
669 """
670 A mixin-class for all statements/entities holding a list of :class:`BaseChoice`.
672 .. seealso::
674 * :class:`Selected waveform <pyVHDLModel.Common.SelectedWaveform>`
675 * :class:`Selected expression <pyVHDLModel.Common.SelectedExpression>`
676 * :class:`Concurrent case <pyVHDLModel.Concurrent.ConcurrentCase>`
677 * :class:`Sequential case <pyVHDLModel.Sequential.SequentialCase>`
678 """
680 _choices: List[BaseChoice] #: List of all choices selecting this alternative.
682 def __init__(self, choices: Nullable[Iterable[BaseChoice]] = None) -> None:
683 """
684 Initializes choices.
686 :param choices: List of all choices selecting this alternative.
687 """
688 self._choices = []
689 if choices is not None:
690 for choice in choices:
691 self._choices.append(choice)
692 choice.Parent = self
694 @readonly
695 def Choices(self) -> List[BaseChoice]:
696 """
697 Read-only property to access the choices (:attr:`_choices`).
699 :returns: List of choices.
700 """
701 return self._choices
704@export
705class Range(ModelEntity):
706 """
707 Base-class for all ranges.
709 VHDL's ``range`` rule offers a range denoted by a name (:class:`RangeFromName`) as well as a range
710 given by explicit bounds (:class:`SimpleRange`).
712 .. seealso::
714 * :class:`Simple range <pyVHDLModel.Base.SimpleRange>`
715 * :class:`Range from name <pyVHDLModel.Base.RangeFromName>`
716 """
719@export
720class SimpleRange(Range):
721 """
722 A range with both bounds given as expressions, e.g. ``0 to 7``.
723 """
725 _leftBound: ExpressionUnion #: The range's left bound.
726 _rightBound: ExpressionUnion #: The range's right bound.
727 _direction: Direction #: The range's direction, either ascending (``to``) or descending (``downto``).
729 def __init__(self, leftBound: ExpressionUnion, rightBound: ExpressionUnion, direction: Direction, parent: Nullable[ModelEntity] = None) -> None:
730 """
731 Initialize a simple range.
733 :param leftBound: The range's left bound.
734 :param rightBound: The range's right bound.
735 :param direction: The range's direction (``to`` or ``downto``).
736 :param parent: The parent model entity.
737 """
738 super().__init__(parent)
740 self._leftBound = leftBound
741 leftBound.Parent = self
743 self._rightBound = rightBound
744 rightBound.Parent = self
746 self._direction = direction
748 @readonly
749 def LeftBound(self) -> ExpressionUnion:
750 """
751 Read-only property to access the range's left bound (:attr:`_leftBound`).
753 :returns: The left bound.
754 """
755 return self._leftBound
757 @readonly
758 def RightBound(self) -> ExpressionUnion:
759 """
760 Read-only property to access the range's right bound (:attr:`_rightBound`).
762 :returns: The right bound.
763 """
764 return self._rightBound
766 @readonly
767 def Direction(self) -> Direction:
768 """
769 Read-only property to access the range's direction (:attr:`_direction`).
771 :returns: The direction.
772 """
773 return self._direction
775 def __str__(self) -> str:
776 """
777 Formats the simple range.
779 **Format:** ``0 to 7``
781 :returns: Formatted simple range.
782 """
783 return f"{self._leftBound!s} {self._direction!s} {self._rightBound!s}"
786@export
787class RangeFromName(Range):
788 """
789 A range denoted by a name, so its bounds are inferred from whatever that name references.
791 The name is represented by a :class:`~pyVHDLModel.Symbol.Symbol`, so the bounds become available once
792 that symbol is resolved. A constrained subtype indication keeps its type mark *and* its range
793 constraint, because it's carried by a :class:`~pyVHDLModel.Symbol.ConstrainedScalarSubtypeSymbol`.
795 .. note::
797 Two forms reach this class, because a parser can't tell them apart beyond "a name, optionally with
798 a range constraint":
800 * a range attribute like ``vector'range``, and
801 * a discrete subtype indication like ``bit`` or ``integer range 0 to 7``.
803 VHDL's grammar puts the latter one level up (``discrete_range ::= discrete_subtype_indication |
804 range``), so representing both as a range deviates from the rule split deliberately.
805 """
807 _symbol: 'Symbol' #: Reference to the name the range's bounds are inferred from.
809 def __init__(self, symbol: 'Symbol', parent: Nullable[ModelEntity] = None) -> None:
810 """
811 Initialize a range denoted by a name.
813 :param symbol: The symbol referencing the range attribute or discrete subtype.
814 :param parent: The parent model entity.
815 """
816 super().__init__(parent)
818 self._symbol = symbol
819 symbol.Parent = self
821 @readonly
822 def Symbol(self) -> 'Symbol':
823 """
824 Read-only property to access the referenced symbol (:attr:`_symbol`).
826 :returns: The symbol.
827 """
828 return self._symbol
830 def __str__(self) -> str:
831 """
832 Formats the range denoted by a name.
834 **Format:** ``v'range``
836 :returns: Formatted range denoted by a name.
837 """
838 return f"{self._symbol!s}"
841@export
842class WaveformElement(ModelEntity):
843 """
844 Represents one element of a waveform in a signal assignment.
846 A waveform element assigns a value (:data:`Expression`) after an optional delay (:data:`After`).
848 .. admonition:: Example
850 .. code-block:: VHDL
852 s <= '1' after 5 ns;
853 -- ^^^ <- Expression
854 -- ^^^^ <- After
856 .. seealso::
858 * :class:`Waveform of a simple assignment <pyVHDLModel.Common.WaveformMixin>`
859 * :class:`Waveform of one conditional branch <pyVHDLModel.Common.ConditionalWaveform>`
860 * :class:`Waveform of one selected alternative <pyVHDLModel.Common.SelectedWaveform>`
861 """
862 _expression: ExpressionUnion #: The value this waveform element assigns.
863 _after: ExpressionUnion #: The delay after which the value is assigned, or ``None`` if none was given.
865 def __init__(self, expression: ExpressionUnion, after: Nullable[ExpressionUnion] = None, parent: Nullable[ModelEntity] = None) -> None:
866 """
867 Initializes a waveform element.
869 :param expression: The value this waveform element assigns.
870 :param after: The delay after which the value is assigned, or ``None`` if none was given.
871 :param parent: The parent model entity of this entity.
872 """
873 super().__init__(parent)
875 self._expression = expression
876 expression.Parent = self
878 self._after = after
879 if after is not None:
880 after.Parent = self
882 @readonly
883 def Expression(self) -> ExpressionUnion:
884 """
885 Read-only property to access the expression (:attr:`_expression`).
887 :returns: The expression.
888 """
889 return self._expression
891 @readonly
892 def After(self) -> Expression:
893 """
894 Read-only property to access the waveform element's delay (:attr:`_after`).
896 :returns: The after.
897 """
898 return self._after