Source code for pyVHDLModel.Base

# ==================================================================================================================== #
#             __     ___   _ ____  _     __  __           _      _                                                     #
#   _ __  _   \ \   / / | | |  _ \| |   |  \/  | ___   __| | ___| |                                                    #
#  | '_ \| | | \ \ / /| |_| | | | | |   | |\/| |/ _ \ / _` |/ _ \ |                                                    #
#  | |_) | |_| |\ 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.

Base-classes for the VHDL language model.
"""
from enum                  import unique, Enum
from typing                import Type, Tuple, List, Iterable, Optional as Nullable, Union, cast

from pyTooling.Common      import getFullyQualifiedName
from pyTooling.Decorators  import export, readonly
from pyTooling.MetaClasses import ExtendedType


__all__ = ["ExpressionUnion"]


ExpressionUnion = Union[
	'BaseExpression',
	'QualifiedExpression',
	'FunctionCall',
	'TypeConversion',
	# ConstantOrSymbol,     TODO: ObjectSymbol
	'Literal',
]


@export
@unique
class Direction(Enum):
	"""An enumeration representing a direction in a range	(``to`` or ``downto``)."""

	To =      0  #: Ascending direction
	DownTo =  1  #: Descending direction

	def __str__(self) -> str:
		"""
		Formats the direction to ``to`` or ``downto``.

		:returns: Formatted direction.
		"""
		return ("to", "downto")[cast(int, self.value)]       # TODO: check performance


@export
@unique
class Mode(Enum):
	"""
	A ``Mode`` is an enumeration. It represents the direction of data exchange (``in``, ``out``, ...) for objects in
	generic, port or parameter lists.

	In case no *mode* is defined, ``Default`` is used, so the *mode* is inferred from context.
	"""

	Default = 0  #: Mode not defined, thus it's context dependent.
	In =      1  #: Input
	Out =     2  #: Output
	InOut =   3  #: Bi-directional
	Buffer =  4  #: Buffered output
	Linkage = 5  #: undocumented

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

		:returns: Formatted mode.
		"""
		return ("", "in", "out", "inout", "buffer", "linkage")[cast(int, self.value)]       # TODO: check performance


@export
class ModelEntity(metaclass=ExtendedType, slots=True):
	"""
	``ModelEntity`` is the base-class for all classes in the VHDL language model, except for mixin classes (see multiple
	inheritance) and enumerations.

	Each entity in this model has a reference to its parent entity. Therefore, a protected variable :attr:`_parent` is
	available and a readonly property :attr:`Parent`.
	"""

	_parent: 'ModelEntity'      #: Reference to a parent entity in the logical model hierarchy.

	def __init__(self, parent: Nullable["ModelEntity"] = None) -> None:
		"""
		Initializes a VHDL model entity.

		:param parent: The parent model entity of this entity.
		"""
		self._parent = parent

	@property
	def Parent(self) -> 'ModelEntity':
		"""
		Property to access the model entity's parent element reference in a logical hierarchy (:attr:`_parent`).

		:returns: Reference to the parent entity.
		"""
		return self._parent

	@Parent.setter
	def Parent(self, parent: 'ModelEntity') -> None:
		if parent is None:
			raise ValueError("Parameter 'parent' is None.")

		self._parent = parent

	def GetAncestor(self, type: Type) -> 'ModelEntity':
		"""
		Return the closest ancestor of the given ``type`` found by walking the parent chain upwards.

		Iterates the parent chain - starting at this model entity - upwards (toward the root of the model) until an
		ancestor of the requested type is found.

		:param type:                Class (type) of the ancestor to find.
		:returns:                   The closest ancestor of the requested type.
		:raises VHDLModelException: If the root of the model is reached without finding an ancestor of the requested
		                            type.
		"""
		# Deferred import to avoid a circular import: Base -> Exception -> Symbol -> Base.
		from pyVHDLModel.Exception import VHDLModelException

		parent = self._parent
		while parent is not None:
			if isinstance(parent, type):
				break

			parent = parent._parent
		else:
			raise VHDLModelException(f"No ancestor of type '{type.__name__}' found for {self!r}.")

		return parent


