From 84b7982235332e51ca157e8bbe500a3f1e51910e Mon Sep 17 00:00:00 2001 From: Dmitry Selyutin Date: Wed, 7 Jun 2023 16:16:57 +0300 Subject: [PATCH] insndb: refactor visitors (again) --- src/openpower/insndb/core.py | 72 ++++++++++++++++++++++-------------- src/openpower/insndb/db.py | 61 ++++++++++++++---------------- 2 files changed, 72 insertions(+), 61 deletions(-) diff --git a/src/openpower/insndb/core.py b/src/openpower/insndb/core.py index 042b938d..ddf2564f 100644 --- a/src/openpower/insndb/core.py +++ b/src/openpower/insndb/core.py @@ -57,33 +57,45 @@ from openpower.decoder.pseudo.pagereader import ISA as _ISA class Node: - @property - def subnodes(self): - yield from () + def visit(self, handler, matcher, depth): + if matcher(node=self, depth=depth): + with handler(node=self, depth=depth): + pass class Visitor: - @_contextlib.contextmanager - def Node(self, node, depth): - yield node - for subnode in node.subnodes: - manager = subnode.__class__.__name__ - manager = getattr(self, manager, self.Node) - with manager(node=subnode, depth=(depth + 1)): - pass + def __init__(self, **parameters): + self.__parameters = _types.MappingProxyType(parameters) + return super().__init__() - def __getattr__(self, attr): - return self.Node + 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): - manager = node.__class__.__name__ - manager = getattr(self, manager, self.Node) - return manager(node=node, depth=depth) + method = node.__class__.__name__ + method = getattr(self, method, self.Node) + return method(node=node, depth=depth) -def visit(visitor, node): - with visitor(node=node, depth=0): - pass +class Matcher(Visitor): + def Node(self, node, depth): + return True + + +class Handler(Visitor): + @_contextlib.contextmanager + def Node(self, node, depth): + yield node + + +def visit(node, handler, matcher=Matcher()): + node.visit(handler=handler, matcher=matcher, depth=0) @_functools.total_ordering @@ -850,10 +862,6 @@ class Extra(Node): seltype: _SelType idx: _SVExtra - def visit(self, visitor): - with visitor.extra(extra=self) as extra: - pass - @_functools.total_ordering @_dataclasses.dataclass(eq=True, frozen=True) @@ -865,10 +873,13 @@ class Record(Node): mdwn: MarkdownRecord svp64: SVP64Record = None - @property - def subnodes(self): - for (name, fields) in self.extras.items(): - yield Extra(name=name, **fields) + 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 extras(self): @@ -3751,6 +3762,13 @@ 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: diff --git a/src/openpower/insndb/db.py b/src/openpower/insndb/db.py index 73f4abe2..522d9650 100644 --- a/src/openpower/insndb/db.py +++ b/src/openpower/insndb/db.py @@ -8,7 +8,8 @@ from openpower.decoder.power_enums import ( ) from openpower.insndb.core import ( Database, - Visitor, + Handler, + Matcher, visit, ) @@ -36,37 +37,23 @@ class SVP64Instruction(Instruction): return self -class BaseVisitor(Visitor): - def __init__(self, **arguments): - self.__arguments = types.MappingProxyType(arguments) - return super().__init__() - - def __getitem__(self, argument): - return self.__arguments[argument] - - -class ListVisitor(BaseVisitor): +class ListHandler(Handler): @contextlib.contextmanager def Record(self, node, depth): print(node.name) yield node -class InstructionVisitor(BaseVisitor): - @contextlib.contextmanager - def Database(self, node, depth): - yield node - for subnode in node.subnodes: - if subnode.name == self["insn"]: - with self(node=subnode, depth=(depth + 1)): - pass +class InstructionMatcher(Matcher): + def Record(self, node, depth): + return (node.name == self["insn"]) -class SVP64InstructionVisitor(InstructionVisitor): +class SVP64InstructionMatcher(InstructionMatcher): pass -class OpcodesVisitor(InstructionVisitor): +class OpcodesHandler(Handler): @contextlib.contextmanager def Record(self, node, depth): for opcode in node.opcodes: @@ -74,7 +61,7 @@ class OpcodesVisitor(InstructionVisitor): yield node -class OperandsVisitor(InstructionVisitor): +class OperandsHandler(Handler): @contextlib.contextmanager def Record(self, node, depth): for operand in node.dynamic_operands: @@ -86,7 +73,7 @@ class OperandsVisitor(InstructionVisitor): yield node -class PCodeVisitor(InstructionVisitor): +class PCodeHandler(Handler): @contextlib.contextmanager def Record(self, node, depth): for line in node.pcode: @@ -94,7 +81,7 @@ class PCodeVisitor(InstructionVisitor): yield node -class ExtrasVisitor(SVP64InstructionVisitor): +class ExtrasHandler(Handler): @contextlib.contextmanager def Extra(self, node, depth): print(node.name) @@ -108,23 +95,28 @@ class ExtrasVisitor(SVP64InstructionVisitor): def main(): commands = { "list": ( - ListVisitor, + ListHandler, + Matcher, "list available instructions", ), "opcodes": ( - OpcodesVisitor, + OpcodesHandler, + InstructionMatcher, "print instruction opcodes", ), "operands": ( - OperandsVisitor, + OperandsHandler, + InstructionMatcher, "print instruction operands", ), "pcode": ( - PCodeVisitor, + PCodeHandler, + InstructionMatcher, "print instruction pseudocode", ), "extras": ( - ExtrasVisitor, + ExtrasHandler, + InstructionMatcher, "print instruction extras (SVP64)", ), } @@ -136,10 +128,10 @@ def main(): default=False) main_subparser = main_parser.add_subparsers(dest="command", required=True) - for (command, (visitor, help)) in commands.items(): + for (command, (handler, matcher, help)) in commands.items(): parser = main_subparser.add_parser(command, help=help) - if issubclass(visitor, InstructionVisitor): - if issubclass(visitor, SVP64InstructionVisitor): + if issubclass(matcher, InstructionMatcher): + if issubclass(matcher, SVP64InstructionMatcher): arg_cls = SVP64Instruction else: arg_cls = Instruction @@ -151,10 +143,11 @@ def main(): log = args.pop("log") if not log: os.environ["SILENCELOG"] = "true" - visitor = commands[command][0](**args) + handler = commands[command][0](**args) + matcher = commands[command][1](**args) db = Database(find_wiki_dir()) - visit(visitor=visitor, node=db) + visit(handler=handler, matcher=matcher, node=db) if __name__ == "__main__": -- 2.30.2