Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(182)

Side by Side Diff: ppapi/generators/idl_node.py

Issue 98803004: Pepper: Clean up IDLNode internals. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix potential KeyError Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ppapi/generators/idl_ast.py ('k') | ppapi/generators/idl_propertynode.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Nodes for PPAPI IDL AST""" 6 """Nodes for PPAPI IDL AST"""
7 7
8 # 8 #
9 # IDL Node 9 # IDL Node
10 # 10 #
11 # IDL Node defines the IDLAttribute and IDLNode objects which are constructed 11 # IDL Node defines the IDLAttribute and IDLNode objects which are constructed
12 # by the parser as it processes the various 'productions'. The IDLAttribute 12 # by the parser as it processes the various 'productions'. The IDLAttribute
13 # objects are assigned to the IDLNode's property dictionary instead of being 13 # objects are assigned to the IDLNode's property dictionary instead of being
14 # applied as children of The IDLNodes, so they do not exist in the final tree. 14 # applied as children of The IDLNodes, so they do not exist in the final tree.
15 # The AST of IDLNodes is the output from the parsing state and will be used 15 # The AST of IDLNodes is the output from the parsing state and will be used
16 # as the source data by the various generators. 16 # as the source data by the various generators.
17 # 17 #
18 18
19 import hashlib
20 import sys 19 import sys
21 20
22 from idl_log import ErrOut, InfoOut, WarnOut 21 from idl_log import ErrOut, InfoOut, WarnOut
23 from idl_propertynode import IDLPropertyNode 22 from idl_propertynode import IDLPropertyNode
24 from idl_namespace import IDLNamespace
25 from idl_release import IDLRelease, IDLReleaseMap 23 from idl_release import IDLRelease, IDLReleaseMap
26 24
27 25
28 # IDLAttribute 26 # IDLAttribute
29 # 27 #
30 # A temporary object used by the parsing process to hold an Extended Attribute 28 # A temporary object used by the parsing process to hold an Extended Attribute
31 # which will be passed as a child to a standard IDLNode. 29 # which will be passed as a child to a standard IDLNode.
32 # 30 #
33 class IDLAttribute(object): 31 class IDLAttribute(object):
34 def __init__(self, name, value): 32 def __init__(self, name, value):
(...skipping 11 matching lines...) Expand all
46 # parents and children. It also contains a namepsace and propertynode to 44 # parents and children. It also contains a namepsace and propertynode to
47 # allow for look-ups. IDLNode is derived from IDLRelease, so it is 45 # allow for look-ups. IDLNode is derived from IDLRelease, so it is
48 # version aware. 46 # version aware.
49 # 47 #
50 class IDLNode(IDLRelease): 48 class IDLNode(IDLRelease):
51 49
52 # Set of object IDLNode types which have a name and belong in the namespace. 50 # Set of object IDLNode types which have a name and belong in the namespace.
53 NamedSet = set(['Enum', 'EnumItem', 'File', 'Function', 'Interface', 51 NamedSet = set(['Enum', 'EnumItem', 'File', 'Function', 'Interface',
54 'Member', 'Param', 'Struct', 'Type', 'Typedef']) 52 'Member', 'Param', 'Struct', 'Type', 'Typedef'])
55 53
56 show_versions = False
57 def __init__(self, cls, filename, lineno, pos, children=None): 54 def __init__(self, cls, filename, lineno, pos, children=None):
58 # Initialize with no starting or ending Version 55 # Initialize with no starting or ending Version
59 IDLRelease.__init__(self, None, None) 56 IDLRelease.__init__(self, None, None)
60 57
61 self.cls = cls 58 self.cls = cls
62 self.lineno = lineno 59 self.lineno = lineno
63 self.pos = pos 60 self.pos = pos
64 self.filename = filename 61 self.filename = filename
65 self.filenode = None 62 self.filenode = None
66 self.hashes = {}
67 self.deps = {} 63 self.deps = {}
68 self.errors = 0 64 self.errors = 0
69 self.namespace = None 65 self.namespace = None
70 self.typelist = None 66 self.typelist = None
71 self.parent = None 67 self.parent = None
72 self.property_node = IDLPropertyNode() 68 self.property_node = IDLPropertyNode()
73 self.unique_releases = None 69 self.unique_releases = None
74 70
75 # A list of unique releases for this node 71 # A list of unique releases for this node
76 self.releases = None 72 self.releases = None
77 73
78 # A map from any release, to the first unique release 74 # A map from any release, to the first unique release
79 self.first_release = None 75 self.first_release = None
80 76
81 # self.children is a list of children ordered as defined 77 # self.children is a list of children ordered as defined
82 self.children = [] 78 self.children = []
83 # Process the passed in list of children, placing ExtAttributes into the 79 # Process the passed in list of children, placing ExtAttributes into the
84 # property dictionary, and nodes into the local child list in order. In 80 # property dictionary, and nodes into the local child list in order. In
85 # addition, add nodes to the namespace if the class is in the NamedSet. 81 # addition, add nodes to the namespace if the class is in the NamedSet.
86 if not children: children = [] 82 if children:
87 for child in children: 83 for child in children:
88 if child.cls == 'ExtAttribute': 84 if child.cls == 'ExtAttribute':
89 self.SetProperty(child.name, child.value) 85 self.SetProperty(child.name, child.value)
90 else: 86 else:
91 self.AddChild(child) 87 self.AddChild(child)
92 88
93 # 89 #
94 # String related functions 90 # String related functions
95 # 91 #
96 # 92 #
97 93
98 # Return a string representation of this node 94 # Return a string representation of this node
99 def __str__(self): 95 def __str__(self):
100 name = self.GetName() 96 name = self.GetName()
101 ver = IDLRelease.__str__(self) 97 if name is None:
102 if name is None: name = '' 98 name = ''
103 if not IDLNode.show_versions: ver = '' 99 return '%s(%s)' % (self.cls, name)
104 return '%s(%s%s)' % (self.cls, name, ver)
105 100
106 # Return file and line number for where node was defined 101 # Return file and line number for where node was defined
107 def Location(self): 102 def Location(self):
108 return '%s(%d)' % (self.filename, self.lineno) 103 return '%s(%d)' % (self.filename, self.lineno)
109 104
110 # Log an error for this object 105 # Log an error for this object
111 def Error(self, msg): 106 def Error(self, msg):
112 self.errors += 1 107 self.errors += 1
113 ErrOut.LogLine(self.filename, self.lineno, 0, ' %s %s' % 108 ErrOut.LogLine(self.filename, self.lineno, 0, ' %s %s' %
114 (str(self), msg)) 109 (str(self), msg))
115 if self.filenode: 110 if self.filenode:
116 errcnt = self.filenode.GetProperty('ERRORS', 0) 111 errcnt = self.filenode.GetProperty('ERRORS')
112 if not errcnt:
113 errcnt = 0
117 self.filenode.SetProperty('ERRORS', errcnt + 1) 114 self.filenode.SetProperty('ERRORS', errcnt + 1)
118 115
119 # Log a warning for this object 116 # Log a warning for this object
120 def Warning(self, msg): 117 def Warning(self, msg):
121 WarnOut.LogLine(self.filename, self.lineno, 0, ' %s %s' % 118 WarnOut.LogLine(self.filename, self.lineno, 0, ' %s %s' %
122 (str(self), msg)) 119 (str(self), msg))
123 120
124 def GetName(self): 121 def GetName(self):
125 return self.GetProperty('NAME') 122 return self.GetProperty('NAME')
126 123
127 def GetNameVersion(self):
128 name = self.GetProperty('NAME', default='')
129 ver = IDLRelease.__str__(self)
130 return '%s%s' % (name, ver)
131
132 # Dump this object and its children 124 # Dump this object and its children
133 def Dump(self, depth=0, comments=False, out=sys.stdout): 125 def Dump(self, depth=0, comments=False, out=sys.stdout):
134 if self.cls in ['Comment', 'Copyright']: 126 if self.cls in ['Comment', 'Copyright']:
135 is_comment = True 127 is_comment = True
136 else: 128 else:
137 is_comment = False 129 is_comment = False
138 130
139 # Skip this node if it's a comment, and we are not printing comments 131 # Skip this node if it's a comment, and we are not printing comments
140 if not comments and is_comment: return 132 if not comments and is_comment:
133 return
141 134
142 tab = ''.rjust(depth * 2) 135 tab = ''.rjust(depth * 2)
143 if is_comment: 136 if is_comment:
144 out.write('%sComment\n' % tab) 137 out.write('%sComment\n' % tab)
145 for line in self.GetName().split('\n'): 138 for line in self.GetName().split('\n'):
146 out.write('%s "%s"\n' % (tab, line)) 139 out.write('%s "%s"\n' % (tab, line))
147 else: 140 else:
148 ver = IDLRelease.__str__(self) 141 ver = IDLRelease.__str__(self)
149 if self.releases: 142 if self.releases:
150 release_list = ': ' + ' '.join(self.releases) 143 release_list = ': ' + ' '.join(self.releases)
(...skipping 11 matching lines...) Expand all
162 continue 155 continue
163 out.write('%s %s : %s\n' % (tab, p, self.GetProperty(p))) 156 out.write('%s %s : %s\n' % (tab, p, self.GetProperty(p)))
164 for child in self.children: 157 for child in self.children:
165 child.Dump(depth+1, comments=comments, out=out) 158 child.Dump(depth+1, comments=comments, out=out)
166 159
167 # 160 #
168 # Search related functions 161 # Search related functions
169 # 162 #
170 # Check if node is of a given type 163 # Check if node is of a given type
171 def IsA(self, *typelist): 164 def IsA(self, *typelist):
172 if self.cls in typelist: return True 165 return self.cls in typelist
173 return False
174 166
175 # Get a list of objects for this key 167 # Get a list of objects for this key
176 def GetListOf(self, *keys): 168 def GetListOf(self, *keys):
177 out = [] 169 out = []
178 for child in self.children: 170 for child in self.children:
179 if child.cls in keys: out.append(child) 171 if child.cls in keys:
172 out.append(child)
180 return out 173 return out
181 174
182 def GetOneOf(self, *keys): 175 def GetOneOf(self, *keys):
183 out = self.GetListOf(*keys) 176 out = self.GetListOf(*keys)
184 if out: return out[0] 177 if out:
178 return out[0]
185 return None 179 return None
186 180
187 def SetParent(self, parent): 181 def SetParent(self, parent):
188 self.property_node.AddParent(parent) 182 self.property_node.AddParent(parent)
189 self.parent = parent 183 self.parent = parent
190 184
191 def AddChild(self, node): 185 def AddChild(self, node):
192 node.SetParent(self) 186 node.SetParent(self)
193 self.children.append(node) 187 self.children.append(node)
194 188
195 # Get a list of all children 189 # Get a list of all children
196 def GetChildren(self): 190 def GetChildren(self):
197 return self.children 191 return self.children
198 192
199 # Get a list of all children of a given version
200 def GetChildrenVersion(self, version):
201 out = []
202 for child in self.children:
203 if child.IsVersion(version): out.append(child)
204 return out
205
206 # Get a list of all children in a given range
207 def GetChildrenRange(self, vmin, vmax):
208 out = []
209 for child in self.children:
210 if child.IsRange(vmin, vmax): out.append(child)
211 return out
212
213 def FindVersion(self, name, version):
214 node = self.namespace.FindNode(name, version)
215 if not node and self.parent:
216 node = self.parent.FindVersion(name, version)
217 return node
218
219 def FindRange(self, name, vmin, vmax):
220 nodes = self.namespace.FindNodes(name, vmin, vmax)
221 if not nodes and self.parent:
222 nodes = self.parent.FindVersion(name, vmin, vmax)
223 return nodes
224
225 def GetType(self, release): 193 def GetType(self, release):
226 if not self.typelist: return None 194 if not self.typelist:
195 return None
227 return self.typelist.FindRelease(release) 196 return self.typelist.FindRelease(release)
228 197
229 def GetHash(self, release):
230 hashval = self.hashes.get(release, None)
231 if hashval is None:
232 hashval = hashlib.sha1()
233 hashval.update(self.cls)
234 for key in self.property_node.GetPropertyList():
235 val = self.GetProperty(key)
236 hashval.update('%s=%s' % (key, str(val)))
237 typeref = self.GetType(release)
238 if typeref:
239 hashval.update(typeref.GetHash(release))
240 for child in self.GetChildren():
241 if child.IsA('Copyright', 'Comment', 'Label'): continue
242 if not child.IsRelease(release):
243 continue
244 hashval.update( child.GetHash(release) )
245 self.hashes[release] = hashval
246 return hashval.hexdigest()
247
248 def GetDeps(self, release, visited=None): 198 def GetDeps(self, release, visited=None):
249 visited = visited or set() 199 visited = visited or set()
250 200
251 # If this release is not valid for this object, then done. 201 # If this release is not valid for this object, then done.
252 if not self.IsRelease(release) or self.IsA('Comment', 'Copyright'): 202 if not self.IsRelease(release) or self.IsA('Comment', 'Copyright'):
253 return set([]) 203 return set([])
254 204
255 # If we have cached the info for this release, return the cached value 205 # If we have cached the info for this release, return the cached value
256 deps = self.deps.get(release, None) 206 deps = self.deps.get(release, None)
257 if deps is not None: 207 if deps is not None:
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 239
290 Since we are returning the corresponding 'first' version for a 240 Since we are returning the corresponding 'first' version for a
291 release, we may return a release version prior to the one in the list.""" 241 release, we may return a release version prior to the one in the list."""
292 my_min, my_max = self.GetMinMax(releases) 242 my_min, my_max = self.GetMinMax(releases)
293 if my_min > releases[-1] or my_max < releases[0]: 243 if my_min > releases[-1] or my_max < releases[0]:
294 return [] 244 return []
295 245
296 out = set() 246 out = set()
297 for rel in releases: 247 for rel in releases:
298 remapped = self.first_release[rel] 248 remapped = self.first_release[rel]
299 if not remapped: continue 249 if not remapped:
250 continue
300 out |= set([remapped]) 251 out |= set([remapped])
301 252
302 # Cache the most recent set of unique_releases 253 # Cache the most recent set of unique_releases
303 self.unique_releases = sorted(out) 254 self.unique_releases = sorted(out)
304 return self.unique_releases 255 return self.unique_releases
305 256
306 def LastRelease(self, release): 257 def LastRelease(self, release):
307 # Get the most recent release from the most recently generated set of 258 # Get the most recent release from the most recently generated set of
308 # cached unique releases. 259 # cached unique releases.
309 if self.unique_releases and self.unique_releases[-1] > release: 260 if self.unique_releases and self.unique_releases[-1] > release:
310 return False 261 return False
311 return True 262 return True
312 263
313 def GetRelease(self, version): 264 def GetRelease(self, version):
314 filenode = self.GetProperty('FILE') 265 filenode = self.GetProperty('FILE')
315 if not filenode: 266 if not filenode:
316 return None 267 return None
317 return filenode.release_map.GetRelease(version) 268 return filenode.release_map.GetRelease(version)
318 269
319 def _GetReleases(self, releases):
320 if not self.releases:
321 my_min, my_max = self.GetMinMax(releases)
322 my_releases = [my_min]
323 if my_max != releases[-1]:
324 my_releases.append(my_max)
325 my_releases = set(my_releases)
326 for child in self.GetChildren():
327 if child.IsA('Copyright', 'Comment', 'Label'):
328 continue
329 my_releases |= child.GetReleases(releases)
330 self.releases = my_releases
331 return self.releases
332
333
334 def _GetReleaseList(self, releases, visited=None): 270 def _GetReleaseList(self, releases, visited=None):
335 visited = visited or set() 271 visited = visited or set()
336 if not self.releases: 272 if not self.releases:
337 # If we are unversionable, then return first available release 273 # If we are unversionable, then return first available release
338 if self.IsA('Comment', 'Copyright', 'Label'): 274 if self.IsA('Comment', 'Copyright', 'Label'):
339 self.releases = [] 275 self.releases = []
340 return self.releases 276 return self.releases
341 277
342 # Generate the first and if deprecated within this subset, the 278 # Generate the first and if deprecated within this subset, the
343 # last release for this node 279 # last release for this node
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
386 my_releases |= set([rel]) 322 my_releases |= set([rel])
387 323
388 self.releases = sorted(my_releases) 324 self.releases = sorted(my_releases)
389 return self.releases 325 return self.releases
390 326
391 def GetReleaseList(self): 327 def GetReleaseList(self):
392 return self.releases 328 return self.releases
393 329
394 def BuildReleaseMap(self, releases): 330 def BuildReleaseMap(self, releases):
395 unique_list = self._GetReleaseList(releases) 331 unique_list = self._GetReleaseList(releases)
396 my_min, my_max = self.GetMinMax(releases) 332 _, my_max = self.GetMinMax(releases)
397 333
398 self.first_release = {} 334 self.first_release = {}
399 last_rel = None 335 last_rel = None
400 for rel in releases: 336 for rel in releases:
401 if rel in unique_list: 337 if rel in unique_list:
402 last_rel = rel 338 last_rel = rel
403 self.first_release[rel] = last_rel 339 self.first_release[rel] = last_rel
404 if rel == my_max: 340 if rel == my_max:
405 last_rel = None 341 last_rel = None
406 342
407 def SetProperty(self, name, val): 343 def SetProperty(self, name, val):
408 self.property_node.SetProperty(name, val) 344 self.property_node.SetProperty(name, val)
409 345
410 def GetProperty(self, name, default=None): 346 def GetProperty(self, name):
411 return self.property_node.GetProperty(name, default) 347 return self.property_node.GetProperty(name)
412
413 def Traverse(self, data, func):
414 func(self, data)
415 for child in self.children:
416 child.Traverse(data, func)
417 348
418 349
419 # 350 #
420 # IDLFile 351 # IDLFile
421 # 352 #
422 # A specialized version of IDLNode which tracks errors and warnings. 353 # A specialized version of IDLNode which tracks errors and warnings.
423 # 354 #
424 class IDLFile(IDLNode): 355 class IDLFile(IDLNode):
425 def __init__(self, name, children, errors=0): 356 def __init__(self, name, children, errors=0):
426 attrs = [IDLAttribute('NAME', name), 357 attrs = [IDLAttribute('NAME', name),
427 IDLAttribute('ERRORS', errors)] 358 IDLAttribute('ERRORS', errors)]
428 if not children: children = [] 359 if not children:
360 children = []
429 IDLNode.__init__(self, 'File', name, 1, 0, attrs + children) 361 IDLNode.__init__(self, 'File', name, 1, 0, attrs + children)
362 # TODO(teravest): Why do we set release map like this here? This looks
363 # suspicious...
430 self.release_map = IDLReleaseMap([('M13', 1.0)]) 364 self.release_map = IDLReleaseMap([('M13', 1.0)])
431 365
432 366
433 # 367 #
434 # Tests 368 # Tests
435 # 369 #
436 def StringTest(): 370 def StringTest():
437 errors = 0 371 errors = 0
438 name_str = 'MyName' 372 name_str = 'MyName'
439 text_str = 'MyNode(%s)' % name_str 373 text_str = 'MyNode(%s)' % name_str
440 name_node = IDLAttribute('NAME', name_str) 374 name_node = IDLAttribute('NAME', name_str)
441 node = IDLNode('MyNode', 'no file', 1, 0, [name_node]) 375 node = IDLNode('MyNode', 'no file', 1, 0, [name_node])
442 if node.GetName() != name_str: 376 if node.GetName() != name_str:
443 ErrOut.Log('GetName returned >%s< not >%s<' % (node.GetName(), name_str)) 377 ErrOut.Log('GetName returned >%s< not >%s<' % (node.GetName(), name_str))
444 errors += 1 378 errors += 1
445 if node.GetProperty('NAME') != name_str: 379 if node.GetProperty('NAME') != name_str:
446 ErrOut.Log('Failed to get name property.') 380 ErrOut.Log('Failed to get name property.')
447 errors += 1 381 errors += 1
448 if str(node) != text_str: 382 if str(node) != text_str:
449 ErrOut.Log('str() returned >%s< not >%s<' % (str(node), text_str)) 383 ErrOut.Log('str() returned >%s< not >%s<' % (str(node), text_str))
450 errors += 1 384 errors += 1
451 if not errors: InfoOut.Log('Passed StringTest') 385 if not errors:
386 InfoOut.Log('Passed StringTest')
452 return errors 387 return errors
453 388
454 389
455 def ChildTest(): 390 def ChildTest():
456 errors = 0 391 errors = 0
457 child = IDLNode('child', 'no file', 1, 0) 392 child = IDLNode('child', 'no file', 1, 0)
458 parent = IDLNode('parent', 'no file', 1, 0, [child]) 393 parent = IDLNode('parent', 'no file', 1, 0, [child])
459 394
460 if child.parent != parent: 395 if child.parent != parent:
461 ErrOut.Log('Failed to connect parent.') 396 ErrOut.Log('Failed to connect parent.')
(...skipping 13 matching lines...) Expand all
475 410
476 if not parent.IsA('parent'): 411 if not parent.IsA('parent'):
477 ErrOut.Log('Expecting parent type') 412 ErrOut.Log('Expecting parent type')
478 errors += 1 413 errors += 1
479 414
480 parent = IDLNode('parent', 'no file', 1, 0, [child, child]) 415 parent = IDLNode('parent', 'no file', 1, 0, [child, child])
481 if [child, child] != parent.GetChildren(): 416 if [child, child] != parent.GetChildren():
482 ErrOut.Log('Failed GetChildren2.') 417 ErrOut.Log('Failed GetChildren2.')
483 errors += 1 418 errors += 1
484 419
485 if not errors: InfoOut.Log('Passed ChildTest') 420 if not errors:
421 InfoOut.Log('Passed ChildTest')
486 return errors 422 return errors
487 423
488 424
489 def Main(): 425 def Main():
490 errors = StringTest() 426 errors = StringTest()
491 errors += ChildTest() 427 errors += ChildTest()
492 428
493 if errors: 429 if errors:
494 ErrOut.Log('IDLNode failed with %d errors.' % errors) 430 ErrOut.Log('IDLNode failed with %d errors.' % errors)
495 return -1 431 return -1
496 return 0 432 return 0
497 433
498 if __name__ == '__main__': 434 if __name__ == '__main__':
499 sys.exit(Main()) 435 sys.exit(Main())
500 436
OLDNEW
« no previous file with comments | « ppapi/generators/idl_ast.py ('k') | ppapi/generators/idl_propertynode.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698