From aeeeddac22ba89891ca4214ddb5cbe42bfd4664c Mon Sep 17 00:00:00 2001 From: Alex Mykyta Date: Thu, 26 Dec 2024 20:13:28 -0800 Subject: [PATCH] Significant cleanup of type hinting. #242 --- pyproject.toml | 1 + src/systemrdl/ast/cast.py | 6 +- src/systemrdl/ast/conditional.py | 6 +- src/systemrdl/ast/literals.py | 2 +- src/systemrdl/ast/references.py | 15 +- src/systemrdl/ast/relational.py | 2 +- src/systemrdl/ast/sequence.py | 9 +- src/systemrdl/compiler.py | 24 +++- src/systemrdl/component.py | 99 ++++++++----- src/systemrdl/core/BaseVisitor.py | 8 +- src/systemrdl/core/ComponentVisitor.py | 60 +++++--- src/systemrdl/core/EnumVisitor.py | 16 +-- src/systemrdl/core/ExprVisitor.py | 2 +- src/systemrdl/core/UDPVisitor.py | 10 +- src/systemrdl/core/elaborate.py | 55 +++---- src/systemrdl/core/namespace.py | 21 ++- src/systemrdl/core/parameter.py | 3 +- src/systemrdl/core/rdlformatcode.py | 12 +- src/systemrdl/core/validate.py | 9 +- src/systemrdl/core/value_normalization.py | 8 +- src/systemrdl/importer.py | 2 +- src/systemrdl/messages.py | 16 ++- src/systemrdl/node.py | 134 +++++++++++++----- src/systemrdl/preprocessor/__init__.py | 8 +- .../preprocessor/perl_preprocessor.py | 6 +- src/systemrdl/preprocessor/segment_map.py | 2 +- .../preprocessor/verilog_preprocessor.py | 18 ++- src/systemrdl/properties/bases.py | 14 +- src/systemrdl/properties/builtin.py | 2 +- src/systemrdl/properties/prop_refs.py | 2 +- src/systemrdl/properties/rulebook.py | 11 +- src/systemrdl/properties/user_defined.py | 2 +- src/systemrdl/rdltypes/__init__.py | 12 +- src/systemrdl/rdltypes/array.py | 9 +- src/systemrdl/rdltypes/references.py | 19 ++- src/systemrdl/rdltypes/user_enum.py | 17 ++- src/systemrdl/rdltypes/user_struct.py | 28 ++-- src/systemrdl/source_ref.py | 25 ++-- src/systemrdl/udp.py | 16 +-- test/mypy.ini | 16 +-- test/requirements.txt | 2 + 41 files changed, 445 insertions(+), 284 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8ae7807..e7cb86a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,6 +10,7 @@ dependencies = [ "antlr4-python3-runtime >= 4.11, < 4.14", "colorama", "markdown", + "typing_extensions", ] authors = [ {name="Alex Mykyta"}, diff --git a/src/systemrdl/ast/cast.py b/src/systemrdl/ast/cast.py index 135d2b0..1a3693c 100644 --- a/src/systemrdl/ast/cast.py +++ b/src/systemrdl/ast/cast.py @@ -9,7 +9,7 @@ if TYPE_CHECKING: from ..compiler import RDLEnvironment from ..source_ref import SourceRefBase - from rdltypes.typing import PreElabRDLType + from ..rdltypes.typing import PreElabRDLType OptionalSourceRef = Optional[SourceRefBase] @@ -22,6 +22,7 @@ class WidthCast(ASTNode): def __init__(self, env: 'RDLEnvironment', src_ref: 'OptionalSourceRef', v: ASTNode, w_expr: Optional[ASTNode]=None, w_int: int=64): super().__init__(env, src_ref) + self.w_expr: Optional[ASTNode] if w_expr is not None: self.v = v self.w_expr = w_expr @@ -33,6 +34,7 @@ def __init__(self, env: 'RDLEnvironment', src_ref: 'OptionalSourceRef', v: ASTNo def predict_type(self) -> Type[int]: if self.cast_width is None: + assert self.w_expr is not None # mutually exclusive if not is_castable(self.w_expr.predict_type(), int): self.msg.fatal( "Width operand of cast expression is not a compatible numeric type", @@ -48,6 +50,7 @@ def predict_type(self) -> Type[int]: def get_min_eval_width(self) -> int: if self.cast_width is None: + assert self.w_expr is not None # mutually exclusive self.cast_width = int(self.w_expr.get_value()) return self.cast_width @@ -55,6 +58,7 @@ def get_min_eval_width(self) -> int: def get_value(self, eval_width: Optional[int]=None) -> int: # Truncate to cast width instead of eval width if self.cast_width is None: + assert self.w_expr is not None # mutually exclusive self.cast_width = int(self.w_expr.get_value()) if self.cast_width == 0: self.msg.fatal( diff --git a/src/systemrdl/ast/conditional.py b/src/systemrdl/ast/conditional.py index aab4cad..c9852d8 100644 --- a/src/systemrdl/ast/conditional.py +++ b/src/systemrdl/ast/conditional.py @@ -7,7 +7,7 @@ if TYPE_CHECKING: from ..compiler import RDLEnvironment from ..source_ref import SourceRefBase - from rdltypes.typing import PreElabRDLType + from ..rdltypes.typing import PreElabRDLType OptionalSourceRef = Optional[SourceRefBase] @@ -21,7 +21,7 @@ def __init__(self, env: 'RDLEnvironment', src_ref: 'OptionalSourceRef', i: ASTNo self.i = i self.j = j self.k = k - self.is_numeric = None # type: bool + self.is_numeric: bool = False def predict_type(self) -> 'PreElabRDLType': t_i = self.i.predict_type() @@ -35,7 +35,7 @@ def predict_type(self) -> 'PreElabRDLType': t_j = self.j.predict_type() t_k = self.k.predict_type() - typ = None # type: Any + typ: Any = None if is_castable(t_j, int) and is_castable(t_k, int): self.is_numeric = True typ = int diff --git a/src/systemrdl/ast/literals.py b/src/systemrdl/ast/literals.py index f1fc66a..405e438 100644 --- a/src/systemrdl/ast/literals.py +++ b/src/systemrdl/ast/literals.py @@ -10,7 +10,7 @@ if TYPE_CHECKING: from ..compiler import RDLEnvironment from ..source_ref import SourceRefBase - from rdltypes.typing import PreElabRDLType, RDLValue + from ..rdltypes.typing import PreElabRDLType, RDLValue OptionalSourceRef = Optional[SourceRefBase] diff --git a/src/systemrdl/ast/references.py b/src/systemrdl/ast/references.py index 3f78e0f..b237d3c 100644 --- a/src/systemrdl/ast/references.py +++ b/src/systemrdl/ast/references.py @@ -11,7 +11,7 @@ from ..compiler import RDLEnvironment from ..core.parameter import Parameter from ..source_ref import SourceRefBase - from rdltypes.typing import PreElabRDLType, RDLValue + from ..rdltypes.typing import PreElabRDLType OptionalSourceRef = Optional[SourceRefBase] @@ -59,7 +59,12 @@ def predict_type(self) -> 'PreElabRDLType': "Cannot index non-array type", self.array.src_ref ) - assert isinstance(array_type, rdltypes.ArrayedType) + if array_type.element_type is None: + # Array type is not known, therefore it must be an emptyy array. + self.msg.fatal( + "Array is empty. Cannot index", + self.array.src_ref + ) return array_type.element_type @@ -162,7 +167,8 @@ def predict_type(self) -> Type[comp.Component]: referenced. Also do some checks on the array indexes """ - current_comp = self.ref_root + current_comp: Optional[comp.Component] = self.ref_root + assert current_comp is not None for name, array_suffixes, name_src_ref in self.ref_elements: # find instance @@ -179,8 +185,7 @@ def predict_type(self) -> Type[comp.Component]: array_suffix.predict_type() # Check array suffixes - if (isinstance(current_comp, comp.AddressableComponent)) and current_comp.is_array: - assert isinstance(current_comp.array_dimensions, list) + if (isinstance(current_comp, comp.AddressableComponent)) and current_comp.array_dimensions: # is an array if len(array_suffixes) != len(current_comp.array_dimensions): self.msg.fatal( diff --git a/src/systemrdl/ast/relational.py b/src/systemrdl/ast/relational.py index f99d74b..5823f37 100644 --- a/src/systemrdl/ast/relational.py +++ b/src/systemrdl/ast/relational.py @@ -21,7 +21,7 @@ def __init__(self, env: 'RDLEnvironment', src_ref: 'OptionalSourceRef', l: ASTNo super().__init__(env, src_ref) self.l = l self.r = r - self.is_numeric = None # type: bool + self.is_numeric: bool = False def predict_type(self) -> Type[bool]: l_type = self.l.predict_type() diff --git a/src/systemrdl/ast/sequence.py b/src/systemrdl/ast/sequence.py index 34667e6..9e0cb38 100644 --- a/src/systemrdl/ast/sequence.py +++ b/src/systemrdl/ast/sequence.py @@ -13,7 +13,7 @@ class Concatenate(ASTNode): def __init__(self, env: 'RDLEnvironment', src_ref: 'OptionalSourceRef', elements: List[ASTNode]): super().__init__(env, src_ref) self.elements = elements - self.type = None # type: Union[Type[int], Type[str]] + self.type: Union[Type[int], Type[str]] = int def predict_type(self) -> Union[Type[int], Type[str]]: element_iter = iter(self.elements) @@ -73,11 +73,10 @@ def __init__(self, env: 'RDLEnvironment', src_ref: 'OptionalSourceRef', reps: AS super().__init__(env, src_ref) self.reps = reps self.concat = concat - self.type = None # type: Union[Type[int], Type[str]] - self.reps_value = None # type: int + self.type: Union[Type[int], Type[str]] = int + self.reps_value: Optional[int] = None - def predict_type(self): - # type: () -> Union[Type[int], Type[str]] + def predict_type(self) -> Union[Type[int], Type[str]]: if not is_castable(self.reps.predict_type(), int): self.msg.fatal( diff --git a/src/systemrdl/compiler.py b/src/systemrdl/compiler.py index 7f6ab25..b07a625 100644 --- a/src/systemrdl/compiler.py +++ b/src/systemrdl/compiler.py @@ -46,7 +46,6 @@ def included_files(self) -> Iterable[str]: class RDLCompiler: - def __init__(self, **kwargs: Any): """ RDLCompiler constructor. @@ -110,14 +109,14 @@ def __init__(self, **kwargs: Any): #: This will be deprecated in a future release. See this page for more details: https://github.com/SystemRDL/systemrdl-compiler/issues/168 self.msg = self.env.msg - self.namespace = NamespaceRegistry(self.env) # type: NamespaceRegistry - self.visitor = RootVisitor(self) - self.root = self.visitor.component # type: comp.Root # type: ignore + self.namespace: NamespaceRegistry = NamespaceRegistry(self.env) + self.visitor: RootVisitor = RootVisitor(self) + self.root = self.visitor.component def define_udp( self, name: str, valid_type: Any, - valid_components: 'Optional[Set[Type[comp.Component]]]'=None, + valid_components: Optional[Set[Type[comp.Component]]]=None, default: Any=None ) -> None: @@ -130,6 +129,15 @@ def define_udp( raise ValueError(f"UDP definition's name '{name}' conflicts with existing built-in RDL property") if name in self.env.property_rules.user_properties: raise ValueError(f"UDP '{name}' has already been defined") + if valid_components is None: + valid_components = { + comp.Field, + comp.Reg, + comp.Regfile, + comp.Addrmap, + comp.Mem, + comp.Signal, + } udp = LegacyExternalUserProperty( self.env, @@ -386,8 +394,10 @@ def elaborate(self, top_def_name: Optional[str]=None, inst_name: Optional[str]=N literal_expr = ast.ExternalLiteral(self.env, value) assign_expr = ast.AssignmentCast(self.env, None, literal_expr, parameter.param_type) - assign_type = assign_expr.predict_type() - if assign_type is None: + try: + # Try to predict type to test if ExternalLiteral maps to a valid RDL type + assign_expr.predict_type() + except ValueError: self.msg.fatal(f"Incorrect type for top-level parameter override of '{param_name}'") parameter.expr = assign_expr diff --git a/src/systemrdl/component.py b/src/systemrdl/component.py index 4c9da3c..8bfca1e 100644 --- a/src/systemrdl/component.py +++ b/src/systemrdl/component.py @@ -2,12 +2,13 @@ import functools from copy import deepcopy from collections import OrderedDict -from typing import Optional, List, Dict, TYPE_CHECKING, Any +from typing import Optional, List, Dict, TYPE_CHECKING, Any, Union if TYPE_CHECKING: from typing import TypeVar from .core.parameter import Parameter from .source_ref import SourceRefBase + from .ast import ASTNode ComponentClass = TypeVar('ComponentClass', bound='Component') @@ -32,14 +33,14 @@ def __init__(self) -> None: #: .. note:: #: This represents the parent *lexical* scope! This does *not* #: refer to the hierarchical parent of this component. - self.parent_scope = None # type: Component + self.parent_scope: Optional[Component] = None # Name of this component's declaration scope # This field is only valid in non-instantiated components (referenced - # via an instance's original_def) + # via an instance's original_def, or a component's parent_scope) # If declaration was anonymous, inherits the first instance's name, # otherwise it contains the original type name. - self._scope_name = None # type: str + self._scope_name: Optional[str] = None #: Named definition identifier. #: If declaration was anonymous, instantiation type names inherit @@ -53,7 +54,7 @@ def __init__(self) -> None: #: #: Importers may leave this as ``None`` if an appropriate type name #: cannot be imported. - self.type_name = None # type: Optional[str] + self.type_name: Optional[str] = None #: List of :class:`~systemrdl.component.Component` instances that are #: direct descendants of this component. @@ -64,50 +65,50 @@ def __init__(self) -> None: #: - All other components follow. #: - AddressableComponents are sorted by ascending base_addr #: - Fields are sorted by ascending low bit - self.children = [] # type: List[Component] + self.children: List[Component] = [] # Parameters of this component definition. # These are listed in the order that they were defined - self.parameters = [] # type: List[Parameter] + self.parameters: List[Parameter] = [] # Properties applied to this component - self.properties = {} # type: Dict[str, Any] + self.properties: Dict[str, Any] = {} #: :ref:`api_src_ref` for each explicit property assignment (if available) - self.property_src_ref = {} # type: Dict[str, SourceRefBase] + self.property_src_ref: Dict[str, SourceRefBase] = {} #: :ref:`api_src_ref` for the component definition - self.def_src_ref = None # type: Optional[SourceRefBase] + self.def_src_ref: Optional[SourceRefBase] = None #------------------------------ # Component instantiation #------------------------------ #: If instantiated, set to True - self.is_instance = False # type: bool + self.is_instance: bool = False #: Name of instantiated element - self.inst_name = None # type: Optional[str] + self.inst_name: Optional[str] = None #: Reference to original :class:`~systemrdl.component.Component` #: definition this instance is derived from. #: #: Importers may leave this as ``None`` if appropriate. - self.original_def = None # type: Optional[Component] + self.original_def: Optional[Component] = None #: True if instance type is external. False if internal. - self.external = None # type: bool + self.external: Optional[bool] = None #: :ref:`api_src_ref` for the component instantiation. - self.inst_src_ref = None # type: Optional[SourceRefBase] + self.inst_src_ref: Optional[SourceRefBase] = None #------------------------------ # List of property names that were assigned via a dynamic property # assignment. - self._dyn_assigned_props = [] # type: List[str] + self._dyn_assigned_props: List[str] = [] # List of child instances that were assigned "through" this component, # from outside this component's scope. - self._dyn_assigned_children = [] # type: List[str] + self._dyn_assigned_children: List[str] = [] def _copy_for_inst(self: 'ComponentClass', memo: Dict[int, Any]) -> 'ComponentClass': @@ -147,7 +148,7 @@ def __repr__(self) -> str: if self.is_instance: name_str = f"{self.inst_name} ({self.type_name})" else: - name_str = self.type_name + name_str = str(self.type_name) return f"<{self.__class__.__qualname__} {name_str} at {id(self):#x}>" @@ -212,6 +213,10 @@ def get_scope_path(self, scope_separator: str="::") -> Optional[str]: # Extend it with its scope name if parent_path: + # If parent scope exists, then its scope name is also guaranteed to + # exist + assert self.parent_scope._scope_name is not None + return( parent_path + scope_separator @@ -232,25 +237,26 @@ def __init__(self) -> None: # Component instantiation #------------------------------ #: Address offset from the parent component. - #: If left as None, compiler will resolve with inferred value. - self.addr_offset = None # type: int + #: If left as None, compiler will resolve with inferred value during + #: elaboration + self.addr_offset: Optional[int] = None #: Address alignment if explicitly assigned by user. - self.addr_align = None # type: Optional[int] + self.addr_align: Optional[int] = None #------------------------------ # Array Properties #------------------------------ #: If true, then ``array_dimensions`` and ``array_stride`` are valid. - self.is_array = False # type: bool + self.is_array: bool = False #: List of sizes for each array dimension. #: Last item in the list iterates the most frequently. - self.array_dimensions = None # type: Optional[List[int]] + self.array_dimensions: Optional[List[int]] = None #: Address offset between array elements. #: If left as None, compiler will resolve with inferred value. - self.array_stride = None # type: Optional[int] + self.array_stride: Optional[int] = None @property @@ -261,11 +267,21 @@ def n_elements(self) -> int: Returns 1 if not an array. """ if self.is_array: - assert isinstance(self.array_dimensions, list) + assert self.array_dimensions is not None return functools.reduce(operator.mul, self.array_dimensions) else: return 1 +class AddressableComponent_PreExprElab(AddressableComponent): + """ + Alternately typed representation for type hinting prior to expression + elaboration + """ + addr_offset: Optional[Union[int, 'ASTNode']] # type: ignore + addr_align: Optional[Union[int, 'ASTNode']] # type: ignore + array_stride: Optional[Union[int, 'ASTNode']] # type: ignore + + class VectorComponent(Component): """ Base class for all components that are vector-like @@ -276,18 +292,31 @@ def __init__(self) -> None: #------------------------------ # Component instantiation #------------------------------ + # Note: All of these are guaranteed to be resolved after elaboration to + # not be None + #: Width of vector in bits - self.width = None # type: int + self.width: Optional[int] = None #: Bit position of most significant bit - self.msb = None # type: int + self.msb: Optional[int] = None #: Bit position of least significant bit - self.lsb = None # type: int + self.lsb: Optional[int] = None #: High index of bit range - self.high = None # type: int + self.high: Optional[int] = None #: Low index of bit range - self.low = None # type: int + self.low: Optional[int] = None + + +class VectorComponent_PreExprElab(VectorComponent): + """ + Alternately typed representation for type hinting prior to expression + elaboration + """ + width: Optional[Union[int, 'ASTNode']] # type: ignore + msb: Optional[Union[int, 'ASTNode']] # type: ignore + lsb: Optional[Union[int, 'ASTNode']] # type: ignore #=============================================================================== class Root(Component): @@ -298,7 +327,7 @@ def __init__(self) -> None: super().__init__() #: Dictionary of :class:`~systemrdl.component.Component` definitions in #: the global root scope. - self.comp_defs = OrderedDict() # type: Dict[str, Component] + self.comp_defs: Dict[str, Component] = OrderedDict() class Signal(VectorComponent): pass @@ -313,22 +342,22 @@ def __init__(self) -> None: #: If true, fields are to be arranged in msb0 order #: #: .. versionadded:: 1.7 - self.is_msb0_order = False # type: bool + self.is_msb0_order: bool = False # List of register inst names that are aliases of this primary # Due to limitations in RDL grammar, these can only be siblings in the hierarchy # so names are unambiguous - self._alias_names = [] # type: List[str] + self._alias_names: List[str] = [] #------------------------------ # Alias Register #------------------------------ #: If true, then ``alias_primary_inst`` is valid - self.is_alias = False # type: bool + self.is_alias: bool = False #: Reference to primary register :class:`~systemrdl.component.Component` #: instance - self.alias_primary_inst = None # type: Optional[Reg] + self.alias_primary_inst: Optional[Reg] = None class Regfile(AddressableComponent): pass diff --git a/src/systemrdl/core/BaseVisitor.py b/src/systemrdl/core/BaseVisitor.py index 64caa92..f274278 100644 --- a/src/systemrdl/core/BaseVisitor.py +++ b/src/systemrdl/core/BaseVisitor.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Type, Union from .helpers import get_ID_text @@ -13,7 +13,6 @@ from ..compiler import RDLCompiler from antlr4.Token import CommonToken from antlr4 import ParserRuleContext - from typing import Union, Type class BaseVisitor(SystemRDLVisitor): @@ -42,8 +41,7 @@ def __init__(self, compiler: 'RDLCompiler') -> None: SystemRDLParser.FIELD_kw : comp.Field, SystemRDLParser.SIGNAL_kw : comp.Signal, } - def datatype_from_token(self, token): - # type: ('CommonToken') -> Type[Union[int, str, bool, rdltypes.BuiltinEnum, rdltypes.UserEnum, rdltypes.UserStruct, rdltypes.references.RefType, comp.Component]] + def datatype_from_token(self, token: 'CommonToken') -> Type[Union[int, str, bool, rdltypes.BuiltinEnum, rdltypes.UserEnum, rdltypes.UserStruct, rdltypes.references.RefType, comp.Component]]: """ Given a SystemRDLParser token, lookup the type This only includes types under the "data_type" grammar rule @@ -60,7 +58,7 @@ def datatype_from_token(self, token): ) if rdltypes.is_user_enum(typ) or rdltypes.is_user_struct(typ): - return typ # type: ignore + return typ else: self.msg.fatal( "Type '%s' is not a struct or enum" % get_ID_text(token), diff --git a/src/systemrdl/core/ComponentVisitor.py b/src/systemrdl/core/ComponentVisitor.py index c35641b..6d6cf3d 100644 --- a/src/systemrdl/core/ComponentVisitor.py +++ b/src/systemrdl/core/ComponentVisitor.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Dict, Tuple, List, Optional, Any +from typing import TYPE_CHECKING, Dict, Tuple, List, Optional, Any, cast from collections import OrderedDict from ..parser.SystemRDLParser import SystemRDLParser @@ -27,8 +27,9 @@ #=============================================================================== class ComponentVisitor(BaseVisitor): comp_type = comp.Component + component: comp.Component - def __init__(self, compiler: 'RDLCompiler', def_name: str=None, param_defs: List[Parameter]=None): + def __init__(self, compiler: 'RDLCompiler', def_name: Optional[str]=None, param_defs: Optional[List[Parameter]]=None): super().__init__(compiler) self.component = self.comp_type() #pylint: disable=not-callable @@ -43,7 +44,7 @@ def __init__(self, compiler: 'RDLCompiler', def_name: str=None, param_defs: List # { # prop_name : (prop_src_ref, prop_rhs) # } - self.property_dict = OrderedDict() # type: Dict[str, Tuple[SourceRefBase, Any]] + self.property_dict: Dict[str, Tuple[SourceRefBase, Any]] = OrderedDict() # Scratchpad of dynamic property assignments encountered in body of component # format is: @@ -52,13 +53,13 @@ def __init__(self, compiler: 'RDLCompiler', def_name: str=None, param_defs: List # prop_name : (prop_src_ref, prop_rhs) # } # } - self.dynamic_property_dict = OrderedDict() # type: Dict[comp.Component, Dict[str, Tuple[SourceRefBase, Any]]] + self.dynamic_property_dict: Dict[comp.Component, Dict[str, Tuple[SourceRefBase, Any]]] = OrderedDict() # Scratchpad to pass stuff down between visitor functions - self._tmp_comp_def = None # type: comp.Component - self._tmp_comp_inst = None # type: comp.Component - self._tmp_inst_type = None # type: CommonToken - self._tmp_alias_primary_inst = None # type: Optional[comp.Reg] + self._tmp_comp_def: comp.Component + self._tmp_comp_inst: comp.Component + self._tmp_inst_type: CommonToken + self._tmp_alias_primary_inst: Optional[comp.Reg] #--------------------------------------------------------------------------- # Component Definitions @@ -162,7 +163,7 @@ def check_comp_def_allowed(self, type_token: 'CommonToken') -> None: SystemRDLParser.SIGNAL_kw : comp.Signal, SystemRDLParser.MEM_kw : comp.Mem } - def define_component(self, body: SystemRDLParser.Component_bodyContext, type_token: 'CommonToken', def_name: str, param_defs: List[Parameter]) -> comp.Component: + def define_component(self, body: SystemRDLParser.Component_bodyContext, type_token: 'CommonToken', def_name: Optional[str], param_defs: List[Parameter]) -> comp.Component: """ Given component definition, recurse to another ComponentVisitor to define a new component @@ -337,7 +338,7 @@ def resolve_inst_external(self, ctx: SystemRDLParser.Component_instsContext, com comp_inst.external = None - def get_instance_assignment(self, ctx: 'ParserRuleContext') -> ast.ASTNode: + def get_instance_assignment(self, ctx: Optional['ParserRuleContext']) -> Optional[ast.ASTNode]: """ Gets the integer expression in any of the four instance assignment operators ('=' '@' '+=' '%=') @@ -462,12 +463,15 @@ def visitComponent_inst(self, ctx: SystemRDLParser.Component_instContext) -> Non comp_inst.properties['reset'] = field_inst_reset elif isinstance(comp_inst, comp.AddressableComponent): - comp_inst.addr_offset = inst_addr_fixed # type: ignore - comp_inst.addr_align = inst_addr_align # type: ignore + # Cast to pre-elaborated variant to satisfy type hinting + comp_inst = cast(comp.AddressableComponent_PreExprElab, comp_inst) + + comp_inst.addr_offset = inst_addr_fixed + comp_inst.addr_align = inst_addr_align if array_suffixes: comp_inst.is_array = True comp_inst.array_dimensions = array_suffixes - comp_inst.array_stride = inst_addr_stride # type: ignore + comp_inst.array_stride = inst_addr_stride else: raise RuntimeError @@ -510,9 +514,10 @@ def visitParam_def_elem(self, ctx: SystemRDLParser.Param_def_elemContext) -> Par # Construct parameter type data_type_token = self.visit(ctx.data_type()) param_data_type = self.datatype_from_token(data_type_token) + param_type: Union[Type[Union[int, str, bool, rdltypes.BuiltinEnum, rdltypes.UserEnum, rdltypes.UserStruct, rdltypes.references.RefType, comp.Component]], rdltypes.ArrayedType] if ctx.array_type_suffix() is None: # Non-array type - param_type = param_data_type # type: Union[Type[Union[int, str, bool, rdltypes.BuiltinEnum, rdltypes.UserEnum, rdltypes.UserStruct, rdltypes.references.RefType, comp.Component]], rdltypes.ArrayedType] + param_type = param_data_type else: # Array-like type param_type = rdltypes.ArrayedType(param_data_type) @@ -542,7 +547,7 @@ def visitParam_def_elem(self, ctx: SystemRDLParser.Param_def_elemContext) -> Par return param - def visitParam_inst(self, ctx: SystemRDLParser.Param_instContext) -> Dict[str, Tuple[ast.ASTNode, SourceRefBase]]: + def visitParam_inst(self, ctx: SystemRDLParser.Param_instContext) -> Dict[str, Tuple[ast.ASTNode, Optional[SourceRefBase]]]: param_assigns = {} for assignment in ctx.getTypedRuleContexts(SystemRDLParser.Param_assignmentContext): param_name, assign_expr = self.visit(assignment) @@ -641,13 +646,15 @@ def visitDynamic_property_assignment(self, ctx: SystemRDLParser.Dynamic_property target_inst._dyn_assigned_children.append(inst_name) # Traverse to next child in token list - target_inst = target_inst.get_child_by_name(inst_name) - if target_inst is None: + next_target_inst = target_inst.get_child_by_name(inst_name) + if next_target_inst is None: # Not found! self.msg.fatal( "Could not resolve hierarchical reference to '%s'" % inst_name, src_ref_from_antlr(name_token) ) + else: + target_inst = next_target_inst # Add assignment to dynamic_property_dict target_inst_dict = self.dynamic_property_dict.get(target_inst, OrderedDict()) @@ -684,7 +691,7 @@ def visitInstance_ref_element(self, ctx: SystemRDLParser.Instance_ref_elementCon return name_token - def visitNormal_prop_assign(self, ctx: SystemRDLParser.Normal_prop_assignContext) -> Tuple[SourceRefBase, str, Optional[ast.ASTNode]]: + def visitNormal_prop_assign(self, ctx: SystemRDLParser.Normal_prop_assignContext) -> Tuple[Optional[SourceRefBase], str, Optional[ast.ASTNode]]: # Get property string if ctx.prop_keyword() is not None: @@ -726,7 +733,7 @@ def visitEncode_prop_assign(self, ctx: SystemRDLParser.Encode_prop_assignContext return src_ref_from_antlr(prop_token), prop_name, rhs # type: ignore - def visitProp_mod_assign(self, ctx: SystemRDLParser.Prop_mod_assignContext) -> Tuple[SourceRefBase, str]: + def visitProp_mod_assign(self, ctx: SystemRDLParser.Prop_mod_assignContext) -> Tuple[Optional[SourceRefBase], str]: prop_mod_token = self.visit(ctx.prop_mod()) prop_mod = prop_mod_token.text @@ -766,7 +773,7 @@ def apply_local_properties(self) -> None: rule.assign_value(self.component, prop_rhs, prop_src_ref) # Apply locally-assigned properties - mutex_bins = {} # type: Dict[str, str] + mutex_bins: Dict[str, str] = {} for prop_name, (prop_src_ref, prop_rhs) in self.property_dict.items(): rule = self.compiler.env.property_rules.lookup_property(prop_name) if rule is None: @@ -797,7 +804,7 @@ def apply_local_properties(self) -> None: def apply_dynamic_properties(self) -> None: for target_inst, target_inst_dict in self.dynamic_property_dict.items(): - mutex_bins = {} # type: Dict[str, str] + mutex_bins: Dict[str, str] = {} for prop_name, (prop_src_ref, prop_rhs) in target_inst_dict.items(): rule = self.compiler.env.property_rules.lookup_property(prop_name) if rule is None: @@ -902,6 +909,7 @@ def visitConstraint_def(self, ctx: SystemRDLParser.Constraint_defContext) -> Non #=============================================================================== class RootVisitor(ComponentVisitor): comp_type = comp.Root + component: comp.Root def visitRoot(self, ctx: SystemRDLParser.RootContext) -> None: self.visitChildren(ctx) @@ -917,11 +925,11 @@ def visitLocal_property_assignment(self, ctx: SystemRDLParser.Local_property_ass super().visitLocal_property_assignment(ctx) - def define_component(self, body: SystemRDLParser.Component_bodyContext, type_token: 'CommonToken', def_name: str, param_defs: List[Parameter]) -> comp.Component: + def define_component(self, body: SystemRDLParser.Component_bodyContext, type_token: 'CommonToken', def_name: Optional[str], param_defs: List[Parameter]) -> comp.Component: comp_def = super().define_component(body, type_token, def_name, param_defs) if def_name is not None: - self.component.comp_defs[def_name] = comp_def # type: ignore + self.component.comp_defs[def_name] = comp_def return comp_def @@ -959,6 +967,7 @@ def visitUdp_def(self, ctx: SystemRDLParser.Udp_defContext) -> None: #=============================================================================== class FieldComponentVisitor(ComponentVisitor): comp_type = comp.Field + component: comp.Field def visitComponent_insts(self, ctx: SystemRDLParser.Component_instsContext) -> None: # Unpack instance def info from parent @@ -992,6 +1001,7 @@ def check_comp_def_allowed(self, type_token: 'CommonToken') -> None: #=============================================================================== class RegComponentVisitor(ComponentVisitor): comp_type = comp.Reg + component: comp.Reg def visitComponent_insts(self, ctx: SystemRDLParser.Component_instsContext) -> None: # Unpack instance def info from parent @@ -1022,6 +1032,7 @@ def check_comp_def_allowed(self, type_token: 'CommonToken') -> None: #=============================================================================== class RegfileComponentVisitor(ComponentVisitor): comp_type = comp.Regfile + component: comp.Regfile def visitComponent_insts(self, ctx: SystemRDLParser.Component_instsContext) -> None: # Unpack instance def info from parent @@ -1051,6 +1062,7 @@ def check_comp_def_allowed(self, type_token: 'CommonToken') -> None: #=============================================================================== class AddrmapComponentVisitor(ComponentVisitor): comp_type = comp.Addrmap + component: comp.Addrmap def visitComponent_insts(self, ctx: SystemRDLParser.Component_instsContext) -> None: # Unpack instance def info from parent @@ -1071,6 +1083,7 @@ def visitComponent_insts(self, ctx: SystemRDLParser.Component_instsContext) -> N #=============================================================================== class MemComponentVisitor(ComponentVisitor): comp_type = comp.Mem + component: comp.Mem def visitComponent_insts(self, ctx: SystemRDLParser.Component_instsContext) -> None: # Unpack instance def info from parent @@ -1100,6 +1113,7 @@ def check_comp_def_allowed(self, type_token: 'CommonToken') -> None: #=============================================================================== class SignalComponentVisitor(ComponentVisitor): comp_type = comp.Signal + component: comp.Signal def visitComponent_insts(self, ctx: SystemRDLParser.Component_instsContext) -> None: self.msg.fatal( diff --git a/src/systemrdl/core/EnumVisitor.py b/src/systemrdl/core/EnumVisitor.py index b34dc2e..91743c1 100644 --- a/src/systemrdl/core/EnumVisitor.py +++ b/src/systemrdl/core/EnumVisitor.py @@ -1,4 +1,4 @@ -from typing import List, TYPE_CHECKING, Tuple, Any, Optional +from typing import List, TYPE_CHECKING, Tuple, Any, Optional, Type from ..parser.SystemRDLParser import SystemRDLParser @@ -16,7 +16,6 @@ from ..source_ref import SourceRefBase from ..compiler import RDLCompiler from .. import component as comp - from typing import Type class EnumVisitor(BaseVisitor): @@ -24,8 +23,7 @@ def __init__(self, compiler: 'RDLCompiler', parent_component: 'comp.Component') super().__init__(compiler) self.parent_component = parent_component - def visitEnum_def(self, ctx): - # type: (SystemRDLParser.Enum_defContext) -> Tuple[Type[rdltypes.UserEnum], str, SourceRefBase] + def visitEnum_def(self, ctx: SystemRDLParser.Enum_defContext) -> Tuple[Type[rdltypes.UserEnum], str, Optional['SourceRefBase']]: self.compiler.namespace.enter_scope() # Allowing enum definitions to access Parameters from the parent scope @@ -37,9 +35,9 @@ def visitEnum_def(self, ctx): enum_name = get_ID_text(ctx.ID()) # Collect members - entry_values = [] # type: List[int] - entry_names = [] # type: List[str] - members = [] # type: List[rdltypes.UserEnumMemberContainer] + entry_values: List[int] = [] + entry_names: List[str] = [] + members: List[rdltypes.UserEnumMemberContainer] = [] for enum_entry_ctx in ctx.getTypedRuleContexts(SystemRDLParser.Enum_entryContext): name_token, value_expr_ctx, rdl_name, rdl_desc = self.visit(enum_entry_ctx) @@ -96,8 +94,8 @@ def visitEnum_entry(self, ctx: SystemRDLParser.Enum_entryContext) -> Tuple['Comm name_token = ctx.ID() value_expr_ctx = ctx.expr() - rdl_name = None # type: Optional[str] - rdl_desc = None # type: Optional[str] + rdl_name: Optional[str] = None + rdl_desc: Optional[str] = None for pa_ctx in ctx.getTypedRuleContexts(SystemRDLParser.Enum_prop_assignContext): prop_token, prop_value = self.visit(pa_ctx) diff --git a/src/systemrdl/core/ExprVisitor.py b/src/systemrdl/core/ExprVisitor.py index c8d3c79..7b7c042 100644 --- a/src/systemrdl/core/ExprVisitor.py +++ b/src/systemrdl/core/ExprVisitor.py @@ -374,7 +374,7 @@ def visitInstance_ref(self, ctx: SystemRDLParser.Instance_refContext) -> ast.AST if isinstance(first_elem, Parameter): # Reference is to a local parameter - ref_expr = ast.ParameterRef(self.compiler.env, first_name_src_ref, first_elem) # type: ast.ASTNode + ref_expr: ast.ASTNode = ast.ParameterRef(self.compiler.env, first_name_src_ref, first_elem) # Wrap ref_expr with array/struct dereferencers as appropriate for array_suffix in first_array_suffixes: diff --git a/src/systemrdl/core/UDPVisitor.py b/src/systemrdl/core/UDPVisitor.py index ae780ae..ad16a39 100644 --- a/src/systemrdl/core/UDPVisitor.py +++ b/src/systemrdl/core/UDPVisitor.py @@ -22,10 +22,10 @@ class UDPVisitor(BaseVisitor): def __init__(self, compiler: 'RDLCompiler') -> None: super().__init__(compiler) - self._constr_componentwidth = None # type: Optional[bool] - self._default_assignment = None # type: Any - self._valid_type = None # type: Optional[Type[Union[int, str, bool, rdltypes.BuiltinEnum, rdltypes.UserEnum, rdltypes.UserStruct, comp.Component, rdltypes.references.RefType]]] - self._bindable_to = None # type: Optional[Set[Type[comp.Component]]] + self._constr_componentwidth: Optional[bool] = None + self._default_assignment: Any = None + self._valid_type: Optional[Type[Union[int, str, bool, rdltypes.BuiltinEnum, rdltypes.UserEnum, rdltypes.UserStruct, comp.Component, rdltypes.references.RefType]]] = None + self._bindable_to: Optional[Set[Type[comp.Component]]] = None def visitUdp_def(self, ctx: SystemRDLParser.Udp_defContext) -> None: udp_name = get_ID_text(ctx.ID()) @@ -146,7 +146,7 @@ def visitUdp_usage(self, ctx: SystemRDLParser.Udp_usageContext) -> None: src_ref_from_antlr(ctx.COMPONENT_kw()) ) - comp_types = [] # type: List[Type[comp.Component]] + comp_types: List[Type[comp.Component]] = [] for token_ctx in ctx.getTypedRuleContexts(SystemRDLParser.Udp_comp_typeContext): token = self.visit(token_ctx) if token.type == SystemRDLParser.ALL_kw: diff --git a/src/systemrdl/core/elaborate.py b/src/systemrdl/core/elaborate.py index 9724cee..25327ce 100644 --- a/src/systemrdl/core/elaborate.py +++ b/src/systemrdl/core/elaborate.py @@ -1,5 +1,5 @@ import hashlib -from typing import TYPE_CHECKING, List, Optional +from typing import TYPE_CHECKING, List, Optional, cast from ..ast import ASTNode from .helpers import is_pow2, roundup_pow2, roundup_to @@ -43,7 +43,9 @@ def enter_Component(self, node: Node) -> None: def enter_AddressableComponent(self, node: AddressableNode) -> None: - assert isinstance(node.inst, comp.AddressableComponent) + # Cast to pre-elaborated variant to satisfy type hinting + node.inst = cast(comp.AddressableComponent_PreExprElab, node.inst) + # Evaluate instance object expressions if isinstance(node.inst.addr_offset, ASTNode): node.inst.addr_offset = node.inst.addr_offset.get_value() @@ -76,7 +78,9 @@ def enter_AddressableComponent(self, node: AddressableNode) -> None: def enter_VectorComponent(self, node: VectorNode) -> None: - assert isinstance(node.inst, comp.VectorComponent) + # Cast to pre-elaborated variant to satisfy type hinting + node.inst = cast(comp.VectorComponent_PreExprElab, node.inst) + # Evaluate instance object expressions if isinstance(node.inst.width, ASTNode): node.inst.width = node.inst.width.get_value() @@ -208,9 +212,9 @@ class StructuralPlacementListener(walker.RDLListener): def __init__(self, msg_handler: 'MessageHandler'): self.msg = msg_handler - self.msb0_mode_stack = [] # type: List[bool] - self.addressing_mode_stack = [] # type: List[rdltypes.AddressingType] - self.alignment_stack = [] # type: List[Optional[int]] + self.msb0_mode_stack: List[bool] = [] + self.addressing_mode_stack: List[rdltypes.AddressingType] = [] + self.alignment_stack: List[Optional[int]] = [] self.max_vreg_width = 0 @@ -250,10 +254,9 @@ def exit_Mem(self, node: MemNode) -> None: def exit_Field(self, node: FieldNode) -> None: - assert isinstance(node.inst, comp.Field) # Resolve field width if node.inst.width is None: - fieldwidth = node.get_property('fieldwidth') + fieldwidth = node.get_property('fieldwidth', default=None) if (node.inst.lsb is not None) and (node.inst.msb is not None): width = abs(node.inst.msb - node.inst.lsb) + 1 @@ -275,11 +278,9 @@ def exit_Field(self, node: FieldNode) -> None: def exit_Signal(self, node: SignalNode) -> None: - assert isinstance(node.inst, comp.Signal) - # Resolve signal width if node.inst.width is None: - signalwidth = node.get_property('signalwidth') + signalwidth = node.get_property('signalwidth', default=None) if signalwidth is not None: node.inst.width = signalwidth @@ -303,8 +304,6 @@ def exit_Signal(self, node: SignalNode) -> None: def exit_Reg(self, node: RegNode) -> None: - assert isinstance(node.inst, comp.Reg) - regwidth = node.get_property('regwidth') self.max_vreg_width = max(regwidth, self.max_vreg_width) @@ -347,11 +346,13 @@ def exit_Reg(self, node: RegNode) -> None: # Assign field positions # Children are iterated in order of declaration - prev_inst = None # type: Optional[comp.Field] + prev_inst: Optional[comp.Field] = None for inst in node.inst.children: if not isinstance(inst, comp.Field): continue + assert inst.width is not None # Width was resolved in field visit + if (inst.lsb is None) or (inst.msb is None): # Offset is not known @@ -369,9 +370,12 @@ def exit_Reg(self, node: RegNode) -> None: if prev_inst is None: inst.lsb = regwidth - 1 else: + assert prev_inst.msb is not None inst.lsb = prev_inst.msb - 1 + assert inst.lsb is not None inst.msb = inst.lsb - inst.width + 1 + assert inst.msb is not None if inst.msb < 0: node.env.msg.fatal( @@ -386,9 +390,12 @@ def exit_Reg(self, node: RegNode) -> None: if prev_inst is None: inst.lsb = 0 else: + assert prev_inst.msb is not None inst.lsb = prev_inst.msb + 1 + assert inst.lsb is not None inst.msb = inst.lsb + inst.width - 1 + assert inst.msb is not None inst.high = max(inst.msb, inst.lsb) inst.low = min(inst.msb, inst.lsb) prev_inst = inst @@ -399,6 +406,7 @@ def get_field_sort_key(inst: comp.Component) -> int: if not isinstance(inst, comp.Field): return -1 else: + assert inst.low is not None return inst.low node.inst.children.sort(key=get_field_sort_key) @@ -419,7 +427,6 @@ def exit_Addrmap(self, node: AddrmapNode) -> None: def exit_AddressableComponent(self, node: AddressableNode) -> None: - assert isinstance(node.inst, comp.AddressableComponent) # Resolve array stride if needed if node.inst.is_array and (node.inst.array_stride is None): node.inst.array_stride = node.size @@ -448,7 +455,6 @@ def resolve_addresses(self, node: AddressableNode, is_bridge: bool = False) -> N for child_node in node.children(skip_not_present=False): if not isinstance(child_node, AddressableNode): continue - assert isinstance(child_node.inst, comp.AddressableComponent) if child_node.inst.addr_offset is not None: # Address is already known. Do not need to infer @@ -519,6 +525,7 @@ def get_child_sort_key(inst: comp.Component) -> int: if not isinstance(inst, comp.AddressableComponent): return -1 else: + assert inst.addr_offset is not None return inst.addr_offset node.inst.children.sort(key=get_child_sort_key) @@ -530,10 +537,10 @@ class LateElabListener(walker.RDLListener): def __init__(self, msg_handler: 'MessageHandler', env: 'RDLEnvironment'): self.msg = msg_handler self.env = env - self.coerce_external_to = None # type: Optional[bool] - self.coerce_end_regfile = None # type: Optional[Node] + self.coerce_external_to: Optional[bool] = None + self.coerce_end_regfile: Optional[Node] = None - self.node_needs_revisit = [] # type: List[Node] + self.node_needs_revisit: List[Node] = [] def enter_Component(self, node: Node) -> None: @@ -565,15 +572,13 @@ def enter_Regfile(self, node: RegfileNode) -> None: def enter_Reg(self, node: RegNode) -> None: - assert isinstance(node.inst, comp.Reg) - if self.coerce_external_to is not None: # Is nested inside regfile that is coercing to a particular inst type node.inst.external = self.coerce_external_to elif node.inst.external is None: if node.inst.is_alias: # inherit internal/external instance type from alias primary - assert isinstance(node.inst.alias_primary_inst, comp.Reg) + assert node.inst.alias_primary_inst is not None if node.inst.alias_primary_inst.external is not None: node.inst.external = node.inst.alias_primary_inst.external else: @@ -585,7 +590,7 @@ def enter_Reg(self, node: RegNode) -> None: # Register aliases with their primary register if node.inst.is_alias: - assert isinstance(node.inst.alias_primary_inst, comp.Reg) + assert node.inst.alias_primary_inst is not None node.inst.alias_primary_inst._alias_names.append(node.inst_name) @@ -628,6 +633,7 @@ def exit_Component(self, node: Node) -> None: for child_name in node.inst._dyn_assigned_children: child = node.inst.get_child_by_name(child_name) assert child is not None + assert child.inst_name is not None # _ if child.type_name is not None: @@ -670,9 +676,8 @@ def revisit_reg(self, node: RegNode) -> None: # Resolve alias register's instance type if it was not possible to do so earlier. # By now, its primary would have been resolved. if node.inst.external is None: - assert isinstance(node.inst, comp.Reg) if node.inst.is_alias: - assert isinstance(node.inst.alias_primary_inst, comp.Reg) + assert node.inst.alias_primary_inst is not None if node.inst.alias_primary_inst.external is not None: node.inst.external = node.inst.alias_primary_inst.external else: diff --git a/src/systemrdl/core/namespace.py b/src/systemrdl/core/namespace.py index 434f6f0..401e228 100644 --- a/src/systemrdl/core/namespace.py +++ b/src/systemrdl/core/namespace.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Dict, List, Union, Type, Tuple +from typing import TYPE_CHECKING, Dict, List, Union, Type, Tuple, Optional from .parameter import Parameter @@ -15,7 +15,7 @@ TypeNSScope = Dict[str, TypeNSEntry] ElementNSRef = Union[comp.Component, Parameter] -ElementNSEntry = Tuple[ElementNSRef, comp.Component] +ElementNSEntry = Tuple[ElementNSRef, Optional[comp.Component]] ElementNSScope = Dict[str, ElementNSEntry] DefaultNSRef = Union['ASTNode', bool, 'rdltypes.InterruptType'] @@ -28,14 +28,14 @@ def __init__(self, env: 'RDLEnvironment'): self.env = env self.msg = env.msg - self.type_ns_stack = [{}] # type: List[TypeNSScope] - self.element_ns_stack = [{}] # type: List[ElementNSScope] - self.default_property_ns_stack = [{}] # type: List[DefaultNSScope] + self.type_ns_stack: List[TypeNSScope] = [{}] + self.element_ns_stack: List[ElementNSScope] = [{}] + self.default_property_ns_stack: List[DefaultNSScope] = [{}] # Control if Parameter objects are visible from parent scopes self.parent_parameters_visible = True - def register_type(self, name: str, ref: TypeNSRef, src_ref: 'SourceRefBase') -> None: + def register_type(self, name: str, ref: TypeNSRef, src_ref: Optional['SourceRefBase']) -> None: if name in self.type_ns_stack[-1]: self.msg.fatal( "Multiple declarations of type '%s'" % name, @@ -43,7 +43,7 @@ def register_type(self, name: str, ref: TypeNSRef, src_ref: 'SourceRefBase') -> ) self.type_ns_stack[-1][name] = ref - def register_element(self, name: str, ref: ElementNSRef, parent_comp_def: comp.Component, src_ref: 'SourceRefBase') -> None: + def register_element(self, name: str, ref: ElementNSRef, parent_comp_def: Optional[comp.Component], src_ref: Optional['SourceRefBase']) -> None: if name in self.element_ns_stack[-1]: self.msg.fatal( "Multiple declarations of instance '%s'" % name, @@ -61,13 +61,13 @@ def register_default_property(self, name: str, ref: DefaultNSRef, src_ref: 'Sour self.default_property_ns_stack[-1][name] = (src_ref, ref) - def lookup_type(self, name: str) -> TypeNSEntry: + def lookup_type(self, name: str) -> Optional[TypeNSEntry]: for scope in reversed(self.type_ns_stack): if name in scope: return scope[name] return None - def lookup_element(self, name: str) -> ElementNSEntry: + def lookup_element(self, name: str) -> Union[ElementNSEntry, Tuple[None, None]]: """ Look up the element (component instance, or parameter) visible in the current scope. @@ -93,8 +93,7 @@ def lookup_element(self, name: str) -> ElementNSEntry: return (el, parent_def) return (None, None) - def get_default_properties(self, comp_type): - # type: (Type[comp.Component]) -> DefaultNSScope + def get_default_properties(self, comp_type: Type[comp.Component]) -> DefaultNSScope: """ Returns a flattened dictionary of all default property assignments visible in the current scope that apply to the current component type. diff --git a/src/systemrdl/core/parameter.py b/src/systemrdl/core/parameter.py index 05a6a01..4632ded 100644 --- a/src/systemrdl/core/parameter.py +++ b/src/systemrdl/core/parameter.py @@ -6,6 +6,7 @@ if TYPE_CHECKING: from .. import rdltypes from ..ast import ASTNode + from ..node import Node class Parameter: def __init__(self, param_type: 'rdltypes.PreElabRDLType', name: str, default_expr: Optional['ASTNode']=None): @@ -16,7 +17,7 @@ def __init__(self, param_type: 'rdltypes.PreElabRDLType', name: str, default_exp # Stores the evaluated result of self.expr so that subsequent queries do # not need to repeatedly re-evaluate it - self._value = None # type: Any + self._value: Any = None def __deepcopy__(self, memo: Dict[int, Any]) -> 'Parameter': diff --git a/src/systemrdl/core/rdlformatcode.py b/src/systemrdl/core/rdlformatcode.py index a6916c4..49438f2 100755 --- a/src/systemrdl/core/rdlformatcode.py +++ b/src/systemrdl/core/rdlformatcode.py @@ -88,35 +88,43 @@ def rdlfc_to_html(text: str, node: Optional[Node]=None, md: Optional['Markdown'] text_segs.append("") elif m.lastgroup == 'color': m2 = re.match(r'\[color=([^\]]+)\]', m.group(0)) + assert m2 is not None text_segs.append('' % m2.group(1)) elif m.lastgroup == 'xcolor': text_segs.append('') elif m.lastgroup == 'size': m2 = re.match(r'\[size=([^\]]+)\]', m.group(0)) + assert m2 is not None text_segs.append('' % m2.group(1)) elif m.lastgroup == 'xsize': text_segs.append('') elif m.lastgroup == 'plainurl': m2 = re.match(r'\[url\](.*?)\[/url\]', m.group(0), re.DOTALL) + assert m2 is not None text_segs.append('%s' % (m2.group(1).strip(), m2.group(1).strip())) elif m.lastgroup == 'url': m2 = re.match(r'\[url=([^\]]+)\]', m.group(0)) + assert m2 is not None text_segs.append('' % m2.group(1).strip()) elif m.lastgroup == 'xurl': text_segs.append('') elif m.lastgroup == 'email': m2 = re.match(r'\[email\](.*?)\[/email\]', m.group(0), re.DOTALL) + assert m2 is not None text_segs.append('%s' % (m2.group(1).strip(), m2.group(1).strip())) elif m.lastgroup == 'img': m2 = re.match(r'\[img\](.*?)\[/img\]', m.group(0), re.DOTALL) + assert m2 is not None text_segs.append('' % m2.group(1)) elif m.lastgroup == 'code': m2 = re.match(r'\[code\](.*?)\s*\[/code\]', m.group(0), re.DOTALL) + assert m2 is not None text_segs.append('%s' % m2.group(1)) elif m.lastgroup == 'list': # List start tag m2 = re.match(r'\[list(?:=([^\]]+))?\]', m.group(0)) + assert m2 is not None ltype = m2.group(1) if ltype is None: text_segs.append('
    ') @@ -168,7 +176,7 @@ def rdlfc_to_html(text: str, node: Optional[Node]=None, md: Optional['Markdown'] elif m.lastgroup == 'sp': text_segs.append(" ") elif m.lastgroup == 'index': - if (node is not None) and isinstance(node, AddressableNode) and node.is_array: + if (node is not None) and isinstance(node, AddressableNode) and node.array_dimensions: subscripts = [] if node.current_idx is None: # Index is not known. Use range @@ -183,7 +191,7 @@ def rdlfc_to_html(text: str, node: Optional[Node]=None, md: Optional['Markdown'] else: text_segs.append(m.group(0)) elif m.lastgroup == 'index_parent': - if (node is not None) and (node.parent is not None) and isinstance(node.parent, AddressableNode) and node.parent.is_array: + if (node is not None) and (node.parent is not None) and isinstance(node.parent, AddressableNode) and node.parent.array_dimensions: subscripts = [] if node.parent.current_idx is None: # Index is not known. Use range diff --git a/src/systemrdl/core/validate.py b/src/systemrdl/core/validate.py index 5df82b4..4321007 100644 --- a/src/systemrdl/core/validate.py +++ b/src/systemrdl/core/validate.py @@ -20,16 +20,16 @@ def __init__(self, env: 'RDLEnvironment'): # Used in field overlap checks # This is a rolling buffer of previous fields that still have a chance # to possibly collide with a future field - self.field_check_buffer = [] # type: List[FieldNode] + self.field_check_buffer: List[FieldNode] = [] # Used in addrmap, regfile, and reg overlap checks # Same concept as the field check buffer, but is also a stack - self.addr_check_buffer_stack = [[]] # type: List[List[AddressableNode]] + self.addr_check_buffer_stack: List[List[AddressableNode]] = [[]] # Keep track of whether a given hierarchy has a reset signal. # Signals can exist in Root, so pre-load with one stack entry - self.has_cpuif_reset_stack = [False] # type: List[bool] - self.has_field_reset_stack = [False] # type: List[bool] + self.has_cpuif_reset_stack: List[bool] = [False] + self.has_field_reset_stack: List[bool] = [False] def enter_Component(self, node: Node) -> None: @@ -41,6 +41,7 @@ def enter_Component(self, node: Node) -> None: prop_value._validate() prop_rule = self.env.property_rules.lookup_property(prop_name) + assert prop_rule is not None prop_rule.validate(node, prop_value) if not isinstance(node, SignalNode): diff --git a/src/systemrdl/core/value_normalization.py b/src/systemrdl/core/value_normalization.py index 8d5ebbf..3da89a6 100644 --- a/src/systemrdl/core/value_normalization.py +++ b/src/systemrdl/core/value_normalization.py @@ -26,8 +26,10 @@ def normalize(value: Any, owner_node: Optional[node.Node]=None) -> str: elif isinstance(value, rdltypes.UserStruct): return normalize_struct(value, owner_node) elif isinstance(value, node.Node): + assert owner_node is not None # None only possible with Parameters, but those cannot have references return normalize_component_ref(value, owner_node) elif isinstance(value, rdltypes.PropertyReference): + assert owner_node is not None # None only possible with Parameters, but those cannot have references return normalize_property_ref(value, owner_node) elif rdltypes.is_user_enum(value): return normalize_user_enum_type(value) @@ -36,7 +38,7 @@ def normalize(value: Any, owner_node: Optional[node.Node]=None) -> str: return "NaN" elif isinstance(value, rdltypes.references.ComponentRef) and owner_node is None: # This only happens if a parameter contains a struct that wraps a reference - # datatype. # Since the parameter's value doesnt bother getting resolved, + # datatype. Since the parameter's value doesnt bother getting resolved, # It shows up as a ComponentRef object here. # SystemRDL spec does not allow references in parameters, so this ends up # being an odd, but convenient place to catch this. @@ -83,7 +85,7 @@ def normalize_enum(value: Union[rdltypes.BuiltinEnum, rdltypes.UserEnum]) -> str return value.name -def normalize_array(value: List[Any], owner_node: Optional[node.Node]=None) -> str: +def normalize_array(value: List[Any], owner_node: Optional[node.Node]) -> str: """ 5.1.1.4 - c.5: Arrays shall be rendered by: @@ -105,7 +107,7 @@ def normalize_array(value: List[Any], owner_node: Optional[node.Node]=None) -> s return md5[:8] -def normalize_struct(value: rdltypes.UserStruct, owner_node: Optional[node.Node]=None) -> str: +def normalize_struct(value: rdltypes.UserStruct, owner_node: Optional[node.Node]) -> str: """ 5.1.1.4 - c.6: Structs shall be rendered by: diff --git a/src/systemrdl/importer.py b/src/systemrdl/importer.py index 86e678b..bd32126 100644 --- a/src/systemrdl/importer.py +++ b/src/systemrdl/importer.py @@ -35,7 +35,7 @@ def __init__(self, compiler: RDLCompiler): #: model construction methods #: By default, this simply points to the file currently being imported, #: without any line offset information - self.default_src_ref = None # type: SourceRefBase + self.default_src_ref: SourceRefBase def import_file(self, path: str) -> None: """ diff --git a/src/systemrdl/messages.py b/src/systemrdl/messages.py index 9e43740..af89476 100644 --- a/src/systemrdl/messages.py +++ b/src/systemrdl/messages.py @@ -1,6 +1,7 @@ import sys import enum -from typing import List, Optional, TYPE_CHECKING, Union +from typing import List, Optional, Union, overload, NoReturn +from typing_extensions import Literal from antlr4.Token import CommonToken from antlr4 import ParserRuleContext, InputStream @@ -15,9 +16,6 @@ from .source_ref import SourceRefBase, src_ref_from_antlr, SegmentedSourceRef from .source_ref import DetailedFileSourceRef, FileSourceRef -if TYPE_CHECKING: - from typing import NoReturn - # Colorama needs to be initialized to properly work in Windows # This is a no-op in other OSes colorama.init() @@ -175,6 +173,14 @@ def __init__(self, printer: MessagePrinter, min_verbosity: Severity=Severity.WAR #: Set to True if an error message was ever emitted self.had_error = False + @overload + def message(self, severity: Literal[Severity.FATAL], text: str, src_ref: Optional[SourceRefBase]=None) -> NoReturn: + ... + + @overload + def message(self, severity: Severity, text: str, src_ref: Optional[SourceRefBase]=None) -> None: + ... + def message(self, severity: Severity, text: str, src_ref: Optional[SourceRefBase]=None) -> None: if severity == Severity.NONE: return @@ -223,7 +229,7 @@ def error(self, text: str, src_ref: Optional[SourceRefBase]=None) -> None: """ self.message(Severity.ERROR, text, src_ref) - def fatal(self, text: str, src_ref: Optional[SourceRefBase]=None) -> 'NoReturn': # type: ignore + def fatal(self, text: str, src_ref: Optional[SourceRefBase]=None) -> NoReturn: """ Print a fatal message. diff --git a/src/systemrdl/node.py b/src/systemrdl/node.py index 27151c3..360d3a0 100644 --- a/src/systemrdl/node.py +++ b/src/systemrdl/node.py @@ -2,7 +2,7 @@ import itertools from copy import deepcopy, copy from collections import deque -from typing import TYPE_CHECKING, Optional, Iterator, Any, List, Dict, Union +from typing import TYPE_CHECKING, Optional, Iterator, Any, List, Dict, Union, overload from . import component as comp from . import rdltypes @@ -22,7 +22,7 @@ class Node: """ - def __init__(self, inst: comp.Component, env: 'RDLEnvironment', parent: Optional['Node']): + def __init__(self, inst: comp.Component, env: 'RDLEnvironment', parent: Optional['Node']) -> None: # Generic Node constructor. # Do not call directly. Use factory() static method instead self.env = env @@ -56,6 +56,45 @@ def __deepcopy__(self, memo: Dict[int, Any]) -> 'Node': setattr(result, k, deepcopy(v, memo)) return result + @overload + @staticmethod + def _factory(inst: comp.Field, env: 'RDLEnvironment', parent: Optional['Node']) -> 'FieldNode': + ... + + @overload + @staticmethod + def _factory(inst: comp.Reg, env: 'RDLEnvironment', parent: Optional['Node']) -> 'RegNode': + ... + + @overload + @staticmethod + def _factory(inst: comp.Regfile, env: 'RDLEnvironment', parent: Optional['Node']) -> 'RegfileNode': + ... + + @overload + @staticmethod + def _factory(inst: comp.Addrmap, env: 'RDLEnvironment', parent: Optional['Node']) -> 'AddrmapNode': + ... + + @overload + @staticmethod + def _factory(inst: comp.Mem, env: 'RDLEnvironment', parent: Optional['Node']) -> 'MemNode': + ... + + @overload + @staticmethod + def _factory(inst: comp.Signal, env: 'RDLEnvironment', parent: Optional['Node']) -> 'SignalNode': + ... + + @overload + @staticmethod + def _factory(inst: comp.AddressableComponent, env: 'RDLEnvironment', parent: Optional['Node']) -> 'AddressableNode': + ... + + @overload + @staticmethod + def _factory(inst: comp.Component, env: 'RDLEnvironment', parent: Optional['Node']) -> 'Node': + ... @staticmethod def _factory(inst: comp.Component, env: 'RDLEnvironment', parent: Optional['Node']=None) -> 'Node': @@ -86,17 +125,19 @@ def unrolled(self) -> Iterator['Node']: .. versionadded:: 1.20.0 """ - cls = type(self) - if isinstance(self, AddressableNode) and self.is_array: # pylint: disable=no-member + if isinstance(self, AddressableNode) and self.array_dimensions: # pylint: disable=no-member + cls = type(self) + # Is an array. Yield a Node object for each instance range_list = [range(n) for n in self.array_dimensions] # pylint: disable=no-member for idxs in itertools.product(*range_list): N = cls(self.inst, self.env, self.parent) - N.current_idx = idxs # type: ignore + N.current_idx = list(idxs) yield N else: + cls2 = type(self) # not an array. Nothing to unroll - yield cls(self.inst, self.env, self.parent) + yield cls2(self.inst, self.env, self.parent) def children(self, unroll: bool=False, skip_not_present: bool=True) -> Iterator['Node']: @@ -124,13 +165,12 @@ def children(self, unroll: bool=False, skip_not_present: bool=True) -> Iterator[ # ispresent was explicitly set to False. Skip it continue - if unroll and isinstance(child_inst, comp.AddressableComponent) and child_inst.is_array: - assert child_inst.array_dimensions is not None + if unroll and isinstance(child_inst, comp.AddressableComponent) and child_inst.array_dimensions: # Unroll the array range_list = [range(n) for n in child_inst.array_dimensions] for idxs in itertools.product(*range_list): N = Node._factory(child_inst, self.env, self) - N.current_idx = idxs # type: ignore # pylint: disable=attribute-defined-outside-init + N.current_idx = list(idxs) yield N else: yield Node._factory(child_inst, self.env, self) @@ -304,7 +344,9 @@ def find_by_path(self, path: str) -> Optional['Node']: If an array index in the path is invalid """ pathparts = path.split('.') - current_node = self + current_node: Optional[Node] = self + assert current_node is not None + for pathpart in pathparts: # If parent reference, jump upwards if pathpart == "^": @@ -326,9 +368,8 @@ def find_by_path(self, path: str) -> Optional['Node']: if idx_list: if not isinstance(current_node, AddressableNode): raise IndexError("Index attempted on unindexable component") - assert isinstance(current_node.inst, comp.AddressableComponent) - if current_node.inst.is_array: + if current_node.inst.array_dimensions: # is an array if len(idx_list) != len(current_node.inst.array_dimensions): raise IndexError("Wrong number of array dimensions") @@ -479,6 +520,7 @@ def get_path_segment(self, array_suffix: str="[{index:d}]", empty_array_suffix: Override how array suffixes are represented when the index is not known """ # pylint: disable=unused-argument + assert self.inst.inst_name is not None return self.inst.inst_name @@ -652,6 +694,7 @@ def inst_name(self) -> str: """ Name of instantiated element """ + assert self.inst.inst_name is not None return self.inst.inst_name @property @@ -728,6 +771,9 @@ def external(self) -> bool: .. versionadded:: 1.9 """ + # Guaranteed after elaboration + assert self.inst.external is not None + return self.inst.external @property @@ -740,7 +786,7 @@ def cpuif_reset(self) -> 'Optional[SignalNode]': .. versionadded:: 1.19 """ - current_node = self + current_node: Optional[Node] = self while current_node is not None: for signal in current_node.signals(): if signal.get_property('cpuif_reset'): @@ -764,22 +810,24 @@ class AddressableNode(Node): """ Base-class for any kind of node that can have an address """ + parent: Union['AddressableNode', 'RootNode'] + inst: comp.AddressableComponent - def __init__(self, inst: comp.AddressableComponent, env: 'RDLEnvironment', parent: Optional[Node]): + def __init__(self, inst: comp.AddressableComponent, env: 'RDLEnvironment', parent: Optional[Node]) -> None: super().__init__(inst, env, parent) #: List of current array indexes this node is referencing where the last #: item in this list iterates the most frequently #: #: If None, then the current index is unknown - self.current_idx = None # type: Optional[List[int]] + self.current_idx: Optional[List[int]] = None def get_path_segment(self, array_suffix: str="[{index:d}]", empty_array_suffix: str="[]") -> str: # Extends get_path_segment() in order to append any array suffixes path_segment = super().get_path_segment(array_suffix, empty_array_suffix) - if self.is_array: + if self.array_dimensions: if self.current_idx is None: # Index is not known. for dim in self.array_dimensions: @@ -815,7 +863,7 @@ def zero_lineage_index(self) -> None: .. versionadded:: 1.7 """ - if self.is_array: + if self.array_dimensions: self.current_idx = [0] * len(self.array_dimensions) if isinstance(self.parent, AddressableNode): @@ -832,7 +880,7 @@ def raw_address_offset(self) -> int: :attr:`address_offset` """ - assert isinstance(self.inst, comp.AddressableComponent) + assert self.inst.addr_offset is not None return self.inst.addr_offset @@ -849,7 +897,8 @@ def address_offset(self) -> int: If this property is referenced on a node whose array index is not fully defined """ - if self.is_array: + if self.array_dimensions: + assert self.array_stride is not None if self.current_idx is None: raise ValueError("Index of array element must be known to derive address") @@ -887,7 +936,6 @@ def raw_absolute_address(self) -> int: .. versionadded:: 1.7 """ if self.parent and not isinstance(self.parent, RootNode): - assert isinstance(self.parent, AddressableNode) return self.parent.raw_absolute_address + self.raw_address_offset else: return self.raw_address_offset @@ -908,7 +956,6 @@ def absolute_address(self) -> int: """ if self.parent and not isinstance(self.parent, RootNode): - assert isinstance(self.parent, AddressableNode) return self.parent.absolute_address + self.address_offset else: return self.address_offset @@ -931,8 +978,8 @@ def total_size(self) -> int: Determine the size (in bytes) of this node. If an array, returns size of the entire array """ - assert isinstance(self.inst, comp.AddressableComponent) if self.is_array: + assert self.array_stride is not None # RDL spec does not explicitly clarify this, but total size for arrays # should include any additional trailing padding implied by the stride. # This makes it consistent with IP-XACT. @@ -948,7 +995,6 @@ def is_array(self) -> bool: """ Indicates that this node represents an array of instances """ - assert isinstance(self.inst, comp.AddressableComponent) return self.inst.is_array @@ -960,7 +1006,6 @@ def array_dimensions(self) -> Optional[List[int]]: If node is not an array (``is_array == False``), then this is ``None`` """ - assert isinstance(self.inst, comp.AddressableComponent) return self.inst.array_dimensions @@ -971,7 +1016,6 @@ def array_stride(self) -> Optional[int]: If node is not an array (``is_array == False``), then this is ``None`` """ - assert isinstance(self.inst, comp.AddressableComponent) return self.inst.array_stride #=============================================================================== @@ -979,13 +1023,15 @@ class VectorNode(Node): """ Base-class for any kind of node that is vector-like. """ + parent: Node + inst: comp.VectorComponent @property def width(self) -> int: """ Width of vector in bits """ - assert isinstance(self.inst, comp.VectorComponent) + assert self.inst.width is not None return self.inst.width @property @@ -993,7 +1039,7 @@ def msb(self) -> int: """ Bit position of most significant bit """ - assert isinstance(self.inst, comp.VectorComponent) + assert self.inst.msb is not None return self.inst.msb @property @@ -1001,7 +1047,7 @@ def lsb(self) -> int: """ Bit position of least significant bit """ - assert isinstance(self.inst, comp.VectorComponent) + assert self.inst.lsb is not None return self.inst.lsb @property @@ -1009,7 +1055,7 @@ def high(self) -> int: """ High index of bit range """ - assert isinstance(self.inst, comp.VectorComponent) + assert self.inst.high is not None return self.inst.high @property @@ -1017,12 +1063,15 @@ def low(self) -> int: """ Low index of bit range """ - assert isinstance(self.inst, comp.VectorComponent) + assert self.inst.low is not None return self.inst.low #=============================================================================== class RootNode(Node): + parent: None + inst: comp.Root + @property def top(self) -> 'AddrmapNode': """ @@ -1036,10 +1085,14 @@ def top(self) -> 'AddrmapNode': #=============================================================================== class SignalNode(VectorNode): - pass + parent: Node + inst: comp.Signal #=============================================================================== class FieldNode(VectorNode): + parent: 'RegNode' + inst: comp.Field + def get_global_type_name(self, separator: str = "__") -> Optional[str]: name = super().get_global_type_name(separator) if name is None: @@ -1069,7 +1122,6 @@ def is_virtual(self) -> bool: """ Determines if this node represents a virtual field (child of a virtual register) """ - assert isinstance(self.parent, RegNode) return self.parent.is_virtual @property @@ -1255,7 +1307,6 @@ def is_alias(self) -> bool: .. versionadded:: 1.23 """ - assert isinstance(self.parent, RegNode) return self.parent.is_alias @@ -1272,7 +1323,6 @@ def alias_primary(self) -> 'FieldNode': if not self.is_alias: raise ValueError("Field is not an alias") - assert isinstance(self.parent, RegNode) primary_reg = self.parent.alias_primary primary_field = primary_reg.get_child_by_name(self.inst_name) assert isinstance(primary_field, FieldNode) @@ -1304,7 +1354,6 @@ def aliases(self, skip_not_present: bool = True) -> Iterator['FieldNode']: .. versionadded:: 1.23 """ - assert isinstance(self.parent, RegNode) for alias_reg in self.parent.aliases(skip_not_present=skip_not_present): alias_field = alias_reg.get_child_by_name(self.inst_name) @@ -1321,6 +1370,8 @@ def aliases(self, skip_not_present: bool = True) -> Iterator['FieldNode']: #=============================================================================== class RegNode(AddressableNode): + parent: Union['AddrmapNode', 'RegNode', 'MemNode'] + inst: comp.Reg @property def size(self) -> int: @@ -1413,7 +1464,6 @@ def is_alias(self) -> bool: .. versionadded:: 1.23 """ - assert isinstance(self.inst, comp.Reg) return self.inst.is_alias @@ -1430,12 +1480,14 @@ def alias_primary(self) -> 'RegNode': if not self.is_alias: raise ValueError("Register is not an alias") + assert self.inst.alias_primary_inst is not None + assert self.inst.alias_primary_inst.inst_name is not None + # Limitations in grammar make it so that an alias primary can only be # referenced by a single ID token. This means the primary cannot be a # hierarchical path, or anything else fancy. This implicitly guarantees # that the alias primary is a sibling in the hierarchy. # Simply look up the sibling by-name. - assert isinstance(self.inst, comp.Reg) name = self.inst.alias_primary_inst.inst_name primary_reg = self.parent.get_child_by_name(name) assert isinstance(primary_reg, RegNode) @@ -1456,7 +1508,6 @@ def has_aliases(self) -> bool: .. versionadded:: 1.23 """ - assert isinstance(self.inst, comp.Reg) return bool(self.inst._alias_names) @@ -1472,7 +1523,6 @@ def aliases(self, skip_not_present: bool = True) -> Iterator['RegNode']: .. versionadded:: 1.23 """ - assert isinstance(self.inst, comp.Reg) for reg_name in self.inst._alias_names: alias_reg = self.parent.get_child_by_name(reg_name) @@ -1493,6 +1543,8 @@ def aliases(self, skip_not_present: bool = True) -> Iterator['RegNode']: #=============================================================================== class RegfileNode(AddressableNode): + parent: 'AddrmapNode' + inst: comp.Regfile @property def size(self) -> int: @@ -1500,6 +1552,8 @@ def size(self) -> int: #=============================================================================== class AddrmapNode(AddressableNode): + parent: Union['AddrmapNode', RootNode] + inst: comp.Addrmap @property def size(self) -> int: @@ -1507,6 +1561,8 @@ def size(self) -> int: #=============================================================================== class MemNode(AddressableNode): + parent: AddrmapNode + inst: comp.Mem @property def size(self) -> int: diff --git a/src/systemrdl/preprocessor/__init__.py b/src/systemrdl/preprocessor/__init__.py index acb8a64..9a39b48 100644 --- a/src/systemrdl/preprocessor/__init__.py +++ b/src/systemrdl/preprocessor/__init__.py @@ -8,7 +8,13 @@ if TYPE_CHECKING: from ..compiler import RDLEnvironment -def preprocess_file(env: 'RDLEnvironment', path: str, search_paths: List[str], defines: Optional[Dict[str,str]]=None) -> Tuple[PreprocessedInputStream, Set[str]]: +def preprocess_file( + env: 'RDLEnvironment', + path: str, + search_paths: List[str], + defines: Optional[Dict[str, str]]=None +) -> Tuple[PreprocessedInputStream, Set[str]]: + # Run file through Perl preprocessor ppp = PerlPreprocessor(env, path, search_paths) preprocessed_text, seg_map = ppp.preprocess() diff --git a/src/systemrdl/preprocessor/perl_preprocessor.py b/src/systemrdl/preprocessor/perl_preprocessor.py index 88364f5..79c1660 100644 --- a/src/systemrdl/preprocessor/perl_preprocessor.py +++ b/src/systemrdl/preprocessor/perl_preprocessor.py @@ -24,7 +24,7 @@ def __init__(self, env: 'RDLEnvironment', path: str, search_paths: List[str], in with open(path, 'r', newline='', encoding='utf_8') as f: self.text = f.read() - self.included_files = set() # type: Set[str] + self.included_files: Set[str] = set() #--------------------------------------------------------------------------- def preprocess(self) -> Tuple[str, segment_map.SegmentMap]: @@ -213,7 +213,7 @@ def get_perl_segments(self, tokens: List[Tuple[str, int, int]]) -> Tuple[List['P returns: (pl_segments, has_perl_tags) """ - pl_segments = [] # type: List[PPPSegment] + pl_segments: List[PPPSegment] = [] has_perl_tags = False pos = 0 @@ -221,7 +221,7 @@ def get_perl_segments(self, tokens: List[Tuple[str, int, int]]) -> Tuple[List['P # Capture any leading text if start != pos: - pl_seg = PPPUnalteredSegment(self, pos, start-1) # type: PPPSegment + pl_seg: PPPSegment = PPPUnalteredSegment(self, pos, start - 1) pl_segments.append(pl_seg) if typ == "incl": diff --git a/src/systemrdl/preprocessor/segment_map.py b/src/systemrdl/preprocessor/segment_map.py index f5d157a..bd90910 100644 --- a/src/systemrdl/preprocessor/segment_map.py +++ b/src/systemrdl/preprocessor/segment_map.py @@ -50,7 +50,7 @@ def __init__(self, start: int, end: int, path: str, parent: Optional['IncludeRef class SegmentMap: def __init__(self) -> None: - self.segments = [] # type: List[Segment] + self.segments: List[Segment] = [] def translate_offset(self, offset: int, round_up: bool) -> Tuple[int, str]: # Scan through segments diff --git a/src/systemrdl/preprocessor/verilog_preprocessor.py b/src/systemrdl/preprocessor/verilog_preprocessor.py index 405b487..86083ef 100644 --- a/src/systemrdl/preprocessor/verilog_preprocessor.py +++ b/src/systemrdl/preprocessor/verilog_preprocessor.py @@ -34,25 +34,23 @@ def __init__(self, env: 'RDLEnvironment', text: str, src_seg_map: Optional[segme self._seg_start_idx = 0 # Macro namespace - self._macro_defs = {} # type: Dict[str, Macro] + self._macro_defs: Dict[str, Macro] = {} if defines is not None: for k, v in defines.items(): macro = Macro(v, []) self._macro_defs[k] = macro self._conditional = ConditionalState() - self._conditional_stack = [] # type: List[ConditionalState] + self._conditional_stack: List[ConditionalState] = [] # Stack of what macros are currently being processed - self._active_macro_stack = [] # type: List[str] + self._active_macro_stack: List[str] = [] - self._output_text_segments = [] # type: List[str] + self._output_text_segments: List[str] = [] self._current_output_idx = 0 - self._output_seg_map = None # type: Optional[segment_map.SegmentMap] - if self._src_seg_map: - self._output_seg_map = segment_map.SegmentMap() + self._output_seg_map = segment_map.SegmentMap() - def preprocess(self) -> Tuple[str, Optional[segment_map.SegmentMap]]: + def preprocess(self) -> Tuple[str, segment_map.SegmentMap]: self.main_scanner() if not self._conditional.is_idle or self._conditional_stack: @@ -538,7 +536,7 @@ def macro_arg_scanner(self) -> List[Tuple[str, SourceRefBase]]: re.DOTALL | re.MULTILINE ) - enclosures_stack = [] # type: List[str] + enclosures_stack: List[str] = [] argvs = [] argv_start_idx = self._scan_idx punc_pairs = { @@ -732,7 +730,7 @@ def prepare_segments(self, contents: str) -> List[Union[int, str]]: ) seg_start_idx = 0 - segments = [] # type: List[Union[int, str]] + segments: List[Union[int, str]] = [] for m in query_regex.finditer(contents): assert m.lastindex is not None diff --git a/src/systemrdl/properties/bases.py b/src/systemrdl/properties/bases.py index d8b2bab..9e0cee7 100644 --- a/src/systemrdl/properties/bases.py +++ b/src/systemrdl/properties/bases.py @@ -16,19 +16,19 @@ #=============================================================================== class PropertyRule: # Set of components this property can be bound to - bindable_to = set() # type: Set[Type[comp.Component]] + bindable_to: Set[Type['comp.Component']] = set() # List of valid assignment types. In order of cast preference - valid_types = tuple() # type: Tuple[Any, ...] + valid_types: Tuple[Any, ...] = tuple() # Default value if not assigned - default = None # type: Any + default: Any = None # Whether dynamic assignments are allowed to be made to this property - dyn_assign_allowed= True # type: bool + dyn_assign_allowed: bool = True # Group string in which this property is mutually exclusive - mutex_group = None # type: Optional[str] + mutex_group: Optional[str] = None def __init__(self, env: 'RDLEnvironment'): @@ -247,7 +247,7 @@ def _validate_width_eq_or_smaller(self, node: m_node.VectorNode, value: Any) -> self.get_src_ref(node) ) - def get_src_ref(self, node: m_node.Node) -> 'SourceRefBase': + def get_src_ref(self, node: m_node.Node) -> Optional['SourceRefBase']: return node.inst.property_src_ref.get(self.get_name(), node.inst.inst_src_ref) @@ -268,7 +268,7 @@ def get_default(self, node: m_node.Node) -> bool: return self.default #=============================================================================== -_MUTEX_PROP_GROUPS = {} # type: Dict[str, Set[str]] +_MUTEX_PROP_GROUPS: Dict[str, Set[str]] = {} def _get_mutex_properties(group_name: str) -> Set[str]: # initialize cache for the first time if needed if not _MUTEX_PROP_GROUPS: diff --git a/src/systemrdl/properties/builtin.py b/src/systemrdl/properties/builtin.py index 1fa43b9..392a7cb 100644 --- a/src/systemrdl/properties/builtin.py +++ b/src/systemrdl/properties/builtin.py @@ -486,7 +486,7 @@ def get_default(self, node: m_node.Node) -> Optional[m_node.SignalNode]: If no field reset signal was explicitly assigned, search for signals in the enclosing hierarchy with field_reset=True """ - current_node = node + current_node: Optional[m_node.Node] = node while current_node is not None: for signal in current_node.signals(): if signal.get_property('field_reset'): diff --git a/src/systemrdl/properties/prop_refs.py b/src/systemrdl/properties/prop_refs.py index 554739e..ac1571e 100644 --- a/src/systemrdl/properties/prop_refs.py +++ b/src/systemrdl/properties/prop_refs.py @@ -51,7 +51,7 @@ class RealOrInferredVectorReference(PropertyValueReference): References the vector that was directly assign to the property, or inferred by setting the property to True """ - complementary_prop = None # type: Optional[str] + complementary_prop: Optional[str] = None def _validate(self) -> None: super()._validate() # validate that this property is enabled in the target (is not False) diff --git a/src/systemrdl/properties/rulebook.py b/src/systemrdl/properties/rulebook.py index 031b8b4..7e9466d 100644 --- a/src/systemrdl/properties/rulebook.py +++ b/src/systemrdl/properties/rulebook.py @@ -16,15 +16,15 @@ def __init__(self, env: 'RDLEnvironment'): self.env = env # Auto-discover all properties defined below and load into dict - self.rdl_properties = {} # type: Dict[str, PropertyRule] + self.rdl_properties: Dict[str, PropertyRule] = {} for prop in get_all_subclasses(PropertyRule): if prop.__name__.startswith("Prop_"): prop_inst = prop(self.env) self.rdl_properties[prop_inst.get_name()] = prop(self.env) - self.user_properties = {} # type: Dict[str, UserProperty] + self.user_properties: Dict[str, UserProperty] = {} - self.rdl_prop_refs = {} # type: Dict[str, Type[rdltypes.PropertyReference]] + self.rdl_prop_refs: Dict[str, Type[rdltypes.PropertyReference]] = {} for prop_ref in get_all_subclasses(rdltypes.PropertyReference): if prop_ref.__name__.startswith("PropRef_"): prop_name = prop_ref.get_name() @@ -42,11 +42,10 @@ def lookup_property(self, prop_name: str, include_soft_udp: bool=False) -> Optio else: return None - def lookup_prop_ref_type(self, prop_ref_name): - # type: (str) -> Optional[Type[rdltypes.PropertyReference]] + def lookup_prop_ref_type(self, prop_ref_name: str) -> Optional[Type[rdltypes.PropertyReference]]: return self.rdl_prop_refs.get(prop_ref_name, None) - def register_udp(self, udp: UserProperty, src_ref: 'SourceRefBase') -> None: + def register_udp(self, udp: UserProperty, src_ref: Optional['SourceRefBase']) -> None: if udp.name in self.user_properties: existing_udp = self.user_properties[udp.name] diff --git a/src/systemrdl/properties/user_defined.py b/src/systemrdl/properties/user_defined.py index 3a1dba3..dddb01c 100644 --- a/src/systemrdl/properties/user_defined.py +++ b/src/systemrdl/properties/user_defined.py @@ -127,7 +127,7 @@ def name(self) -> str: return self._name @property - def bindable_to(self) -> 'Set[Type[comp.Component]]': # type: ignore + def bindable_to(self) -> 'Set[Type[comp.Component]]': # type: ignore # overriding base class var as property return self._valid_components @property diff --git a/src/systemrdl/rdltypes/__init__.py b/src/systemrdl/rdltypes/__init__.py index 323425a..f7b5011 100644 --- a/src/systemrdl/rdltypes/__init__.py +++ b/src/systemrdl/rdltypes/__init__.py @@ -19,7 +19,7 @@ def get_rdltype(value: Any) -> 'PreElabRDLType': """ Given a value, return the type identifier object used within the RDL compiler - If not a supported type, return None + If not a supported type, raises ValueError """ if isinstance(value, (int, bool, str)): @@ -34,18 +34,16 @@ def get_rdltype(value: Any) -> 'PreElabRDLType': elif isinstance(value, list): # Create ArrayedType representation # Determine element type and make sure it is uniform - array_el_type = None # type: Optional[PreElabRDLType] + array_el_type: Optional[PreElabRDLType] = None + for el in value: el_type = get_rdltype(el) - if el_type is None: - return None - if (array_el_type is not None) and (el_type != array_el_type): - return None + raise ValueError("Array literal is not of uniform type") array_el_type = el_type return ArrayedType(array_el_type) else: - return None + raise ValueError("Could not map to RDL type") class NoValue: diff --git a/src/systemrdl/rdltypes/array.py b/src/systemrdl/rdltypes/array.py index e01fbce..6900a35 100644 --- a/src/systemrdl/rdltypes/array.py +++ b/src/systemrdl/rdltypes/array.py @@ -1,4 +1,4 @@ -from typing import Any, TYPE_CHECKING +from typing import Any, TYPE_CHECKING, Optional if TYPE_CHECKING: from .typing import PreElabRDLType @@ -9,9 +9,12 @@ class ArrayedType(): Once elaborated, arrays are converted to Python lists In the meantime, this placeholder is used to communicate expected type - information during compilation type checking + information during compilation type checking. + + If element_type is None, then the array being represented is empty, and + therefore its element type is indeterminate """ - def __init__(self, element_type: 'PreElabRDLType'): + def __init__(self, element_type: Optional['PreElabRDLType']): self.element_type = element_type def __eq__(self, other: Any) -> bool: diff --git a/src/systemrdl/rdltypes/references.py b/src/systemrdl/rdltypes/references.py index 6c91648..d791dfb 100644 --- a/src/systemrdl/rdltypes/references.py +++ b/src/systemrdl/rdltypes/references.py @@ -19,7 +19,7 @@ class ComponentRef: When a user requests the reference value, it is resolved into a Node object """ - def __init__(self, ref_root: 'comp.Component', ref_elements: List[RefElement]): + def __init__(self, ref_root: 'comp.Component', ref_elements: List[RefElement]) -> None: # Handle to the component definition where ref_elements is relative to # This is the original_def, and NOT the actual instance self.ref_root = ref_root @@ -37,7 +37,7 @@ def build_node_ref(self, assignee_node: Node) -> Node: """ Resolves the component reference into a Node object """ - current_node = assignee_node + current_node: Optional[Node] = assignee_node # Traverse up from assignee until ref_root is reached while True: if current_node is None: @@ -46,19 +46,26 @@ def build_node_ref(self, assignee_node: Node) -> Node: break current_node = current_node.parent + # Above loop can only exit if not None + assert current_node is not None + for inst_name, idx_list, name_src_ref in self.ref_elements: # find instance current_node = current_node.get_child_by_name(inst_name) - + assert current_node is not None # Check if indexes are valid if idx_list: # Reference contains one or more suffixes # Validation during compilation would have already enforced that # references are sane. + # Safe to expect this to be an AddressableNode assert isinstance(current_node, AddressableNode) + # If idx_list is not empty, guaranteed to be an array node + assert current_node.array_dimensions is not None + for i, idx in enumerate(idx_list): if idx >= current_node.array_dimensions[i]: current_node.env.msg.fatal( @@ -103,16 +110,16 @@ class PropertyReference: print(next_prop.name) # prints: "intr" """ - allowed_inst_type = None # type: Type[comp.Component] + allowed_inst_type: Type[comp.Component] - def __init__(self, src_ref: 'SourceRefBase', env: 'RDLEnvironment', comp_ref: ComponentRef): + def __init__(self, src_ref: Optional['SourceRefBase'], env: 'RDLEnvironment', comp_ref: ComponentRef) -> None: self.env = env self.src_ref = src_ref self._comp_ref = comp_ref #: Node object that represents the component instance from which the #: property is being referenced. - self.node = None # type: Node + self.node: Node def __repr__(self) -> str: return f"<{self.__class__.__qualname__} {self.node.get_path()}->{self.name} at {id(self):#x}>" diff --git a/src/systemrdl/rdltypes/user_enum.py b/src/systemrdl/rdltypes/user_enum.py index 9a8123a..29f3f79 100644 --- a/src/systemrdl/rdltypes/user_enum.py +++ b/src/systemrdl/rdltypes/user_enum.py @@ -1,9 +1,9 @@ from typing import Optional, Dict, Any, TYPE_CHECKING, List, Type, Generator +from typing_extensions import TypeIs from collections import OrderedDict import inspect import copyreg - from ..core import rdlformatcode from .. import component as comp @@ -11,7 +11,6 @@ from markdown import Markdown - class UserEnumMemberContainer: """ Container class used only when defining a new UserEnum. @@ -34,8 +33,8 @@ class UserEnumMeta(type): Metaclass for UserEnum """ - _member_map = {} # type: Dict[str, UserEnum] - _parent_scope = None # type: Optional[comp.Component] + _member_map: Dict[str, 'UserEnum'] = {} + _parent_scope: Optional[comp.Component] = None def __bool__(cls) -> bool: # classes/types should always be True. @@ -107,7 +106,7 @@ def define_new(cls, name: str, members: List[UserEnumMemberContainer], _parent_s raise ValueError("All members of an enum shall have unique values") # Create the new class - classdict = { + classdict: Dict[str, Any] = { '_member_map': OrderedDict(), '_parent_scope': _parent_scope, } @@ -150,6 +149,10 @@ def get_scope_path(cls, scope_separator: str="::") -> str: # Get parent definition's scope path parent_path = parent_scope.get_scope_path(scope_separator) + # If parent scope exists, then its scope name is also guaranteed to + # exist + assert parent_scope._scope_name is not None + # Extend it with its scope name if parent_path: return( @@ -276,7 +279,7 @@ def _reduce_user_enum(c: Type[UserEnum]) -> Any: return 'UserEnum' assert len(c.__bases__) == 1 # Only supporting single-inheritence - base_cls = c.__bases__[0] # type: Type[UserEnum] + base_cls: Type[UserEnum] = c.__bases__[0] # decompose members back into factory containers members = [] @@ -291,7 +294,7 @@ def _reduce_user_enum(c: Type[UserEnum]) -> Any: copyreg.pickle(UserEnumMeta, _reduce_user_enum) # type: ignore -def is_user_enum(t: Any) -> bool: +def is_user_enum(t: Any) -> TypeIs[Type[UserEnum]]: """ Test if type ``t`` is a :class:`~UserEnum` diff --git a/src/systemrdl/rdltypes/user_struct.py b/src/systemrdl/rdltypes/user_struct.py index 8e1aa93..a92a8ae 100644 --- a/src/systemrdl/rdltypes/user_struct.py +++ b/src/systemrdl/rdltypes/user_struct.py @@ -1,4 +1,5 @@ from typing import Optional, Dict, Any, Type, TYPE_CHECKING +from typing_extensions import TypeIs from collections import OrderedDict import inspect import copyreg @@ -16,11 +17,17 @@ class UserStructMeta(type): Declare a metaclass for UserStruct so that it can be uniquely identified during dynamic type pickling """ - _members = OrderedDict() # type: UserStructMembers - _is_abstract = True # type: bool - _parent_scope = None # type: Optional[comp.Component] - - def define_new(cls, name: str, members: UserStructMembers, is_abstract: bool=False, _parent_scope: Optional[comp.Component]=None) -> Type['UserStruct']: + _members: UserStructMembers = OrderedDict() + _is_abstract: bool = True + _parent_scope: Optional[comp.Component] = None + + def define_new( + cls, + name: str, + members: UserStructMembers, + is_abstract: bool=False, + _parent_scope: Optional[comp.Component]=None + ) -> Type['UserStruct']: """ Define a new struct type derived from the current type. @@ -92,7 +99,7 @@ class UserStruct(metaclass=UserStructMeta): ... """ - def __init__(self, values: Dict[str, Any]): + def __init__(self, values: Dict[str, Any]) -> None: """ Create an instance of the struct @@ -159,8 +166,13 @@ def get_scope_path(cls, scope_separator: str="::") -> str: # Get parent definition's scope path parent_path = parent_scope.get_scope_path(scope_separator) + # If parent scope exists, then its scope name is also guaranteed to + # exist + assert parent_scope._scope_name is not None + # Extend it with its scope name if parent_path: + return( parent_path + scope_separator @@ -184,7 +196,7 @@ def _reduce_user_struct(c: Type[UserStruct]) -> Any: return 'UserStruct' assert len(c.__bases__) == 1 # Only supporting single-inheritence - base_cls = c.__bases__[0] # type: Type[UserStruct] + base_cls: Type[UserStruct] = c.__bases__[0] # remove members that exist in base class unique_members = c._members.copy() @@ -197,7 +209,7 @@ def _reduce_user_struct(c: Type[UserStruct]) -> Any: # Utility functions -def is_user_struct(t: Any) -> bool: +def is_user_struct(t: Any) -> TypeIs[Type[UserStruct]]: """ Test if type ``t`` is a :class:`~UserStruct` """ diff --git a/src/systemrdl/source_ref.py b/src/systemrdl/source_ref.py index aa9cb75..29fe530 100644 --- a/src/systemrdl/source_ref.py +++ b/src/systemrdl/source_ref.py @@ -1,4 +1,4 @@ -from typing import Tuple, Union, Dict, Any +from typing import Tuple, Union, Dict, Any, Optional from antlr4.Token import CommonToken from antlr4 import ParserRuleContext @@ -33,7 +33,7 @@ class FileSourceRef(SourceRefBase): Some register model importers may only be able to provide limited source context. """ - def __init__(self, path: str): + def __init__(self, path: str) -> None: super().__init__() self._path = path @@ -94,14 +94,14 @@ class DirectSourceRef(DetailedFileSourceRef): """ Source reference that points directly to a file's coordinates. """ - def __init__(self, path: str, start_idx: int, end_idx: int): + def __init__(self, path: str, start_idx: int, end_idx: int) -> None: super().__init__(path) - self._start_idx = start_idx - self._end_idx = end_idx + self._start_idx: int = start_idx + self._end_idx: int = end_idx - self._line = None # type: int - self._line_text = None # type: str - self._line_selection = None # type: Tuple[int, int] + self._line: Optional[int] = None + self._line_text: Optional[str] = None + self._line_selection: Optional[Tuple[int, int]] = None def _extract_line_info(self) -> None: idx = 0 @@ -143,18 +143,21 @@ def path(self) -> str: def line(self) -> int: if self._line is None: self._extract_line_info() + assert self._line is not None return self._line @property def line_text(self) -> str: if self._line_text is None: self._extract_line_info() + assert self._line_text is not None return self._line_text @property def line_selection(self) -> Tuple[int, int]: if self._line_selection is None: self._extract_line_info() + assert self._line_selection is not None return self._line_selection @@ -164,9 +167,10 @@ class SegmentedSourceRef(DirectSourceRef): Source reference that requires coordinate transformation through one or more segment maps """ + _path: Optional[str] # type: ignore # overriding this to be optional def __init__(self, seg_map: SegmentMap, start_idx: int, end_idx: int): - super().__init__(None, None, None) + super().__init__(None, None, None) # type: ignore # overriding this to be optional self._seg_map = seg_map self._seg_start_idx = start_idx @@ -176,6 +180,7 @@ def __init__(self, seg_map: SegmentMap, start_idx: int, end_idx: int): def path(self) -> str: if self._path is None: self._resolve_seg_map() + assert self._path is not None return self._path def _resolve_seg_map(self) -> None: @@ -185,7 +190,7 @@ def _resolve_seg_map(self) -> None: #------------------------------------------------------------------------------- -def src_ref_from_antlr(antlr_ref: Union[CommonToken, TerminalNodeImpl, ParserRuleContext]) -> 'SourceRefBase': +def src_ref_from_antlr(antlr_ref: Union[CommonToken, TerminalNodeImpl, ParserRuleContext]) -> Optional[SourceRefBase]: # Normalize to pair of CommonToken objects if isinstance(antlr_ref, CommonToken): token = antlr_ref diff --git a/src/systemrdl/udp.py b/src/systemrdl/udp.py index f25be98..2d9529d 100644 --- a/src/systemrdl/udp.py +++ b/src/systemrdl/udp.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Any, Set, Type +from typing import TYPE_CHECKING, Any, Set, Type, Optional import re from . import component as comp @@ -15,11 +15,11 @@ class UDPDefinition: """ #: User-defined property name - name = "" # type: str + name: str = "" #: Set of :class:`~systemrdl.component.Component` types the UDP can be bound to. #: By default, the UDP can be bound to all components. - valid_components = { + valid_components: Set[Type[comp.Component]] = { comp.Field, comp.Reg, comp.Regfile, @@ -27,23 +27,23 @@ class UDPDefinition: comp.Mem, comp.Signal, # TODO: constraint, - } # type: Set[Type[comp.Component]] + } #: Data type of the assignment value that this UDP will enforce. #: If this is a reference, either specify the specific component type class #: (eg. :class:`~systemrdl.component.Field`), or the generic representation #: of all references: :class:`~systemrdl.rdltypes.references.RefType` - valid_type = None # type: Any + valid_type: Any = None #: Specifies the value assigned if a value is not specified when the UDP is bound to a component. #: Value must be compatible with ``valid_type`` - default_assignment = None # type: Any + default_assignment: Any = None #: If set to True, enables a validation check that enforces that the #: assigned value of the property shall not have a value of 1 for any #: bit beyond the width of the field. #: This can only be used if ``valid_type`` is ``int`` - constr_componentwidth = False + constr_componentwidth: bool = False def __init__(self, env: 'RDLEnvironment') -> None: self.env = env @@ -66,7 +66,7 @@ def msg(self) -> 'MessageHandler': """ return self.env.msg - def get_src_ref(self, node: 'Node') -> 'SourceRefBase': + def get_src_ref(self, node: 'Node') -> Optional['SourceRefBase']: """ Get the src_ref object for this property assignment. diff --git a/test/mypy.ini b/test/mypy.ini index 4ef7f86..de6e865 100644 --- a/test/mypy.ini +++ b/test/mypy.ini @@ -1,6 +1,8 @@ [mypy] + +# antlr4 library provides poor type hints. Ignoring ignore_missing_imports = True -strict_optional = False + disallow_incomplete_defs = True disallow_untyped_defs = True warn_unused_configs = True @@ -8,6 +10,7 @@ warn_unused_ignores = True warn_unreachable = True disallow_untyped_calls = True +# Ignore untyped Antlr-generated output [mypy-systemrdl.parser.*] ignore_errors = True @@ -21,18 +24,7 @@ disallow_untyped_calls = False disallow_untyped_calls = False [mypy-systemrdl.core.ExprVisitor] -disallow_untyped_calls = False -disallow_incomplete_defs = False -disallow_untyped_defs = False ignore_errors = True [mypy-systemrdl.core.StructVisitor] -disallow_untyped_calls = False -disallow_incomplete_defs = False -disallow_untyped_defs = False ignore_errors = True - -[mypy-systemrdl.preprocessor.verilog_preprocessor] -strict_optional = True -[mypy-systemrdl.preprocessor.perl_preprocessor] -strict_optional = True diff --git a/test/requirements.txt b/test/requirements.txt index f791b28..f7eac65 100644 --- a/test/requirements.txt +++ b/test/requirements.txt @@ -3,6 +3,8 @@ pytest-cov parameterized pylint types-Markdown +types-colorama +#types-antlr4-python3-runtime # Avoiding newer mypy for now because I didn't know how to do type hints # 5 years ago...