131 lines · python
1# DExTer : Debugging Experience Tester2# ~~~~~~ ~ ~~ ~ ~~3#4# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5# See https://llvm.org/LICENSE.txt for license information.6# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7"""Set of data classes for representing the complete debug program state at a8fixed point in execution.9"""10 11import os12 13from collections import OrderedDict14from pathlib import PurePath15from typing import List16 17 18class SourceLocation:19 def __init__(self, path: str = None, lineno: int = None, column: int = None):20 if path:21 path = os.path.normcase(path)22 self.path = path23 self.lineno = lineno24 self.column = column25 26 def __str__(self):27 return "{}({}:{})".format(self.path, self.lineno, self.column)28 29 def match(self, other) -> bool:30 """Returns true iff all the properties that appear in `self` have the31 same value in `other`, but not necessarily vice versa.32 """33 if not other or not isinstance(other, SourceLocation):34 return False35 36 if self.path and (37 other.path is None or (PurePath(self.path) != PurePath(other.path))38 ):39 return False40 41 if self.lineno and (self.lineno != other.lineno):42 return False43 44 if self.column and (self.column != other.column):45 return False46 47 return True48 49 50class StackFrame:51 def __init__(52 self,53 function: str = None,54 is_inlined: bool = None,55 location: SourceLocation = None,56 watches: OrderedDict = None,57 ):58 if watches is None:59 watches = {}60 61 self.function = function62 self.is_inlined = is_inlined63 self.location = location64 self.watches = watches65 66 def __str__(self):67 return "{}{}: {} | {}".format(68 self.function,69 " (inlined)" if self.is_inlined else "",70 self.location,71 {k: str(self.watches[k]) for k in self.watches},72 )73 74 def match(self, other) -> bool:75 """Returns true iff all the properties that appear in `self` have the76 same value in `other`, but not necessarily vice versa.77 """78 if not other or not isinstance(other, StackFrame):79 return False80 81 if self.location and not self.location.match(other.location):82 return False83 84 if self.watches:85 for name in iter(self.watches):86 try:87 if isinstance(self.watches[name], dict):88 for attr in iter(self.watches[name]):89 if (90 getattr(other.watches[name], attr, None)91 != self.watches[name][attr]92 ):93 return False94 else:95 if other.watches[name].value != self.watches[name]:96 return False97 except KeyError:98 return False99 100 return True101 102 103class ProgramState:104 def __init__(self, frames: List[StackFrame] = None):105 self.frames = frames106 107 def __str__(self):108 return "\n".join(109 map(110 lambda enum: "Frame {}: {}".format(enum[0], enum[1]),111 enumerate(self.frames),112 )113 )114 115 def match(self, other) -> bool:116 """Returns true iff all the properties that appear in `self` have the117 same value in `other`, but not necessarily vice versa.118 """119 if not other or not isinstance(other, ProgramState):120 return False121 122 if self.frames:123 for idx, frame in enumerate(self.frames):124 try:125 if not frame.match(other.frames[idx]):126 return False127 except (IndexError, KeyError):128 return False129 130 return True131