board_inspector: refactor tree visitors and transformers

Tree visitors usually have a fixed direction (either top-down or bottom-up)
and invoking a visitor with a wrong direction typically leads to unintended
behavior. However, the current implementation exposes both `visit_topdown`
and `visit_bottomup` methods to users, allowing callers to invoke the
visitors in an undesigned way. The same issue exists in the implementation
of transformers.

This patch refactors the base classes of visitors and transformers so that
they require an explicit direction from their sub-classes to
initialize. Callers of the visitors and transformers are now expected to
invoke the `visit` or `transform` methods without assuming the correct
direction of the visitor or transformer. The original `visit_topdown` or
`visit_bottomup` methods (or their transformer counterparts) are now
used to initialize the `visit` method and can be used by the subclasses in
case those subclasses visits the tree in a customized manner.

Tracked-On: #6287
Signed-off-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
Junjie Mao 2021-07-21 09:46:54 +08:00 committed by wenlingz
parent 55554e7d56
commit e91ace7341
4 changed files with 54 additions and 31 deletions

View File

@ -8,7 +8,7 @@ import logging
from . import grammar from . import grammar
from .context import * from .context import *
from .exception import * from .exception import *
from .tree import Tree, Transformer from .tree import Tree, Transformer, Direction
class Factory: class Factory:
@staticmethod @staticmethod
@ -406,7 +406,7 @@ class OptionFactory(Factory):
class DeferredExpansion(Transformer): class DeferredExpansion(Transformer):
def __init__(self, context): def __init__(self, context):
super().__init__() super().__init__(Direction.TOPDOWN)
self.context = context self.context = context
nodes = ["DefScope", "DefDevice", "DefMethod", "DefPowerRes", "DefProcessor", "DefThermalZone", nodes = ["DefScope", "DefDevice", "DefMethod", "DefPowerRes", "DefProcessor", "DefThermalZone",

View File

@ -3,6 +3,7 @@
# SPDX-License-Identifier: BSD-3-Clause # SPDX-License-Identifier: BSD-3-Clause
# #
from enum import Enum
from copy import copy from copy import copy
from . import grammar from . import grammar
@ -44,38 +45,54 @@ class Tree:
setattr(self, elem, self.children[i]) setattr(self, elem, self.children[i])
i += 1 i += 1
class Visitor: class Direction(Enum):
def __init__(self): TOPDOWN = 1
self.depth = 0 BOTTOMUP = 2
CUSTOMIZED = 3
def __visit(self, tree): class Visitor:
def __init__(self, direction):
self.depth = 0
if direction == Direction.TOPDOWN:
self.visit = self._visit_topdown
elif direction == Direction.BOTTOMUP:
self.visit = self._visit_bottomup
def __visit_node(self, tree):
fn = getattr(self, tree.label, None) fn = getattr(self, tree.label, None)
if not fn: if not fn:
fn = getattr(self, "default", None) fn = getattr(self, "default", None)
if fn: if fn:
fn(tree) fn(tree)
def visit_topdown(self, tree): def _visit_topdown(self, tree):
self.__visit(tree) self.__visit_node(tree)
self.depth += 1 self.depth += 1
for child in tree.children: for child in tree.children:
if isinstance(child, Tree): if isinstance(child, Tree):
self.visit_topdown(child) self.visit(child)
self.depth -= 1 self.depth -= 1
def visit_bottomup(self, tree): def _visit_bottomup(self, tree):
self.depth += 1 self.depth += 1
for child in tree.children: for child in tree.children:
if isinstance(child, Tree): if isinstance(child, Tree):
self.visit_bottomup(child) self.visit(child)
self.depth -= 1 self.depth -= 1
self.__visit(tree) self.__visit_node(tree)
def visit(self, tree):
raise NotImplementedError
class Transformer: class Transformer:
def __init__(self): def __init__(self, direction):
self.depth = 0 self.depth = 0
if direction == Direction.TOPDOWN:
self.transform = self._transform_topdown
elif direction == Direction.BOTTOMUP:
self.transform = self._transform_bottomup
def __transform(self, tree): def __transform_node(self, tree):
fn = getattr(self, tree.label, None) fn = getattr(self, tree.label, None)
if not fn: if not fn:
fn = getattr(self, "default", None) fn = getattr(self, "default", None)
@ -84,22 +101,25 @@ class Transformer:
else: else:
return tree return tree
def transform_topdown(self, tree): def _transform_topdown(self, tree):
new_tree = self.__transform(tree) new_tree = self.__transform_node(tree)
self.depth += 1 self.depth += 1
for i, child in enumerate(tree.children): for i, child in enumerate(tree.children):
if isinstance(child, Tree): if isinstance(child, Tree):
tree.children[i] = self.transform_topdown(child) tree.children[i] = self.transform(child)
self.depth -= 1 self.depth -= 1
return new_tree return new_tree
def transform_bottomup(self, tree): def _transform_bottomup(self, tree):
self.depth += 1 self.depth += 1
for i, child in enumerate(tree.children): for i, child in enumerate(tree.children):
if isinstance(child, Tree): if isinstance(child, Tree):
tree.children[i] = self.transform_bottomup(child) tree.children[i] = self.transform(child)
self.depth -= 1 self.depth -= 1
return self.__transform(tree) return self.__transform_node(tree)
def transform(self, tree):
raise NotImplementedError
class Interpreter: class Interpreter:
def __init__(self, context): def __init__(self, context):

View File

@ -5,7 +5,7 @@
import sys import sys
from .tree import Visitor from .tree import Visitor, Direction
from . import grammar from . import grammar
class PrintLayoutVisitor(Visitor): class PrintLayoutVisitor(Visitor):
@ -13,6 +13,9 @@ class PrintLayoutVisitor(Visitor):
def __is_printable(s): def __is_printable(s):
return all(ord(c) >= 0x20 and ord(c) < 0xFF for c in s) return all(ord(c) >= 0x20 and ord(c) < 0xFF for c in s)
def __init__(self):
super().__init__(Direction.TOPDOWN)
def default(self, tree): def default(self, tree):
indent = " " * self.depth indent = " " * self.depth
print(f"{indent}{tree.label}", end="") print(f"{indent}{tree.label}", end="")
@ -30,7 +33,7 @@ class PrintLayoutVisitor(Visitor):
class ConditionallyUnregisterSymbolVisitor(Visitor): class ConditionallyUnregisterSymbolVisitor(Visitor):
def __init__(self, interpreter): def __init__(self, interpreter):
super().__init__() super().__init__(Direction.CUSTOMIZED)
self.context = interpreter.context self.context = interpreter.context
self.interpreter = interpreter self.interpreter = interpreter
self.conditionally_hidden = False self.conditionally_hidden = False
@ -48,7 +51,7 @@ class ConditionallyUnregisterSymbolVisitor(Visitor):
self.context.unregister_object(realpath) self.context.unregister_object(realpath)
return f return f
def visit_topdown(self, tree): def visit(self, tree):
if not self.conditionally_hidden and tree.label == "DefIfElse": if not self.conditionally_hidden and tree.label == "DefIfElse":
self.context.change_scope(tree.scope) self.context.change_scope(tree.scope)
cond = self.interpreter.interpret(tree.children[1]).get() cond = self.interpreter.interpret(tree.children[1]).get()
@ -57,25 +60,25 @@ class ConditionallyUnregisterSymbolVisitor(Visitor):
self.depth += 1 self.depth += 1
if cond: if cond:
if hasattr(tree, "TermList"): if hasattr(tree, "TermList"):
self.visit_topdown(tree.TermList) self.visit(tree.TermList)
if hasattr(tree, "DefElse") and tree.DefElse: if hasattr(tree, "DefElse") and tree.DefElse:
self.conditionally_hidden = True self.conditionally_hidden = True
self.visit_topdown(tree.DefElse) self.visit(tree.DefElse)
self.conditionally_hidden = False self.conditionally_hidden = False
else: else:
if hasattr(tree, "TermList"): if hasattr(tree, "TermList"):
self.conditionally_hidden = True self.conditionally_hidden = True
self.visit_topdown(tree.TermList) self.visit(tree.TermList)
self.conditionally_hidden = False self.conditionally_hidden = False
if hasattr(tree, "DefElse") and tree.DefElse: if hasattr(tree, "DefElse") and tree.DefElse:
self.visit_topdown(tree.DefElse) self.visit(tree.DefElse)
self.depth -= 1 self.depth -= 1
elif tree.label not in ["DefMethod"]: elif tree.label not in ["DefMethod"]:
super().visit_topdown(tree) self._visit_topdown(tree)
class GenerateBinaryVisitor(Visitor): class GenerateBinaryVisitor(Visitor):
def __init__(self): def __init__(self):
super().__init__() super().__init__(Direction.BOTTOMUP)
@staticmethod @staticmethod
def __format_length(length): def __format_length(length):

View File

@ -27,7 +27,7 @@ def DSDT(val):
context.switch_stream(t) context.switch_stream(t)
tree = Tree() tree = Tree()
AMLCode.parse(context, tree) AMLCode.parse(context, tree)
tree = DeferredExpansion(context).transform_topdown(tree) tree = DeferredExpansion(context).transform(tree)
context.trees[os.path.basename(t)] = tree context.trees[os.path.basename(t)] = tree
except Exception as e: except Exception as e:
context.current_stream.dump() context.current_stream.dump()
@ -36,5 +36,5 @@ def DSDT(val):
context.skip_external_on_lookup() context.skip_external_on_lookup()
visitor = ConditionallyUnregisterSymbolVisitor(ConcreteInterpreter(context)) visitor = ConditionallyUnregisterSymbolVisitor(ConcreteInterpreter(context))
for tree in context.trees.values(): for tree in context.trees.values():
visitor.visit_topdown(tree) visitor.visit(tree)
return context return context