@export
class NamedEntityMixin(metaclass=ExtendedType, mixin=True):
	"""
	A ``NamedEntityMixin`` is a mixin class for all VHDL entities that have an identifier.

	Protected variables :attr:`_identifier` and :attr:`_normalizedIdentifier` are available to derived classes as well as
	two readonly properties :attr:`Identifier` and :attr:`NormalizedIdentifier` for public access.

	.. seealso::

	   * :class:`Attribute <pyVHDLModel.Declaration.Attribute>`
	   * :class:`Alias <pyVHDLModel.Declaration.Alias>`
	   * :class:`Design unit <pyVHDLModel.DesignUnit.DesignUnit>`
	   * :class:`Component <pyVHDLModel.DesignUnit.Component>`
	   * :class:`Mode view declaration <pyVHDLModel.Interface.ModeViewDeclaration>`
	   * :class:`Interface package <pyVHDLModel.Interface.InterfacePackage>`
	   * :class:`Default clock <pyVHDLModel.PSLModel.DefaultClock>`
	   * :class:`Subprogram <pyVHDLModel.Subprogram.Subprogram>`
	   * :class:`Base type <pyVHDLModel.Type.BaseType>`
	   * :class:`Library <pyVHDLModel.Library>`
	"""

	_identifier:           str  #: The identifier of a model entity.
	_normalizedIdentifier: str  #: The normalized (lower case) identifier of a model entity.

	def __init__(self, identifier: str) -> None:
		"""
		Initializes a named entity.

		:param identifier: Identifier (name) of the model entity.
		"""
		self._identifier = identifier
		self._normalizedIdentifier = identifier.lower()

	@readonly
	def Identifier(self) -> str:
		"""
		Read-only property to access the model entity's identifier (:attr:`_identifier`).

		:returns: Name of a model entity.
		"""
		return self._identifier

	@readonly
	def NormalizedIdentifier(self) -> str:
		"""
		Read-only property to access the model entity's normalized identifier (:attr:`_normalizedIdentifier`).

		:returns: Normalized name of a model entity.
		"""
		return self._normalizedIdentifier


@export
class OptionallyNamedEntityMixin(metaclass=ExtendedType, mixin=True):
	"""
	A ``OptionallyNamedEntityMixin`` is a mixin class for all VHDL entities that have an optional identifier.

	Protected variables :attr:`_identifier` and :attr:`_normalizedIdentifier` are available to derived classes as well as
	two readonly properties :attr:`Identifier` and :attr:`NormalizedIdentifier` for public access.

	.. seealso::

	   * :class:`Interface group <pyVHDLModel.Interface.InterfaceGroup>`
	"""

	_identifier:           Nullable[str]  #: The identifier of a model entity.
	_normalizedIdentifier: Nullable[str]  #: The normalized (lower case) identifier of a model entity.

	def __init__(self, identifier: Nullable[str]) -> None:
		"""
		Initializes a named entity.

		:param identifier: Identifier (name) of the model entity.
		"""
		self._identifier = identifier
		self._normalizedIdentifier = identifier.lower() if identifier is not None else None

	@readonly
	def Identifier(self) -> Nullable[str]:
		"""
		Read-only property to access the model entity's optional identifier (:attr:`_identifier`).

		:returns: Name of a model entity, or ``None`` if unnamed.
		"""
		return self._identifier

	@readonly
	def NormalizedIdentifier(self) -> Nullable[str]:
		"""
		Read-only property to access the model entity's optional normalized identifier (:attr:`_normalizedIdentifier`).

		:returns: Normalized name of a model entity, or ``None`` if unnamed.
		"""
		return self._normalizedIdentifier


