summaryrefslogtreecommitdiffstats
path: root/tools/idl_parser/idl_node.py
blob: e50fc4e1baead7d9b5498c4138e83211d0af2946 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#!/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