Source code for pyVHDLModel.Name

# ==================================================================================================================== #
#             __     ___   _ ____  _     __  __           _      _                                                     #
#   _ __  _   \ \   / / | | |  _ \| |   |  \/  | ___   __| | ___| |                                                    #
#  | '_ \| | | \ \ / /| |_| | | | | |   | |\/| |/ _ \ / _` |/ _ \ |                                                    #
#  | |_) | |_| |\ V / |  _  | |_| | |___| |  | | (_) | (_| |  __/ |                                                    #
#  | .__/ \__, | \_/  |_| |_|____/|_____|_|  |_|\___/ \__,_|\___|_|                                                    #
#  |_|    |___/                                                                                                        #
# ==================================================================================================================== #
# Authors:                                                                                                             #
#   Patrick Lehmann                                                                                                    #
#                                                                                                                      #
# License:                                                                                                             #
# ==================================================================================================================== #
# Copyright 2017-2026 Patrick Lehmann - Boetzingen, Germany                                                            #
# Copyright 2016-2017 Patrick Lehmann - Dresden, Germany                                                               #
#                                                                                                                      #
# Licensed under the Apache License, Version 2.0 (the "License");                                                      #
# you may not use this file except in compliance with the License.                                                     #
# You may obtain a copy of the License at                                                                              #
#                                                                                                                      #
#   http://www.apache.org/licenses/LICENSE-2.0                                                                         #
#                                                                                                                      #
# Unless required by applicable law or agreed to in writing, software                                                  #
# distributed under the License is distributed on an "AS IS" BASIS,                                                    #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                                             #
# See the License for the specific language governing permissions and                                                  #
# limitations under the License.                                                                                       #
#                                                                                                                      #
# SPDX-License-Identifier: Apache-2.0                                                                                  #
# ==================================================================================================================== #
#
"""
This module contains parts of an abstract document language model for VHDL.

VHDL uses *names* to express cross-references from *usage locations* to *declarations*. Here, *names* are single or
combined identifiers. :mod:`Symbols <pyVHDLModel.Symbol>` are structures representing a *name* and a reference
(pointer) to the referenced vhdl language entity.
"""
from typing import List, Iterable, Optional as Nullable

from pyTooling.Decorators import export, readonly

from pyVHDLModel.Base import ModelEntity, ExpressionUnion


@export
class Name(ModelEntity):
	"""
	``Name`` is the base-class for all *names* in the VHDL language model.

	.. seealso::

	   * :class:`Simple name <pyVHDLModel.Name.SimpleName>`
	   * :class:`Parenthesis name <pyVHDLModel.Name.ParenthesisName>`
	   * :class:`Indexed name <pyVHDLModel.Name.IndexedName>`
	   * :class:`Sliced name <pyVHDLModel.Name.SlicedName>`
	   * :class:`Selected name <pyVHDLModel.Name.SelectedName>`
	   * :class:`Attribute name <pyVHDLModel.Name.AttributeName>`
	   * :class:`Open name <pyVHDLModel.Name.OpenName>`
	"""

	_identifier: str            #: The name's identifier.
	_normalizedIdentifier: str  #: The normalized (lower case) identifier.
	# TODO: seams to be unused. There is no reverse linking, or?
	_root: Nullable['Name']  #: Reference to the root of the name chain.
	_prefix: Nullable['Name']   #: Reference to the name's prefix, or ``None`` for a simple name.

	def __init__(self, identifier: str, prefix: Nullable["Name"] = None, parent: Nullable[ModelEntity] = None) -> None:
		"""
		Initializes a name.

		:param identifier: The name's identifier.
		:param prefix:     Reference to the name's prefix, or ``None`` for a simple name.
		:param parent:     The parent model entity of this entity.
		"""
		super().__init__(parent)

		self._identifier = identifier
		self._normalizedIdentifier = identifier.lower()

		if prefix is None:
			self._prefix = None
			self._root = self
		else:
			self._prefix = prefix
			self._root = prefix._root

	@readonly
	def Identifier(self) -> str:
		"""
		Read-only property to access the identifier this name references (:attr:`_identifier`).

		:returns: The referenced identifier.
		"""
		return self._identifier

	@readonly
	def NormalizedIdentifier(self) -> str:
		"""
		Read-only property to access the normalized identifier this name references (:attr:`_normalizedIdentifier`).

		:returns: The referenced identifier (normalized).
		"""
		return self._normalizedIdentifier

	@readonly
	def Root(self) -> 'Name':
		"""
		Read-only property to access the root (left-most) element in a chain of names (:attr:`_root`).

		In case the name is a :class:`simple name <SimpleName>`, the root points to the name itself.

		:returns: The name's root element.
		"""
		return self._root

	@readonly
	def Prefix(self) -> Nullable['Name']:
		"""
		Read-only property to access the name's prefix in a chain of names (:attr:`_prefix`).

		:returns: The name left from current name, if not a simple name, otherwise ``None``.
		"""
		return self._prefix

	@readonly
	def HasPrefix(self) -> bool:
		"""
		Check if the name has a prefix, i.e. :attr:`_prefix` is set.

		This is true for all names except :class:`simple names <SimpleName>`.

		:returns: ``True``, if the name has a prefix.
		"""
		return self._prefix is not None

	def __repr__(self) -> str:
		"""
		Formats a representation of the name.

		**Format:** ``Name: 'sig'``

		:returns: String representation of the name.
		"""
		return f"Name: '{self.__str__()}'"

	def __str__(self) -> str:
		"""
		Formats the name.

		**Format:** ``sig``

		:returns: Formatted name.
		"""
		return self._identifier