@export
class MultipleNamedEntityMixin(metaclass=ExtendedType, mixin=True):
	"""
	A ``MultipleNamedEntityMixin`` is a mixin class for all VHDL entities that declare multiple instances at once by
	defining multiple identifiers.

	Protected variables :attr:`_identifiers` and :attr:`_normalizedIdentifiers` are available to derived classes as well
	as two readonly properties :attr:`Identifiers` and :attr:`NormalizedIdentifiers` for public access.

	.. seealso::

	   * :class:`Mode view element <pyVHDLModel.Interface.ModeViewElement>`
	   * :class:`Obj <pyVHDLModel.Object.Obj>`
	   * :class:`Record type element <pyVHDLModel.Type.RecordTypeElement>`
	"""

	_identifiers:           Tuple[str]  #: A list of identifiers.
	_normalizedIdentifiers: Tuple[str]  #: A list of normalized (lower case) identifiers.

	def __init__(self, identifiers: Iterable[str]) -> None:
		"""
		Initializes a multiple-named entity.

		:param identifiers: Sequence of identifiers (names) of the model entity.
		"""
		self._identifiers = tuple(identifiers)
		self._normalizedIdentifiers = tuple([identifier.lower() for identifier in identifiers])

	@readonly
	def Identifiers(self) -> Tuple[str]:
		"""
		Read-only property to access the model entity's identifiers (:attr:`_identifiers`).

		:returns: Tuple of identifiers.
		"""
		return self._identifiers

	@readonly
	def NormalizedIdentifiers(self) -> Tuple[str]:
		"""
		Read-only property to access the model entity's normalized identifiers (:attr:`_normalizedIdentifiers`).

		:returns: Tuple of normalized identifiers.
		"""
		return self._normalizedIdentifiers


@export
def identifiersOf(item) -> Tuple[str, ...]:
	"""
	Return an item's identifier(s), regardless of how many names its declaration carries.

	VHDL entities come in two shapes: singularly named ones deriving from :class:`NamedEntityMixin`
	(``generic (type T)``, ``GenericProcedureInterfaceItem``, ...) and plurally named ones deriving from
	:class:`MultipleNamedEntityMixin`, where one declaration names several items at once
	(``port (p1, p2 : in bit)``, and every ``Constant``/``Signal``/``Variable``/``File``-derived item).

	:param item:      A singularly or plurally named entity.
	:returns:         The item's identifiers.
	:raises TypeError: If the item is neither singularly nor plurally named.

	.. seealso::

	   :func:`normalizedIdentifiersOf`
	     The same, but normalized (lower case) - use that for dictionary keys and name resolution.
	"""
	if isinstance(item, MultipleNamedEntityMixin):
		return item._identifiers
	elif isinstance(item, NamedEntityMixin):
		return (item._identifier, )

	ex = TypeError(f"Item '{item}' is neither a NamedEntityMixin nor a MultipleNamedEntityMixin.")
	ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.")
	raise ex


@export
def normalizedIdentifiersOf(item) -> Tuple[str, ...]:
	"""
	Return an item's normalized (lower case) identifier(s).

	This is the form used as dictionary keys and for name resolution, because VHDL identifiers are
	case-insensitive.

	:param item:      A singularly or plurally named entity.
	:returns:         The item's normalized identifiers.
	:raises TypeError: If the item is neither singularly nor plurally named.

	.. seealso::

	   :func:`identifiersOf`
	     The same, but as written in the source - use that for rendering.
	"""
	if isinstance(item, MultipleNamedEntityMixin):
		return item._normalizedIdentifiers
	elif isinstance(item, NamedEntityMixin):
		return (item._normalizedIdentifier, )

	ex = TypeError(f"Item '{item}' is neither a NamedEntityMixin nor a MultipleNamedEntityMixin.")
	ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.")
	raise ex


