from core.ast.nodes import GenericNodeConcept, NodeConcept from core.builtin_concepts import ListConcept class ConceptNodeVisitor: """ Base class to visit NodeConcept It is insolently inspired by python AST.Visitor class """ def visit(self, node): """Visit a node.""" name = node.node_type if isinstance(node, GenericNodeConcept) else node.name name = str(name).capitalize() method = 'visit_' + name visitor = getattr(self, method, self.generic_visit) return visitor(node) def generic_visit(self, node): """Called if no explicit visitor function exists for a node.""" for field, value in iter_props(node): if isinstance(value, ListConcept): for item in value: if isinstance(item, NodeConcept): self.visit(item) elif isinstance(value, NodeConcept): self.visit(value) def visit_Constant(self, node): value = node.get_prop("value") type_name = _const_node_type_names.get(type(value)) if type_name is None: for cls, name in _const_node_type_names.items(): if isinstance(value, cls): type_name = name break if type_name is not None: method = 'visit_' + type_name try: visitor = getattr(self, method) except AttributeError: pass else: import warnings warnings.warn(f"{method} is deprecated; add visit_Constant", PendingDeprecationWarning, 2) return visitor(node) return self.generic_visit(node) class UnreferencedNamesVisitor(ConceptNodeVisitor): def __init__(self, sheerka): self.names = set() self.sheerka = sheerka def visit_Name(self, node): parents = get_parents(node) if ("For", "target") in parents: # variable used by the 'for' iteration return if ("Call", "func") in parents: # name of the function return if ("Assign", "targets") in parents: # variable which is assigned return if self.can_be_discarded(self.sheerka.value(node), parents): return self.names.add(self.sheerka.value(node)) def can_be_discarded(self, variable_name, parents): for node in (parent.node for parent in parents): if node is None: return False if node.get_node_type() == "For" and self.sheerka.value(node.get_prop("target")) == variable_name: # variable used by the loop return True if node.get_node_type() == "FunctionDef": # variable defined as a function parameter args = node.get_prop("args") args_values = list(self.sheerka.values(args.get_prop("args"))) if variable_name in args_values: return True return False class ExtractPredicateVisitor(ConceptNodeVisitor): def __init__(self, variable_name): self.predicates = [] self.variable_name = variable_name def get_parents(node): if node.parent is None: return [] res = [] while True: if node.parent is None: break res.append(node.parent) node = node.parent.node return res def iter_props(node): for p in node.props: yield p, node.props[p].value _const_node_type_names = { bool: 'NameConstant', # should be before int type(None): 'NameConstant', int: 'Num', float: 'Num', complex: 'Num', str: 'Str', bytes: 'Bytes', type(...): 'Ellipsis', }