# =============================================================================
# ____ _ _ ____ _ _
# _ __ _ _ / ___| | | | _ \| | __| | ___ _ __ ___
# | '_ \| | | | | _| |_| | | | | | / _` |/ _ \| '_ ` _ \
# | |_) | |_| | |_| | _ | |_| | |___ | (_| | (_) | | | | | |
# | .__/ \__, |\____|_| |_|____/|_____(_)__,_|\___/|_| |_| |_|
# |_| |___/
# =============================================================================
# Authors:
# Patrick Lehmann
#
# Package module: A pretty printer to format the DOM as a tree in text form.
#
# 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 List, Union
from pyTooling.Decorators import export
from pyGHDL.dom.Concurrent import (
ConcurrentBlockStatement,
ProcessStatement,
IfGenerateStatement,
CaseGenerateStatement,
ForGenerateStatement,
ComponentInstantiation,
ConfigurationInstantiation,
EntityInstantiation,
ConcurrentProcedureCall,
)
from pyVHDLModel.SyntaxModel import (
GenericInterfaceItem,
NamedEntityMixin,
PortInterfaceItem,
WithDefaultExpressionMixin,
Function,
BaseType,
FullType,
BaseConstant,
ConcurrentStatement,
)
from pyGHDL import GHDLBaseException
from pyGHDL.dom.NonStandard import Document, Design, Library
from pyGHDL.dom.DesignUnit import (
Entity,
Architecture,
Package,
PackageBody,
Configuration,
Context,
Component,
UseClause,
PackageInstantiation,
)
from pyGHDL.dom.Symbol import (
SimpleSubtypeSymbol,
ConstrainedCompositeSubtypeSymbol,
)
from pyGHDL.dom.Type import (
IntegerType,
Subtype,
ArrayType,
RecordType,
AccessType,
EnumeratedType,
FileType,
ProtectedType,
ProtectedTypeBody,
PhysicalType,
IncompleteType,
)
from pyGHDL.dom.InterfaceItem import (
GenericConstantInterfaceItem,
PortSignalInterfaceItem,
GenericTypeInterfaceItem,
)
from pyGHDL.dom.Object import Constant, Signal, SharedVariable, File
from pyGHDL.dom.Attribute import Attribute, AttributeSpecification
from pyGHDL.dom.Subprogram import Procedure
from pyGHDL.dom.Misc import Alias
from pyGHDL.dom.PSL import DefaultClock
StringBuffer = List[str]
[docs]@export
class PrettyPrintException(GHDLBaseException):
pass
[docs]@export
class PrettyPrint:
# _buffer: StringBuffer
#
# def __init__(self):
# self._buffer = []
def formatDesign(self, design: Design, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
buffer.append(f"{prefix}Libraries:")
for library in design.Libraries.values():
buffer.append(f"{prefix} - Name: {library.Identifier}")
for line in self.formatLibrary(library, level + 2):
buffer.append(line)
buffer.append(f"{prefix}Documents:")
for document in design.Documents:
buffer.append(f"{prefix} - Path: '{document.Path}':")
for line in self.formatDocument(document, level + 2):
buffer.append(line)
return buffer
def formatLibrary(self, library: Library, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
buffer.append(f"{prefix}Entities:")
for entity in library.Entities:
buffer.append(f"{prefix} - {entity.Identifier}({', '.join([a.Identifier for a in entity.Architectures])})")
buffer.append(f"{prefix}Packages:")
for package in library.Packages:
if isinstance(package, Package):
buffer.append(f"{prefix} - {package.Identifier}")
elif isinstance(package, PackageInstantiation):
buffer.append(f"{prefix} - {package.Identifier} instantiate from {package.PackageReference}")
buffer.append(f"{prefix}Configurations:")
for configuration in library.Configurations:
buffer.append(f"{prefix} - {configuration.Identifier}")
buffer.append(f"{prefix}Contexts:")
for context in library.Contexts:
buffer.append(f"{prefix} - {context.Identifier}")
return buffer
def formatDocument(self, document: Document, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
buffer.append(f"{prefix}Entities:")
for entity in document.Entities:
for line in self.formatEntity(entity, level + 1):
buffer.append(line)
buffer.append(f"{prefix}Architectures:")
for architecture in document.Architectures:
for line in self.formatArchitecture(architecture, level + 1):
buffer.append(line)
buffer.append(f"{prefix}Packages:")
for package in document.Packages:
if isinstance(package, Package):
gen = self.formatPackage
else:
gen = self.formatPackageInstance
for line in gen(package, level + 1):
buffer.append(line)
buffer.append(f"{prefix}PackageBodies:")
for packageBodies in document.PackageBodies:
for line in self.formatPackageBody(packageBodies, level + 1):
buffer.append(line)
buffer.append(f"{prefix}Configurations:")
for configuration in document.Configurations:
for line in self.formatConfiguration(configuration, level + 1):
buffer.append(line)
buffer.append(f"{prefix}Contexts:")
for context in document.Contexts:
for line in self.formatContext(context, level + 1):
buffer.append(line)
return buffer
def formatEntity(self, entity: Entity, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
buffer.append(
f"{prefix}- Name: {entity.Identifier}\n"
f"{prefix} File: {entity.Position.Filename.name}\n"
f"{prefix} Position: {entity.Position.Line}:{entity.Position.Column}"
)
buffer.append(f"{prefix} Generics:")
for generic in entity.GenericItems:
for line in self.formatGeneric(generic, level + 1):
buffer.append(line)
buffer.append(f"{prefix} Ports:")
for port in entity.PortItems:
for line in self.formatPort(port, level + 1):
buffer.append(line)
buffer.append(f"{prefix} Declared:")
for item in entity.DeclaredItems:
for line in self.formatDeclaredItems(item, level + 1):
buffer.append(line)
buffer.append(f"{prefix} Statements:")
for item in entity.Statements:
buffer.append(f"{prefix} ...")
buffer.append(f"{prefix} Architectures:")
for item in entity.Architectures:
buffer.append(f"{prefix} - {item.Identifier}")
return buffer
def formatArchitecture(self, architecture: Architecture, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
buffer.append(
f"{prefix}- Name: {architecture.Identifier}\n"
f"{prefix} File: {architecture.Position.Filename.name}\n"
f"{prefix} Position: {architecture.Position.Line}:{architecture.Position.Column}"
)
buffer.append(f"{prefix} Entity: {architecture.Entity.SymbolName}")
buffer.append(f"{prefix} Declared:")
for item in architecture.DeclaredItems:
for line in self.formatDeclaredItems(item, level + 2):
buffer.append(line)
buffer.append(f"{prefix} Hierarchy:")
for item in architecture.Statements:
for line in self.formatHierarchy(item, level + 2):
buffer.append(line)
buffer.append(f"{prefix} Statements:")
for item in architecture.Statements:
buffer.append(f"{prefix} ...")
# for line in self.formatStatements(item, level + 2):
# buffer.append(line)
return buffer
def formatComponent(self, component: Component, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
buffer.append(f"{prefix}- Component: {component.Identifier}")
buffer.append(f"{prefix} Generics:")
for generic in component.GenericItems:
for line in self.formatGeneric(generic, level + 1):
buffer.append(line)
buffer.append(f"{prefix} Ports:")
for port in component.PortItems:
for line in self.formatPort(port, level + 1):
buffer.append(line)
return buffer
def formatPackage(self, package: Package, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
buffer.append(
f"{prefix}- Name: {package.Identifier}\n"
f"{prefix} File: {package.Position.Filename.name}\n"
f"{prefix} Position: {package.Position.Line}:{package.Position.Column}"
)
buffer.append(f"{prefix} Declared:")
for item in package.DeclaredItems:
for line in self.formatDeclaredItems(item, level + 1):
buffer.append(line)
return buffer
def formatPackageInstance(self, package: PackageInstantiation, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
buffer.append(f"{prefix}- Name: {package.Identifier}")
buffer.append(f"{prefix} Package: {package.PackageReference!s}")
buffer.append(f"{prefix} Generic Map: ...")
# for item in package.GenericItems:
# for line in self.formatGeneric(item, level + 1):
# buffer.append(line)
return buffer
def formatPackageBody(self, packageBody: PackageBody, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
buffer.append(f"{prefix}- Name: {packageBody.Identifier}")
buffer.append(f"{prefix} Declared:")
for item in packageBody.DeclaredItems:
for line in self.formatDeclaredItems(item, level + 1):
buffer.append(line)
return buffer
def formatConfiguration(self, configuration: Configuration, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
buffer.append(f"{prefix}- Name: {configuration.Identifier}")
return buffer
def formatContext(self, context: Context, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
buffer.append(f"{prefix}- Name: {context.Identifier}")
return buffer
def formatGeneric(self, generic: Union[NamedEntityMixin, GenericInterfaceItem], level: int = 0) -> StringBuffer:
if isinstance(generic, GenericConstantInterfaceItem):
return self.formatGenericConstant(generic, level)
elif isinstance(generic, GenericTypeInterfaceItem):
return self.formatGenericType(generic, level)
else:
raise PrettyPrintException(
f"Unhandled generic kind '{generic.__class__.__name__}' for generic '{generic.Identifiers[0]}'."
)
def formatPort(self, port: Union[NamedEntityMixin, PortInterfaceItem], level: int = 0) -> StringBuffer:
if isinstance(port, PortSignalInterfaceItem):
return self.formatPortSignal(port, level)
else:
raise PrettyPrintException(
f"Unhandled port kind '{port.__class__.__name__}' for port '{port.Identifiers[0]}'."
)
def formatGenericConstant(self, generic: GenericConstantInterfaceItem, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
subTypeIndication = self.formatSubtypeIndication(generic.Subtype, "generic", generic.Identifiers[0])
buffer.append(
f"{prefix} - {', '.join(generic.Identifiers)} : {generic.Mode!s} {subTypeIndication}{self.formatInitialValue(generic)}"
)
return buffer
def formatGenericType(self, generic: GenericConstantInterfaceItem, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
buffer.append(f"{prefix} - type {generic.Identifier}")
return buffer
def formatPortSignal(self, port: PortSignalInterfaceItem, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
subTypeIndication = self.formatSubtypeIndication(port.Subtype, "port", port.Identifiers[0])
buffer.append(
f"{prefix} - {', '.join(port.Identifiers)} : {port.Mode} {subTypeIndication}{self.formatInitialValue(port)}"
)
return buffer
def formatDeclaredItems(self, item, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
if isinstance(item, BaseConstant):
subTypeIndication = self.formatSubtypeIndication(item.Subtype, "constant", item.Identifiers[0])
initValue = f" := {item.DefaultExpression}" if isinstance(item, Constant) else ""
buffer.append(f"{prefix}- constant {', '.join(item.Identifiers)} : {subTypeIndication}{initValue}")
elif isinstance(item, SharedVariable):
subTypeIndication = self.formatSubtypeIndication(item.Subtype, "shared variable", item.Identifiers[0])
buffer.append(f"{prefix}- shared variable {', '.join(item.Identifiers)} : {subTypeIndication}")
elif isinstance(item, Signal):
subTypeIndication = self.formatSubtypeIndication(item.Subtype, "signal", item.Identifiers[0])
initValue = f" := {item.DefaultExpression}" if item.DefaultExpression is not None else ""
buffer.append(f"{prefix}- signal {', '.join(item.Identifiers)} : {subTypeIndication}{initValue}")
elif isinstance(item, File):
subTypeIndication = self.formatSubtypeIndication(item.Subtype, "file", item.Identifiers[0])
buffer.append(f"{prefix}- File {', '.join(item.Identifiers)} : {subTypeIndication}")
elif isinstance(item, (FullType, IncompleteType)):
buffer.append(f"{prefix}- {self.formatType(item)}")
elif isinstance(item, Subtype):
buffer.append(f"{prefix}- subtype {item.Identifier} is ?????")
elif isinstance(item, Alias):
buffer.append(f"{prefix}- alias {item.Identifier} is ?????")
elif isinstance(item, Function):
buffer.append(f"{prefix}- function {item.Identifier} return {item.ReturnType}")
elif isinstance(item, Procedure):
buffer.append(f"{prefix}- procedure {item.Identifier}")
elif isinstance(item, Component):
for line in self.formatComponent(item, level):
buffer.append(line)
elif isinstance(item, Attribute):
buffer.append(f"{prefix}- attribute {item.Identifier} : {item.Subtype}")
elif isinstance(item, AttributeSpecification):
buffer.append(f"{prefix}- attribute {item.Attribute} of {'????'} : {'????'} is {'????'}")
elif isinstance(item, UseClause):
buffer.append(f"{prefix}- use {', '.join([str(n) for n in item.Names])}")
elif isinstance(item, Package):
buffer.append(f"{prefix}- package {item.Identifier} is ..... end package")
elif isinstance(item, PackageInstantiation):
buffer.append(f"{prefix}- package {item.Identifier} is new {item.PackageReference} generic map (.....)")
elif isinstance(item, DefaultClock):
buffer.append(f"{prefix}- default {item.Identifier} is {'...'}")
else:
raise PrettyPrintException(f"Unhandled declared item kind '{item.__class__.__name__}'.")
return buffer
def formatType(self, item: BaseType) -> str:
result = f"type {item.Identifier} is "
if isinstance(item, IncompleteType):
result += ""
elif isinstance(item, IntegerType):
result += f"range {item.Range!s}"
elif isinstance(item, EnumeratedType):
result += "(........)"
elif isinstance(item, PhysicalType):
result += " is range ....... units ..... end units"
elif isinstance(item, ArrayType):
result += "array(........) of ....."
elif isinstance(item, RecordType):
result += "record ..... end record"
elif isinstance(item, AccessType):
result += "access ....."
elif isinstance(item, FileType):
result += "file ....."
elif isinstance(item, ProtectedType):
result += "protected ..... end protected"
elif isinstance(item, ProtectedTypeBody):
result += "protected body ..... end protected body"
else:
raise PrettyPrintException(f"Unknown type '{item.__class__.__name__}'")
return result
def formatSubtypeIndication(self, subtypeIndication, entity: str, name: str) -> str:
if isinstance(subtypeIndication, SimpleSubtypeSymbol):
return f"{subtypeIndication.SymbolName}"
elif isinstance(subtypeIndication, ConstrainedCompositeSubtypeSymbol):
constraints = []
for constraint in subtypeIndication.Constraints:
constraints.append(str(constraint))
return f"{subtypeIndication.SymbolName}({', '.join(constraints)})"
else:
raise PrettyPrintException(
f"Unhandled subtype kind '{subtypeIndication.__class__.__name__}' for {entity} '{name}'."
)
def formatInitialValue(self, item: WithDefaultExpressionMixin) -> str:
return f" := {item.DefaultExpression}" if item.DefaultExpression is not None else ""
def formatHierarchy(self, statement: ConcurrentStatement, level: int = 0) -> StringBuffer:
buffer = []
prefix = " " * level
if isinstance(statement, ProcessStatement):
buffer.append(f"{prefix}- {statement.Label}: process(...)")
elif isinstance(statement, EntityInstantiation):
buffer.append(f"{prefix}- {statement.Label}: entity {statement.Entity}")
elif isinstance(statement, ComponentInstantiation):
buffer.append(f"{prefix}- {statement.Label}: component {statement.Component}")
elif isinstance(statement, ConfigurationInstantiation):
buffer.append(f"{prefix}- {statement.Label}: configuration {statement.Configuration}")
elif isinstance(statement, ConcurrentBlockStatement):
buffer.append(f"{prefix}- {statement.Label}: block")
for stmt in statement.Statements:
for line in self.formatHierarchy(stmt, level + 2):
buffer.append(line)
elif isinstance(statement, IfGenerateStatement):
buffer.append(f"{prefix}- {statement.Label}: if {statement.IfBranch.Condition} generate")
for stmt in statement.IfBranch.Statements:
for line in self.formatHierarchy(stmt, level + 2):
buffer.append(line)
for elsifBranch in statement.ElsifBranches:
buffer.append(f"{prefix} {statement.Label}: elsif {elsifBranch.Condition} generate")
for stmt in elsifBranch.Statements:
for line in self.formatHierarchy(stmt, level + 2):
buffer.append(line)
if statement.ElseBranch is not None:
buffer.append(f"{prefix} {statement.Label}: else generate")
for stmt in statement.ElseBranch.Statements:
for line in self.formatHierarchy(stmt, level + 2):
buffer.append(line)
elif isinstance(statement, CaseGenerateStatement):
buffer.append(f"{prefix}- {statement.Label}: case {statement.SelectExpression} generate")
for case in statement.Cases:
buffer.append(f"{prefix} {case!s}")
for stmt in case.Statements:
for line in self.formatHierarchy(stmt, level + 2):
buffer.append(line)
elif isinstance(statement, ForGenerateStatement):
buffer.append(f"{prefix}- {statement.Label}: for {statement.LoopIndex} in {statement.Range} generate")
for stmt in statement.Statements:
for line in self.formatHierarchy(stmt, level + 2):
buffer.append(line)
elif isinstance(statement, ConcurrentProcedureCall):
buffer.append(f"{prefix}- {statement.Label}: {statement.Procedure!s}(...)")
return buffer