@export
class SimpleName(Name):
	"""
	A *simple name* is a name made from a single word.

	For example, the entity name in an architecture declaration is a simple name, while the name of the architecture
	itself is an identifier. The simple name references is again an identifier in the entity declaration, thus names
	reference other (already) declared language entities.
	"""


@export
class ParenthesisName(Name):
	"""
	Represents a name followed by a parenthesized association list.

	Used where indexing and a function call are indistinguishable before resolution.
	"""
	_associations: List  #: List of all associations in the parenthesis.

	def __init__(self, prefix: Name, associations: Iterable, parent: Nullable[ModelEntity] = None) -> None:
		"""
		Initializes a name followed by a parenthesized association list.

		:param prefix:       Reference to the name's prefix, or ``None`` for a simple name.
		:param associations: List of all associations in the parenthesis.
		:param parent:       The parent model entity of this entity.
		"""
		super().__init__("", prefix, parent)

		self._associations = []
		for association in associations:
			self._associations.append(association)
			association.Parent = self

	@readonly
	def Associations(self) -> List:
		"""
		Read-only property to access the associations (:attr:`_associations`).

		:returns: List of associations.
		"""
		return self._associations

[docs] def __str__(self) -> str: """ Formats the parenthesis name. **Format:** ``func(a, b)`` :returns: Formatted parenthesis name. """ return f"{self._prefix!s}({', '.join(str(a) for a in self._associations)})"
@export class IndexedName(Name): """ Represents a name indexing an array by one or more values. .. admonition:: Example .. code-block:: VHDL s <= v(0); -- ^^^^ <- the indexed name """ _indices: List[ExpressionUnion] #: List of all index expressions, one per dimension. def __init__(self, prefix: Name, indices: Iterable[ExpressionUnion], parent: Nullable[ModelEntity] = None) -> None: """ Initializes a name indexing an array by one or more values. :param prefix: Reference to the name's prefix, or ``None`` for a simple name. :param indices: List of all index expressions, one per dimension. :param parent: The parent model entity of this entity. """ super().__init__("", prefix, parent) self._indices = [] for index in indices: self._indices.append(index) index.Parent = self @readonly def Indices(self) -> List[ExpressionUnion]: """ Read-only property to access the indices (:attr:`_indices`). :returns: List of indices. """ return self._indices
[docs] def __str__(self) -> str: """ Formats the indexed name. **Format:** ``arr(0)`` :returns: Formatted indexed name. """ return f"{self._prefix!s}({', '.join(str(i) for i in self._indices)})"
@export class SlicedName(Name): """ Represents a name selecting a slice of an array. .. admonition:: Example .. code-block:: VHDL vres := v(3 downto 0); -- ^^^^^^^^^^^^^ <- the sliced name """ pass @export class SelectedName(Name): """ A *selected name* is a name made from multiple words separated by a dot (``.``). For example, the library and entity name in a direct entity instantiation is a selected name. Here the entity identifier is a selected name. The library identifier is a :class:`simple name <SimpleName>`, which is referenced by the selected name via the :attr:`~pyVHDLModel.Name.Prefix` property. .. seealso:: * :class:`All name <pyVHDLModel.Name.AllName>` """ def __init__(self, identifier: str, prefix: Name, parent: Nullable[ModelEntity] = None) -> None: """ Initializes a selected name. :param identifier: The name's identifier. :param prefix: Reference to the name's prefix, or ``None`` for a simple name. :param parent: The parent model entity of this entity. """ super().__init__(identifier, prefix, parent)
[docs] def __str__(self) -> str: """ Formats the selected name. **Format:** ``rec.elem`` :returns: Formatted selected name. """ return f"{self._prefix!s}.{self._identifier}"
@export class AttributeName(Name): """ Represents a name selecting an attribute of its prefix. .. admonition:: Example .. code-block:: VHDL for i in v'range loop -- ^^^^^^^ <- the attribute name """ def __init__(self, identifier: str, prefix: Name, parent: Nullable[ModelEntity] = None) -> None: """ Initializes a name selecting an attribute of its prefix. :param identifier: The name's identifier. :param prefix: Reference to the name's prefix, or ``None`` for a simple name. :param parent: The parent model entity of this entity. """ super().__init__(identifier, prefix, parent)
[docs] def __str__(self) -> str: """ Formats the attribute name. **Format:** ``v'range`` :returns: Formatted attribute name. """ return f"{self._prefix!s}'{self._identifier}"
@export class AllName(SelectedName): """ The *all name* represents the reserved word ``all`` used in names. Most likely this name is used in use-statements. """ def __init__(self, prefix: Name, parent: Nullable[ModelEntity] = None) -> None: """ Initializes an ``all`` name. :param prefix: Reference to the name's prefix, or ``None`` for a simple name. :param parent: The parent model entity of this entity. """ super().__init__("all", prefix, parent) # TODO: the case of 'ALL' is not preserved @export class OpenName(Name): """ The *open name* represents the reserved word ``open``. Most likely this name is used in port associations. """ def __init__(self, parent: Nullable[ModelEntity] = None) -> None: """ Initializes an ``open`` name. :param parent: The parent model entity of this entity. """ super().__init__("open", parent=parent) # TODO: the case of 'OPEN' is not preserved
[docs] def __str__(self) -> str: """ Formats the open name. **Format:** ``open`` :returns: Formatted open name. """ return "open"