Source code for pyccel.parser.errors

from collections import OrderedDict

# ...
#ERROR = 'error'
#INTERNAL = 'internal'
#WARNING = 'warning'
#FATAL = 'fatal'
#
#PYCCEL = 'pyccel'
#
#def make_symbol(s):
#    return str(s)

try:
    from termcolor import colored
    ERROR = colored('error', 'red', attrs=['blink', 'bold'])
    INTERNAL = colored('internal', attrs=['blink', 'bold'])
    WARNING = colored('warning', 'green', attrs=['blink'])
    FATAL = colored('fatal', 'red', attrs=['blink', 'bold'])

    PYCCEL = colored('pyccel', attrs=['bold'])

    def make_symbol(s):
        return colored(str(s), attrs=['bold'])
except:
    ERROR = 'error'
    INTERNAL = 'internal'
    WARNING = 'warning'
    FATAL = 'fatal'

    PYCCEL = 'pyccel'

    def make_symbol(s):
        return str(s)
# ...

_severity_registry = {'error': ERROR,
                      'internal': INTERNAL,
                      'fatal': FATAL,
                      'warning': WARNING}


[docs]def make_symbol(s): return str(s)
[docs]class PyccelError(Exception): def __init__(self, message, errors=''): # Call the base class constructor with the parameters it needs super(PyccelError, self).__init__(message) # Now for your custom code... self.errors = errors
[docs]class PyccelSyntaxError(Exception): pass
[docs]class PyccelSemanticError(Exception): pass
[docs]class PyccelCodegenError(Exception): pass
[docs]class ErrorInfo: """Representation of a single error message.""" def __init__(self, filename, line=None, column=None, severity=None, message='', symbol=None, blocker=False): # The source file that was the source of this error. self.filename = filename # The line number related to this error within file. self.line = line # The column number related to this error with file. if isinstance(column, (tuple, list)): column = '-'.join(str(i) for i in column) self.column = column # Either 'error', 'fatal', or 'warning'. self.severity = severity # The error message. self.message = message # Symbol associated to the message self.symbol = symbol # If True, we should halt build after the file that generated this error. self.blocker = blocker or (severity == 'fatal') def __str__(self): pattern = '|{severity}' text = pattern.format(severity=_severity_registry[self.severity]) if self.line: if not self.column: text = '{text}: {line}'.format(text=text, line=self.line) else: text = '{text}: [{line},{column}]'.format(text=text, line=self.line, column=self.column) text = '{text}| {msg}'.format(text=text, msg=self.message) if self.symbol: symbol = make_symbol(self.symbol) text = '{text} ({symbol})'.format(text=text, symbol=symbol) return text
def _singleton(cls): """ A Class representing a singleton. Python does not offer this pattern. """ instances = {} def getinstance(): if cls not in instances: instances[cls] = cls() # Line 5 return instances[cls] return getinstance
[docs]@_singleton class ErrorsMode: """Developper or User mode. pyccel command line will set it. """ def __init__(self): self._mode = 'user' @property def value(self): return self._mode def set_mode(self, mode): assert(mode in ['user', 'developer']) self._mode = mode
[docs]@_singleton class Errors: """Container for compile errors. """ def __init__(self): self.error_info_map = None self._target = None self._parser_stage = None self._mode = ErrorsMode().value self.initialize() @property def parser_stage(self): return self._parser_stage @property def target(self): return self._target @property def mode(self): return self._mode def initialize(self): self.error_info_map = OrderedDict() self._target = {} self._target['file'] = None self._target['module'] = None self._target['function'] = None self._target['class'] = None def reset(self): self.initialize() def set_parser_stage(self, stage): assert(stage in ['syntax', 'semantic', 'codegen']) self._parser_stage = stage def set_target(self, target, kind): assert(kind in ['file', 'module', 'function', 'class']) self._target[kind] = target def unset_target(self, kind): assert(kind in ['file', 'module', 'function', 'class']) self._target[kind] = None def reset_target(self): """.""" self._target = {} self._target['file'] = None self._target['module'] = None self._target['function'] = None self._target['class'] = None def report(self, message, line = None, column = None, bounding_box = None, blocker = False, severity = 'error', symbol = None, filename = None, verbose = False): """Report message at the given line using the current error context. stage: 'syntax', 'semantic' or 'codegen' """ # filter internal errors if (self.mode == 'user') and (severity == 'internal'): return if filename is None: filename = self.target['file'] # TODO improve. it is assumed here that tl and br have the same line if bounding_box: tl = bounding_box.top_left br = bounding_box.bottom_right line = tl.line column = (tl.column, br.column) info = ErrorInfo(filename, line=line, column=column, severity=severity, message=message, symbol=symbol, blocker=blocker) if verbose: print(info) if blocker: # we first print all messages self.check() print(info) raise SystemExit(0) self.add_error_info(info) def _add_error_info(self, file, info): if file not in self.error_info_map: self.error_info_map[file] = [] self.error_info_map[file].append(info) def add_error_info(self, info): self._add_error_info(info.filename, info) def num_messages(self): """Return the number of generated messages.""" return sum(len(x) for x in self.error_info_map.values()) def is_errors(self): """Are there any generated errors?""" return bool(self.error_info_map) def is_blockers(self): """Are the any errors that are blockers?""" return any(err for errs in self.error_info_map.values() for err in errs if err.blocker) def blocker_filename(self): """Return the file with a blocking error, or None if not possible.""" for errs in self.error_info_map.values(): for err in errs: if err.blocker: return err.filename return None def format_messages(self, error_info): """Return a string list that represents the error messages. Use a form suitable for displaying to the user. """ pass def check(self): """.""" if self.num_messages() > 0: print(self.__str__()) def __str__(self): print_path = (len(self.error_info_map.keys()) > 1) text = '{}:'.format(PYCCEL) if self.parser_stage: text = '{text} [{stage}] \n'.format(text=text, stage=self.parser_stage) for path in self.error_info_map.keys(): errors = self.error_info_map[path] if print_path: text += ' filename :: {path}\n'.format(path=path) for err in errors: text += ' ' + str(err) + '\n' return text
if __name__ == '__main__': from pyccel.parser.messages import NO_RETURN_VALUE_EXPECTED from pyccel.parser.messages import INCOMPATIBLE_RETURN_VALUE_TYPE from pyccel.parser.messages import UNDEFINED_VARIABLE errors = Errors() errors.set_parser_stage('semantic') errors.set_target('script.py', 'file') errors.report(NO_RETURN_VALUE_EXPECTED, severity='warning', line=24) errors.set_target('make_knots', 'function') errors.report(INCOMPATIBLE_RETURN_VALUE_TYPE, symbol='y', severity='error', line=34, column=17) errors.unset_target('function') errors.check() errors.set_target('eval_bsplines', 'function') errors.report(UNDEFINED_VARIABLE, symbol='x', severity='error', blocker=True) errors.unset_target('function')