@export
class LabeledEntityMixin(metaclass=ExtendedType, mixin=True):
	"""
	A ``LabeledEntityMixin`` is a mixin class for all VHDL entities that can have labels.

	protected variables :attr:`_label` and :attr:`_normalizedLabel` are available to derived classes as well as two
	readonly properties :attr:`Label` and :attr:`NormalizedLabel` for public access.

	.. seealso::

	   * :class:`Statement <pyVHDLModel.Common.Statement>`
	   * :class:`Concurrent block statement <pyVHDLModel.Concurrent.ConcurrentBlockStatement>`
	   * :class:`Concurrent case <pyVHDLModel.Concurrent.ConcurrentCase>`
	"""
	_label:           Nullable[str]  #: The label of a model entity.
	_normalizedLabel: Nullable[str]  #: The normalized (lower case) label of a model entity.

	def __init__(self, label: Nullable[str]) -> None:
		"""
		Initializes a labeled entity.

		:param label: Label of the model entity.
		"""
		self._label = label
		self._normalizedLabel = label.lower() if label is not None else None

	@readonly
	def Label(self) -> Nullable[str]:
		"""
		Read-only property to access the model entity's label (:attr:`_label`).

		:returns: Label of a model entity.
		"""
		return self._label

	@readonly
	def NormalizedLabel(self) -> Nullable[str]:
		"""
		Read-only property to access the model entity's normalized label (:attr:`_normalizedLabel`).

		:returns: Normalized label of a model entity.
		"""
		return self._normalizedLabel


@export
class DocumentedEntityMixin(metaclass=ExtendedType, mixin=True):
	"""
	A ``DocumentedEntityMixin`` is a mixin class for all VHDL entities that can have an associated documentation.

	A protected variable :attr:`_documentation` is available to derived classes as well as a readonly property
	:attr:`Documentation` for public access.
	"""

	_documentation: Nullable[str]  #: The associated documentation of a model entity.

	def __init__(self, documentation: Nullable[str]) -> None:
		"""
		Initializes a documented entity.

		:param documentation: Documentation of a model entity.
		"""
		self._documentation = documentation

	@readonly
	def Documentation(self) -> Nullable[str]:
		"""
		Read-only property to access the model entity's documentation (:attr:`_documentation`).

		:returns: Associated documentation of a model entity.
		"""
		return self._documentation


@export
class ConditionalMixin(metaclass=ExtendedType, mixin=True):
	"""
	A ``ConditionalMixin`` is a mixin-class for all statements with a condition.

	.. seealso::

	   * :class:`Conditional branch mixin <pyVHDLModel.Base.ConditionalBranchMixin>`
	   * :class:`Assert statement mixin <pyVHDLModel.Base.AssertStatementMixin>`
	   * :class:`Conditional waveform <pyVHDLModel.Common.ConditionalWaveform>`
	   * :class:`Conditional expression <pyVHDLModel.Common.ConditionalExpression>`
	   * :class:`While loop statement <pyVHDLModel.Sequential.WhileLoopStatement>`
	   * :class:`Loop control statement <pyVHDLModel.Sequential.LoopControlStatement>`
	   * :class:`Wait statement <pyVHDLModel.Sequential.WaitStatement>`
	"""

	_condition: ExpressionUnion  #: The condition guarding this statement.

	def __init__(self, condition: Nullable[ExpressionUnion] = None) -> None:
		"""
		Initializes a statement with a condition.

		When the condition is not None, the condition's parent reference is set to this statement.

		:param condition: The expression representing the condition.
		"""
		self._condition = condition
		if condition is not None:
			condition.Parent = self

	@readonly
	def Condition(self) -> ExpressionUnion:
		"""
		Read-only property to access the condition of a statement (:attr:`_condition`).

		:returns: The expression representing the condition of a statement.
		"""
		return self._condition


@export
class BranchMixin(metaclass=ExtendedType, mixin=True):
	"""
	A ``BranchMixin`` is a mixin-class for all statements with branches.

	.. seealso::

	   * :class:`Conditional branch mixin <pyVHDLModel.Base.ConditionalBranchMixin>`
	   * :class:`Else branch mixin <pyVHDLModel.Base.ElseBranchMixin>`
	"""

	def __init__(self) -> None:
		"""
		Initializes a branch.
		"""
		pass


