# =============================================================================
# ____ _ _ ____ _ _
# _ __ _ _ / ___| | | | _ \| | __| | ___ _ __ ___
# | '_ \| | | | | _| |_| | | | | | / _` |/ _ \| '_ ` _ \
# | |_) | |_| | |_| | _ | |_| | |___ | (_| | (_) | | | | | |
# | .__/ \__, |\____|_| |_|____/|_____(_)__,_|\___/|_| |_| |_|
# |_| |___/
# =============================================================================
# Authors:
# Patrick Lehmann
#
# Package module: DOM: Configurations, block/component configurations, binding indications.
#
# License:
# ============================================================================
# Copyright (C) 2019-2026 Tristan Gingold
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <gnu.org/licenses>.
#
# SPDX-License-Identifier: GPL-2.0-or-later
# ============================================================================
"""
This module implements derived configuration classes from :mod:`pyVHDLModel.Configuration`.
"""
from typing import List, Generator, Union
from pyTooling.Decorators import export, InheritDocString
from pyVHDLModel.Symbol import Symbol, PossibleReference
from pyVHDLModel.Name import Name
from pyVHDLModel.Association import GenericAssociationItem, PortAssociationItem
from pyVHDLModel.Configuration import EntityAspect as VHDLModel_EntityAspect
from pyVHDLModel.Configuration import EntityAspectEntity as VHDLModel_EntityAspectEntity
from pyVHDLModel.Configuration import EntityAspectConfiguration as VHDLModel_EntityAspectConfiguration
from pyVHDLModel.Configuration import EntityAspectOpen as VHDLModel_EntityAspectOpen
from pyVHDLModel.Configuration import BindingIndication as VHDLModel_BindingIndication
from pyVHDLModel.Configuration import AllInstantiationList as VHDLModel_AllInstantiationList
from pyVHDLModel.Configuration import OthersInstantiationList as VHDLModel_OthersInstantiationList
from pyVHDLModel.Configuration import ComponentConfiguration as VHDLModel_ComponentConfiguration
from pyVHDLModel.Configuration import BlockConfiguration as VHDLModel_BlockConfiguration
from pyGHDL.libghdl._types import Iir
from pyGHDL.libghdl.vhdl import nodes
from pyGHDL.libghdl import utils
from pyGHDL.dom import DOMMixin, DOMException, Position
from pyGHDL.dom._Utils import GetIirKindOfNode
from pyGHDL.dom.Symbol import EntitySymbol, ArchitectureSymbol, ConfigurationSymbol, ComponentInstantiationSymbol
[docs]
@export
@InheritDocString(VHDLModel_EntityAspectEntity, merge=True)
class EntityAspectEntity(VHDLModel_EntityAspectEntity, DOMMixin):
"""
This class implements a :mod:`pyGHDL.dom` object derived from :class:`pyVHDLModel.Configuration.EntityAspectEntity`.
"""
[docs]
def __init__(self, node: Iir, entity: EntitySymbol, architecture: ArchitectureSymbol = None) -> None:
"""
Initializes an entity aspect naming an entity, optionally with an architecture.
:param node: The IIR node this object was translated from.
:param entity: Reference to the named entity.
:param architecture: Reference to the selected architecture, or ``None`` if none was given.
"""
super().__init__(entity, architecture)
DOMMixin.__init__(self, node)
[docs]
@classmethod
def parse(cls, entityAspectNode: Iir) -> "EntityAspectEntity":
"""
Translates the IIR node of the entity aspect to an :class:`EntityAspectEntity`.
:param entityAspectNode: The IIR node of the entity aspect.
:returns: The translated entity aspect.
"""
from pyGHDL.dom._Translate import GetName
entityNameNode = nodes.Get_Entity_Name(entityAspectNode)
entity = EntitySymbol(entityNameNode, GetName(entityNameNode))
architectureNode = nodes.Get_Architecture(entityAspectNode)
architecture = (
None
if architectureNode == nodes.Null_Iir
else ArchitectureSymbol(architectureNode, GetName(architectureNode))
)
return cls(entityAspectNode, entity, architecture)
[docs]
@export
@InheritDocString(VHDLModel_EntityAspectConfiguration, merge=True)
class EntityAspectConfiguration(VHDLModel_EntityAspectConfiguration, DOMMixin):
"""
This class implements a :mod:`pyGHDL.dom` object derived from :class:`pyVHDLModel.Configuration.EntityAspectConfiguration`.
"""
[docs]
def __init__(self, node: Iir, configuration: ConfigurationSymbol) -> None:
"""
Initializes an entity aspect naming a configuration.
:param node: The IIR node this object was translated from.
:param configuration: Reference to the named configuration.
"""
super().__init__(configuration)
DOMMixin.__init__(self, node)
[docs]
@classmethod
def parse(cls, entityAspectNode: Iir) -> "EntityAspectConfiguration":
"""
Translates the IIR node of the entity aspect to an :class:`EntityAspectConfiguration`.
:param entityAspectNode: The IIR node of the entity aspect.
:returns: The translated entity aspect.
"""
from pyGHDL.dom._Translate import GetName
configurationNameNode = nodes.Get_Configuration_Name(entityAspectNode)
configuration = ConfigurationSymbol(configurationNameNode, GetName(configurationNameNode))
return cls(entityAspectNode, configuration)
[docs]
@export
@InheritDocString(VHDLModel_EntityAspectOpen, merge=True)
class EntityAspectOpen(VHDLModel_EntityAspectOpen, DOMMixin):
"""
This class implements a :mod:`pyGHDL.dom` object derived from :class:`pyVHDLModel.Configuration.EntityAspectOpen`.
"""
[docs]
def __init__(self, node: Iir) -> None:
"""
Initializes an entity aspect denoting :vhdlkw:`open`.
:param node: The IIR node this object was translated from.
"""
super().__init__()
DOMMixin.__init__(self, node)
[docs]
@classmethod
def parse(cls, entityAspectNode: Iir) -> "EntityAspectOpen":
"""
Translates the IIR node of the entity aspect to an :class:`EntityAspectOpen`.
:param entityAspectNode: The IIR node of the entity aspect.
:returns: The translated entity aspect.
"""
return cls(entityAspectNode)
def GetEntityAspectFromNode(entityAspectNode: Iir) -> VHDLModel_EntityAspect:
"""
Translates an entity aspect to the matching :class:`~pyVHDLModel.Configuration.EntityAspect` subclass.
:param entityAspectNode: The IIR node of the entity aspect.
:returns: The translated entity aspect.
:raises DOMException: If the entity aspect's kind is not handled.
"""
kind = GetIirKindOfNode(entityAspectNode)
if kind == nodes.Iir_Kind.Entity_Aspect_Entity:
return EntityAspectEntity.parse(entityAspectNode)
elif kind == nodes.Iir_Kind.Entity_Aspect_Configuration:
return EntityAspectConfiguration.parse(entityAspectNode)
elif kind == nodes.Iir_Kind.Entity_Aspect_Open:
return EntityAspectOpen.parse(entityAspectNode)
else:
position = Position.parse(entityAspectNode)
raise DOMException(f"Unknown entity aspect kind '{kind.name}' at {position}.")
[docs]
@export
@InheritDocString(VHDLModel_BindingIndication, merge=True)
class BindingIndication(VHDLModel_BindingIndication, DOMMixin):
"""
This class implements a :mod:`pyGHDL.dom` object derived from :class:`pyVHDLModel.Configuration.BindingIndication`.
"""
[docs]
def __init__(
self,
node: Iir,
entityAspect: VHDLModel_EntityAspect = None,
genericAssociationItems: List[GenericAssociationItem] = None,
portAssociationItems: List[PortAssociationItem] = None,
) -> None:
"""
Initializes a binding indication.
:param node: The IIR node this object was translated from.
:param entityAspect: The bound design entity, or ``None`` if not given.
:param genericAssociationItems: List of all generic associations in the generic map aspect.
:param portAssociationItems: List of all port associations in the port map aspect.
"""
super().__init__(entityAspect, genericAssociationItems, portAssociationItems)
DOMMixin.__init__(self, node)
[docs]
@classmethod
def parse(cls, bindingIndicationNode: Iir) -> "BindingIndication":
"""
Translates the IIR node of the binding indication to a :class:`BindingIndication`.
:param bindingIndicationNode: The IIR node of the binding indication.
:returns: The translated binding indication.
"""
from pyGHDL.dom._Translate import GetGenericMapAspect, GetPortMapAspect
entityAspectNode = nodes.Get_Entity_Aspect(bindingIndicationNode)
entityAspect = None if entityAspectNode == nodes.Null_Iir else GetEntityAspectFromNode(entityAspectNode)
genericAssociationItems = GetGenericMapAspect(nodes.Get_Generic_Map_Aspect_Chain(bindingIndicationNode))
portAssociationItems = GetPortMapAspect(nodes.Get_Port_Map_Aspect_Chain(bindingIndicationNode))
return cls(bindingIndicationNode, entityAspect, genericAssociationItems, portAssociationItems)
[docs]
@export
@InheritDocString(VHDLModel_AllInstantiationList, merge=True)
class AllInstantiationList(VHDLModel_AllInstantiationList, DOMMixin):
"""
This class implements a :mod:`pyGHDL.dom` object derived from :class:`pyVHDLModel.Configuration.AllInstantiationList`.
"""
[docs]
def __init__(self, node: Iir) -> None:
"""
Initializes an instantiation list denoting :vhdlkw:`all`.
:param node: The IIR node this object was translated from.
"""
super().__init__()
DOMMixin.__init__(self, node)
[docs]
@export
@InheritDocString(VHDLModel_OthersInstantiationList, merge=True)
class OthersInstantiationList(VHDLModel_OthersInstantiationList, DOMMixin):
"""
This class implements a :mod:`pyGHDL.dom` object derived from :class:`pyVHDLModel.Configuration.OthersInstantiationList`.
"""
[docs]
def __init__(self, node: Iir) -> None:
"""
Initializes an instantiation list denoting :vhdlkw:`others`.
:param node: The IIR node this object was translated from.
"""
super().__init__()
DOMMixin.__init__(self, node)
[docs]
@export
class ComponentConfiguration(VHDLModel_ComponentConfiguration, DOMMixin):
"""
.. note::
Also used for configuration specifications (``for U1 : comp use entity ...;`` declared
directly in an architecture's declarative part) - GHDL represents both with the identical
field structure (``Instantiation_List``, ``Component_Name``, ``Binding_Indication``).
"""
[docs]
def __init__(
self,
node: Iir,
instantiationList: Union[List[Name], "AllInstantiationList", "OthersInstantiationList"],
componentName: ComponentInstantiationSymbol,
bindingIndication: BindingIndication = None,
) -> None:
"""
Initializes a component configuration.
:param node: The IIR node this object was translated from.
:param instantiationList: The instances this configuration applies to.
:param componentName: Reference to the component being configured.
:param bindingIndication: The binding indication, or ``None`` if none was given.
"""
super().__init__(instantiationList, componentName, bindingIndication)
DOMMixin.__init__(self, node)
[docs]
@classmethod
def parse(cls, node: Iir) -> "ComponentConfiguration":
"""
Translates an IIR node to a :class:`ComponentConfiguration`.
:param node: The IIR node this object is translated from.
:returns: The translated object.
"""
from pyGHDL.dom._Translate import GetName
instList = nodes.Get_Instantiation_List(node)
if instList == nodes.Iir_Flist_All:
instantiationList = AllInstantiationList(node)
elif instList == nodes.Iir_Flist_Others:
instantiationList = OthersInstantiationList(node)
else:
instantiationList = []
for labelNode in utils.flist_iter(instList):
instantiationList.append(GetName(labelNode))
componentNameNode = nodes.Get_Component_Name(node)
componentName = ComponentInstantiationSymbol(componentNameNode, GetName(componentNameNode))
bindingIndicationNode = nodes.Get_Binding_Indication(node)
bindingIndication = (
None if bindingIndicationNode == nodes.Null_Iir else BindingIndication.parse(bindingIndicationNode)
)
return cls(node, instantiationList, componentName, bindingIndication)
[docs]
@export
@InheritDocString(VHDLModel_BlockConfiguration, merge=True)
class BlockConfiguration(VHDLModel_BlockConfiguration, DOMMixin):
"""
This class implements a :mod:`pyGHDL.dom` object derived from :class:`pyVHDLModel.Configuration.BlockConfiguration`.
"""
[docs]
def __init__(
self,
node: Iir,
blockSpecification: Symbol,
items: List[Union["BlockConfiguration", ComponentConfiguration]] = None,
) -> None:
"""
Initializes a block configuration.
:param node: The IIR node this object was translated from.
:param blockSpecification: The configured block.
:param items: Nested configurations.
"""
super().__init__(blockSpecification, items)
DOMMixin.__init__(self, node)
[docs]
@classmethod
def parse(cls, node: Iir) -> "BlockConfiguration":
"""
Translates an IIR node to a :class:`BlockConfiguration`.
:param node: The IIR node this object is translated from.
:returns: The translated object.
"""
from pyGHDL.dom._Translate import GetName
from pyGHDL.dom.Symbol import Symbol as DOMSymbol
blockSpecificationNode = nodes.Get_Block_Specification(node)
blockSpecification = DOMSymbol(
blockSpecificationNode,
GetName(blockSpecificationNode),
PossibleReference.Architecture | PossibleReference.Label,
)
items = list(GetConfigurationItemsFromChainedNodes(nodes.Get_Configuration_Item_Chain(node)))
return cls(node, blockSpecification, items)
def GetConfigurationItemsFromChainedNodes(
nodeChain: Iir,
) -> Generator[Union[BlockConfiguration, ComponentConfiguration], None, None]:
"""
Translates a chain of configuration items to :class:`ComponentConfiguration` and :class:`BlockConfiguration`.
:param nodeChain: The IIR node starting the chain of configuration items.
:returns: Generator yielding the translated configuration items, in source order.
:raises DOMException: If a configuration item's kind is not handled.
"""
for item in utils.chain_iter(nodeChain):
kind = GetIirKindOfNode(item)
if kind == nodes.Iir_Kind.Component_Configuration:
yield ComponentConfiguration.parse(item)
elif kind == nodes.Iir_Kind.Block_Configuration:
yield BlockConfiguration.parse(item)
else:
position = Position.parse(item)
raise DOMException(f"Unknown configuration item kind '{kind.name}' at {position}.")