Coverage for pyVHDLModel/Base.py: 77%
178 statements
« prev ^ index » next coverage.py v7.6.7, created at 2024-11-22 22:15 +0000
« prev ^ index » next coverage.py v7.6.7, created at 2024-11-22 22:15 +0000
1# ==================================================================================================================== #
2# __ ___ _ ____ _ __ __ _ _ #
3# _ __ _ \ \ / / | | | _ \| | | \/ | ___ __| | ___| | #
4# | '_ \| | | \ \ / /| |_| | | | | | | |\/| |/ _ \ / _` |/ _ \ | #
5# | |_) | |_| |\ V / | _ | |_| | |___| | | | (_) | (_| | __/ | #
6# | .__/ \__, | \_/ |_| |_|____/|_____|_| |_|\___/ \__,_|\___|_| #
7# |_| |___/ #
8# ==================================================================================================================== #
9# Authors: #
10# Patrick Lehmann #
11# #
12# License: #
13# ==================================================================================================================== #
14# Copyright 2017-2024 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, Iterable, Optional as Nullable, Union, cast
40from pyTooling.Decorators import export, readonly
41from pyTooling.MetaClasses import ExtendedType
44__all__ = ["ExpressionUnion"]
47ExpressionUnion = Union[
48 'BaseExpression',
49 'QualifiedExpression',
50 'FunctionCall',
51 'TypeConversion',
52 # ConstantOrSymbol, TODO: ObjectSymbol
53 'Literal',
54]
57@export
58@unique
59class Direction(Enum):
60 """An enumeration representing a direction in a range (``to`` or ``downto``)."""
62 To = 0 #: Ascending direction
63 DownTo = 1 #: Descending direction
65 def __str__(self) -> str:
66 """
67 Formats the direction to ``to`` or ``downto``.
69 :returns: Formatted direction.
70 """
71 return ("to", "downto")[cast(int, self.value)] # TODO: check performance
74@export
75@unique
76class Mode(Enum):
77 """
78 A ``Mode`` is an enumeration. It represents the direction of data exchange (``in``, ``out``, ...) for objects in
79 generic, port or parameter lists.
81 In case no *mode* is defined, ``Default`` is used, so the *mode* is inferred from context.
82 """
84 Default = 0 #: Mode not defined, thus it's context dependent.
85 In = 1 #: Input
86 Out = 2 #: Output
87 InOut = 3 #: Bi-directional
88 Buffer = 4 #: Buffered output
89 Linkage = 5 #: undocumented
91 def __str__(self) -> str:
92 """
93 Formats the direction.
95 :returns: Formatted direction.
96 """
97 return ("", "in", "out", "inout", "buffer", "linkage")[cast(int, self.value)] # TODO: check performance
100@export
101class ModelEntity(metaclass=ExtendedType, slots=True):
102 """
103 ``ModelEntity`` is the base-class for all classes in the VHDL language model, except for mixin classes (see multiple
104 inheritance) and enumerations.
106 Each entity in this model has a reference to its parent entity. Therefore, a protected variable :attr:`_parent` is
107 available and a readonly property :attr:`Parent`.
108 """
110 _parent: 'ModelEntity' #: Reference to a parent entity in the logical model hierarchy.
112 def __init__(self, parent: Nullable["ModelEntity"] = None) -> None:
113 """
114 Initializes a VHDL model entity.
116 :param parent: The parent model entity of this entity.
117 """
118 self._parent = parent
120 @readonly
121 def Parent(self) -> 'ModelEntity':
122 """
123 Read-only property to access the model entity's parent element reference in a logical hierarchy (:attr:`_parent`).
125 :returns: Reference to the parent entity.
126 """
127 return self._parent
129 def GetAncestor(self, type: Type) -> 'ModelEntity':
130 parent = self._parent
131 while not isinstance(parent, type):
132 parent = parent._parent
134 return parent
137@export
138class NamedEntityMixin(metaclass=ExtendedType, mixin=True):
139 """
140 A ``NamedEntityMixin`` is a mixin class for all VHDL entities that have identifiers.
142 Protected variables :attr:`_identifier` and :attr:`_normalizedIdentifier` are available to derived classes as well as
143 two readonly properties :attr:`Identifier` and :attr:`NormalizedIdentifier` for public access.
144 """
146 _identifier: str #: The identifier of a model entity.
147 _normalizedIdentifier: str #: The normalized (lower case) identifier of a model entity.
149 def __init__(self, identifier: str) -> None:
150 """
151 Initializes a named entity.
153 :param identifier: Identifier (name) of the model entity.
154 """
155 self._identifier = identifier
156 self._normalizedIdentifier = identifier.lower()
158 @readonly
159 def Identifier(self) -> str:
160 """
161 Returns a model entity's identifier (name).
163 :returns: Name of a model entity.
164 """
165 return self._identifier
167 @readonly
168 def NormalizedIdentifier(self) -> str:
169 """
170 Returns a model entity's normalized identifier (lower case name).
172 :returns: Normalized name of a model entity.
173 """
174 return self._normalizedIdentifier
177@export
178class MultipleNamedEntityMixin(metaclass=ExtendedType, mixin=True):
179 """
180 A ``MultipleNamedEntityMixin`` is a mixin class for all VHDL entities that declare multiple instances at once by
181 defining multiple identifiers.
183 Protected variables :attr:`_identifiers` and :attr:`_normalizedIdentifiers` are available to derived classes as well
184 as two readonly properties :attr:`Identifiers` and :attr:`NormalizedIdentifiers` for public access.
185 """
187 _identifiers: Tuple[str] #: A list of identifiers.
188 _normalizedIdentifiers: Tuple[str] #: A list of normalized (lower case) identifiers.
190 def __init__(self, identifiers: Iterable[str]) -> None:
191 """
192 Initializes a multiple-named entity.
194 :param identifiers: Sequence of identifiers (names) of the model entity.
195 """
196 self._identifiers = tuple(identifiers)
197 self._normalizedIdentifiers = tuple([identifier.lower() for identifier in identifiers])
199 @readonly
200 def Identifiers(self) -> Tuple[str]:
201 """
202 Returns a model entity's tuple of identifiers (names).
204 :returns: Tuple of identifiers.
205 """
206 return self._identifiers
208 @readonly
209 def NormalizedIdentifiers(self) -> Tuple[str]:
210 """
211 Returns a model entity's tuple of normalized identifiers (lower case names).
213 :returns: Tuple of normalized identifiers.
214 """
215 return self._normalizedIdentifiers
218@export
219class LabeledEntityMixin(metaclass=ExtendedType, mixin=True):
220 """
221 A ``LabeledEntityMixin`` is a mixin class for all VHDL entities that can have labels.
223 protected variables :attr:`_label` and :attr:`_normalizedLabel` are available to derived classes as well as two
224 readonly properties :attr:`Label` and :attr:`NormalizedLabel` for public access.
225 """
226 _label: Nullable[str] #: The label of a model entity.
227 _normalizedLabel: Nullable[str] #: The normalized (lower case) label of a model entity.
229 def __init__(self, label: Nullable[str]) -> None:
230 """
231 Initializes a labeled entity.
233 :param label: Label of the model entity.
234 """
235 self._label = label
236 self._normalizedLabel = label.lower() if label is not None else None
238 @readonly
239 def Label(self) -> Nullable[str]:
240 """
241 Returns a model entity's label.
243 :returns: Label of a model entity.
244 """
245 return self._label
247 @readonly
248 def NormalizedLabel(self) -> Nullable[str]:
249 """
250 Returns a model entity's normalized (lower case) label.
252 :returns: Normalized label of a model entity.
253 """
254 return self._normalizedLabel
257@export
258class DocumentedEntityMixin(metaclass=ExtendedType, mixin=True):
259 """
260 A ``DocumentedEntityMixin`` is a mixin class for all VHDL entities that can have an associated documentation.
262 A protected variable :attr:`_documentation` is available to derived classes as well as a readonly property
263 :attr:`Documentation` for public access.
264 """
266 _documentation: Nullable[str] #: The associated documentation of a model entity.
268 def __init__(self, documentation: Nullable[str]) -> None:
269 """
270 Initializes a documented entity.
272 :param documentation: Documentation of a model entity.
273 """
274 self._documentation = documentation
276 @readonly
277 def Documentation(self) -> Nullable[str]:
278 """
279 Returns a model entity's associated documentation.
281 :returns: Associated documentation of a model entity.
282 """
283 return self._documentation
286@export
287class ConditionalMixin(metaclass=ExtendedType, mixin=True):
288 """A ``ConditionalMixin`` is a mixin-class for all statements with a condition."""
290 _condition: ExpressionUnion
292 def __init__(self, condition: Nullable[ExpressionUnion] = None) -> None:
293 """
294 Initializes a statement with a condition.
296 When the condition is not None, the condition's parent reference is set to this statement.
298 :param condition: The expression representing the condition.
299 """
300 self._condition = condition
301 if condition is not None:
302 condition._parent = self
304 @readonly
305 def Condition(self) -> ExpressionUnion:
306 """
307 Read-only property to access the condition of a statement (:attr:`_condition`).
309 :returns: The expression representing the condition of a statement.
310 """
311 return self._condition
314@export
315class BranchMixin(metaclass=ExtendedType, mixin=True):
316 """A ``BranchMixin`` is a mixin-class for all statements with branches."""
318 def __init__(self) -> None:
319 pass
322@export
323class ConditionalBranchMixin(BranchMixin, ConditionalMixin, mixin=True):
324 """A ``BaseBranch`` is a mixin-class for all branch statements with a condition."""
325 def __init__(self, condition: ExpressionUnion) -> None:
326 super().__init__()
327 ConditionalMixin.__init__(self, condition)
330@export
331class IfBranchMixin(ConditionalBranchMixin, mixin=True):
332 """A ``BaseIfBranch`` is a mixin-class for all if-branches."""
335@export
336class ElsifBranchMixin(ConditionalBranchMixin, mixin=True):
337 """A ``BaseElsifBranch`` is a mixin-class for all elsif-branches."""
340@export
341class ElseBranchMixin(BranchMixin, mixin=True):
342 """A ``BaseElseBranch`` is a mixin-class for all else-branches."""
345@export
346class ReportStatementMixin(metaclass=ExtendedType, mixin=True):
347 """A ``MixinReportStatement`` is a mixin-class for all report and assert statements."""
349 _message: Nullable[ExpressionUnion]
350 _severity: Nullable[ExpressionUnion]
352 def __init__(self, message: Nullable[ExpressionUnion] = None, severity: Nullable[ExpressionUnion] = None) -> None:
353 self._message = message
354 if message is not None:
355 message._parent = self
357 self._severity = severity
358 if severity is not None:
359 severity._parent = self
361 @property
362 def Message(self) -> Nullable[ExpressionUnion]:
363 return self._message
365 @property
366 def Severity(self) -> Nullable[ExpressionUnion]:
367 return self._severity
370@export
371class AssertStatementMixin(ReportStatementMixin, ConditionalMixin, mixin=True):
372 """A ``MixinAssertStatement`` is a mixin-class for all assert statements."""
374 def __init__(self, condition: ExpressionUnion, message: Nullable[ExpressionUnion] = None, severity: Nullable[ExpressionUnion] = None) -> None:
375 super().__init__(message, severity)
376 ConditionalMixin.__init__(self, condition)
379class BlockStatementMixin(metaclass=ExtendedType, mixin=True):
380 """A ``BlockStatement`` is a mixin-class for all block statements."""
382 def __init__(self) -> None:
383 pass
386@export
387class BaseChoice(ModelEntity):
388 """A ``Choice`` is a base-class for all choices."""
391@export
392class BaseCase(ModelEntity):
393 """
394 A ``Case`` is a base-class for all cases.
395 """
398@export
399class Range(ModelEntity):
400 _leftBound: ExpressionUnion
401 _rightBound: ExpressionUnion
402 _direction: Direction
404 def __init__(self, leftBound: ExpressionUnion, rightBound: ExpressionUnion, direction: Direction, parent: ModelEntity = None) -> None:
405 super().__init__(parent)
407 self._leftBound = leftBound
408 leftBound._parent = self
410 self._rightBound = rightBound
411 rightBound._parent = self
413 self._direction = direction
415 @property
416 def LeftBound(self) -> ExpressionUnion:
417 return self._leftBound
419 @property
420 def RightBound(self) -> ExpressionUnion:
421 return self._rightBound
423 @property
424 def Direction(self) -> Direction:
425 return self._direction
427 def __str__(self) -> str:
428 return f"{self._leftBound!s} {self._direction!s} {self._rightBound!s}"
431@export
432class WaveformElement(ModelEntity):
433 _expression: ExpressionUnion
434 _after: ExpressionUnion
436 def __init__(self, expression: ExpressionUnion, after: Nullable[ExpressionUnion] = None, parent: ModelEntity = None) -> None:
437 super().__init__(parent)
439 self._expression = expression
440 expression._parent = self
442 self._after = after
443 if after is not None:
444 after._parent = self
446 @property
447 def Expression(self) -> ExpressionUnion:
448 return self._expression
450 @property
451 def After(self) -> Expression:
452 return self._after