@export
class ConditionalBranchMixin(BranchMixin, ConditionalMixin, mixin=True):
	"""
	A ``BaseBranch`` is a mixin-class for all branch statements with a condition.

	.. seealso::

	   * :class:`If branch mixin <pyVHDLModel.Base.IfBranchMixin>`
	   * :class:`Elsif branch mixin <pyVHDLModel.Base.ElsifBranchMixin>`
	"""
	def __init__(self, condition: ExpressionUnion) -> None:
		"""
		Initializes a conditional branch.

		:param condition: The condition guarding this statement.
		"""
		super().__init__()
		ConditionalMixin.__init__(self, condition)


@export
class IfBranchMixin(ConditionalBranchMixin, mixin=True):
	"""
	A ``BaseIfBranch`` is a mixin-class for all if-branches.

	.. seealso::

	   * :class:`If generate branch <pyVHDLModel.Concurrent.IfGenerateBranch>`
	   * :class:`If branch <pyVHDLModel.Sequential.IfBranch>`
	"""


@export
class ElsifBranchMixin(ConditionalBranchMixin, mixin=True):
	"""
	A ``BaseElsifBranch`` is a mixin-class for all elsif-branches.

	.. seealso::

	   * :class:`Elsif generate branch <pyVHDLModel.Concurrent.ElsifGenerateBranch>`
	   * :class:`Elsif branch <pyVHDLModel.Sequential.ElsifBranch>`
	"""


@export
class ElseBranchMixin(BranchMixin, mixin=True):
	"""
	A ``BaseElseBranch`` is a mixin-class for all else-branches.

	.. seealso::

	   * :class:`Else generate branch <pyVHDLModel.Concurrent.ElseGenerateBranch>`
	   * :class:`Else branch <pyVHDLModel.Sequential.ElseBranch>`
	"""


@export
class ReportStatementMixin(metaclass=ExtendedType, mixin=True):
	"""
	A ``MixinReportStatement`` is a mixin-class for all report and assert statements.

	.. seealso::

	   * :class:`Assert statement mixin <pyVHDLModel.Base.AssertStatementMixin>`
	   * :class:`Sequential report statement <pyVHDLModel.Sequential.SequentialReportStatement>`
	"""

	_message:  Nullable[ExpressionUnion]  #: The reported message, or ``None`` if none was given.
	_severity: Nullable[ExpressionUnion]  #: The reported severity level, or ``None`` if none was given.

	def __init__(self, message: Nullable[ExpressionUnion] = None, severity: Nullable[ExpressionUnion] = None) -> None:
		"""
		Initializes a report statement.

		:param message:  The reported message, or ``None`` if none was given.
		:param severity: The reported severity level, or ``None`` if none was given.
		"""
		self._message = message
		if message is not None:
			message.Parent = self

		self._severity = severity
		if severity is not None:
			severity.Parent = self

	@readonly
	def Message(self) -> Nullable[ExpressionUnion]:
		"""
		Read-only property to access the message (:attr:`_message`).

		:returns: The message, or ``None`` if not set.
		"""
		return self._message

	@readonly
	def Severity(self) -> Nullable[ExpressionUnion]:
		"""
		Read-only property to access the severity (:attr:`_severity`).

		:returns: The severity, or ``None`` if not set.
		"""
		return self._severity


@export
class AssertStatementMixin(ReportStatementMixin, ConditionalMixin, mixin=True):
	"""
	A ``MixinAssertStatement`` is a mixin-class for all assert statements.

	.. seealso::

	   * :class:`Concurrent assert statement <pyVHDLModel.Concurrent.ConcurrentAssertStatement>`
	   * :class:`Sequential assert statement <pyVHDLModel.Sequential.SequentialAssertStatement>`
	"""

	def __init__(self, condition: ExpressionUnion, message: Nullable[ExpressionUnion] = None, severity: Nullable[ExpressionUnion] = None) -> None:
		"""
		Initializes an assert statement.

		:param condition: The condition guarding this statement.
		:param message:   The reported message, or ``None`` if none was given.
		:param severity:  The reported severity level, or ``None`` if none was given.
		"""
		super().__init__(message, severity)
		ConditionalMixin.__init__(self, condition)


