1""" 2======================================================================== 3errors.py 4======================================================================== 5Errors thrown by other files in this folder. 6 7Author : Shunning Jiang 8Date : Dec 27, 2018 9""" 10import inspect 11 12 13class FieldReassignError( Exception ): 14 """ Raise when a deprecated API is called""" 15 16class PyMTLDeprecationError( Exception ): 17 """ Raise when a deprecated API is called""" 18 19class SignalTypeError( Exception ): 20 """ Raise when a declared signal is of wrong type """ 21 22class MultiWriterError( Exception ): 23 """ Raise when a variable is written by multiple update blocks/nets """ 24 25class NoWriterError( Exception ): 26 """ Raise when a net has no writer (driver) """ 27 def __init__( self, nets ): 28 return super().__init__( \ 29 "The following nets need drivers.\nNet:\n - {} ".format( 30 "\nNet:\n - ".join( [ "\n - ".join( [ repr(x) for x in y ] ) 31 for y in nets ]) ) ) 32 33class WriteNonSignalError( Exception ): 34 """ In update/update_ff, raise when a component is assigned """ 35 def __init__( self, hostobj, blk, lineno, obj ): 36 37 filepath = inspect.getfile( hostobj.__class__ ) 38 blk_src, base_lineno = inspect.getsourcelines( blk ) 39 40 # Shunning: we need to subtract 1 from inspect's lineno when we add it 41 # to base_lineno because it starts from 1! 42 lineno -= 1 43 error_lineno = base_lineno + lineno 44 45 return super().__init__( \ 46""" 47In file {}:{} in {} 48 49{} {} 50^^^ Cannot Assign to {} of type {}. 51In update block, assigning values to components/interfaces/method ports is forbidden. 52(when constructing instance {} of class \"{}\" in the hierarchy) 53 54Suggestion: check the declaration of the variables, or fix this assignment.""".format( \ 55 filepath, error_lineno, blk.__name__, 56 error_lineno, blk_src[ lineno ].lstrip(''), 57 repr(obj), obj.__class__.__name__, 58 repr(hostobj), hostobj.__class__.__name__ ) 59 ) 60 61class UpdateBlockWriteError( Exception ): 62 """ In update, raise when signal is not @= -ed """ 63 def __init__( self, hostobj, blk, op, lineno, suggestion ): 64 65 filepath = inspect.getfile( hostobj.__class__ ) 66 blk_src, base_lineno = inspect.getsourcelines( blk ) 67 68 # Shunning: we need to subtract 1 from inspect's lineno when we add it 69 # to base_lineno because it starts from 1! 70 lineno -= 1 71 error_lineno = base_lineno + lineno 72 73 return super().__init__( \ 74""" 75In file {}:{} in {} 76 77{} {} 78^^^ In update, only '@=' statements can assign value to signals, not {} 79(when constructing instance {} of class \"{}\" in the hierarchy) 80 81Suggestion: Line {} {}""".format( \ 82 filepath, error_lineno, blk.__name__, 83 error_lineno, blk_src[ lineno ].lstrip(''), op, 84 repr(hostobj), hostobj.__class__.__name__, 85 error_lineno, suggestion ) 86 ) 87 88class UpdateFFBlockWriteError( Exception ): 89 """ In update_ff, raise when signal is not <<= -ed""" 90 def __init__( self, hostobj, blk, op, lineno, suggestion ): 91 92 filepath = inspect.getfile( hostobj.__class__ ) 93 blk_src, base_lineno = inspect.getsourcelines( blk ) 94 95 # Shunning: we need to subtract 1 from inspect's lineno when we add it 96 # to base_lineno because it starts from 1! 97 lineno -= 1 98 error_lineno = base_lineno + lineno 99 100 return super().__init__( \ 101""" 102In file {}:{} in {} 103 104{} {} 105^^^ In update_ff, only '<<=' statements can assign value to signals, not {} 106(when constructing instance {} of class \"{}\" in the hierarchy) 107 108Suggestion: Line {} {}""".format( \ 109 filepath, error_lineno, blk.__name__, 110 error_lineno, blk_src[ lineno ].lstrip(''), op, 111 repr(hostobj), hostobj.__class__.__name__, 112 error_lineno, suggestion ) 113 ) 114 115class UpdateFFNonTopLevelSignalError( Exception ): 116 """ In update_ff, raise when non-top signal is <<= -ed""" 117 def __init__( self, hostobj, blk, lineno ): 118 filepath = inspect.getfile( hostobj.__class__ ) 119 blk_src, base_lineno = inspect.getsourcelines( blk ) 120 121 # Shunning: we need to subtract 1 from inspect's lineno when we add it 122 # to base_lineno because it starts from 1! 123 lineno -= 1 124 error_lineno = base_lineno + lineno 125 126 return super().__init__( \ 127""" 128In file {}:{} in {} 129 130{} {} 131^^^ In update_ff, currently only top level signals (not a slice or a subfield) can appear on the left-hand side of '<<=' 132(when constructing instance {} of class \"{}\" in the hierarchy) 133""".format( \ 134 filepath, error_lineno, blk.__name__, 135 error_lineno, blk_src[ lineno ].lstrip(''), 136 repr(hostobj), hostobj.__class__.__name__, 137 ) 138 ) 139 140class VarNotDeclaredError( Exception ): 141 """ Raise when a variable in an update block is not declared """ 142 def __init__( self, obj, field, blk=None, blk_hostobj=None, lineno=0 ): 143 144 if not blk: 145 return super().__init__() # this is just temporary message 146 147 filepath = inspect.getfile( blk_hostobj.__class__ ) 148 blk_src, base_lineno = inspect.getsourcelines( blk ) 149 150 # Shunning: we need to subtract 1 from inspect's lineno when we add it 151 # to base_lineno because it starts from 1! 152 lineno -= 1 153 error_lineno = base_lineno + lineno 154 155 return super().__init__( \ 156""" 157In file {}:{} in {} 158 159{} {} 160^^^ Field \"{}\" of object \"{}\" (class \"{}\") is accessed in block \"{}\", 161 but {} does not have field \"{}\". 162(when constructing instance {} of class \"{}\" in the hierarchy) 163 164Suggestion: fix incorrect field access at line {}, or fix the declaration somewhere.""".format( \ 165 filepath, error_lineno, blk.__name__, 166 error_lineno, blk_src[ lineno ].lstrip(''), 167 field, repr(obj), obj.__class__.__name__, blk.__name__, 168 repr(obj), field, 169 repr(blk_hostobj), blk_hostobj.__class__.__name__, 170 error_lineno ) ) 171 172class InvalidIndexError( Exception ): 173 """ Raise when a variable in an update block is not declared """ 174 def __init__( self, obj, idx, blk=None, blk_hostobj=None, lineno=0 ): 175 176 if not blk: 177 return super().__init__() # this is just temporary message 178 179 filepath = inspect.getfile( blk_hostobj.__class__ ) 180 blk_src, base_lineno = inspect.getsourcelines( blk ) 181 182 # Shunning: we need to subtract 1 from inspect's lineno when we add it 183 # to base_lineno because it starts from 1! 184 lineno -= 1 185 error_lineno = base_lineno + lineno 186 187 if isinstance( idx, tuple ): 188 idx_str = f"[{idx.start}:{idx.stop}]" 189 else: 190 idx_str = f"[{idx}]" 191 192 from pymtl3.datatypes import Bits 193 return super().__init__( \ 194""" 195In file {}:{} in {} 196 197{} {} 198^^^ Slice {} of object \"{}\" (class \"{}\") is accessed in block \"{}\", 199 but {} has \"{}\" type{}. 200(when constructing instance {} of class \"{}\" in the hierarchy) 201 202Suggestion: fix incorrect field access at line {}, or fix the declaration somewhere.""".format( \ 203 filepath, error_lineno, blk.__name__, 204 error_lineno, blk_src[ lineno ].lstrip(''), 205 idx_str, repr(obj), obj.__class__.__name__, blk.__name__, 206 repr(obj), obj._dsl.Type.__name__, "" if issubclass( obj._dsl.Type, Bits ) else ", not BitsN type", 207 repr(blk_hostobj), blk_hostobj.__class__.__name__, 208 error_lineno ) ) 209 210class UnmarkedUpdateOnceError( Exception ): 211 """ In update, raise when signal is not @= -ed """ 212 def __init__( self, hostobj, blk, objs ): 213 214 filepath = inspect.getfile( hostobj.__class__ ) 215 blk_src, base_lineno = inspect.getsourcelines( blk ) 216 return super().__init__( \ 217""" 218In file {}:{} (component {}): 219Since update block {} calls the CL/FL method ports/interfaces below, it should be marked as @update_once 220- {} 221 222Suggestion: Mark update block {} as @update_once""".format( \ 223 filepath, base_lineno, repr(hostobj), blk.__name__, 224 "\n- ".join( sorted( [repr(x) for x in objs] ) ), 225 blk.__name__ ) 226 ) 227 228class UpblkFuncSameNameError( Exception ): 229 """ Raise when two update block/function are declared with the same name """ 230 def __init__( self, name ): 231 return super().__init__( \ 232 " Cannot declare two update blocks/functions with the same name {}".format( name ) ) 233 234class UpblkCyclicError( Exception ): 235 """ Raise when update blocks have cyclic dependencies """ 236 237class InvalidConstraintError( Exception ): 238 """ Raise when a defined constraint is of wrong format """ 239 def __init__( self ): 240 return super().__init__( \ 241 "Constraints between two variables are not allowed!" ) 242 243class InvalidConnectionError( Exception ): 244 """ Raise upon an inappropriate attempt to connect two variables """ 245 246class InvalidFuncCallError( Exception ): 247 """ Raise upon an inappropriate @s.func function call """ 248 249class InvalidPlaceholderError( Exception ): 250 """ Raise upon declaring an update block in a placeholder component. """ 251 252class NotElaboratedError( Exception ): 253 """ Raise when processing a model that hasn't been elaborated yet """ 254 def __init__( self ): 255 return super().__init__( \ 256 "Please elaborate the model first." ) 257 258class InvalidAPICallError( Exception ): 259 """ Raise when processing a model that hasn't been elaborated yet """ 260 def __init__( self, api_name, obj, top ): 261 return super().__init__( \ 262 "{} is only allowed to be called at the top module that .elaborate() " 263 "was called on (an instance of {}), but this API call is on {}." \ 264 .format( api_name, top.__class__, "top."+repr(obj)[2:] ) ) 265 266class UnsetMetadataError( Exception ): 267 """ Raised when the value of a given metadata key is not set. """ 268 def __init__( self, key, obj ): 269 return super().__init__( 270 f"\nAttempting to retrieve unset metadata {key} from component {obj}!" ) 271 272class LeftoverPlaceholderError( Exception ): 273 """ Raise upon declaring an update block in a placeholder component. """ 274 def __init__( self, placeholders ): 275 return super().__init__( \ 276 "Please replace all placeholders with valid components:\n - {}".format( 277 "\n - ".join( [ "top.{} (instance of {})".format( repr(x)[2:], x.__class__ ) \ 278 for x in placeholders ] ) ) ) 279