| #!/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. |
| '''IDL Node defines the IDLAttribute and IDLNode objects which are constructed |
| by the parser as it processes the various 'productions'.''' |
| # pylint: disable=unidiomatic-typecheck |
| 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): |
| '''A temporary object used by the parsing process to hold an Extended |
| Attribute which will be passed as a child to a standard IDLNode.''' |
| |
| def __init__(self, name, value): |
| self._cls = 'Property' |
| self.name = name |
| self.value = value |
| |
| def __str__(self): |
| return f'{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 namespace and propertynode to |
| # allow for look-ups. IDLNode is derived from IDLRelease, so it is |
| # version aware. |
| # |
| class IDLNode(object): |
| '''This class implements the AST tree, providing the associations between |
| parents and children. It also contains a namespace and propertynode to |
| allow for look-ups. IDLNode is derived from IDLRelease, so it is |
| version aware.''' |
| |
| 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 f'{self._cls}({name})' |
| |
| def GetLogLine(self, msg): |
| filename, lineno = self.GetFileAndLine() |
| return f'{filename}({lineno}) : {msg}\n' |
| |
| # 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): |
| '''Class implementing DumpTreeSearch''' |
| |
| 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 + f' {key}: {str(value)}') |
| if proplist: |
| self.out.append(tab + ' PROPERTIES') |
| self.out.extend(proplist) |
| |
| if filter_nodes is 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 # pylint: disable=protected-access |
| self._children.append(child) |
| continue |
| raise RuntimeError(f'Adding child of type {type(child).__name__}.\n') |
| |
| |
| # |
| # 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 |