From 2adf0427aa4af779780e90996626a47a8f02b76e Mon Sep 17 00:00:00 2001 From: Dmitry Selyutin Date: Wed, 7 Jun 2023 22:57:16 +0300 Subject: [PATCH] insndb: decouple visitors and walking --- src/openpower/insndb/core.py | 71 ++++++++++--------------------- src/openpower/insndb/db.py | 82 ++++++++++++++++++++---------------- 2 files changed, 68 insertions(+), 85 deletions(-) diff --git a/src/openpower/insndb/core.py b/src/openpower/insndb/core.py index ddf2564f..2876e787 100644 --- a/src/openpower/insndb/core.py +++ b/src/openpower/insndb/core.py @@ -56,46 +56,32 @@ from openpower.decoder.power_fields import ( from openpower.decoder.pseudo.pagereader import ISA as _ISA -class Node: - def visit(self, handler, matcher, depth): - if matcher(node=self, depth=depth): - with handler(node=self, depth=depth): - pass - - class Visitor: - def __init__(self, **parameters): - self.__parameters = _types.MappingProxyType(parameters) - return super().__init__() - - def __contains__(self, key): - return self.__parameters.__contains__(key) - - def __getitem__(self, key): - return self.__parameters.__getitem__(key) - - def Node(self, node, depth): - raise NotImplementedError() - - def __call__(self, node, depth): + def __call__(self, node): method = node.__class__.__name__ method = getattr(self, method, self.Node) - return method(node=node, depth=depth) - + return method(node=node) -class Matcher(Visitor): - def Node(self, node, depth): - return True - - -class Handler(Visitor): @_contextlib.contextmanager - def Node(self, node, depth): + def Node(self, node): + for subnode in node.subnodes: + with self(subnode): + pass yield node -def visit(node, handler, matcher=Matcher()): - node.visit(handler=handler, matcher=matcher, depth=0) +class Node: + @property + def subnodes(self): + yield from () + + +def walk(root): + nodes = _collections.deque([root]) + while nodes: + node = nodes.popleft() + nodes.extend(node.subnodes) + yield node @_functools.total_ordering @@ -873,13 +859,10 @@ class Record(Node): mdwn: MarkdownRecord svp64: SVP64Record = None - def visit(self, handler, matcher, depth): - if matcher(node=self, depth=depth): - with handler(node=self, depth=depth): - for (name, fields) in self.extras.items(): - extra = Extra(name=name, **fields) - extra.visit(depth=(depth + 1), - handler=handler, matcher=matcher) + @property + def subnodes(self): + for (name, fields) in self.extras.items(): + yield Extra(name=name, **fields) @property def extras(self): @@ -3762,17 +3745,9 @@ class Database(Node): return super().__init__() - def visit(self, handler, matcher, depth): - if matcher(node=self, depth=depth): - with handler(node=self, depth=depth): - for record in self: - record.visit(depth=(depth + 1), - handler=handler, matcher=matcher) - @property def subnodes(self): - for record in self.__db: - yield record + yield from self def __repr__(self): return repr(self.__db) diff --git a/src/openpower/insndb/db.py b/src/openpower/insndb/db.py index 522d9650..748f60ab 100644 --- a/src/openpower/insndb/db.py +++ b/src/openpower/insndb/db.py @@ -8,9 +8,7 @@ from openpower.decoder.power_enums import ( ) from openpower.insndb.core import ( Database, - Handler, - Matcher, - visit, + Visitor, ) @@ -37,33 +35,40 @@ class SVP64Instruction(Instruction): return self -class ListHandler(Handler): +class RecordNameVisitor(Visitor): + def __init__(self, name): + self.__name = name + self.__records = set() + return super().__init__() + @contextlib.contextmanager - def Record(self, node, depth): - print(node.name) + def Record(self, node): + if node.name == self.__name: + self.__records.add(node) yield node - -class InstructionMatcher(Matcher): - def Record(self, node, depth): - return (node.name == self["insn"]) + def __iter__(self): + yield from self.__records -class SVP64InstructionMatcher(InstructionMatcher): - pass +class ListVisitor(Visitor): + @contextlib.contextmanager + def Record(self, node): + print(node.name) + yield node -class OpcodesHandler(Handler): +class OpcodesVisitor(Visitor): @contextlib.contextmanager - def Record(self, node, depth): + def Record(self, node): for opcode in node.opcodes: print(opcode) yield node -class OperandsHandler(Handler): +class OperandsVisitor(Visitor): @contextlib.contextmanager - def Record(self, node, depth): + def Record(self, node): for operand in node.dynamic_operands: print(operand.name, ",".join(map(str, operand.span))) for operand in node.static_operands: @@ -73,17 +78,17 @@ class OperandsHandler(Handler): yield node -class PCodeHandler(Handler): +class PCodeVisitor(Visitor): @contextlib.contextmanager - def Record(self, node, depth): + def Record(self, node): for line in node.pcode: print(line) yield node -class ExtrasHandler(Handler): +class ExtrasVisitor(Visitor): @contextlib.contextmanager - def Extra(self, node, depth): + def Extra(self, node): print(node.name) print(" sel", node.sel) print(" reg", node.reg) @@ -95,28 +100,23 @@ class ExtrasHandler(Handler): def main(): commands = { "list": ( - ListHandler, - Matcher, + ListVisitor, "list available instructions", ), "opcodes": ( - OpcodesHandler, - InstructionMatcher, + OpcodesVisitor, "print instruction opcodes", ), "operands": ( - OperandsHandler, - InstructionMatcher, + OperandsVisitor, "print instruction operands", ), "pcode": ( - PCodeHandler, - InstructionMatcher, + PCodeVisitor, "print instruction pseudocode", ), "extras": ( - ExtrasHandler, - InstructionMatcher, + ExtrasVisitor, "print instruction extras (SVP64)", ), } @@ -128,10 +128,10 @@ def main(): default=False) main_subparser = main_parser.add_subparsers(dest="command", required=True) - for (command, (handler, matcher, help)) in commands.items(): - parser = main_subparser.add_parser(command, help=help) - if issubclass(matcher, InstructionMatcher): - if issubclass(matcher, SVP64InstructionMatcher): + for (command, (visitor, helper)) in commands.items(): + parser = main_subparser.add_parser(command, help=helper) + if command not in ("list",): + if command in ("extras",): arg_cls = SVP64Instruction else: arg_cls = Instruction @@ -143,11 +143,19 @@ def main(): log = args.pop("log") if not log: os.environ["SILENCELOG"] = "true" - handler = commands[command][0](**args) - matcher = commands[command][1](**args) + visitor = commands[command][0]() db = Database(find_wiki_dir()) - visit(handler=handler, matcher=matcher, node=db) + if command in ("list",): + nodes = (db,) + else: + match = RecordNameVisitor(name=args["insn"]) + with match(node=db): + nodes = frozenset(match) + + for node in nodes: + with visitor(node=node): + pass if __name__ == "__main__": -- 2.30.2