Source code for pyGHDL.dom._Translate

# =============================================================================
#               ____ _   _ ____  _          _
#  _ __  _   _ / ___| | | |  _ \| |      __| | ___  _ __ ___
# | '_ \| | | | |  _| |_| | | | | |     / _` |/ _ \| '_ ` _ \
# | |_) | |_| | |_| |  _  | |_| | |___ | (_| | (_) | | | | | |
# | .__/ \__, |\____|_| |_|____/|_____(_)__,_|\___/|_| |_| |_|
# |_|    |___/
# =============================================================================
# Authors:
#   Patrick Lehmann
#
# Package module:   DOM: IIR to *** translations.
#
# License:
# ============================================================================
#  Copyright (C) 2019-2021 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 offers helper functions to translate often used IIR substructures to pyGHDL.dom (pyVHDLModel) constructs.
"""

from typing import List, Generator, Type, Dict, Union, Optional as Nullable

from pyTooling.Decorators import export
from pyTooling.Warning import WarningCollector

from pyVHDLModel.Base import ModelEntity, Direction, ExpressionUnion, Range
from pyVHDLModel.Name import Name
from pyVHDLModel.Symbol import Symbol
from pyVHDLModel.Association import AssociationItem
from pyVHDLModel.Interface import GenericInterfaceItemMixin, PortInterfaceItemMixin, ParameterInterfaceItemMixin
from pyVHDLModel.Type import BaseType
from pyVHDLModel.Sequential import SequentialStatement
from pyVHDLModel.Concurrent import ConcurrentStatement

from pyGHDL.libghdl import utils
from pyGHDL.libghdl._types import Iir
from pyGHDL.libghdl.vhdl import nodes
from pyGHDL.dom.Sequential import (
    IfStatement,
    ForLoopStatement,
    WhileLoopStatement,
    CaseStatement,
    SequentialReportStatement,
    SequentialAssertStatement,
    WaitStatement,
    SequentialSimpleSignalAssignment,
    NullStatement,
    NextStatement,
    ExitStatement,
    ReturnStatement,
    SequentialProcedureCall,
)

from pyGHDL.dom import Position, DOMException
from pyGHDL.dom._Utils import GetNameOfNode, GetLabelOfNode, GetIirKindOfNode, GetDocumentationOfNode
from pyGHDL.dom.Name import (
    SimpleName,
    SelectedName,
    AttributeName,
    ParenthesisName,
    AllName,
    OpenName,
)
from pyGHDL.dom.Symbol import (
    SimpleObjectOrFunctionCallSymbol,
    SimpleSubtypeSymbol,
    ConstrainedArraySubtypeSymbol,
    IndexedObjectOrFunctionCallSymbol,
    ConstrainedScalarSubtypeSymbol,
    ConstrainedRecordSubtypeSymbol,
    RecordElementSymbol,
    RangeAttributeSymbol,
)
from pyGHDL.dom.Type import (
    IntegerType,
    Subtype,
    ArrayType,
    RecordType,
    EnumeratedType,
    AccessType,
    ProtectedType,
    ProtectedTypeBody,
    FileType,
    PhysicalType,
    IncompleteType,
)
from pyGHDL.dom.Range import RangeFromName, SimpleRange
from pyGHDL.dom.Literal import (
    IntegerLiteral,
    CharacterLiteral,
    FloatingPointLiteral,
    StringLiteral,
    PhysicalIntegerLiteral,
    PhysicalFloatingLiteral,
    NullLiteral,
)
from pyGHDL.dom.Object import Variable
from pyGHDL.dom.Expression import (
    SubtractionExpression,
    AdditionExpression,
    MultiplyExpression,
    DivisionExpression,
    InverseExpression,
    ExponentiationExpression,
    Aggregate,
    NegationExpression,
    ParenthesisExpression,
    ConcatenationExpression,
    QualifiedExpression,
    ModuloExpression,
    RemainderExpression,
    AndExpression,
    NandExpression,
    OrExpression,
    NorExpression,
    XorExpression,
    XnorExpression,
    UnaryAndExpression,
    UnaryXnorExpression,
    UnaryXorExpression,
    UnaryNorExpression,
    UnaryOrExpression,
    UnaryNandExpression,
    EqualExpression,
    UnequalExpression,
    LessThanExpression,
    GreaterThanExpression,
    GreaterEqualExpression,
    LessEqualExpression,
    ShiftLeftLogicExpression,
    ShiftRightLogicExpression,
    ShiftLeftArithmeticExpression,
    ShiftRightArithmeticExpression,
    RotateLeftExpression,
    RotateRightExpression,
    RangeExpression,
    QualifiedExpressionAllocation,
    SubtypeAllocation,
    IdentityExpression,
    AbsoluteExpression,
    MatchingGreaterEqualExpression,
    MatchingEqualExpression,
    MatchingUnequalExpression,
    MatchingLessThanExpression,
    MatchingLessEqualExpression,
    MatchingGreaterThanExpression,
)
from pyGHDL.dom.Concurrent import (
    ConcurrentBlockStatement,
    EntityInstantiation,
    ConfigurationInstantiation,
    ComponentInstantiation,
    ProcessStatement,
    IfGenerateStatement,
    ForGenerateStatement,
    CaseGenerateStatement,
    ConcurrentSimpleSignalAssignment,
    ConcurrentProcedureCall,
    GenericAssociationItem,
    PortAssociationItem,
    ParameterAssociationItem,
    ConcurrentAssertStatement,
)
from pyGHDL.dom.Subprogram import Function, Procedure
from pyGHDL.dom.PSL import DefaultClock


[docs] @export def GetName(node: Iir) -> Name: """ Translates a *name* IIR node to a :class:`~pyVHDLModel.Name.Name`. A name can be a *simple name* or complex name consisting of *selected*, *parenthesis*, *attribute*, ... *names*. Complex names are composed as a chain of name objects, which can be traversed using the :attr:`~pyVHDLModel.Name.Name.Prefix` property. :param node: The name IIR node to translate. :returns: A name object. """ kind = GetIirKindOfNode(node) if kind == nodes.Iir_Kind.Simple_Name: name = GetNameOfNode(node) return SimpleName(node, name) elif kind == nodes.Iir_Kind.Selected_Name: name = GetNameOfNode(node) prefixName = GetName(nodes.Get_Prefix(node)) return SelectedName(node, name, prefixName) elif kind == nodes.Iir_Kind.Parenthesis_Name: prefixName = GetName(nodes.Get_Prefix(node)) associations = GetAssociations(node) return ParenthesisName(node, prefixName, associations) elif kind == nodes.Iir_Kind.Attribute_Name: name = GetNameOfNode(node) prefixName = GetName(nodes.Get_Prefix(node)) return AttributeName(node, name, prefixName) elif kind == nodes.Iir_Kind.Selected_By_All_Name: prefixName = GetName(nodes.Get_Prefix(node)) return AllName(node, prefixName) else: raise DOMException(f"Unknown name kind '{kind.name}'")
def GetAssociations(node: Iir) -> List: """ Translates the association chain of an indexed name, a slice or a function call to a list of expressions. Only the actual part of each association is translated; a formal part, if present, is discarded. The three constructs this is used for cannot be told apart before the name is resolved, so they share one translation. :param node: The IIR node carrying the association chain. :returns: List of the translated actual expressions, in source order. :raises DOMException: If an association element is neither by expression nor by name. """ associations = [] for item in utils.chain_iter(nodes.Get_Association_Chain(node)): kind = GetIirKindOfNode(item) if kind in (nodes.Iir_Kind.Association_Element_By_Expression, nodes.Iir_Kind.Association_Element_By_Name): actual = nodes.Get_Actual(item) expr = GetExpressionFromNode(actual) associations.append(expr) else: raise DOMException( f"Unknown association kind '{kind.name}' in array index/slice or function call '{node}'." ) return associations
[docs] @export def GetArrayConstraintsFromSubtypeIndication( subtypeIndication: Iir, ) -> List: """ Translates the index constraints of an array subtype indication to a list of ranges. A constraint is either a range expression (``0 to 7``) or a name denoting a range (``v'range``, ``my_range``). :param subtypeIndication: The IIR node of the array subtype indication. :returns: List of the translated index constraints, one per dimension. :raises DOMException: If a constraint is neither a range expression nor a name. """ constraints = [] for constraint in utils.flist_iter(nodes.Get_Index_Constraint_List(subtypeIndication)): constraintKind = GetIirKindOfNode(constraint) if constraintKind == nodes.Iir_Kind.Range_Expression: constraints.append(RangeExpression.parse(constraint)) elif constraintKind in ( nodes.Iir_Kind.Simple_Name, nodes.Iir_Kind.Parenthesis_Name, nodes.Iir_Kind.Selected_Name, nodes.Iir_Kind.Attribute_Name, ): constraints.append(GetName(constraint)) else: position = Position.parse(constraint) raise DOMException( f"Unknown constraint kind '{constraintKind.name}' for constraint '{constraint}' in subtype indication '{subtypeIndication}' at {position}." ) return constraints
[docs] @export def GetRecordConstraintsFromSubtypeIndication( subtypeIndication: Iir, ) -> Dict: """ Translates the element constraints of a record subtype indication to a dictionary. The dictionary is keyed by a :class:`~pyGHDL.dom.Symbol.RecordElementSymbol` naming the constrained element; the values are not translated yet. :param subtypeIndication: The IIR node of the record subtype indication. :returns: Mapping from record element symbol to its constraint. :raises DOMException: If an element of the chain is not a record element constraint. """ constraints = {} recordElementConstraint = nodes.Get_Owned_Elements_Chain(subtypeIndication) while recordElementConstraint != nodes.Null_Iir: recordElementKind = GetIirKindOfNode(recordElementConstraint) if recordElementKind == nodes.Iir_Kind.Record_Element_Constraint: recordElementName = GetNameOfNode(recordElementConstraint) sym = RecordElementSymbol(recordElementConstraint, SimpleName(recordElementConstraint, recordElementName)) constraints[sym] = None else: position = Position.parse(recordElementConstraint) raise DOMException( f"Unknown constraint kind '{recordElementKind.name}' for constraint '{recordElementConstraint}' in subtype indication '{subtypeIndication}' at {position}." ) recordElementConstraint = nodes.Get_Chain(recordElementConstraint) return constraints
[docs] @export def GetTypeFromNode(node: Iir) -> BaseType: """ Translates a type declaration to the matching :mod:`pyGHDL.dom.Type` class. The doc-comment attaches to the type *declaration*, not to the type definition inside it, so it is read here and handed to whichever class parses the definition. A declaration without a definition is an incomplete type. :param node: The IIR node of the type declaration. :returns: The translated type. :raises DOMException: If the type definition's kind is not handled. """ typeName = GetNameOfNode(node) # A doc comment attaches to the type *declaration*, not the type definition inside it, so it is read # here and handed to whichever class parses the definition. documentation = GetDocumentationOfNode(node) typeDefinition = nodes.Get_Type_Definition(node) if typeDefinition is nodes.Null_Iir: return IncompleteType(node, typeName, documentation) kind = GetIirKindOfNode(typeDefinition) if kind == nodes.Iir_Kind.Enumeration_Type_Definition: return EnumeratedType.parse(typeName, typeDefinition, documentation) elif kind == nodes.Iir_Kind.Array_Type_Definition: return ArrayType.parse(typeName, typeDefinition, documentation) elif kind == nodes.Iir_Kind.Record_Type_Definition: return RecordType.parse(typeName, typeDefinition, documentation) elif kind == nodes.Iir_Kind.Access_Type_Definition: return AccessType.parse(typeName, typeDefinition, documentation) elif kind == nodes.Iir_Kind.File_Type_Definition: return FileType.parse(typeName, typeDefinition, documentation) elif kind == nodes.Iir_Kind.Protected_Type_Declaration: return ProtectedType.parse(typeName, typeDefinition, documentation) else: position = Position.parse(typeDefinition) raise DOMException( f"GetTypeFromNode: Unknown type definition kind '{kind.name}' for type '{typeName}' at {position}." )
[docs] @export def GetAnonymousTypeFromNode(node: Iir) -> BaseType: """ Translates an anonymous type declaration to the matching :mod:`pyGHDL.dom.Type` class. GHDL creates an anonymous type declaration for the type definitions that have no name of their own - an integer or physical type behind a subtype, for instance. :param node: The IIR node of the anonymous type declaration. :returns: The translated type. :raises DOMException: If the type definition's kind is not handled. """ typeName = GetNameOfNode(node) documentation = GetDocumentationOfNode(node) typeDefinition = nodes.Get_Type_Definition(node) if typeDefinition is nodes.Null_Iir: return IncompleteType(node, typeName, documentation) kind = GetIirKindOfNode(typeDefinition) if kind == nodes.Iir_Kind.Range_Expression: r = GetRangeFromNode(typeDefinition) return IntegerType(node, typeName, r, documentation) elif kind in (nodes.Iir_Kind.Attribute_Name, nodes.Iir_Kind.Parenthesis_Name): n = GetName(typeDefinition) return IntegerType(node, typeName, n, documentation) elif kind == nodes.Iir_Kind.Physical_Type_Definition: return PhysicalType.parse(typeName, typeDefinition, documentation) elif kind == nodes.Iir_Kind.Array_Subtype_Definition: WarningCollector.Raise(NotImplementedError("Array_Subtype_Definition")) return ArrayType(typeDefinition, "????", [], None, documentation) else: position = Position.parse(typeDefinition) raise DOMException( f"GetAnonymousTypeFromNode: Unknown type definition kind '{kind.name}' for type '{typeName}' at {position}." )
[docs] @export def GetSubtypeIndicationFromNode(node: Iir, entity: str, name: str) -> Symbol: """ Extracts the subtype indication from an IIR node and translates it to a :class:`~pyVHDLModel.Symbol.Symbol`. .. note:: This function calls :func:`GetSubtypeIndicationFromIndicationNode`. This function should be used directly if :pycode:`nodes.Get_Subtype_Indication(...)` was already called or a subtype indication is return by another getter. :param node: The IIR node to get the subtype indication from. :param entity: The entity kind the subtype indication is extracted from (e.g. :vhdlkw:`constant`). Used in exception messages. :param name: The entity's name the subtype indication is extracted from (e.g. ``BITS``). Used in exception messages. :returns: A symbol representing a reference to a type/subtype and possible array or record constraints. """ subtypeIndicationNode = nodes.Get_Subtype_Indication(node) return GetSubtypeIndicationFromIndicationNode(subtypeIndicationNode, entity, name)
[docs] @export def GetSubtypeIndicationFromIndicationNode(subtypeIndicationNode: Iir, entity: str, name: str) -> Symbol: """ Translate a subtype indication to a :class:`~pyVHDLModel.Symbol.Symbol`. :param subtypeIndicationNode: The subtype indication IIR node. :param entity: The entity kind the subtype indication is extracted from (e.g. :vhdlkw:`constant`). Used in exception messages. :param name: The entity's name the subtype indication is extracted from (e.g. ``BITS``). Used in exception messages. :returns: A symbol referencing a type or subtype, with array or record constraints. """ if subtypeIndicationNode is nodes.Null_Iir: raise ValueError("Parameter 'subtypeIndicationNode' is 'Null_Iir'.") kind = GetIirKindOfNode(subtypeIndicationNode) if kind in ( nodes.Iir_Kind.Simple_Name, nodes.Iir_Kind.Selected_Name, nodes.Iir_Kind.Attribute_Name, ): return GetSimpleTypeFromNode(subtypeIndicationNode) elif kind == nodes.Iir_Kind.Subtype_Definition: return GetScalarConstrainedSubtypeFromNode(subtypeIndicationNode) elif kind == nodes.Iir_Kind.Array_Subtype_Definition: return GetArrayConstrainedSubtypeFromNode(subtypeIndicationNode) elif kind == nodes.Iir_Kind.Record_Subtype_Definition: return GetRecordConstrainedSubtypeFromNode(subtypeIndicationNode) else: raise DOMException(f"Unknown kind '{kind.name}' for an subtype indication in a {entity} of `{name}`.")
[docs] @export def GetSimpleTypeFromNode(subtypeIndicationNode: Iir) -> SimpleSubtypeSymbol: """ Translates a subtype indication that is just a type mark to a simple subtype symbol. :param subtypeIndicationNode: The IIR node of the subtype indication. :returns: A subtype symbol referencing the type mark. """ subtypeName = GetName(subtypeIndicationNode) return SimpleSubtypeSymbol(subtypeIndicationNode, subtypeName)
[docs] @export def GetScalarConstrainedSubtypeFromNode( subtypeIndicationNode: Iir, ) -> Union[SimpleSubtypeSymbol, ConstrainedScalarSubtypeSymbol]: """ Translate a scalar subtype indication IIR node to a subtype symbol. A ``Subtype_Definition`` node carries a type mark and *optionally* a range constraint, because the node is also used for a subtype indication that only adds a resolution indication (``subtype resolvedBit is resolveBit myBit;``). Without a range constraint the result is a :class:`~pyVHDLModel.Symbol.SimpleSubtypeSymbol`; with one it is a :class:`~pyVHDLModel.Symbol.ConstrainedScalarSubtypeSymbol`, whose constraint is mandatory. :param subtypeIndicationNode: The subtype indication IIR node. :returns: The translated subtype symbol. :raises DOMException: If the range constraint's IIR node isn't a known range. """ typeMark = nodes.Get_Subtype_Type_Mark(subtypeIndicationNode) typeMarkName = GetNameOfNode(typeMark) simpleTypeMark = SimpleName(typeMark, typeMarkName) rangeConstraint = nodes.Get_Range_Constraint(subtypeIndicationNode) if rangeConstraint == nodes.Null_Iir: return SimpleSubtypeSymbol(subtypeIndicationNode, simpleTypeMark) rangeKind = GetIirKindOfNode(rangeConstraint) if rangeKind == nodes.Iir_Kind.Range_Expression: constraint = GetRangeFromNode(rangeConstraint) elif rangeKind in ( nodes.Iir_Kind.Attribute_Name, nodes.Iir_Kind.Parenthesis_Name, ): # A range attribute like `natural range vector'range`. constraint = RangeFromName(rangeConstraint, RangeAttributeSymbol(rangeConstraint, GetName(rangeConstraint))) else: position = Position.parse(subtypeIndicationNode) ex = DOMException( f"Unknown range constraint kind '{rangeKind.name}' in a subtype indication at line {position.Line}." ) ex.add_note("Supported: a range expression or a range attribute name.") raise ex return ConstrainedScalarSubtypeSymbol(subtypeIndicationNode, simpleTypeMark, constraint)
[docs] @export def GetArrayConstrainedSubtypeFromNode( subtypeIndicationNode: Iir, ) -> ConstrainedArraySubtypeSymbol: """ Translates an array subtype indication with an index constraint to a constrained array subtype symbol. :param subtypeIndicationNode: The IIR node of the array subtype indication. :returns: A subtype symbol carrying the type mark and one range per dimension. """ typeMark = nodes.Get_Subtype_Type_Mark(subtypeIndicationNode) typeMarkName = GetNameOfNode(typeMark) simpleTypeMark = SimpleName(typeMark, typeMarkName) constraints = GetArrayConstraintsFromSubtypeIndication(subtypeIndicationNode) return ConstrainedArraySubtypeSymbol(subtypeIndicationNode, simpleTypeMark, constraints)
[docs] @export def GetRecordConstrainedSubtypeFromNode( subtypeIndicationNode: Iir, ) -> ConstrainedRecordSubtypeSymbol: """ Translates a record subtype indication with an element constraint to a constrained record subtype symbol. :param subtypeIndicationNode: The IIR node of the record subtype indication. :returns: A subtype symbol carrying the type mark and the constrained elements. """ typeMark = nodes.Get_Subtype_Type_Mark(subtypeIndicationNode) typeMarkName = GetNameOfNode(typeMark) simpleTypeMark = SimpleName(typeMark, typeMarkName) constraints = GetRecordConstraintsFromSubtypeIndication(subtypeIndicationNode) return ConstrainedRecordSubtypeSymbol(subtypeIndicationNode, simpleTypeMark, constraints)
[docs] @export def GetSubtypeFromNode(subtypeNode: Iir) -> Symbol: """ Translates a subtype declaration to a :class:`~pyGHDL.dom.Type.Subtype`. :param subtypeNode: The IIR node of the subtype declaration. :returns: The translated subtype, carrying the symbol of its subtype indication. """ subtypeName = GetNameOfNode(subtypeNode) symbol = GetSubtypeIndicationFromNode(subtypeNode, "subtype", subtypeName) return Subtype(subtypeNode, subtypeName, symbol)
[docs] @export def GetRangeFromNode(node: Iir) -> SimpleRange: """ Translate a range IIR node to a :class:`~pyVHDLModel.Base.SimpleRange`. :param node: The IIR node representing a range. :returns: The translated range object. """ direction = nodes.Get_Direction(node) leftBound = nodes.Get_Left_Limit_Expr(node) rightBound = nodes.Get_Right_Limit_Expr(node) return SimpleRange( node, GetExpressionFromNode(leftBound), GetExpressionFromNode(rightBound), Direction.DownTo if direction else Direction.To, )
[docs] @export def GetDiscreteRangeFromNode(discreteRangeNode: Iir, entity: str) -> Range: """ Translate a discrete range IIR node to a :class:`~pyVHDLModel.Base.Range`. A discrete range is either an explicit range (``0 to 7``, ``vector'range``) or a discrete subtype indication - a type mark (``bit``), optionally with a range constraint (``integer range 0 to 7``). Everything but the explicit-bounds form becomes a :class:`~pyVHDLModel.Base.RangeFromName` wrapping the referenced symbol. Shared by :vhdlkw:`for..loop` statements, :vhdlkw:`for..generate` statements and aggregate choices, which all use the same VHDL ``discrete_range`` grammar rule. :param discreteRangeNode: The IIR node representing a discrete range. :param entity: The construct the discrete range appears in (e.g. :vhdlkw:`for..loop`). Used in exception messages. :returns: The translated range. :raises DOMException: If the IIR node's kind isn't a known discrete range. """ rangeKind = GetIirKindOfNode(discreteRangeNode) if rangeKind == nodes.Iir_Kind.Range_Expression: return GetRangeFromNode(discreteRangeNode) elif rangeKind == nodes.Iir_Kind.Subtype_Definition: # A subtype indication like `integer range 0 to 7`, which keeps its type mark alongside the # range constraint. return RangeFromName(discreteRangeNode, GetScalarConstrainedSubtypeFromNode(discreteRangeNode)) elif rangeKind in ( nodes.Iir_Kind.Simple_Name, nodes.Iir_Kind.Selected_Name, ): # A bare type mark like `bit` or `work.pkg.sub`. return RangeFromName(discreteRangeNode, GetSimpleTypeFromNode(discreteRangeNode)) elif rangeKind in ( nodes.Iir_Kind.Attribute_Name, nodes.Iir_Kind.Parenthesis_Name, ): # A range attribute like `vector'range`. return RangeFromName(discreteRangeNode, RangeAttributeSymbol(discreteRangeNode, GetName(discreteRangeNode))) position = Position.parse(discreteRangeNode) ex = DOMException(f"Unknown discrete range kind '{rangeKind.name}' in {entity} at line {position.Line}.") ex.add_note("Supported: a range expression, a range attribute name, or a discrete subtype indication.") raise ex
__EXPRESSION_TRANSLATION = { nodes.Iir_Kind.Simple_Name: SimpleObjectOrFunctionCallSymbol, nodes.Iir_Kind.Selected_Name: IndexedObjectOrFunctionCallSymbol, nodes.Iir_Kind.Selected_By_All_Name: IndexedObjectOrFunctionCallSymbol, nodes.Iir_Kind.Attribute_Name: IndexedObjectOrFunctionCallSymbol, nodes.Iir_Kind.Parenthesis_Name: IndexedObjectOrFunctionCallSymbol, nodes.Iir_Kind.Null_Literal: NullLiteral, nodes.Iir_Kind.Integer_Literal: IntegerLiteral, nodes.Iir_Kind.Floating_Point_Literal: FloatingPointLiteral, nodes.Iir_Kind.Physical_Int_Literal: PhysicalIntegerLiteral, nodes.Iir_Kind.Physical_Fp_Literal: PhysicalFloatingLiteral, nodes.Iir_Kind.Character_Literal: CharacterLiteral, nodes.Iir_Kind.String_Literal8: StringLiteral, nodes.Iir_Kind.Identity_Operator: IdentityExpression, nodes.Iir_Kind.Negation_Operator: NegationExpression, nodes.Iir_Kind.Absolute_Operator: AbsoluteExpression, nodes.Iir_Kind.Range_Expression: RangeExpression, nodes.Iir_Kind.Addition_Operator: AdditionExpression, nodes.Iir_Kind.Concatenation_Operator: ConcatenationExpression, nodes.Iir_Kind.Not_Operator: InverseExpression, nodes.Iir_Kind.Parenthesis_Expression: ParenthesisExpression, nodes.Iir_Kind.Substraction_Operator: SubtractionExpression, nodes.Iir_Kind.Multiplication_Operator: MultiplyExpression, nodes.Iir_Kind.Division_Operator: DivisionExpression, nodes.Iir_Kind.Modulus_Operator: ModuloExpression, nodes.Iir_Kind.Remainder_Operator: RemainderExpression, nodes.Iir_Kind.Exponentiation_Operator: ExponentiationExpression, nodes.Iir_Kind.And_Operator: AndExpression, nodes.Iir_Kind.Nand_Operator: NandExpression, nodes.Iir_Kind.Or_Operator: OrExpression, nodes.Iir_Kind.Nor_Operator: NorExpression, nodes.Iir_Kind.Xor_Operator: XorExpression, nodes.Iir_Kind.Xnor_Operator: XnorExpression, nodes.Iir_Kind.Reduction_And_Operator: UnaryAndExpression, nodes.Iir_Kind.Reduction_Nand_Operator: UnaryNandExpression, nodes.Iir_Kind.Reduction_Or_Operator: UnaryOrExpression, nodes.Iir_Kind.Reduction_Nor_Operator: UnaryNorExpression, nodes.Iir_Kind.Reduction_Xor_Operator: UnaryXorExpression, nodes.Iir_Kind.Reduction_Xnor_Operator: UnaryXnorExpression, nodes.Iir_Kind.Equality_Operator: EqualExpression, nodes.Iir_Kind.Inequality_Operator: UnequalExpression, nodes.Iir_Kind.Less_Than_Operator: LessThanExpression, nodes.Iir_Kind.Less_Than_Or_Equal_Operator: LessEqualExpression, nodes.Iir_Kind.Greater_Than_Operator: GreaterThanExpression, nodes.Iir_Kind.Greater_Than_Or_Equal_Operator: GreaterEqualExpression, nodes.Iir_Kind.Match_Equality_Operator: MatchingEqualExpression, nodes.Iir_Kind.Match_Inequality_Operator: MatchingUnequalExpression, nodes.Iir_Kind.Match_Less_Than_Operator: MatchingLessThanExpression, nodes.Iir_Kind.Match_Less_Than_Or_Equal_Operator: MatchingLessEqualExpression, nodes.Iir_Kind.Match_Greater_Than_Operator: MatchingGreaterThanExpression, nodes.Iir_Kind.Match_Greater_Than_Or_Equal_Operator: MatchingGreaterEqualExpression, nodes.Iir_Kind.Sll_Operator: ShiftLeftLogicExpression, nodes.Iir_Kind.Srl_Operator: ShiftRightLogicExpression, nodes.Iir_Kind.Sla_Operator: ShiftLeftArithmeticExpression, nodes.Iir_Kind.Sra_Operator: ShiftRightArithmeticExpression, nodes.Iir_Kind.Rol_Operator: RotateLeftExpression, nodes.Iir_Kind.Ror_Operator: RotateRightExpression, nodes.Iir_Kind.Qualified_Expression: QualifiedExpression, nodes.Iir_Kind.Aggregate: Aggregate, nodes.Iir_Kind.Allocator_By_Subtype: SubtypeAllocation, nodes.Iir_Kind.Allocator_By_Expression: QualifiedExpressionAllocation, }
[docs] @export def GetExpressionFromNode(node: Iir) -> ExpressionUnion: """ Translates an expression IIR node to an :class:`~pyVHDLModel.Expression.BaseExpression`. :param node: The IIR node representing an expression. :returns: The translated expression. """ kind = GetIirKindOfNode(node) try: cls = __EXPRESSION_TRANSLATION[kind] except KeyError: position = Position.parse(node) raise DOMException(f"Unknown expression kind '{kind.name}' in expression '{node}' at {position}.") return cls.parse(node)
def GetOptionalExpressionFromNode(node: Iir) -> Nullable[ExpressionUnion]: """ Like :func:`GetExpressionFromNode`, but for fields that may legitimately be absent (e.g. an optional condition on the final branch of a conditional assignment, or on an unconditional :vhdlkw:`exit`/:vhdlkw:`next` statement) - returns ``None`` instead of translating when ``node`` is ``Null_Iir``, rather than requiring every call site to repeat that check. :param node: The IIR node representing an expression, or ``Null_Iir`` if absent. :returns: The translated expression, or ``None``. """ return None if node == nodes.Null_Iir else GetExpressionFromNode(node)
[docs] @export def GetModeViewElementsFromChainedNodes(nodeChain: Iir) -> Generator["ModeViewElement", None, None]: """ Translates a chain of mode view elements (IIR nodes) to a sequence of :class:`pyVHDLModel.Interface.ModeViewElement`. :param nodeChain: The IIR node representing the first mode view element in the chain. :returns: A generator returning mode view elements. .. note:: Unlike declarations/interface items (where the *last* node in a ``Has_Identifier_List`` group owns the shared subtype/value and earlier ones are Null), mode view elements are the other way around: the *first* node in the group (``Has_Identifier_List == True``) owns the real ``Mode``/ ``Mode_View_Name`` - subsequent nodes only contribute their identifier, ending with the node where ``Has_Identifier_List`` becomes ``False``. Verified against real GHDL analysis for ``x, y : out;``: ``x`` has ``Has_Identifier_List=True``, ``Mode=out``; ``y`` has ``Has_Identifier_List=False``, ``Mode=<unset>``. """ from pyGHDL.dom.InterfaceItem import SimpleModeViewElement, CompositeModeViewElement furtherIdentifiers = [] element = nodeChain while element != nodes.Null_Iir: kind = GetIirKindOfNode(element) if kind == nodes.Iir_Kind.Simple_Mode_View_Element: parseMethod = SimpleModeViewElement.parse elif kind in (nodes.Iir_Kind.Array_Mode_View_Element, nodes.Iir_Kind.Record_Mode_View_Element): parseMethod = CompositeModeViewElement.parse else: position = Position.parse(element) raise DOMException(f"Unknown mode view element kind '{kind.name}' at {position}.") elementToParse = element if nodes.Get_Has_Identifier_List(element): nextNode = nodes.Get_Chain(element) for nextElement in utils.chain_iter(nextNode): furtherIdentifiers.append(GetNameOfNode(nextElement)) if not nodes.Get_Has_Identifier_List(nextElement): element = nodes.Get_Chain(nextElement) break else: element = nodes.Null_Iir else: element = nodes.Get_Chain(element) yield parseMethod(elementToParse, furtherIdentifiers) furtherIdentifiers.clear()
[docs] @export def GetGenericsFromChainedNodes(nodeChain: Iir) -> Generator[GenericInterfaceItemMixin, None, None]: """ Translates a chain of generics (IIR nodes) to a sequence of :class:`pyVHDLModel.Interface.GenericInterfaceItem`. :param nodeChain: The IIR node representing the first generic in the chain. :returns: A generator returning generic interface items. """ from pyGHDL.dom.InterfaceItem import ( GenericTypeInterfaceItem, GenericPackageInterfaceItem, GenericProcedureInterfaceItem, GenericFunctionInterfaceItem, ) furtherIdentifiers = [] generic = nodeChain while generic != nodes.Null_Iir: kind = GetIirKindOfNode(generic) if kind == nodes.Iir_Kind.Interface_Constant_Declaration: from pyGHDL.dom.InterfaceItem import GenericConstantInterfaceItem parseNode = generic # Lookahead for generics with multiple identifiers at once if nodes.Get_Has_Identifier_List(generic): nextNode = nodes.Get_Chain(generic) for nextGeneric in utils.chain_iter(nextNode): # Consecutive identifiers are found, if the subtype indication is Null if nodes.Get_Subtype_Indication(nextGeneric) == nodes.Null_Iir: furtherIdentifiers.append(GetNameOfNode(nextGeneric)) else: generic = nextGeneric break # The last consecutive identifiers has no Identifier_List flag if not nodes.Get_Has_Identifier_List(nextGeneric): generic = nodes.Get_Chain(nextGeneric) break else: generic = nodes.Null_Iir else: generic = nodes.Get_Chain(generic) yield GenericConstantInterfaceItem.parse(parseNode, furtherIdentifiers) furtherIdentifiers.clear() continue else: if kind == nodes.Iir_Kind.Interface_Type_Declaration: yield GenericTypeInterfaceItem.parse(generic) elif kind == nodes.Iir_Kind.Interface_Package_Declaration: yield GenericPackageInterfaceItem.parse(generic) elif kind == nodes.Iir_Kind.Interface_Procedure_Declaration: yield GenericProcedureInterfaceItem.parse(generic) elif kind == nodes.Iir_Kind.Interface_Function_Declaration: yield GenericFunctionInterfaceItem.parse(generic) else: position = Position.parse(generic) raise DOMException(f"Unknown generic kind '{kind.name}' in generic '{generic}' at {position}.") generic = nodes.Get_Chain(generic)
[docs] @export def GetPortsFromChainedNodes(nodeChain: Iir) -> Generator[PortInterfaceItemMixin, None, None]: """ Translates a chain of ports (IIR nodes) to a sequence of :class:`pyVHDLModel.Interface.PortInterfaceItem`. :param nodeChain: The IIR node representing the first port in the chain. :returns: A generator returning port interface items. """ furtherIdentifiers = [] port = nodeChain while port != nodes.Null_Iir: kind = GetIirKindOfNode(port) if kind == nodes.Iir_Kind.Interface_Signal_Declaration: from pyGHDL.dom.InterfaceItem import PortSimpleSignalInterfaceItem parseMethod = PortSimpleSignalInterfaceItem.parse parseNode = port elif kind == nodes.Iir_Kind.Interface_View_Declaration: from pyGHDL.dom.InterfaceItem import PortViewSignalInterfaceItem parseMethod = PortViewSignalInterfaceItem.parse parseNode = port else: position = Position.parse(port) raise DOMException(f"Unknown port kind '{kind.name}' in port '{port}' at {position}.") # Lookahead for ports with multiple identifiers at once if nodes.Get_Has_Identifier_List(port): nextNode = nodes.Get_Chain(port) for nextPort in utils.chain_iter(nextNode): # Consecutive identifiers are found, if the subtype indication is Null if nodes.Get_Subtype_Indication(nextPort) == nodes.Null_Iir: furtherIdentifiers.append(GetNameOfNode(nextPort)) else: port = nextPort break # The last consecutive identifiers has no Identifier_List flag if not nodes.Get_Has_Identifier_List(nextPort): port = nodes.Get_Chain(nextPort) break else: port = nodes.Null_Iir else: port = nodes.Get_Chain(port) yield parseMethod(parseNode, furtherIdentifiers) furtherIdentifiers.clear()
[docs] @export def GetParameterFromChainedNodes(nodeChain: Iir) -> Generator[ParameterInterfaceItemMixin, None, None]: """ Translates a chain of parameters (IIR nodes) to a sequence of :class:`pyVHDLModel.Interface.ParameterInterfaceItem`. :param nodeChain: The IIR node representing the first parameter in the chain. :returns: A generator returning parameter interface items. """ identifiers = [] parameter = nodeChain while parameter != nodes.Null_Iir: kind = GetIirKindOfNode(parameter) if kind == nodes.Iir_Kind.Interface_Constant_Declaration: from pyGHDL.dom.InterfaceItem import ParameterConstantInterfaceItem parseMethod = ParameterConstantInterfaceItem.parse parseNode = parameter elif kind == nodes.Iir_Kind.Interface_Variable_Declaration: from pyGHDL.dom.InterfaceItem import ParameterVariableInterfaceItem parseMethod = ParameterVariableInterfaceItem.parse parseNode = parameter elif kind == nodes.Iir_Kind.Interface_Signal_Declaration: from pyGHDL.dom.InterfaceItem import ParameterSimpleSignalInterfaceItem parseMethod = ParameterSimpleSignalInterfaceItem.parse parseNode = parameter elif kind == nodes.Iir_Kind.Interface_View_Declaration: from pyGHDL.dom.InterfaceItem import ParameterViewSignalInterfaceItem parseMethod = ParameterViewSignalInterfaceItem.parse parseNode = parameter elif kind == nodes.Iir_Kind.Interface_File_Declaration: from pyGHDL.dom.InterfaceItem import ParameterFileInterfaceItem parseMethod = ParameterFileInterfaceItem.parse parseNode = parameter else: position = Position.parse(parameter) raise DOMException(f"Unknown parameter kind '{kind.name}' in parameter '{parameter}' at {position}.") # Lookahead for parameters with multiple identifiers at once if nodes.Get_Has_Identifier_List(parameter): nextNode = nodes.Get_Chain(parameter) for nextParameter in utils.chain_iter(nextNode): # Consecutive identifiers are found, if the subtype indication is Null if nodes.Get_Subtype_Indication(nextParameter) == nodes.Null_Iir: identifiers.append(GetNameOfNode(nextParameter)) else: parameter = nextParameter break # The last consecutive identifiers has no Identifier_List flag if not nodes.Get_Has_Identifier_List(nextParameter): parameter = nodes.Get_Chain(nextParameter) break else: parameter = nodes.Null_Iir else: parameter = nodes.Get_Chain(parameter) yield parseMethod(parseNode, identifiers)
def GetMapAspect(mapAspect: Iir, cls: Type, entity: str) -> Generator[AssociationItem, None, None]: """ Translates a generic, port or parameter map aspect to association items. An association without a formal part is positional, so its formal is ``None``. An association to :vhdlkw:`open` yields an :class:`~pyGHDL.dom.Name.OpenName` as the actual. :param mapAspect: The IIR node starting the association chain of the map aspect. :param cls: The association item class to instantiate, e.g. :class:`~pyGHDL.dom.Concurrent.PortAssociationItem`. :param entity: The kind of map aspect (:vhdlkw:`generic`, :vhdlkw:`port`, :vhdlkw:`parameter`). Used in exception messages. :returns: Generator yielding the translated association items, in source order. :raises DOMException: If an association element is neither by expression nor open. """ for item in utils.chain_iter(mapAspect): kind = GetIirKindOfNode(item) if kind is nodes.Iir_Kind.Association_Element_By_Expression: formalNode = nodes.Get_Formal(item) if formalNode is nodes.Null_Iir: formal = None else: formal = GetName(formalNode) actual = GetExpressionFromNode(nodes.Get_Actual(item)) yield cls(item, formal, actual) elif kind is nodes.Iir_Kind.Association_Element_Open: formalNode = nodes.Get_Formal(item) if formalNode is nodes.Null_Iir: formal = None else: formal = GetName(formalNode) yield cls(item, formal, OpenName(item)) else: pos = Position.parse(item) raise DOMException(f"Unknown association kind '{kind.name}' in {entity} map at line {pos.Line}.") def GetGenericMapAspect(genericMapAspect: Iir) -> Generator[GenericAssociationItem, None, None]: """ Translates a generic map aspect to generic association items. :param genericMapAspect: The IIR node starting the generic map aspect's association chain. :returns: Generator yielding the translated generic associations, in source order. """ return GetMapAspect(genericMapAspect, GenericAssociationItem, "generic") def GetPortMapAspect(portMapAspect: Iir) -> Generator[PortAssociationItem, None, None]: """ Translates a port map aspect to port association items. :param portMapAspect: The IIR node starting the port map aspect's association chain. :returns: Generator yielding the translated port associations, in source order. """ return GetMapAspect(portMapAspect, PortAssociationItem, "port") def GetParameterMapAspect(parameterMapAspect: Iir) -> Generator[ParameterAssociationItem, None, None]: """ Translates a subprogram call's parameter map to parameter association items. :param parameterMapAspect: The IIR node starting the parameter map's association chain. :returns: Generator yielding the translated parameter associations, in source order. """ return GetMapAspect(parameterMapAspect, ParameterAssociationItem, "parameter") def GetDeclaredItemsFromChainedNodes(nodeChain: Iir, entity: str, name: str) -> Generator[ModelEntity, None, None]: """ Translates a chain of declarations to the matching :mod:`pyGHDL.dom` objects. GHDL splits a declaration naming several identifiers (``signal a, b : bit;``) into one node per identifier. They are collected here and yielded as a single object carrying all identifiers. :param nodeChain: The IIR node starting the chain of declarations. :param entity: The kind of declarative region the chain belongs to. Used in exception messages. :param name: The name of that declarative region. Used in exception messages. :returns: Generator yielding the translated declared items, in source order. :raises DOMException: If a declaration's kind is not handled. """ furtherIdentifiers = [] item = nodeChain lastKind = None while item != nodes.Null_Iir: kind = GetIirKindOfNode(item) if kind == nodes.Iir_Kind.Constant_Declaration: from pyGHDL.dom.Object import Constant objectParseMethod = Constant.parse objectItem = item elif kind == nodes.Iir_Kind.Variable_Declaration: from pyGHDL.dom.Object import SharedVariable if nodes.Get_Shared_Flag(item): objectParseMethod = SharedVariable.parse objectItem = item else: objectParseMethod = Variable.parse objectItem = item elif kind == nodes.Iir_Kind.Signal_Declaration: from pyGHDL.dom.Object import Signal objectParseMethod = Signal.parse objectItem = item elif kind == nodes.Iir_Kind.File_Declaration: from pyGHDL.dom.Object import File objectParseMethod = File.parse objectItem = item else: if kind == nodes.Iir_Kind.Type_Declaration: yield GetTypeFromNode(item) elif kind == nodes.Iir_Kind.Anonymous_Type_Declaration: yield GetAnonymousTypeFromNode(item) elif kind == nodes.Iir_Kind.Subtype_Declaration: yield GetSubtypeFromNode(item) elif kind == nodes.Iir_Kind.Mode_View_Declaration: from pyGHDL.dom.InterfaceItem import ModeViewDeclaration yield ModeViewDeclaration.parse(item) elif kind == nodes.Iir_Kind.Function_Declaration: yield Function.parse(item) lastKind = kind item = nodes.Get_Chain(item) continue elif kind == nodes.Iir_Kind.Function_Instantiation_Declaration: from pyGHDL.dom.Subprogram import FunctionInstantiation yield FunctionInstantiation.parse(item) elif kind == nodes.Iir_Kind.Procedure_Instantiation_Declaration: from pyGHDL.dom.Subprogram import ProcedureInstantiation yield ProcedureInstantiation.parse(item) elif kind == nodes.Iir_Kind.Function_Body: if lastKind is nodes.Iir_Kind.Function_Declaration: pass else: position = Position.parse(item) raise DOMException( f"Found unexpected function body '{GetNameOfNode(item)}' in {entity} '{name}' at {position}." ) elif kind == nodes.Iir_Kind.Procedure_Declaration: yield Procedure.parse(item) lastKind = kind item = nodes.Get_Chain(item) continue elif kind == nodes.Iir_Kind.Procedure_Body: if lastKind is nodes.Iir_Kind.Procedure_Declaration: pass else: position = Position.parse(item) raise DOMException( f"Found unexpected procedure body '{GetNameOfNode(item)}' in {entity} '{name}' at {position}." ) elif kind == nodes.Iir_Kind.Protected_Type_Body: yield ProtectedTypeBody.parse(item) elif kind == nodes.Iir_Kind.Object_Alias_Declaration: from pyGHDL.dom.Misc import Alias yield Alias.parse(item) elif kind == nodes.Iir_Kind.Configuration_Specification: from pyGHDL.dom.Configuration import ComponentConfiguration yield ComponentConfiguration.parse(item) elif kind == nodes.Iir_Kind.Component_Declaration: from pyGHDL.dom.DesignUnit import Component yield Component.parse(item) elif kind == nodes.Iir_Kind.Attribute_Declaration: from pyGHDL.dom.Attribute import Attribute yield Attribute.parse(item) elif kind == nodes.Iir_Kind.Attribute_Specification: from pyGHDL.dom.Attribute import AttributeSpecification yield AttributeSpecification.parse(item) elif kind == nodes.Iir_Kind.Use_Clause: from pyGHDL.dom.DesignUnit import UseClause yield UseClause.parse(item) elif kind == nodes.Iir_Kind.Package_Declaration: from pyGHDL.dom.DesignUnit import Package yield Package.parse(item, None) # TODO: Can it have a context? elif kind == nodes.Iir_Kind.Package_Instantiation_Declaration: from pyGHDL.dom.DesignUnit import PackageInstantiation yield PackageInstantiation.parse(item) elif kind == nodes.Iir_Kind.Psl_Default_Clock: yield DefaultClock.parse(item) elif kind == nodes.Iir_Kind.Group_Declaration: WarningCollector.Raise(NotImplementedError(f"Group declaration in {name}")) elif kind == nodes.Iir_Kind.Group_Template_Declaration: WarningCollector.Raise(NotImplementedError(f"Group template declaration in {name}")) elif kind == nodes.Iir_Kind.Disconnection_Specification: WarningCollector.Raise(NotImplementedError(f"Disconnect specification in {name}")) elif kind == nodes.Iir_Kind.Nature_Declaration: WarningCollector.Raise(NotImplementedError(f"Nature declaration in {name}")) elif kind == nodes.Iir_Kind.Free_Quantity_Declaration: WarningCollector.Raise(NotImplementedError(f"Free quantity declaration in {name}")) elif kind == nodes.Iir_Kind.Across_Quantity_Declaration: WarningCollector.Raise(NotImplementedError(f"Across quantity declaration in {name}")) elif kind == nodes.Iir_Kind.Through_Quantity_Declaration: WarningCollector.Raise(NotImplementedError(f"Through quantity declaration in {name}")) elif kind == nodes.Iir_Kind.Terminal_Declaration: WarningCollector.Raise(NotImplementedError(f"Terminal declaration in {name}")) else: position = Position.parse(item) raise DOMException(f"Unknown declared item kind '{kind.name}' in {entity} '{name}' at {position}.") lastKind = None item = nodes.Get_Chain(item) continue # Lookahead for objects with multiple identifiers at once if nodes.Get_Has_Identifier_List(item): nextNode = nodes.Get_Chain(item) for nextItem in utils.chain_iter(nextNode): # Consecutive identifiers are found, if the subtype indication is Null if nodes.Get_Subtype_Indication(nextItem) == nodes.Null_Iir: furtherIdentifiers.append(GetNameOfNode(nextItem)) else: item = nextItem break # The last consecutive identifiers has no Identifier_List flag if not nodes.Get_Has_Identifier_List(nextItem): item = nodes.Get_Chain(nextItem) break else: item = nodes.Null_Iir else: item = nodes.Get_Chain(item) yield objectParseMethod(objectItem, furtherIdentifiers) furtherIdentifiers.clear() def GetConcurrentStatementsFromChainedNodes( nodeChain: Iir, entity: str, name: str ) -> Generator[ConcurrentStatement, None, None]: """ Translates a chain of concurrent statements to the matching :mod:`pyGHDL.dom.Concurrent` objects. :param nodeChain: The IIR node starting the chain of concurrent statements. :param entity: The kind of statement region the chain belongs to. Used in exception messages. :param name: The name of that statement region. Used in exception messages. :returns: Generator yielding the translated statements, in source order. :raises DOMException: If a statement's kind is not handled. """ for statement in utils.chain_iter(nodeChain): label = GetLabelOfNode(statement) position = Position.parse(statement) kind = GetIirKindOfNode(statement) if kind == nodes.Iir_Kind.Sensitized_Process_Statement: yield ProcessStatement.parse(statement, label, True) elif kind == nodes.Iir_Kind.Process_Statement: yield ProcessStatement.parse(statement, label, False) elif kind == nodes.Iir_Kind.Concurrent_Simple_Signal_Assignment: yield ConcurrentSimpleSignalAssignment.parse(statement, label) elif kind == nodes.Iir_Kind.Concurrent_Conditional_Signal_Assignment: from pyGHDL.dom.Concurrent import ConcurrentConditionalSignalAssignment yield ConcurrentConditionalSignalAssignment.parse(statement, label) elif kind == nodes.Iir_Kind.Concurrent_Selected_Signal_Assignment: from pyGHDL.dom.Concurrent import ConcurrentSelectedSignalAssignment yield ConcurrentSelectedSignalAssignment.parse(statement, label) elif kind == nodes.Iir_Kind.Concurrent_Procedure_Call_Statement: yield ConcurrentProcedureCall.parse(statement, label) elif kind == nodes.Iir_Kind.Component_Instantiation_Statement: instantiatedUnit = nodes.Get_Instantiated_Unit(statement) instantiatedUnitKind = GetIirKindOfNode(instantiatedUnit) if instantiatedUnitKind == nodes.Iir_Kind.Entity_Aspect_Entity: yield EntityInstantiation.parse(statement, instantiatedUnit, label) elif instantiatedUnitKind == nodes.Iir_Kind.Entity_Aspect_Configuration: yield ConfigurationInstantiation.parse(statement, instantiatedUnit, label) elif ( instantiatedUnitKind == nodes.Iir_Kind.Simple_Name or instantiatedUnitKind == nodes.Iir_Kind.Selected_Name ): yield ComponentInstantiation.parse(statement, instantiatedUnit, label) else: raise DOMException( f"Unknown instantiation kind '{instantiatedUnitKind.name}' in instantiation of label {label} at {position}." ) elif kind == nodes.Iir_Kind.Block_Statement: yield ConcurrentBlockStatement.parse(statement, label) elif kind == nodes.Iir_Kind.If_Generate_Statement: yield IfGenerateStatement.parse(statement, label) elif kind == nodes.Iir_Kind.Case_Generate_Statement: yield CaseGenerateStatement.parse(statement, label) elif kind == nodes.Iir_Kind.For_Generate_Statement: yield ForGenerateStatement.parse(statement, label) elif kind == nodes.Iir_Kind.Psl_Assert_Directive: yield ConcurrentAssertStatement.parse(statement, label) elif kind == nodes.Iir_Kind.Simple_Simultaneous_Statement: WarningCollector.Raise( NotImplementedError(f"Simple simultaneous statement (label: '{label}') at line {position.Line}") ) else: raise DOMException( f"Unknown concurrent statement of kind '{kind.name}' in {entity} '{name}' at {position}." ) def GetSequentialStatementsFromChainedNodes( nodeChain: Iir, entity: str, name: str ) -> Generator[SequentialStatement, None, None]: """ Translates a chain of sequential statements to the matching :mod:`pyGHDL.dom.Sequential` objects. :param nodeChain: The IIR node starting the chain of sequential statements. :param entity: The kind of statement region the chain belongs to. Used in exception messages. :param name: The name of that statement region. Used in exception messages. :returns: Generator yielding the translated statements, in source order. :raises DOMException: If a statement's kind is not handled. """ for statement in utils.chain_iter(nodeChain): label = GetLabelOfNode(statement) position = Position.parse(statement) kind = GetIirKindOfNode(statement) if kind == nodes.Iir_Kind.If_Statement: yield IfStatement.parse(statement, label) elif kind == nodes.Iir_Kind.Case_Statement: yield CaseStatement.parse(statement, label) elif kind == nodes.Iir_Kind.For_Loop_Statement: yield ForLoopStatement.parse(statement, label) elif kind == nodes.Iir_Kind.While_Loop_Statement: yield WhileLoopStatement.parse(statement, label) elif kind == nodes.Iir_Kind.Simple_Signal_Assignment_Statement: yield SequentialSimpleSignalAssignment.parse(statement, label) elif kind == nodes.Iir_Kind.Variable_Assignment_Statement: from pyGHDL.dom.Sequential import SequentialVariableAssignment yield SequentialVariableAssignment.parse(statement, label) elif kind == nodes.Iir_Kind.Conditional_Variable_Assignment_Statement: from pyGHDL.dom.Sequential import SequentialConditionalVariableAssignment yield SequentialConditionalVariableAssignment.parse(statement, label) elif kind == nodes.Iir_Kind.Conditional_Signal_Assignment_Statement: from pyGHDL.dom.Sequential import SequentialConditionalSignalAssignment yield SequentialConditionalSignalAssignment.parse(statement, label) elif kind == nodes.Iir_Kind.Selected_Variable_Assignment_Statement: from pyGHDL.dom.Sequential import SequentialSelectedVariableAssignment yield SequentialSelectedVariableAssignment.parse(statement, label) elif kind == nodes.Iir_Kind.Selected_Waveform_Assignment_Statement: from pyGHDL.dom.Sequential import SequentialSelectedSignalAssignment yield SequentialSelectedSignalAssignment.parse(statement, label) elif kind == nodes.Iir_Kind.Signal_Force_Assignment_Statement: from pyGHDL.dom.Sequential import SignalForceAssignment yield SignalForceAssignment.parse(statement, label) elif kind == nodes.Iir_Kind.Signal_Release_Assignment_Statement: from pyGHDL.dom.Sequential import SignalReleaseAssignment yield SignalReleaseAssignment.parse(statement, label) elif kind == nodes.Iir_Kind.Wait_Statement: yield WaitStatement.parse(statement, label) elif kind == nodes.Iir_Kind.Procedure_Call_Statement: yield SequentialProcedureCall.parse(statement, label) elif kind == nodes.Iir_Kind.Report_Statement: yield SequentialReportStatement.parse(statement, label) elif kind == nodes.Iir_Kind.Assertion_Statement: yield SequentialAssertStatement.parse(statement, label) elif kind == nodes.Iir_Kind.Null_Statement: yield NullStatement(statement, label) elif kind == nodes.Iir_Kind.Next_Statement: yield NextStatement.parse(statement, label) elif kind == nodes.Iir_Kind.Exit_Statement: yield ExitStatement.parse(statement, label) elif kind == nodes.Iir_Kind.Return_Statement: yield ReturnStatement.parse(statement, label) else: raise DOMException( f"Unknown sequential statement of kind '{kind.name}' in {entity} '{name}' at {position}." )