# =============================================================================
# ____ _ _ ____ _ _
# _ __ _ _ / ___| | | | _ \| | __| | ___ _ __ ___
# | '_ \| | | | | _| |_| | | | | | / _` |/ _ \| '_ ` _ \
# | |_) | |_| | |_| | _ | |_| | |___ | (_| | (_) | | | | | |
# | .__/ \__, |\____|_| |_|____/|_____(_)__,_|\___/|_| |_| |_|
# |_| |___/
# =============================================================================
# Authors:
# Patrick Lehmann
#
# Package module: DOM: Sequential statements.
#
# 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
# ============================================================================
from typing import Iterable
from pyTooling.Decorators import export
from pyVHDLModel.Base import ExpressionUnion
from pyVHDLModel.Symbol import Symbol
from pyVHDLModel.Sequential import SequentialStatement, SequentialChoice, SequentialCase
from pyVHDLModel.Sequential import IfBranch as VHDLModel_IfBranch
from pyVHDLModel.Sequential import ElsifBranch as VHDLModel_ElsifBranch
from pyVHDLModel.Sequential import ElseBranch as VHDLModel_ElseBranch
from pyVHDLModel.Sequential import IndexedChoice as VHDLModel_IndexedChoice
from pyVHDLModel.Sequential import RangedChoice as VHDLModel_RangedChoice
from pyVHDLModel.Sequential import Case as VHDLModel_Case
from pyVHDLModel.Sequential import OthersCase as VHDLModel_OthersCase
from pyVHDLModel.Sequential import IfStatement as VHDLModel_IfStatement
from pyVHDLModel.Sequential import CaseStatement as VHDLModel_CaseStatement
from pyVHDLModel.Sequential import ForLoopStatement as VHDLModel_ForLoopStatement
from pyVHDLModel.Sequential import NullStatement as VHDLModel_NullStatement
from pyVHDLModel.Sequential import WaitStatement as VHDLModel_WaitStatement
from pyVHDLModel.Sequential import SequentialProcedureCall as VHDLModel_SequentialProcedureCall
from pyVHDLModel.Sequential import SequentialSimpleSignalAssignment as VHDLModel_SequentialSimpleSignalAssignment
from pyVHDLModel.Sequential import SequentialReportStatement as VHDLModel_SequentialReportStatement
from pyVHDLModel.Sequential import SequentialAssertStatement as VHDLModel_SequentialAssertStatement
from pyGHDL.libghdl import Iir, utils
from pyGHDL.libghdl.vhdl import nodes
from pyGHDL.dom import DOMMixin, Position, DOMException
from pyGHDL.dom._Utils import GetNameOfNode
from pyGHDL.dom.Range import Range
from pyGHDL.dom.Concurrent import WaveformElement, ParameterAssociationItem # TODO: move out from concurrent?
[docs]@export
class IfBranch(VHDLModel_IfBranch):
[docs] def __init__(
self,
branchNode: Iir,
condition: ExpressionUnion,
statements: Iterable[SequentialStatement] = None,
):
super().__init__(condition, statements)
DOMMixin.__init__(self, branchNode)
@classmethod
def parse(cls, branchNode: Iir, label: str) -> "IfBranch":
from pyGHDL.dom._Translate import (
GetSequentialStatementsFromChainedNodes,
GetExpressionFromNode,
)
condition = GetExpressionFromNode(nodes.Get_Condition(branchNode))
statementChain = nodes.Get_Sequential_Statement_Chain(branchNode)
statements = GetSequentialStatementsFromChainedNodes(statementChain, "if branch", label)
return cls(branchNode, condition, statements)
[docs]@export
class ElsifBranch(VHDLModel_ElsifBranch):
[docs] def __init__(
self,
branchNode: Iir,
condition: ExpressionUnion,
statements: Iterable[SequentialStatement] = None,
):
super().__init__(condition, statements)
DOMMixin.__init__(self, branchNode)
@classmethod
def parse(cls, branchNode: Iir, condition: Iir, label: str) -> "ElsifBranch":
from pyGHDL.dom._Translate import (
GetSequentialStatementsFromChainedNodes,
GetExpressionFromNode,
)
condition = GetExpressionFromNode(condition)
statementChain = nodes.Get_Sequential_Statement_Chain(branchNode)
statements = GetSequentialStatementsFromChainedNodes(statementChain, "elsif branch", label)
return cls(branchNode, condition, statements)
[docs]@export
class ElseBranch(VHDLModel_ElseBranch):
[docs] def __init__(
self,
branchNode: Iir,
statements: Iterable[SequentialStatement] = None,
):
super().__init__(statements)
DOMMixin.__init__(self, branchNode)
@classmethod
def parse(cls, branchNode: Iir, label: str) -> "ElseBranch":
from pyGHDL.dom._Translate import (
GetSequentialStatementsFromChainedNodes,
)
statementChain = nodes.Get_Sequential_Statement_Chain(branchNode)
statements = GetSequentialStatementsFromChainedNodes(statementChain, "else branch", label)
return cls(branchNode, statements)
[docs]@export
class IfStatement(VHDLModel_IfStatement, DOMMixin):
[docs] def __init__(
self,
ifNode: Iir,
ifBranch: IfBranch,
elsifBranches: Iterable[ElsifBranch] = None,
elseBranch: ElseBranch = None,
label: str = None,
):
super().__init__(ifBranch, elsifBranches, elseBranch, label)
DOMMixin.__init__(self, ifNode)
@classmethod
def parse(cls, ifNode: Iir, label: str) -> "IfStatement":
ifBranch = IfBranch.parse(ifNode, label)
elsifBranches = []
elseBranch = None
# WORKAROUND: Python 3.8 syntax
# elseClause = generateNode
# while (elseClause := nodes.Get_Generate_Else_Clause(elseClause)) != nodes.Null_Iir:
elseClause = nodes.Get_Else_Clause(ifNode)
while elseClause != nodes.Null_Iir:
condition = nodes.Get_Condition(elseClause)
if condition != nodes.Null_Iir:
elsifBranches.append(ElsifBranch.parse(elseClause, condition, label))
else:
elseBranch = ElseBranch.parse(elseClause, label)
break
elseClause = nodes.Get_Else_Clause(elseClause)
return cls(ifNode, ifBranch, elsifBranches, elseBranch, label)
[docs]@export
class IndexedChoice(VHDLModel_IndexedChoice, DOMMixin):
[docs] def __init__(self, node: Iir, expression: ExpressionUnion):
super().__init__(expression)
DOMMixin.__init__(self, node)
[docs]@export
class RangedChoice(VHDLModel_RangedChoice, DOMMixin):
[docs] def __init__(self, node: Iir, rng: Range):
super().__init__(rng)
DOMMixin.__init__(self, node)
[docs]@export
class Case(VHDLModel_Case, DOMMixin):
[docs] def __init__(
self,
node: Iir,
choices: Iterable[SequentialChoice],
statements: Iterable[SequentialStatement] = None,
):
super().__init__(choices, statements)
DOMMixin.__init__(self, node)
@classmethod
def parse(cls, caseNode: Iir, choices: Iterable[SequentialChoice], label: str) -> "Case":
from pyGHDL.dom._Translate import GetSequentialStatementsFromChainedNodes
statementChain = nodes.Get_Associated_Chain(caseNode)
statements = GetSequentialStatementsFromChainedNodes(statementChain, "case", label)
return cls(caseNode, choices, statements)
[docs]@export
class OthersCase(VHDLModel_OthersCase, DOMMixin):
[docs] def __init__(
self,
caseNode: Iir,
statements: Iterable[SequentialStatement] = None,
):
super().__init__(statements)
DOMMixin.__init__(self, caseNode)
@classmethod
def parse(cls, caseNode: Iir, label: str = None) -> "OthersCase":
from pyGHDL.dom._Translate import GetSequentialStatementsFromChainedNodes
body = nodes.Get_Associated_Block(caseNode)
if body is nodes.Null_Iir:
return cls(caseNode)
statementChain = nodes.Get_Concurrent_Statement_Chain(body)
statements = GetSequentialStatementsFromChainedNodes(statementChain, "case others", label)
return cls(caseNode, statements)
[docs]@export
class CaseStatement(VHDLModel_CaseStatement, DOMMixin):
[docs] def __init__(
self,
caseNode: Iir,
label: str,
expression: ExpressionUnion,
cases: Iterable[SequentialCase],
):
super().__init__(expression, cases, label)
DOMMixin.__init__(self, caseNode)
@classmethod
def parse(cls, caseNode: Iir, label: str) -> "CaseStatement":
from pyGHDL.dom._Utils import GetIirKindOfNode
from pyGHDL.dom._Translate import (
GetExpressionFromNode,
GetRangeFromNode,
GetNameFromNode,
)
expression = GetExpressionFromNode(nodes.Get_Expression(caseNode))
cases = []
choices = None
alternative = nodes.Get_Case_Statement_Alternative_Chain(caseNode)
cNode = alternative
while alternative != nodes.Null_Iir:
choiceKind = GetIirKindOfNode(alternative)
sameAlternative = nodes.Get_Same_Alternative_Flag(alternative)
if choiceKind in (
nodes.Iir_Kind.Choice_By_Name,
nodes.Iir_Kind.Choice_By_Expression,
):
choiceExpression = GetExpressionFromNode(nodes.Get_Choice_Expression(alternative))
choice = IndexedChoice(alternative, choiceExpression)
if sameAlternative:
choices.append(choice)
alternative = nodes.Get_Chain(alternative)
continue
elif choiceKind is nodes.Iir_Kind.Choice_By_Range:
choiceRange = nodes.Get_Choice_Range(alternative)
choiceRangeKind = GetIirKindOfNode(choiceRange)
if choiceRangeKind == nodes.Iir_Kind.Range_Expression:
rng = GetRangeFromNode(choiceRange)
elif choiceRangeKind in (
nodes.Iir_Kind.Attribute_Name,
nodes.Iir_Kind.Parenthesis_Name,
):
rng = GetNameFromNode(choiceRange)
else:
pos = Position.parse(alternative)
raise DOMException(
f"Unknown choice range kind '{choiceRangeKind.name}' in case statement at line {pos.Line}."
)
choice = RangedChoice(alternative, rng)
if sameAlternative:
choices.append(choice)
alternative = nodes.Get_Chain(alternative)
continue
elif choiceKind is nodes.Iir_Kind.Choice_By_Others:
if choices is not None:
cases.append(Case.parse(alternative, choices, label))
choices = None
cases.append(OthersCase.parse(alternative, label))
alternative = nodes.Get_Chain(alternative)
cNode = alternative
continue
else:
pos = Position.parse(alternative)
raise DOMException(f"Unknown choice kind '{choiceKind.name}' in case statement at line {pos.Line}.")
if choices is not None:
cases.append(Case.parse(cNode, choices, label))
cNode = alternative
choices = [
choice,
]
alternative = nodes.Get_Chain(alternative)
if choices is not None:
cases.append(Case.parse(cNode, choices, label))
return cls(caseNode, label, expression, cases)
[docs]@export
class ForLoopStatement(VHDLModel_ForLoopStatement, DOMMixin):
[docs] def __init__(
self,
loopNode: Iir,
loopIndex: str,
rng: Range,
statements: Iterable[SequentialStatement] = None,
label: str = None,
):
super().__init__(loopIndex, rng, statements, label)
DOMMixin.__init__(self, loopNode)
@classmethod
def parse(cls, loopNode: Iir, label: str) -> "ForLoopStatement":
from pyGHDL.dom._Utils import GetIirKindOfNode
from pyGHDL.dom._Translate import (
GetSequentialStatementsFromChainedNodes,
GetRangeFromNode,
GetNameFromNode,
)
spec = nodes.Get_Parameter_Specification(loopNode)
loopIndex = GetNameOfNode(spec)
discreteRange = nodes.Get_Discrete_Range(spec)
rangeKind = GetIirKindOfNode(discreteRange)
if rangeKind == nodes.Iir_Kind.Range_Expression:
rng = GetRangeFromNode(discreteRange)
elif rangeKind in (
nodes.Iir_Kind.Attribute_Name,
nodes.Iir_Kind.Parenthesis_Name,
):
rng = GetNameFromNode(discreteRange)
else:
pos = Position.parse(loopNode)
raise DOMException(
f"Unknown discrete range kind '{rangeKind.name}' in for...loop statement at line {pos.Line}."
)
statementChain = nodes.Get_Sequential_Statement_Chain(loopNode)
statements = GetSequentialStatementsFromChainedNodes(statementChain, "for", label)
return cls(loopNode, loopIndex, rng, statements, label)
[docs]@export
class SequentialSimpleSignalAssignment(VHDLModel_SequentialSimpleSignalAssignment, DOMMixin):
[docs] def __init__(
self,
assignmentNode: Iir,
target: Symbol,
waveform: Iterable[WaveformElement],
label: str = None,
):
super().__init__(target, waveform, label)
DOMMixin.__init__(self, assignmentNode)
@classmethod
def parse(cls, assignmentNode: Iir, label: str = None) -> "SequentialSimpleSignalAssignment":
from pyGHDL.dom._Translate import GetNameFromNode
target = nodes.Get_Target(assignmentNode)
targetName = GetNameFromNode(target)
waveform = []
for wave in utils.chain_iter(nodes.Get_Waveform_Chain(assignmentNode)):
waveform.append(WaveformElement.parse(wave))
return cls(assignmentNode, targetName, waveform, label)
[docs]@export
class SequentialProcedureCall(VHDLModel_SequentialProcedureCall, DOMMixin):
[docs] def __init__(
self,
callNode: Iir,
procedureName: Symbol,
parameterMappings: Iterable[ParameterAssociationItem],
label: str = None,
):
super().__init__(procedureName, parameterMappings, label)
DOMMixin.__init__(self, callNode)
@classmethod
def parse(cls, callNode: Iir, label: str) -> "SequentialProcedureCall":
from pyGHDL.dom._Translate import GetNameFromNode, GetParameterMapAspect
cNode = nodes.Get_Procedure_Call(callNode)
prefix = nodes.Get_Prefix(cNode)
procedureName = GetNameFromNode(prefix)
parameterAssociations = GetParameterMapAspect(nodes.Get_Parameter_Association_Chain(cNode))
return cls(callNode, procedureName, parameterAssociations, label)
[docs]@export
class SequentialAssertStatement(VHDLModel_SequentialAssertStatement, DOMMixin):
[docs] def __init__(
self,
assertNode: Iir,
condition: ExpressionUnion,
message: ExpressionUnion = None,
severity: ExpressionUnion = None,
label: str = None,
):
super().__init__(condition, message, severity, label)
DOMMixin.__init__(self, assertNode)
@classmethod
def parse(cls, assertNode: Iir, label: str) -> "SequentialAssertStatement":
from pyGHDL.dom._Translate import GetExpressionFromNode
condition = GetExpressionFromNode(nodes.Get_Assertion_Condition(assertNode))
messageNode = nodes.Get_Report_Expression(assertNode)
message = None if messageNode is nodes.Null_Iir else GetExpressionFromNode(messageNode)
severityNode = nodes.Get_Severity_Expression(assertNode)
severity = None if severityNode is nodes.Null_Iir else GetExpressionFromNode(severityNode)
return cls(assertNode, condition, message, severity, label)
[docs]@export
class SequentialReportStatement(VHDLModel_SequentialReportStatement, DOMMixin):
[docs] def __init__(
self,
reportNode: Iir,
message: ExpressionUnion,
severity: ExpressionUnion = None,
label: str = None,
):
super().__init__(message, severity, label)
DOMMixin.__init__(self, reportNode)
@classmethod
def parse(cls, reportNode: Iir, label: str) -> "SequentialReportStatement":
from pyGHDL.dom._Translate import GetExpressionFromNode
message = GetExpressionFromNode(nodes.Get_Report_Expression(reportNode))
severityNode = nodes.Get_Severity_Expression(reportNode)
severity = None if severityNode is nodes.Null_Iir else GetExpressionFromNode(severityNode)
return cls(reportNode, message, severity, label)
[docs]@export
class NullStatement(VHDLModel_NullStatement, DOMMixin):
[docs] def __init__(
self,
waitNode: Iir,
label: str = None,
):
super().__init__(label)
DOMMixin.__init__(self, waitNode)
[docs]@export
class WaitStatement(VHDLModel_WaitStatement, DOMMixin):
[docs] def __init__(
self,
waitNode: Iir,
sensitivityList: Iterable[Symbol] = None,
condition: ExpressionUnion = None,
timeout: ExpressionUnion = None,
label: str = None,
):
super().__init__(sensitivityList, condition, timeout, label)
DOMMixin.__init__(self, waitNode)
@classmethod
def parse(cls, waitNode: Iir, label: str) -> "WaitStatement":
from pyGHDL.dom._Utils import GetIirKindOfNode
from pyGHDL.dom._Translate import GetExpressionFromNode
sensitivityList = None
sensitivityListNode = nodes.Get_Sensitivity_List(waitNode)
if sensitivityListNode is not nodes.Null_Iir:
print(GetIirKindOfNode(sensitivityListNode))
conditionNode = nodes.Get_Condition_Clause(waitNode)
condition = None if conditionNode is nodes.Null_Iir else GetExpressionFromNode(conditionNode)
timeoutNode = nodes.Get_Timeout_Clause(waitNode)
timeout = None if timeoutNode is nodes.Null_Iir else GetExpressionFromNode(timeoutNode)
return cls(waitNode, sensitivityList, condition, timeout, label)