"""Defines source maps: dictionaries that map lines in generated source to debug information.""" class SourceMapBase(object): """Define a base class for source maps: objects that can convert line numbers to debug information.""" def get_debug_info(self, line_number): """Gets the debug information for the given line number, or None if no debug info was found.""" raise NotImplementedError() class SourceMap(SourceMapBase): """A source map, which converts generated source lines to debug information.""" def __init__(self): SourceMapBase.__init__(self) self.lines = {} def map_line(self, line_number, debug_info): """Assigns the given debug information to the given line.""" self.lines[line_number] = debug_info def get_debug_info(self, line_number): """Gets the debug information for the given line number, or None if no debug info was found.""" if line_number in self.lines: return self.lines[line_number] else: return None def __str__(self): return '\n'.join( ['%d: %s' % pair for pair in sorted(self.lines.items(), key=lambda (key, _): key)]) class SourceMapBuilder(object): """A type of object that makes it easy to build source maps for hierarchical instructions.""" def __init__(self, initial_line_number=0): self.source_map = SourceMap() self.debug_info_stack = [] self.line_number = initial_line_number - 1 def push_debug_info(self, debug_info): """Informs the source map that subsequent lines of code will have the given debug information associated with them.""" self.debug_info_stack.append(debug_info) def pop_debug_info(self): """Informs the source map that the debug information that was pushed last should be discarded in favor of the debug information that was pushed onto the stack just prior to it.""" return self.debug_info_stack.pop() def append_line(self): """Has the source map builder increment its line number counter, and assigns the debug information that is at the top of the debug information stack to that line.""" self.line_number += 1 if len(self.debug_info_stack) > 0: self.source_map.map_line(self.line_number, self.debug_info_stack[-1]) def __str__(self): return str(self.source_map) class ManualSourceMap(SourceMapBase): """A source map whose debug information can be set and reset. Line numbers are ignored.""" def __init__(self): SourceMapBase.__init__(self) self.debug_information = None def get_debug_info(self, _): """Gets the debug information for the given line number, or None if no debug info was found.""" return self.debug_information def __str__(self): return str(self.debug_information) class InterpreterSourceMap(SourceMapBase): """A source map that extracts debug information from the reference interpreter's debug info stack. Line numbers are ignored.""" def __init__(self, kernel, task_name, stack_index): SourceMapBase.__init__(self) self.kernel = kernel self.task_name = task_name self.stack_index = stack_index def get_debug_info(self, _): """Gets the debug information for the given line number, or None if no debug info was found.""" return self.kernel.debug_info[self.task_name][self.stack_index] def __str__(self): return str(self.get_debug_info(None))