Exemplo n.º 1
0
class CTraverser(c_ast.NodeVisitor):

     top_level = '__file__' # The fake name for containing-function of 
                            # top level function calls
     def __init__(self):
          self._data = ParserData(self.top_level)

     def visit_FuncDef(self, node):
          # For now, we assume that function name is unique (i.e. no overloading),
          # so ignore param types and return type
          self._data.parse_func(node.decl.name, self.generic_visit, node)

     def visit_FuncCall(self, node):
          name = node.name
          if isinstance(name, c_ast.ID):
               self._data.func_called(node.name.name)
          else:
               # The next most common case is struct reference, as e.g. for a stored callback.
               # So isinstance(name, c_ast.StructRef) == True, and `name` has two c_ast.ID
               # children (like a->b). To try and handle more general cases than just a
               # StructRef, we find the textually-latest c_ast.ID node -- i.e. the one
               # furthest down the AST. This should be the text directly left of the
               # opening paren of the function call. Delegate to the helper function for clarity.
               # For example: if our call looks like:
               #
               # val = structptr1->child1.callback(args);
               #
               # Then 'structptr1', 'child1', and 'callback' will all appear as c_ast.ID nodes
               # somewhere in `name.children()`. We want the textually latest, i.e. rightmost
               # name -- 'callback' -- and use that as the "name" of the function.
               retval = self._find_furthest_node(name, c_ast.ID)
               if retval is None:
                    raise ValueError('Got a function call with no ID node')
               self._data.func_called(retval.name)

          self.generic_visit(node)

     def _find_furthest_node(self, startnode, cls):
          for attr, value in reversed(startnode.children()):
               if isinstance(value, cls):
                    return value
               else:
                    self._find_furthest_node(value, cls)
          return None

     def result(self):
          '''After parsing is complete, call this to get the function->subcalls
          dictionary and nested functions set (as a tuple).'''
          return self._data.result()
Exemplo n.º 2
0
class PythonTraverser(ast.NodeVisitor):

     top_level = '__module__' # The fake name for containing-function of 
                            # top level function calls
     def __init__(self):
          self._data = ParserData(self.top_level)

     def _generic_visit(self, thing): 
          # Like super's visit, except also accepts the list "nodes" as well
          # Alternately, super().generic_visit is equivalent to:
          # def generic_visit(self, node):
          #      for field, value in iter_fields(node):
          #           self._generic_visit(value)
          if isinstance(thing, list):
               for thng in thing:
                    if isinstance(thng, ast.AST):
                         self.visit(thng)
          elif isinstance(thing, ast.AST):
               self.visit(thing)

     def visit_FunctionDef(self, node):
          self._data.parse_func(node.name, self._generic_visit, node.body)

     def visit_Call(self, node):
          # A function's "name" need not be an identifier, e.g. 
          # for i in mylist:
          #    mylist[i](myargs, mykwargs)
          # For now, if this is the case, then ignore this node
          #print('visiting call node inside function', self.current_func)
          if isinstance(node.func, ast.Name): # simple call by identifier
               self._data.func_called(node.func.id)
               #print(self.current_func, node.func.id)
          elif isinstance(node.func, ast.Attribute): # call by attribute
               self._data.func_called(node.func.attr)
               # For now, we ignore whatever object(s) whose attr is the func
               # ignore(node.func.value)            
          self.generic_visit(node)

     def result(self):
          '''After parsing is complete, call this to get the function->subcalls
          dictionary and nested functions set (as a tuple).'''
          return self._data.result()
Exemplo n.º 3
0
 def __init__(self):
      self._data = ParserData(self.top_level)