#!/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