class BlockStatementMixin(metaclass=ExtendedType, mixin=True):
	"""
	A ``BlockStatement`` is a mixin-class for all block statements.

	.. seealso::

	   * :class:`Concurrent block statement <pyVHDLModel.Concurrent.ConcurrentBlockStatement>`
	"""

	def __init__(self) -> None:
		"""
		Initializes a block statement.
		"""
		pass


@export
class BaseChoice(ModelEntity):
	"""
	A ``Choice`` is a base-class for all choices.

	.. seealso::

	   * :class:`Concurrent choice <pyVHDLModel.Concurrent.ConcurrentChoice>`
	   * :class:`Sequential choice <pyVHDLModel.Sequential.SequentialChoice>`
	"""


@export
class BaseCase(ModelEntity):
	"""
	A ``Case`` is a base-class for all cases.

	.. seealso::

	   * :class:`Selected waveform <pyVHDLModel.Common.SelectedWaveform>`
	   * :class:`Others selected waveform <pyVHDLModel.Common.OthersSelectedWaveform>`
	   * :class:`Selected expression <pyVHDLModel.Common.SelectedExpression>`
	   * :class:`Others selected expression <pyVHDLModel.Common.OthersSelectedExpression>`
	   * :class:`Concurrent case <pyVHDLModel.Concurrent.ConcurrentCase>`
	   * :class:`Sequential case <pyVHDLModel.Sequential.SequentialCase>`
	"""


@export
class ChoicesMixin(metaclass=ExtendedType, mixin=True):
	"""
	A mixin-class for all statements/entities holding a list of :class:`BaseChoice`.

	.. seealso::

	   * :class:`Selected waveform <pyVHDLModel.Common.SelectedWaveform>`
	   * :class:`Selected expression <pyVHDLModel.Common.SelectedExpression>`
	   * :class:`Concurrent case <pyVHDLModel.Concurrent.ConcurrentCase>`
	   * :class:`Sequential case <pyVHDLModel.Sequential.SequentialCase>`
	"""

	_choices: List[BaseChoice]  #: List of all choices selecting this alternative.

	def __init__(self, choices: Nullable[Iterable[BaseChoice]] = None) -> None:
		"""
		Initializes choices.

		:param choices: List of all choices selecting this alternative.
		"""
		self._choices = []
		if choices is not None:
			for choice in choices:
				self._choices.append(choice)
				choice.Parent = self

	@readonly
	def Choices(self) -> List[BaseChoice]:
		"""
		Read-only property to access the choices (:attr:`_choices`).

		:returns: List of choices.
		"""
		return self._choices


@export
class Range(ModelEntity):
	"""
	Base-class for all ranges.

	VHDL's ``range`` rule offers a range denoted by a name (:class:`RangeFromName`) as well as a range
	given by explicit bounds (:class:`SimpleRange`).

	.. seealso::

	   * :class:`Simple range <pyVHDLModel.Base.SimpleRange>`
	   * :class:`Range from name <pyVHDLModel.Base.RangeFromName>`
	"""


@export
class SimpleRange(Range):
	"""
	A range with both bounds given as expressions, e.g. ``0 to 7``.
	"""

	_leftBound:  ExpressionUnion  #: The range's left bound.
	_rightBound: ExpressionUnion  #: The range's right bound.
	_direction:  Direction        #: The range's direction, either ascending (``to``) or descending (``downto``).

	def __init__(self, leftBound: ExpressionUnion, rightBound: ExpressionUnion, direction: Direction, parent: Nullable[ModelEntity] = None) -> None:
		"""
		Initialize a simple range.

		:param leftBound:  The range's left bound.
		:param rightBound: The range's right bound.
		:param direction:  The range's direction (``to`` or ``downto``).
		:param parent:     The parent model entity.
		"""
		super().__init__(parent)

		self._leftBound = leftBound
		leftBound.Parent = self

		self._rightBound = rightBound
		rightBound.Parent = self

		self._direction = direction

	@readonly
	def LeftBound(self) -> ExpressionUnion:
		"""
		Read-only property to access the range's left bound (:attr:`_leftBound`).

		:returns: The left bound.
		"""
		return self._leftBound

	@readonly
	def RightBound(self) -> ExpressionUnion:
		"""
		Read-only property to access the range's right bound (:attr:`_rightBound`).

		:returns: The right bound.
		"""
		return self._rightBound

	@readonly
	def Direction(self) -> Direction:
		"""
		Read-only property to access the range's direction (:attr:`_direction`).

		:returns: The direction.
		"""
		return self._direction

