| #!/usr/bin/env python | 
 | # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | # Use of this source code is governed by a BSD-style license that can be | 
 | # found in the LICENSE file. | 
 |  | 
 | import sys | 
 |  | 
 | # | 
 | # IDL Node | 
 | # | 
 | # IDL Node defines the IDLAttribute and IDLNode objects which are constructed | 
 | # by the parser as it processes the various 'productions'.  The IDLAttribute | 
 | # objects are assigned to the IDLNode's property dictionary instead of being | 
 | # applied as children of The IDLNodes, so they do not exist in the final tree. | 
 | # The AST of IDLNodes is the output from the parsing state and will be used | 
 | # as the source data by the various generators. | 
 | # | 
 |  | 
 |  | 
 | # | 
 | # CopyToList | 
 | # | 
 | # Takes an input item, list, or None, and returns a new list of that set. | 
 | def CopyToList(item): | 
 |   # If the item is 'Empty' make it an empty list | 
 |   if not item: | 
 |     item = [] | 
 |  | 
 |   # If the item is not a list | 
 |   if type(item) is not type([]): | 
 |     item = [item] | 
 |  | 
 |   # Make a copy we can modify | 
 |   return list(item) | 
 |  | 
 |  | 
 | # IDLSearch | 
 | # | 
 | # A temporary object used by the parsing process to hold an Extended Attribute | 
 | # which will be passed as a child to a standard IDLNode. | 
 | # | 
 | class IDLSearch(object): | 
 |   def __init__(self): | 
 |     self.depth = 0 | 
 |  | 
 |   def Enter(self, node): | 
 |     pass | 
 |  | 
 |   def Exit(self, node): | 
 |     pass | 
 |  | 
 |  | 
 | # IDLAttribute | 
 | # | 
 | # A temporary object used by the parsing process to hold an Extended Attribute | 
 | # which will be passed as a child to a standard IDLNode. | 
 | # | 
 | class IDLAttribute(object): | 
 |   def __init__(self, name, value): | 
 |     self._cls = 'Property' | 
 |     self.name = name | 
 |     self.value = value | 
 |  | 
 |   def __str__(self): | 
 |     return '%s=%s' % (self.name, self.value) | 
 |  | 
 |   def GetClass(self): | 
 |     return self._cls | 
 |  | 
 | # | 
 | # IDLNode | 
 | # | 
 | # This class implements the AST tree, providing the associations between | 
 | # parents and children.  It also contains a namepsace and propertynode to | 
 | # allow for look-ups.  IDLNode is derived from IDLRelease, so it is | 
 | # version aware. | 
 | # | 
 | class IDLNode(object): | 
 |   def __init__(self, cls, filename, lineno, pos, children=None): | 
 |     self._cls = cls | 
 |     self._properties = { | 
 |       'ERRORS' : [], | 
 |       'WARNINGS': [], | 
 |       'FILENAME': filename, | 
 |       'LINENO' : lineno, | 
 |       'POSSITION' : pos, | 
 |     } | 
 |  | 
 |     self._children = [] | 
 |     self._parent = None | 
 |     self.AddChildren(children) | 
 |  | 
 | # | 
 | # | 
 | # | 
 |   # Return a string representation of this node | 
 |   def __str__(self): | 
 |     name = self.GetProperty('NAME','') | 
 |     return '%s(%s)' % (self._cls, name) | 
 |  | 
 |   def GetLogLine(self, msg): | 
 |     filename, lineno = self.GetFileAndLine() | 
 |     return '%s(%d) : %s\n' % (filename, lineno, msg) | 
 |  | 
 |   # Log an error for this object | 
 |   def Error(self, msg): | 
 |     self.GetProperty('ERRORS').append(msg) | 
 |     sys.stderr.write(self.GetLogLine('error: ' + msg)) | 
 |  | 
 |   # Log a warning for this object | 
 |   def Warning(self, msg): | 
 |     self.GetProperty('WARNINGS').append(msg) | 
 |     sys.stdout.write(self.GetLogLine('warning:' + msg)) | 
 |  | 
 |   # Return file and line number for where node was defined | 
 |   def GetFileAndLine(self): | 
 |     return self.GetProperty('FILENAME'), self.GetProperty('LINENO') | 
 |  | 
 |   def GetClass(self): | 
 |     return self._cls | 
 |  | 
 |   def GetName(self): | 
 |     return self.GetProperty('NAME') | 
 |  | 
 |   def GetParent(self): | 
 |     return self._parent | 
 |  | 
 |   def Traverse(self, search, filter_nodes): | 
 |     if self._cls in filter_nodes: | 
 |       return '' | 
 |  | 
 |     search.Enter(self) | 
 |     search.depth += 1 | 
 |     for child in self._children: | 
 |       child.Traverse(search, filter_nodes) | 
 |     search.depth -= 1 | 
 |     search.Exit(self) | 
 |  | 
 |  | 
 |   def Tree(self, filter_nodes=None, accept_props=None): | 
 |     class DumpTreeSearch(IDLSearch): | 
 |       def __init__(self, props): | 
 |         IDLSearch.__init__(self) | 
 |         self.out = [] | 
 |         self.props = props | 
 |  | 
 |       def Enter(self, node): | 
 |         tab = ''.rjust(self.depth * 2) | 
 |         self.out.append(tab + str(node)) | 
 |         if self.props: | 
 |           proplist = [] | 
 |           for key, value in node.GetProperties().iteritems(): | 
 |             if key in self.props: | 
 |               proplist.append(tab + '    %s: %s' % (key, str(value))) | 
 |           if proplist: | 
 |             self.out.append(tab + '  PROPERTIES') | 
 |             self.out.extend(proplist) | 
 |  | 
 |     if filter_nodes == None: | 
 |       filter_nodes = ['Comment', 'Copyright'] | 
 |  | 
 |     search = DumpTreeSearch(accept_props) | 
 |     self.Traverse(search, filter_nodes) | 
 |     return search.out | 
 |  | 
 | # | 
 | # Search related functions | 
 | # | 
 |   # Check if node is of a given type | 
 |   def IsA(self, *typelist): | 
 |     if self._cls in typelist: | 
 |       return True | 
 |     return False | 
 |  | 
 |   # Get a list of all children | 
 |   def GetChildren(self): | 
 |     return self._children | 
 |  | 
 |   def GetListOf(self, *keys): | 
 |     out = [] | 
 |     for child in self.GetChildren(): | 
 |       if child.GetClass() in keys: | 
 |         out.append(child) | 
 |     return out | 
 |  | 
 |   def GetOneOf(self, *keys): | 
 |     out = self.GetListOf(*keys) | 
 |     if out: | 
 |       return out[0] | 
 |     return None | 
 |  | 
 |   def AddChildren(self, children): | 
 |     children = CopyToList(children) | 
 |     for child in children: | 
 |       if not child: | 
 |         continue | 
 |       if type(child) == IDLAttribute: | 
 |         self.SetProperty(child.name, child.value) | 
 |         continue | 
 |       if type(child) == IDLNode: | 
 |         child._parent = self | 
 |         self._children.append(child) | 
 |         continue | 
 |       raise RuntimeError('Adding child of type %s.\n' % type(child).__name__) | 
 |  | 
 |  | 
 | # | 
 | # Property Functions | 
 | # | 
 |   def SetProperty(self, name, val): | 
 |     self._properties[name] = val | 
 |  | 
 |   def GetProperty(self, name, default=None): | 
 |     return self._properties.get(name, default) | 
 |  | 
 |   def GetProperties(self): | 
 |     return self._properties |