Coverage for pyVHDLModel/Declaration.py: 94%
128 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.
36"""
37from __future__ import annotations
39from enum import unique, Enum
40from typing import TYPE_CHECKING, ClassVar, Iterable, Union, Optional as Nullable
42from pyTooling.Decorators import export, readonly
44from pyVHDLModel.Base import ModelEntity, NamedEntityMixin, DocumentedEntityMixin, ReservedWord as _ReservedWord
45from pyVHDLModel.Expression import BaseExpression, QualifiedExpression, FunctionCall, TypeConversion, Literal
46from pyVHDLModel.Name import Name
47from pyVHDLModel.Symbol import Symbol, SubtypeSymbol
49if TYPE_CHECKING: 49 ↛ 50line 49 didn't jump to line 50 because the condition on line 49 was never true
50 from pyVHDLModel.Visitor import Visitor
54ExpressionUnion = Union[
55 BaseExpression,
56 QualifiedExpression,
57 FunctionCall,
58 TypeConversion,
59 # ConstantOrSymbol, TODO: ObjectSymbol
60 Literal,
61]
64@export
65@unique
66class EntityClass(Enum):
67 """An ``EntityClass`` is an enumeration. It represents a VHDL language entity class (``entity``, ``label``, ...)."""
69 Entity = 0 #: Entity
70 Architecture = 1 #: Architecture
71 Configuration = 2 #: Configuration
72 Procedure = 3 #: Procedure
73 Function = 4 #: Function
74 Package = 5 #: Package
75 Type = 6 #: Type
76 Subtype = 7 #: Subtype
77 Constant = 8 #: Constant
78 Signal = 9 #: Signal
79 Variable = 10 #: Variable
80 Component = 11 #: Component
81 Label = 12 #: Label
82 Literal = 13 #: Literal
83 Units = 14 #: Units
84 Group = 15 #: Group
85 File = 16 #: File
86 Property = 17 #: Property
87 Sequence = 18 #: Sequence
88 View = 19 #: View
89 Others = 20 #: Others
91 __RESERVED_WORDS: ClassVar[dict[int, _ReservedWord]] = {
92 0: _ReservedWord.Entity,
93 1: _ReservedWord.Architecture,
94 2: _ReservedWord.Configuration,
95 3: _ReservedWord.Procedure,
96 4: _ReservedWord.Function,
97 5: _ReservedWord.Package,
98 6: _ReservedWord.Type,
99 7: _ReservedWord.Subtype,
100 8: _ReservedWord.Constant,
101 9: _ReservedWord.Signal,
102 10: _ReservedWord.Variable,
103 11: _ReservedWord.Component,
104 12: _ReservedWord.Label,
105 13: _ReservedWord.Literal,
106 14: _ReservedWord.Units,
107 15: _ReservedWord.Group,
108 16: _ReservedWord.File,
109 17: _ReservedWord.Property,
110 18: _ReservedWord.Sequence,
111 19: _ReservedWord.View
112 } #: The reserved word of each entity class, by value; ``Others`` has none.
114 @readonly
115 def ReservedWord(self) -> Nullable[_ReservedWord]:
116 """
117 Read-only property to return the reserved word of the entity class.
119 :returns: The reserved word, or ``None`` for ``EntityClass.Others``.
120 """
121 return self.__RESERVED_WORDS.get(self.value, None)
124@export
125class Attribute(ModelEntity, NamedEntityMixin, DocumentedEntityMixin):
126 """
127 Represents an attribute declaration.
129 .. admonition:: Example
131 .. code-block:: VHDL
133 attribute TotalBits : natural;
134 """
136 _subtype: Symbol #: Reference to the attribute's subtype.
138 def __init__(
139 self,
140 identifier: str,
141 subtype: Symbol,
142 documentation: Nullable[str] = None,
143 parent: Nullable[ModelEntity] = None
144 ) -> None:
145 """
146 Initializes an attribute declaration.
148 :param identifier: The identifier of a model entity.
149 :param subtype: Reference to the attribute's subtype.
150 :param documentation: The documentation comment associated with this declaration.
151 :param parent: The parent model entity of this entity.
152 """
153 super().__init__(parent)
154 NamedEntityMixin.__init__(self, identifier)
155 DocumentedEntityMixin.__init__(self, documentation)
157 self._subtype = subtype
158 subtype.Parent = self
160 def Visit(self, visitor: Visitor) -> None:
161 """
162 Walk this attribute declaration and its subtype with a visitor.
164 :param visitor: The visitor receiving the events.
165 """
166 visitor.VisitAttribute(self)
167 self._subtype.Visit(visitor)
168 visitor.DepartAttribute(self)
170 @readonly
171 def Subtype(self) -> None:
172 """
173 Read-only property to access the subtype (:attr:`_subtype`).
175 :returns: The subtype.
176 """
177 return self._subtype
179 def __str__(self) -> str:
180 """
181 Formats the attribute declaration.
183 **Format:** ``attribute myAttribute: bit``
185 :returns: Formatted attribute declaration.
186 """
187 return f"attribute {self._identifier}: {self._subtype}"
190@export
191class AttributeSpecification(ModelEntity, DocumentedEntityMixin):
192 """
193 Represents an attribute specification.
195 .. admonition:: Example
197 .. code-block:: VHDL
199 attribute TotalBits of BusType : subtype is 32;
200 """
202 _identifiers: list[Name] #: List of all names the attribute is specified for.
203 _attribute: Name #: Reference to the specified attribute.
204 _entityClass: EntityClass #: The entity class the named items belong to.
205 _expression: ExpressionUnion #: The value assigned to the attribute.
207 def __init__(
208 self,
209 identifiers: Iterable[Name],
210 attribute: Name,
211 entityClass: EntityClass,
212 expression: ExpressionUnion,
213 documentation: Nullable[str] = None,
214 parent: Nullable[ModelEntity] = None
215 ) -> None:
216 """
217 Initializes an attribute specification.
219 :param identifiers: List of all names the attribute is specified for.
220 :param attribute: Reference to the specified attribute.
221 :param entityClass: The entity class the named items belong to.
222 :param expression: The value assigned to the attribute.
223 :param documentation: The documentation comment associated with this declaration.
224 :param parent: The parent model entity of this entity.
225 """
226 super().__init__(parent)
227 DocumentedEntityMixin.__init__(self, documentation)
229 self._identifiers = identifierList = [] # TODO: convert to dict
230 for identifier in identifiers:
231 identifierList.append(identifier)
232 identifier.Parent = self
234 self._attribute = attribute
235 attribute.Parent = self
237 self._entityClass = entityClass
239 self._expression = expression
240 expression.Parent = self
242 def Visit(self, visitor: Visitor) -> None:
243 """
244 Walk this attribute specification, its attribute, its entity specification and its expression with a visitor.
246 :param visitor: The visitor receiving the events.
247 """
248 visitor.VisitAttributeSpecification(self)
249 self._attribute.Visit(visitor)
250 visitor.VisitEntitySpecification(self)
251 for index, name in enumerate(self._identifiers):
252 if index > 0:
253 visitor.VisitComma(self)
255 name.Visit(visitor)
257 visitor.DepartEntitySpecification(self)
258 visitor.VisitIs(self)
259 self._expression.Visit(visitor)
260 visitor.DepartAttributeSpecification(self)
262 @readonly
263 def Identifiers(self) -> list[Name]:
264 """
265 Read-only property to access the identifiers (:attr:`_identifiers`).
267 :returns: List of identifiers.
268 """
269 return self._identifiers
271 @readonly
272 def Attribute(self) -> Name:
273 """
274 Read-only property to access the attribute (:attr:`_attribute`).
276 :returns: The attribute.
277 """
278 return self._attribute
280 @readonly
281 def EntityClass(self) -> EntityClass:
282 """
283 Read-only property to access the entity class (:attr:`_entityClass`).
285 :returns: The entity class.
286 """
287 return self._entityClass
289 @readonly
290 def Expression(self) -> ExpressionUnion:
291 """
292 Read-only property to access the expression (:attr:`_expression`).
294 :returns: The expression.
295 """
296 return self._expression
299# TODO: move somewhere else
300@export
301class Alias(ModelEntity, NamedEntityMixin, DocumentedEntityMixin):
302 """
303 Represents an alias declaration.
305 :attr:`Name` is a :class:`~pyVHDLModel.Symbol.Symbol` - like every other cross-reference in this
306 model - rather than a bare :class:`~pyVHDLModel.Name.Name`, so it participates in the usual
307 resolve-later mechanism (:attr:`~pyVHDLModel.Symbol.Symbol.Reference` /
308 :attr:`~pyVHDLModel.Symbol.Symbol.IsResolved`). Unlike ``PackageReferenceSymbol`` and similar,
309 there is no single fixed :class:`~pyVHDLModel.Symbol.PossibleReference` value that always fits: an
310 alias without a subtype indication can refer to almost anything nameable (an object, a type, a
311 subprogram, a literal, ...), while an alias *with* a subtype indication can - per the LRM - only
312 ever refer to an object (a constant, variable, signal, or file); the ``possibleReferences`` passed
313 to the ``Symbol`` should reflect whichever case applies.
315 .. admonition:: Example
317 .. code-block:: VHDL
319 alias a : bit_vector(3 downto 0) is s(3 downto 0);
320 -- ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^
321 -- optional Subtype Name
323 alias b is s;
324 -- ^
325 -- Name
326 """
328 _name: Symbol #: Reference to the name being aliased.
329 _subtype: Nullable[SubtypeSymbol] #: Reference to the alias' subtype, or ``None`` if none was given.
331 def __init__(
332 self,
333 identifier: str,
334 name: Symbol,
335 subtype: Nullable[SubtypeSymbol] = None,
336 documentation: Nullable[str] = None,
337 parent: Nullable[ModelEntity] = None
338 ) -> None:
339 """
340 Initializes an alias declaration.
342 :param identifier: The identifier of a model entity.
343 :param name: Reference to the name being aliased.
344 :param subtype: Reference to the alias' subtype, or ``None`` if none was given.
345 :param documentation: The documentation comment associated with this declaration.
346 :param parent: The parent model entity of this entity.
347 """
348 super().__init__(parent)
349 NamedEntityMixin.__init__(self, identifier)
350 DocumentedEntityMixin.__init__(self, documentation)
352 self._name = name
353 name.Parent = self
355 self._subtype = subtype
356 if subtype is not None:
357 subtype.Parent = self
359 def Visit(self, visitor: Visitor) -> None:
360 """
361 Walk this alias declaration, its subtype (if any) and its name with a visitor.
363 :param visitor: The visitor receiving the events.
364 """
365 visitor.VisitAlias(self)
366 if self._subtype is not None:
367 self._subtype.Visit(visitor)
369 visitor.VisitIs(self)
370 self._name.Visit(visitor)
371 visitor.DepartAlias(self)
373 @readonly
374 def Name(self) -> Symbol:
375 """
376 Read-only property to access the name (:attr:`_name`).
378 :returns: The name.
379 """
380 return self._name
382 @readonly
383 def Subtype(self) -> Nullable[SubtypeSymbol]:
384 """
385 Read-only property to access the subtype (:attr:`_subtype`).
387 :returns: The subtype, or ``None`` if not set.
388 """
389 return self._subtype
391 def __str__(self) -> str:
392 """
393 Formats the alias declaration.
395 **Format:** ``alias myAlias : bit is target``, or without the subtype when none was given
397 :returns: Formatted alias declaration.
398 """
399 subtype = f" : {self._subtype}" if self._subtype is not None else ""
400 return f"alias {self._identifier}{subtype} is {self._name}"