[docs] def __str__(self) -> str: """ Formats the simple range. **Format:** ``0 to 7`` :returns: Formatted simple range. """ return f"{self._leftBound!s} {self._direction!s} {self._rightBound!s}"
@export class RangeFromName(Range): """ A range denoted by a name, so its bounds are inferred from whatever that name references. The name is represented by a :class:`~pyVHDLModel.Symbol.Symbol`, so the bounds become available once that symbol is resolved. A constrained subtype indication keeps its type mark *and* its range constraint, because it's carried by a :class:`~pyVHDLModel.Symbol.ConstrainedScalarSubtypeSymbol`. .. note:: Two forms reach this class, because a parser can't tell them apart beyond "a name, optionally with a range constraint": * a range attribute like ``vector'range``, and * a discrete subtype indication like ``bit`` or ``integer range 0 to 7``. VHDL's grammar puts the latter one level up (``discrete_range ::= discrete_subtype_indication | range``), so representing both as a range deviates from the rule split deliberately. """ _symbol: 'Symbol' #: Reference to the name the range's bounds are inferred from. def __init__(self, symbol: 'Symbol', parent: Nullable[ModelEntity] = None) -> None: """ Initialize a range denoted by a name. :param symbol: The symbol referencing the range attribute or discrete subtype. :param parent: The parent model entity. """ super().__init__(parent) self._symbol = symbol symbol.Parent = self @readonly def Symbol(self) -> 'Symbol': """ Read-only property to access the referenced symbol (:attr:`_symbol`). :returns: The symbol. """ return self._symbol
[docs] def __str__(self) -> str: """ Formats the range denoted by a name. **Format:** ``v'range`` :returns: Formatted range denoted by a name. """ return f"{self._symbol!s}"
@export class WaveformElement(ModelEntity): """ Represents one element of a waveform in a signal assignment. A waveform element assigns a value (:data:`Expression`) after an optional delay (:data:`After`). .. admonition:: Example .. code-block:: VHDL s <= '1' after 5 ns; -- ^^^ <- Expression -- ^^^^ <- After .. seealso:: * :class:`Waveform of a simple assignment <pyVHDLModel.Common.WaveformMixin>` * :class:`Waveform of one conditional branch <pyVHDLModel.Common.ConditionalWaveform>` * :class:`Waveform of one selected alternative <pyVHDLModel.Common.SelectedWaveform>` """ _expression: ExpressionUnion #: The value this waveform element assigns. _after: ExpressionUnion #: The delay after which the value is assigned, or ``None`` if none was given. def __init__(self, expression: ExpressionUnion, after: Nullable[ExpressionUnion] = None, parent: Nullable[ModelEntity] = None) -> None: """ Initializes a waveform element. :param expression: The value this waveform element assigns. :param after: The delay after which the value is assigned, or ``None`` if none was given. :param parent: The parent model entity of this entity. """ super().__init__(parent) self._expression = expression expression.Parent = self self._after = after if after is not None: after.Parent = self @readonly def Expression(self) -> ExpressionUnion: """ Read-only property to access the expression (:attr:`_expression`). :returns: The expression. """ return self._expression @readonly def After(self) -> Expression: """ Read-only property to access the waveform element's delay (:attr:`_after`). :returns: The after. """ return self._after