Coverage for pyVHDLModel/Name.py: 100%
86 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.
35VHDL uses *names* to express cross-references from *usage locations* to *declarations*. Here, *names* are single or
36combined identifiers. :mod:`Symbols <pyVHDLModel.Symbol>` are structures representing a *name* and a reference
37(pointer) to the referenced vhdl language entity.
38"""
39from typing import List, Iterable, Optional as Nullable
41from pyTooling.Decorators import export, readonly
43from pyVHDLModel.Base import ModelEntity, ExpressionUnion
46@export
47class Name(ModelEntity):
48 """
49 ``Name`` is the base-class for all *names* in the VHDL language model.
51 .. seealso::
53 * :class:`Simple name <pyVHDLModel.Name.SimpleName>`
54 * :class:`Parenthesis name <pyVHDLModel.Name.ParenthesisName>`
55 * :class:`Indexed name <pyVHDLModel.Name.IndexedName>`
56 * :class:`Sliced name <pyVHDLModel.Name.SlicedName>`
57 * :class:`Selected name <pyVHDLModel.Name.SelectedName>`
58 * :class:`Attribute name <pyVHDLModel.Name.AttributeName>`
59 * :class:`Open name <pyVHDLModel.Name.OpenName>`
60 """
62 _identifier: str #: The name's identifier.
63 _normalizedIdentifier: str #: The normalized (lower case) identifier.
64 # TODO: seams to be unused. There is no reverse linking, or?
65 _root: Nullable['Name'] #: Reference to the root of the name chain.
66 _prefix: Nullable['Name'] #: Reference to the name's prefix, or ``None`` for a simple name.
68 def __init__(self, identifier: str, prefix: Nullable["Name"] = None, parent: Nullable[ModelEntity] = None) -> None:
69 """
70 Initializes a name.
72 :param identifier: The name's identifier.
73 :param prefix: Reference to the name's prefix, or ``None`` for a simple name.
74 :param parent: The parent model entity of this entity.
75 """
76 super().__init__(parent)
78 self._identifier = identifier
79 self._normalizedIdentifier = identifier.lower()
81 if prefix is None:
82 self._prefix = None
83 self._root = self
84 else:
85 self._prefix = prefix
86 self._root = prefix._root
88 @readonly
89 def Identifier(self) -> str:
90 """
91 Read-only property to access the identifier this name references (:attr:`_identifier`).
93 :returns: The referenced identifier.
94 """
95 return self._identifier
97 @readonly
98 def NormalizedIdentifier(self) -> str:
99 """
100 Read-only property to access the normalized identifier this name references (:attr:`_normalizedIdentifier`).
102 :returns: The referenced identifier (normalized).
103 """
104 return self._normalizedIdentifier
106 @readonly
107 def Root(self) -> 'Name':
108 """
109 Read-only property to access the root (left-most) element in a chain of names (:attr:`_root`).
111 In case the name is a :class:`simple name <SimpleName>`, the root points to the name itself.
113 :returns: The name's root element.
114 """
115 return self._root
117 @readonly
118 def Prefix(self) -> Nullable['Name']:
119 """
120 Read-only property to access the name's prefix in a chain of names (:attr:`_prefix`).
122 :returns: The name left from current name, if not a simple name, otherwise ``None``.
123 """
124 return self._prefix
126 @readonly
127 def HasPrefix(self) -> bool:
128 """
129 Check if the name has a prefix, i.e. :attr:`_prefix` is set.
131 This is true for all names except :class:`simple names <SimpleName>`.
133 :returns: ``True``, if the name has a prefix.
134 """
135 return self._prefix is not None
137 def __repr__(self) -> str:
138 """
139 Formats a representation of the name.
141 **Format:** ``Name: 'sig'``
143 :returns: String representation of the name.
144 """
145 return f"Name: '{self.__str__()}'"
147 def __str__(self) -> str:
148 """
149 Formats the name.
151 **Format:** ``sig``
153 :returns: Formatted name.
154 """
155 return self._identifier
158@export
159class SimpleName(Name):
160 """
161 A *simple name* is a name made from a single word.
163 For example, the entity name in an architecture declaration is a simple name, while the name of the architecture
164 itself is an identifier. The simple name references is again an identifier in the entity declaration, thus names
165 reference other (already) declared language entities.
166 """
169@export
170class ParenthesisName(Name):
171 """
172 Represents a name followed by a parenthesized association list.
174 Used where indexing and a function call are indistinguishable before resolution.
175 """
176 _associations: List #: List of all associations in the parenthesis.
178 def __init__(self, prefix: Name, associations: Iterable, parent: Nullable[ModelEntity] = None) -> None:
179 """
180 Initializes a name followed by a parenthesized association list.
182 :param prefix: Reference to the name's prefix, or ``None`` for a simple name.
183 :param associations: List of all associations in the parenthesis.
184 :param parent: The parent model entity of this entity.
185 """
186 super().__init__("", prefix, parent)
188 self._associations = []
189 for association in associations:
190 self._associations.append(association)
191 association.Parent = self
193 @readonly
194 def Associations(self) -> List:
195 """
196 Read-only property to access the associations (:attr:`_associations`).
198 :returns: List of associations.
199 """
200 return self._associations
202 def __str__(self) -> str:
203 """
204 Formats the parenthesis name.
206 **Format:** ``func(a, b)``
208 :returns: Formatted parenthesis name.
209 """
210 return f"{self._prefix!s}({', '.join(str(a) for a in self._associations)})"
213@export
214class IndexedName(Name):
215 """
216 Represents a name indexing an array by one or more values.
218 .. admonition:: Example
220 .. code-block:: VHDL
222 s <= v(0);
223 -- ^^^^ <- the indexed name
224 """
225 _indices: List[ExpressionUnion] #: List of all index expressions, one per dimension.
227 def __init__(self, prefix: Name, indices: Iterable[ExpressionUnion], parent: Nullable[ModelEntity] = None) -> None:
228 """
229 Initializes a name indexing an array by one or more values.
231 :param prefix: Reference to the name's prefix, or ``None`` for a simple name.
232 :param indices: List of all index expressions, one per dimension.
233 :param parent: The parent model entity of this entity.
234 """
235 super().__init__("", prefix, parent)
237 self._indices = []
238 for index in indices:
239 self._indices.append(index)
240 index.Parent = self
242 @readonly
243 def Indices(self) -> List[ExpressionUnion]:
244 """
245 Read-only property to access the indices (:attr:`_indices`).
247 :returns: List of indices.
248 """
249 return self._indices
251 def __str__(self) -> str:
252 """
253 Formats the indexed name.
255 **Format:** ``arr(0)``
257 :returns: Formatted indexed name.
258 """
259 return f"{self._prefix!s}({', '.join(str(i) for i in self._indices)})"
262@export
263class SlicedName(Name):
264 """
265 Represents a name selecting a slice of an array.
267 .. admonition:: Example
269 .. code-block:: VHDL
271 vres := v(3 downto 0);
272 -- ^^^^^^^^^^^^^ <- the sliced name
273 """
274 pass
277@export
278class SelectedName(Name):
279 """
280 A *selected name* is a name made from multiple words separated by a dot (``.``).
282 For example, the library and entity name in a direct entity instantiation is a selected name. Here the entity
283 identifier is a selected name. The library identifier is a :class:`simple name <SimpleName>`, which is
284 referenced by the selected name via the :attr:`~pyVHDLModel.Name.Prefix` property.
286 .. seealso::
288 * :class:`All name <pyVHDLModel.Name.AllName>`
289 """
291 def __init__(self, identifier: str, prefix: Name, parent: Nullable[ModelEntity] = None) -> None:
292 """
293 Initializes a selected name.
295 :param identifier: The name's identifier.
296 :param prefix: Reference to the name's prefix, or ``None`` for a simple name.
297 :param parent: The parent model entity of this entity.
298 """
299 super().__init__(identifier, prefix, parent)
301 def __str__(self) -> str:
302 """
303 Formats the selected name.
305 **Format:** ``rec.elem``
307 :returns: Formatted selected name.
308 """
309 return f"{self._prefix!s}.{self._identifier}"
312@export
313class AttributeName(Name):
314 """
315 Represents a name selecting an attribute of its prefix.
317 .. admonition:: Example
319 .. code-block:: VHDL
321 for i in v'range loop
322 -- ^^^^^^^ <- the attribute name
323 """
324 def __init__(self, identifier: str, prefix: Name, parent: Nullable[ModelEntity] = None) -> None:
325 """
326 Initializes a name selecting an attribute of its prefix.
328 :param identifier: The name's identifier.
329 :param prefix: Reference to the name's prefix, or ``None`` for a simple name.
330 :param parent: The parent model entity of this entity.
331 """
332 super().__init__(identifier, prefix, parent)
334 def __str__(self) -> str:
335 """
336 Formats the attribute name.
338 **Format:** ``v'range``
340 :returns: Formatted attribute name.
341 """
342 return f"{self._prefix!s}'{self._identifier}"
345@export
346class AllName(SelectedName):
347 """
348 The *all name* represents the reserved word ``all`` used in names.
350 Most likely this name is used in use-statements.
351 """
352 def __init__(self, prefix: Name, parent: Nullable[ModelEntity] = None) -> None:
353 """
354 Initializes an ``all`` name.
356 :param prefix: Reference to the name's prefix, or ``None`` for a simple name.
357 :param parent: The parent model entity of this entity.
358 """
359 super().__init__("all", prefix, parent) # TODO: the case of 'ALL' is not preserved
362@export
363class OpenName(Name):
364 """
365 The *open name* represents the reserved word ``open``.
367 Most likely this name is used in port associations.
368 """
369 def __init__(self, parent: Nullable[ModelEntity] = None) -> None:
370 """
371 Initializes an ``open`` name.
373 :param parent: The parent model entity of this entity.
374 """
375 super().__init__("open", parent=parent) # TODO: the case of 'OPEN' is not preserved
377 def __str__(self) -> str:
378 """
379 Formats the open name.
381 **Format:** ``open``
383 :returns: Formatted open name.
384 """
385 return "open"