Coverage for pyVHDLModel/Common.py: 99%
151 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.
35Common definitions and Mixins are used by many classes in the model as base-classes.
36"""
37from typing import List, Iterable, Union, Optional as Nullable
39from pyTooling.Decorators import export, readonly
40from pyTooling.MetaClasses import ExtendedType
42from pyVHDLModel.Base import ModelEntity, LabeledEntityMixin, BaseCase, BaseChoice, WaveformElement, ConditionalMixin, ChoicesMixin
43from pyVHDLModel.Expression import BaseExpression, QualifiedExpression, FunctionCall, TypeConversion, Literal
44from pyVHDLModel.Symbol import Symbol, SignalSymbol, VariableSymbol
45from pyVHDLModel.Association import ParameterAssociationItem
48ExpressionUnion = Union[
49 BaseExpression,
50 QualifiedExpression,
51 FunctionCall,
52 TypeConversion,
53 # ConstantOrSymbol, TODO: ObjectSymbol
54 Literal,
55]
58@export
59class AllowBlackboxMixin(metaclass=ExtendedType, mixin=True):
60 """
61 A mixin-class for language entities that may permit blackboxes.
63 The setting is inherited from the parent when not set locally (:data:`AllowBlackbox`).
65 .. seealso::
67 * :class:`Concurrent block statement <pyVHDLModel.Concurrent.ConcurrentBlockStatement>`
68 * :class:`Generate branch <pyVHDLModel.Concurrent.GenerateBranch>`
69 * :class:`Generate statement <pyVHDLModel.Concurrent.GenerateStatement>`
70 * :class:`Concurrent case <pyVHDLModel.Concurrent.ConcurrentCase>`
71 * :class:`Package <pyVHDLModel.DesignUnit.Package>`
72 * :class:`Entity <pyVHDLModel.DesignUnit.Entity>`
73 * :class:`Architecture <pyVHDLModel.DesignUnit.Architecture>`
74 * :class:`Component <pyVHDLModel.DesignUnit.Component>`
75 * :class:`Design <pyVHDLModel.Design>`
76 * :class:`Library <pyVHDLModel.Library>`
77 """
78 _allowBlackbox: Nullable[bool] #: Allow blackboxes for components in language entity.
80 def __init__(self, allowBlackbox: Nullable[bool] = None) -> None:
81 """
82 Initializes a hierarchical model entity allow for blackboxes.
84 :param allowBlackbox: Allow blackboxes for components in language entity.
85 """
86 self._allowBlackbox = allowBlackbox
88 @property
89 def AllowBlackbox(self) -> bool:
90 """
91 Property to return whether a design supports blackboxes, inherited from the parent if not set locally
92 (:attr:`_allowBlackbox`).
94 .. rubric:: Algorithm
96 1. If allow blackbox property is locally set, return the local value,
97 2. Otherwise, return allow blackbox value from parent object.
99 :returns: ``True``, if blackboxes are allowed.
100 :raises VHDLModelException: If neither a local value is set nor a parent object is available to inherit the
101 value from.
102 """
103 if self._allowBlackbox is not None:
104 return self._allowBlackbox
105 elif self._parent is None:
106 from pyVHDLModel.Exception import VHDLModelException
108 raise VHDLModelException(f"AllowBlackbox is not set on {self!r} and no parent is available to inherit it from.")
109 else:
110 return self._parent.AllowBlackbox
112 @AllowBlackbox.setter
113 def AllowBlackbox(self, value: Nullable[bool]) -> None:
114 self._allowBlackbox = value
117@export
118class Statement(ModelEntity, LabeledEntityMixin):
119 """
120 A ``Statement`` is a base-class for all statements.
122 .. seealso::
124 * :class:`Concurrent statement <pyVHDLModel.Concurrent.ConcurrentStatement>`
125 * :class:`Sequential statement <pyVHDLModel.Sequential.SequentialStatement>`
126 """
127 def __init__(self, label: Nullable[str] = None, parent=None) -> None:
128 """
129 Initializes a statement.
131 :param label: The label of a model entity.
132 :param parent: The parent model entity of this entity.
133 """
134 super().__init__(parent)
135 LabeledEntityMixin.__init__(self, label)
138@export
139class ProcedureCallMixin(metaclass=ExtendedType, mixin=True):
140 """
141 A mixin-class for statements calling a procedure.
143 The called procedure is available as :data:`Procedure`, its actual parameters as
144 :data:`ParameterAssociationItems`.
146 .. seealso::
148 * :class:`Concurrent procedure call <pyVHDLModel.Concurrent.ConcurrentProcedureCall>`
149 * :class:`Sequential procedure call <pyVHDLModel.Sequential.SequentialProcedureCall>`
150 """
151 # TODO: implement a ProcedureSymbol
152 _procedure: Symbol #: Reference to the called procedure.
153 _parameterAssociationItems: List[ParameterAssociationItem] #: List of all parameter associations of the call.
155 def __init__(self, procedureName: Symbol, parameterAssociationItems: Nullable[Iterable[ParameterAssociationItem]] = None) -> None:
156 """
157 Initializes a procedure call.
159 :param procedureName: Reference to the called procedure.
160 :param parameterAssociationItems: List of all parameter associations of the call.
161 """
162 self._procedure = procedureName
163 procedureName.Parent = self
165 # TODO: extract to mixin
166 self._parameterAssociationItems = []
167 if parameterAssociationItems is not None:
168 for parameterMapping in parameterAssociationItems:
169 self._parameterAssociationItems.append(parameterMapping)
170 parameterMapping.Parent = self
172 @readonly
173 def Procedure(self) -> Symbol:
174 """
175 Read-only property to access the procedure (:attr:`_procedure`).
177 :returns: The procedure.
178 """
179 return self._procedure
181 @readonly
182 def ParameterAssociationItems(self) -> List[ParameterAssociationItem]:
183 """
184 Read-only property to access the parameter association items (:attr:`_parameterAssociationItems`).
186 :returns: List of parameter association items.
187 """
188 return self._parameterAssociationItems
191@export
192class AssignmentMixin(metaclass=ExtendedType, mixin=True):
193 """
194 A mixin-class for all assignment statements.
196 .. seealso::
198 * :class:`Signal assignment mixin <pyVHDLModel.Common.SignalAssignmentMixin>`
199 * :class:`Variable assignment mixin <pyVHDLModel.Common.VariableAssignmentMixin>`
200 * :class:`Conditional variable assignment <pyVHDLModel.Sequential.SequentialConditionalVariableAssignment>`
201 * :class:`Sequential selected variable assignment <pyVHDLModel.Sequential.SequentialSelectedVariableAssignment>`
202 """
204 _target: Symbol #: Reference to the assignment's destination.
206 def __init__(self, target: Symbol) -> None:
207 """
208 Initializes an assignment.
210 :param target: Reference to the assignment's destination.
211 """
212 self._target = target
213 target.Parent = self
215 @readonly
216 def Target(self) -> Symbol:
217 """
218 Read-only property to access the target (:attr:`_target`).
220 :returns: The target.
221 """
222 return self._target
225@export
226class SignalAssignmentMixin(AssignmentMixin, mixin=True):
227 """
228 A mixin-class for all signal assignment statements.
230 .. seealso::
232 * :class:`Concurrent signal assignment <pyVHDLModel.Concurrent.ConcurrentSignalAssignment>`
233 * :class:`Sequential signal assignment <pyVHDLModel.Sequential.SequentialSignalAssignment>`
234 * :class:`Conditional signal assignment <pyVHDLModel.Sequential.SequentialConditionalSignalAssignment>`
235 * :class:`Sequential selected signal assignment <pyVHDLModel.Sequential.SequentialSelectedSignalAssignment>`
236 * :class:`Signal force assignment <pyVHDLModel.Sequential.SignalForceAssignment>`
237 * :class:`Signal release assignment <pyVHDLModel.Sequential.SignalReleaseAssignment>`
238 """
240 @readonly
241 def Target(self) -> SignalSymbol:
242 """
243 Read-only property to access the target (:attr:`_target`).
245 :returns: The target.
246 """
247 return self._target
250@export
251class VariableAssignmentMixin(AssignmentMixin, mixin=True):
252 """
253 A mixin-class for all variable assignment statements.
255 .. seealso::
257 * :class:`Sequential variable assignment <pyVHDLModel.Sequential.SequentialVariableAssignment>`
258 """
260 # FIXME: move to sequential?
261 _expression: ExpressionUnion #: The assigned expression.
263 def __init__(self, target: VariableSymbol, expression: ExpressionUnion) -> None:
264 """
265 Initializes a variable assignment.
267 :param target: Reference to the assignment's destination.
268 :param expression: The assigned expression.
269 """
270 super().__init__(target)
272 self._expression = expression
273 expression.Parent = self
275 @readonly
276 def Target(self) -> VariableSymbol:
277 """
278 Read-only property to access the target (:attr:`_target`).
280 :returns: The target.
281 """
282 return self._target
284 @readonly
285 def Expression(self) -> ExpressionUnion:
286 """
287 Read-only property to access the expression (:attr:`_expression`).
289 :returns: The expression.
290 """
291 return self._expression
294@export
295class WaveformMixin(metaclass=ExtendedType, mixin=True):
296 """
297 A mixin-class for all statements/entities holding a waveform (a list of :class:`WaveformElement`).
299 .. seealso::
301 * :class:`Conditional waveform <pyVHDLModel.Common.ConditionalWaveform>`
302 * :class:`Selected waveform <pyVHDLModel.Common.SelectedWaveform>`
303 * :class:`Others selected waveform <pyVHDLModel.Common.OthersSelectedWaveform>`
304 * :class:`Concurrent simple signal assignment <pyVHDLModel.Concurrent.ConcurrentSimpleSignalAssignment>`
305 * :class:`Sequential simple signal assignment <pyVHDLModel.Sequential.SequentialSimpleSignalAssignment>`
306 * :class:`Waveform element <pyVHDLModel.Base.WaveformElement>`
307 """
309 _waveform: List[WaveformElement] #: List of all waveform elements, in the order they were written.
311 def __init__(self, waveform: Iterable[WaveformElement]) -> None:
312 """
313 Initializes a waveform.
315 :param waveform: List of all waveform elements, in the order they were written.
316 """
317 self._waveform = []
318 for waveformElement in waveform:
319 self._waveform.append(waveformElement)
320 waveformElement.Parent = self
322 @readonly
323 def Waveform(self) -> List[WaveformElement]:
324 """
325 Read-only property to access the waveform (:attr:`_waveform`).
327 :returns: List of waveform.
328 """
329 return self._waveform
332@export
333class ExpressionMixin(metaclass=ExtendedType, mixin=True):
334 """
335 A mixin-class for all statements/entities holding a single expression.
337 .. seealso::
339 * :class:`Conditional expression <pyVHDLModel.Common.ConditionalExpression>`
340 * :class:`Selected expression <pyVHDLModel.Common.SelectedExpression>`
341 * :class:`Others selected expression <pyVHDLModel.Common.OthersSelectedExpression>`
342 * :class:`Concurrent selected signal assignment <pyVHDLModel.Concurrent.ConcurrentSelectedSignalAssignment>`
343 * :class:`Sequential selected variable assignment <pyVHDLModel.Sequential.SequentialSelectedVariableAssignment>`
344 * :class:`Sequential selected signal assignment <pyVHDLModel.Sequential.SequentialSelectedSignalAssignment>`
345 * :class:`Signal force assignment <pyVHDLModel.Sequential.SignalForceAssignment>`
346 """
348 _expression: ExpressionUnion #: The expression held by this construct.
350 def __init__(self, expression: ExpressionUnion) -> None:
351 """
352 Initializes an expression.
354 :param expression: The expression held by this construct.
355 """
356 self._expression = expression
357 expression.Parent = self
359 @readonly
360 def Expression(self) -> ExpressionUnion:
361 """
362 Read-only property to access the expression (:attr:`_expression`).
364 :returns: The expression.
365 """
366 return self._expression
369@export
370class ConditionalWaveform(ModelEntity, WaveformMixin, ConditionalMixin):
371 """
372 Represents one branch of a conditional signal assignment.
374 Each branch pairs a waveform (:data:`Waveform`) with a condition (:data:`Condition`). The final
375 branch has no ``when``, so its condition is ``None``.
377 .. admonition:: Example
379 .. code-block:: VHDL
381 s <= '1' when cond else '0';
382 -- ^^^^^^^^^^^^^ <- this branch: Waveform=['1'], Condition=cond
383 -- ^^^ <- final branch (no ``when``): Waveform=['0'], Condition=None
385 .. seealso::
387 * :class:`Waveform element <pyVHDLModel.Base.WaveformElement>`
388 * :class:`Conditional expression <pyVHDLModel.Common.ConditionalExpression>`
389 """
391 def __init__(
392 self,
393 waveform: Iterable[WaveformElement],
394 condition: Nullable[ExpressionUnion] = None,
395 parent: Nullable[ModelEntity] = None
396 ) -> None:
397 """
398 Initializes a conditional waveform.
400 :param waveform: List of all waveform elements, in the order they were written.
401 :param condition: The condition selecting this alternative.
402 :param parent: The parent model entity of this entity.
403 """
404 super().__init__(parent)
405 WaveformMixin.__init__(self, waveform)
406 ConditionalMixin.__init__(self, condition)
409@export
410class ConditionalExpression(ModelEntity, ExpressionMixin, ConditionalMixin):
411 """
412 Represents one branch of a conditional variable assignment.
414 Each branch pairs an expression (:data:`Expression`) with a condition (:data:`Condition`). The
415 final branch has no ``when``, so its condition is ``None``.
417 .. admonition:: Example
419 .. code-block:: VHDL
421 v := '1' when cond else '0';
422 -- ^^^^^^^^^^^^^ <- this branch: Expression='1', Condition=cond
423 -- ^^^ <- final branch (no ``when``): Expression='0', Condition=None
425 .. seealso::
427 * :class:`Conditional waveform <pyVHDLModel.Common.ConditionalWaveform>`
428 """
430 def __init__(
431 self,
432 expression: ExpressionUnion,
433 condition: Nullable[ExpressionUnion] = None,
434 parent: Nullable[ModelEntity] = None
435 ) -> None:
436 """
437 Initializes a conditional expression.
439 :param expression: The value assigned when the condition holds.
440 :param condition: The condition selecting this alternative.
441 :param parent: The parent model entity of this entity.
442 """
443 super().__init__(parent)
444 ExpressionMixin.__init__(self, expression)
445 ConditionalMixin.__init__(self, condition)
448@export
449class ConditionalWaveformsMixin(metaclass=ExtendedType, mixin=True):
450 """
451 A mixin-class for all statements holding a list of :class:`ConditionalWaveform` (both the
452 concurrent and sequential forms of a conditional signal assignment).
454 .. seealso::
456 * :class:`Conditional signal assignment <pyVHDLModel.Concurrent.ConcurrentConditionalSignalAssignment>`
457 * :class:`Conditional signal assignment <pyVHDLModel.Sequential.SequentialConditionalSignalAssignment>` """
459 _conditionalWaveforms: List[ConditionalWaveform] #: All alternatives, in order.
461 def __init__(self, conditionalWaveforms: Iterable[ConditionalWaveform]) -> None:
462 """
463 Initializes conditional waveforms.
465 :param conditionalWaveforms: All alternatives, in order.
466 """
467 self._conditionalWaveforms = []
468 for conditionalWaveform in conditionalWaveforms:
469 self._conditionalWaveforms.append(conditionalWaveform)
470 conditionalWaveform.Parent = self
472 @readonly
473 def ConditionalWaveforms(self) -> List[ConditionalWaveform]:
474 """
475 Read-only property to access the conditional waveforms (:attr:`_conditionalWaveforms`).
477 :returns: List of conditional waveforms.
478 """
479 return self._conditionalWaveforms
482@export
483class SelectedWaveform(BaseCase, WaveformMixin, ChoicesMixin):
484 """
485 Represents one alternative of a selected signal assignment.
487 Each alternative pairs a waveform (:data:`Waveform`) with the choices selecting it
488 (:data:`Choices`).
490 .. admonition:: Example
492 .. code-block:: VHDL
494 with sel select s <= '1' when '0', '0' when others;
495 -- ^^^^^^^^^^^^ <- this alternative: Choices=['0'], Waveform=['1']
497 .. seealso::
499 * :class:`Waveform element <pyVHDLModel.Base.WaveformElement>`
500 * :class:`Selected expression <pyVHDLModel.Common.SelectedExpression>`
501 """
503 def __init__(
504 self,
505 choices: Iterable[BaseChoice],
506 waveform: Iterable[WaveformElement],
507 parent: Nullable[ModelEntity] = None
508 ) -> None:
509 """
510 Initializes a selected waveform.
512 :param choices: List of all choices selecting this alternative.
513 :param waveform: List of all waveform elements, in the order they were written.
514 :param parent: The parent model entity of this entity.
515 """
516 super().__init__(parent)
517 WaveformMixin.__init__(self, waveform)
518 ChoicesMixin.__init__(self, choices)
521@export
522class OthersSelectedWaveform(BaseCase, WaveformMixin):
523 """
524 Represents the ``others`` alternative of a selected signal assignment.
526 It supplies the waveform (:data:`Waveform`) for every choice not named explicitly.
528 .. admonition:: Example
530 .. code-block:: VHDL
532 with sel select s <= '1' when '0', '0' when others;
533 -- ^^^^^^^^^^^^^^^ <- the others alternative
534 """
536 def __init__(self, waveform: Iterable[WaveformElement], parent: Nullable[ModelEntity] = None) -> None:
537 """
538 Initializes an others selected waveform.
540 :param waveform: List of all waveform elements, in the order they were written.
541 :param parent: The parent model entity of this entity.
542 """
543 super().__init__(parent)
544 WaveformMixin.__init__(self, waveform)
547@export
548class SelectedExpression(BaseCase, ExpressionMixin, ChoicesMixin):
549 """
550 Represents one alternative of a selected variable assignment.
552 Each alternative pairs an expression (:data:`Expression`) with the choices selecting it
553 (:data:`Choices`).
555 .. admonition:: Example
557 .. code-block:: VHDL
559 with sel select v := '1' when '0', '0' when others;
560 -- ^^^^^^^^^^^^ <- this alternative: Choices=['0'], Expression='1'
562 .. seealso::
564 * :class:`Selected waveform <pyVHDLModel.Common.SelectedWaveform>`
565 """
567 def __init__(
568 self,
569 choices: Iterable[BaseChoice],
570 expression: ExpressionUnion,
571 parent: Nullable[ModelEntity] = None
572 ) -> None:
573 """
574 Initializes a selected expression.
576 :param choices: List of all choices selecting this alternative.
577 :param expression: The value assigned for the matching choices.
578 :param parent: The parent model entity of this entity.
579 """
580 super().__init__(parent)
581 ExpressionMixin.__init__(self, expression)
582 ChoicesMixin.__init__(self, choices)
585@export
586class OthersSelectedExpression(BaseCase, ExpressionMixin):
587 """
588 Represents the ``others`` alternative of a selected variable assignment.
590 It supplies the expression (:data:`Expression`) for every choice not named explicitly.
592 .. admonition:: Example
594 .. code-block:: VHDL
596 with sel select v := '1' when '0', '0' when others;
597 -- ^^^^^^^^^^^^^^^ <- the others alternative
598 """
600 def __init__(self, expression: ExpressionUnion, parent: Nullable[ModelEntity] = None) -> None:
601 """
602 Initializes an others selected expression.
604 :param expression: The value assigned for every unnamed choice.
605 :param parent: The parent model entity of this entity.
606 """
607 super().__init__(parent)
608 ExpressionMixin.__init__(self, expression)
611@export
612class SelectedWaveformsMixin(metaclass=ExtendedType, mixin=True):
613 """
614 A mixin-class for all statements holding a list of :class:`SelectedWaveform`/
615 :class:`OthersSelectedWaveform` (both the concurrent and sequential forms of a selected signal
616 assignment).
618 .. seealso::
620 * :class:`Concurrent selected signal assignment <pyVHDLModel.Concurrent.ConcurrentSelectedSignalAssignment>`
621 * :class:`Sequential selected signal assignment <pyVHDLModel.Sequential.SequentialSelectedSignalAssignment>`
622 """
624 _selectedWaveforms: List[Union[SelectedWaveform, OthersSelectedWaveform]] #: All alternatives, in order.
626 def __init__(self, selectedWaveforms: Iterable[Union[SelectedWaveform, OthersSelectedWaveform]]) -> None:
627 """
628 Initializes selected waveforms.
630 :param selectedWaveforms: All alternatives, in order.
631 """
632 self._selectedWaveforms = []
633 for selectedWaveform in selectedWaveforms:
634 self._selectedWaveforms.append(selectedWaveform)
635 selectedWaveform.Parent = self
637 @readonly
638 def SelectedWaveforms(self) -> List[Union[SelectedWaveform, OthersSelectedWaveform]]:
639 """
640 Read-only property to access the selected waveforms (:attr:`_selectedWaveforms`).
642 :returns: List of selected waveforms.
643 """
644 return self._selectedWaveforms
647@export
648class SelectedExpressionsMixin(metaclass=ExtendedType, mixin=True):
649 """
650 A mixin-class for all statements holding a list of :class:`SelectedExpression`/
651 :class:`OthersSelectedExpression`.
653 .. seealso::
655 * :class:`Sequential selected variable assignment <pyVHDLModel.Sequential.SequentialSelectedVariableAssignment>`
656 """
658 _selectedExpressions: List[Union[SelectedExpression, OthersSelectedExpression]] #: All alternatives, in order.
660 def __init__(self, selectedExpressions: Iterable[Union[SelectedExpression, OthersSelectedExpression]]) -> None:
661 """
662 Initializes selected expressions.
664 :param selectedExpressions: All alternatives, in order.
665 """
666 self._selectedExpressions = []
667 for selectedExpression in selectedExpressions:
668 self._selectedExpressions.append(selectedExpression)
669 selectedExpression.Parent = self
671 @readonly
672 def SelectedExpressions(self) -> List[Union[SelectedExpression, OthersSelectedExpression]]:
673 """
674 Read-only property to access the selected expressions (:attr:`_selectedExpressions`).
676 :returns: List of selected expressions.
677 """
678 return self._selectedExpressions