Fix the no password save issue for ajax login
[chromium-blink-merge.git] / ppapi / generators / idl_node.py
blobec40ffe6e242ffd9881223bf688dd6dae7b2247b
1 #!/usr/bin/env python
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
4 # found in the LICENSE file.
6 """Nodes for PPAPI IDL AST"""
9 # IDL Node
11 # IDL Node defines the IDLAttribute and IDLNode objects which are constructed
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
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
16 # as the source data by the various generators.
19 import hashlib
20 import sys
22 from idl_log import ErrOut, InfoOut, WarnOut
23 from idl_propertynode import IDLPropertyNode
24 from idl_namespace import IDLNamespace
25 from idl_release import IDLRelease, IDLReleaseMap
28 # IDLAttribute
30 # 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.
33 class IDLAttribute(object):
34 def __init__(self, name, value):
35 self.cls = 'ExtAttribute'
36 self.name = name
37 self.value = value
39 def __str__(self):
40 return '%s=%s' % (self.name, self.value)
43 # IDLNode
45 # This class implements the AST tree, providing the associations between
46 # parents and children. It also contains a namepsace and propertynode to
47 # allow for look-ups. IDLNode is derived from IDLRelease, so it is
48 # version aware.
50 class IDLNode(IDLRelease):
52 # Set of object IDLNode types which have a name and belong in the namespace.
53 NamedSet = set(['Enum', 'EnumItem', 'File', 'Function', 'Interface',
54 'Member', 'Param', 'Struct', 'Type', 'Typedef'])
56 show_versions = False
57 def __init__(self, cls, filename, lineno, pos, children=None):
58 # Initialize with no starting or ending Version
59 IDLRelease.__init__(self, None, None)
61 self.cls = cls
62 self.lineno = lineno
63 self.pos = pos
64 self.filename = filename
65 self.filenode = None
66 self.hashes = {}
67 self.deps = {}
68 self.errors = 0
69 self.namespace = None
70 self.typelist = None
71 self.parent = None
72 self.property_node = IDLPropertyNode()
74 # A list of unique releases for this node
75 self.releases = None
77 # A map from any release, to the first unique release
78 self.first_release = None
80 # self.children is a list of children ordered as defined
81 self.children = []
82 # Process the passed in list of children, placing ExtAttributes into the
83 # property dictionary, and nodes into the local child list in order. In
84 # addition, add nodes to the namespace if the class is in the NamedSet.
85 if not children: children = []
86 for child in children:
87 if child.cls == 'ExtAttribute':
88 self.SetProperty(child.name, child.value)
89 else:
90 self.AddChild(child)
93 # String related functions
97 # Return a string representation of this node
98 def __str__(self):
99 name = self.GetName()
100 ver = IDLRelease.__str__(self)
101 if name is None: name = ''
102 if not IDLNode.show_versions: ver = ''
103 return '%s(%s%s)' % (self.cls, name, ver)
105 # Return file and line number for where node was defined
106 def Location(self):
107 return '%s(%d)' % (self.filename, self.lineno)
109 # Log an error for this object
110 def Error(self, msg):
111 self.errors += 1
112 ErrOut.LogLine(self.filename, self.lineno, 0, ' %s %s' %
113 (str(self), msg))
114 if self.filenode:
115 errcnt = self.filenode.GetProperty('ERRORS', 0)
116 self.filenode.SetProperty('ERRORS', errcnt + 1)
118 # Log a warning for this object
119 def Warning(self, msg):
120 WarnOut.LogLine(self.filename, self.lineno, 0, ' %s %s' %
121 (str(self), msg))
123 def GetName(self):
124 return self.GetProperty('NAME')
126 def GetNameVersion(self):
127 name = self.GetProperty('NAME', default='')
128 ver = IDLRelease.__str__(self)
129 return '%s%s' % (name, ver)
131 # Dump this object and its children
132 def Dump(self, depth=0, comments=False, out=sys.stdout):
133 if self.cls in ['Comment', 'Copyright']:
134 is_comment = True
135 else:
136 is_comment = False
138 # Skip this node if it's a comment, and we are not printing comments
139 if not comments and is_comment: return
141 tab = ''.rjust(depth * 2)
142 if is_comment:
143 out.write('%sComment\n' % tab)
144 for line in self.GetName().split('\n'):
145 out.write('%s "%s"\n' % (tab, line))
146 else:
147 ver = IDLRelease.__str__(self)
148 if self.releases:
149 release_list = ': ' + ' '.join(self.releases)
150 else:
151 release_list = ': undefined'
152 out.write('%s%s%s%s\n' % (tab, self, ver, release_list))
153 if self.typelist:
154 out.write('%s Typelist: %s\n' % (tab, self.typelist.GetReleases()[0]))
155 properties = self.property_node.GetPropertyList()
156 if properties:
157 out.write('%s Properties\n' % tab)
158 for p in properties:
159 if is_comment and p == 'NAME':
160 # Skip printing the name for comments, since we printed above already
161 continue
162 out.write('%s %s : %s\n' % (tab, p, self.GetProperty(p)))
163 for child in self.children:
164 child.Dump(depth+1, comments=comments, out=out)
167 # Search related functions
169 # Check if node is of a given type
170 def IsA(self, *typelist):
171 if self.cls in typelist: return True
172 return False
174 # Get a list of objects for this key
175 def GetListOf(self, *keys):
176 out = []
177 for child in self.children:
178 if child.cls in keys: out.append(child)
179 return out
181 def GetOneOf(self, *keys):
182 out = self.GetListOf(*keys)
183 if out: return out[0]
184 return None
186 def SetParent(self, parent):
187 self.property_node.AddParent(parent)
188 self.parent = parent
190 def AddChild(self, node):
191 node.SetParent(self)
192 self.children.append(node)
194 # Get a list of all children
195 def GetChildren(self):
196 return self.children
198 # Get a list of all children of a given version
199 def GetChildrenVersion(self, version):
200 out = []
201 for child in self.children:
202 if child.IsVersion(version): out.append(child)
203 return out
205 # Get a list of all children in a given range
206 def GetChildrenRange(self, vmin, vmax):
207 out = []
208 for child in self.children:
209 if child.IsRange(vmin, vmax): out.append(child)
210 return out
212 def FindVersion(self, name, version):
213 node = self.namespace.FindNode(name, version)
214 if not node and self.parent:
215 node = self.parent.FindVersion(name, version)
216 return node
218 def FindRange(self, name, vmin, vmax):
219 nodes = self.namespace.FindNodes(name, vmin, vmax)
220 if not nodes and self.parent:
221 nodes = self.parent.FindVersion(name, vmin, vmax)
222 return nodes
224 def GetType(self, release):
225 if not self.typelist: return None
226 return self.typelist.FindRelease(release)
228 def GetHash(self, release):
229 hashval = self.hashes.get(release, None)
230 if hashval is None:
231 hashval = hashlib.sha1()
232 hashval.update(self.cls)
233 for key in self.property_node.GetPropertyList():
234 val = self.GetProperty(key)
235 hashval.update('%s=%s' % (key, str(val)))
236 typeref = self.GetType(release)
237 if typeref:
238 hashval.update(typeref.GetHash(release))
239 for child in self.GetChildren():
240 if child.IsA('Copyright', 'Comment', 'Label'): continue
241 if not child.IsRelease(release):
242 continue
243 hashval.update( child.GetHash(release) )
244 self.hashes[release] = hashval
245 return hashval.hexdigest()
247 def GetDeps(self, release, visited=None):
248 visited = visited or set()
250 # If this release is not valid for this object, then done.
251 if not self.IsRelease(release) or self.IsA('Comment', 'Copyright'):
252 return set([])
254 # If we have cached the info for this release, return the cached value
255 deps = self.deps.get(release, None)
256 if deps is not None:
257 return deps
259 # If we are already visited, then return
260 if self in visited:
261 return set([self])
263 # Otherwise, build the dependency list
264 visited |= set([self])
265 deps = set([self])
267 # Get child deps
268 for child in self.GetChildren():
269 deps |= child.GetDeps(release, visited)
270 visited |= set(deps)
272 # Get type deps
273 typeref = self.GetType(release)
274 if typeref:
275 deps |= typeref.GetDeps(release, visited)
277 self.deps[release] = deps
278 return deps
280 def GetVersion(self, release):
281 filenode = self.GetProperty('FILE')
282 if not filenode:
283 return None
284 return filenode.release_map.GetVersion(release)
286 def GetUniqueReleases(self, releases):
287 """Return the unique set of first releases corresponding to input
289 Since we are returning the corresponding 'first' version for a
290 release, we may return a release version prior to the one in the list."""
291 my_min, my_max = self.GetMinMax(releases)
292 if my_min > releases[-1] or my_max < releases[0]:
293 return []
295 out = set()
296 for rel in releases:
297 remapped = self.first_release[rel]
298 if not remapped: continue
299 out |= set([remapped])
300 out = sorted(out)
301 return out
304 def GetRelease(self, version):
305 filenode = self.GetProperty('FILE')
306 if not filenode:
307 return None
308 return filenode.release_map.GetRelease(version)
310 def _GetReleases(self, releases):
311 if not self.releases:
312 my_min, my_max = self.GetMinMax(releases)
313 my_releases = [my_min]
314 if my_max != releases[-1]:
315 my_releases.append(my_max)
316 my_releases = set(my_releases)
317 for child in self.GetChildren():
318 if child.IsA('Copyright', 'Comment', 'Label'):
319 continue
320 my_releases |= child.GetReleases(releases)
321 self.releases = my_releases
322 return self.releases
325 def _GetReleaseList(self, releases, visited=None):
326 visited = visited or set()
327 if not self.releases:
328 # If we are unversionable, then return first available release
329 if self.IsA('Comment', 'Copyright', 'Label'):
330 self.releases = []
331 return self.releases
333 # Generate the first and if deprecated within this subset, the
334 # last release for this node
335 my_min, my_max = self.GetMinMax(releases)
337 if my_max != releases[-1]:
338 my_releases = set([my_min, my_max])
339 else:
340 my_releases = set([my_min])
342 # Break cycle if we reference ourselves
343 if self in visited:
344 return [my_min]
346 visited |= set([self])
348 # Files inherit all their releases from items in the file
349 if self.IsA('AST', 'File'):
350 my_releases = set()
352 # Visit all children
353 child_releases = set()
355 # Exclude sibling results from parent visited set
356 cur_visits = visited
358 for child in self.children:
359 child_releases |= set(child._GetReleaseList(releases, cur_visits))
360 visited |= set(child_releases)
362 # Visit my type
363 type_releases = set()
364 if self.typelist:
365 type_list = self.typelist.GetReleases()
366 for typenode in type_list:
367 type_releases |= set(typenode._GetReleaseList(releases, cur_visits))
369 type_release_list = sorted(type_releases)
370 if my_min < type_release_list[0]:
371 type_node = type_list[0]
372 self.Error('requires %s in %s which is undefined at %s.' % (
373 type_node, type_node.filename, my_min))
375 for rel in child_releases | type_releases:
376 if rel >= my_min and rel <= my_max:
377 my_releases |= set([rel])
379 self.releases = sorted(my_releases)
380 return self.releases
382 def GetReleaseList(self):
383 return self.releases
385 def BuildReleaseMap(self, releases):
386 unique_list = self._GetReleaseList(releases)
387 my_min, my_max = self.GetMinMax(releases)
389 self.first_release = {}
390 last_rel = None
391 for rel in releases:
392 if rel in unique_list:
393 last_rel = rel
394 self.first_release[rel] = last_rel
395 if rel == my_max:
396 last_rel = None
398 def SetProperty(self, name, val):
399 self.property_node.SetProperty(name, val)
401 def GetProperty(self, name, default=None):
402 return self.property_node.GetProperty(name, default)
404 def Traverse(self, data, func):
405 func(self, data)
406 for child in self.children:
407 child.Traverse(data, func)
411 # IDLFile
413 # A specialized version of IDLNode which tracks errors and warnings.
415 class IDLFile(IDLNode):
416 def __init__(self, name, children, errors=0):
417 attrs = [IDLAttribute('NAME', name),
418 IDLAttribute('ERRORS', errors)]
419 if not children: children = []
420 IDLNode.__init__(self, 'File', name, 1, 0, attrs + children)
421 self.release_map = IDLReleaseMap([('M13', 1.0)])
425 # Tests
427 def StringTest():
428 errors = 0
429 name_str = 'MyName'
430 text_str = 'MyNode(%s)' % name_str
431 name_node = IDLAttribute('NAME', name_str)
432 node = IDLNode('MyNode', 'no file', 1, 0, [name_node])
433 if node.GetName() != name_str:
434 ErrOut.Log('GetName returned >%s< not >%s<' % (node.GetName(), name_str))
435 errors += 1
436 if node.GetProperty('NAME') != name_str:
437 ErrOut.Log('Failed to get name property.')
438 errors += 1
439 if str(node) != text_str:
440 ErrOut.Log('str() returned >%s< not >%s<' % (str(node), text_str))
441 errors += 1
442 if not errors: InfoOut.Log('Passed StringTest')
443 return errors
446 def ChildTest():
447 errors = 0
448 child = IDLNode('child', 'no file', 1, 0)
449 parent = IDLNode('parent', 'no file', 1, 0, [child])
451 if child.parent != parent:
452 ErrOut.Log('Failed to connect parent.')
453 errors += 1
455 if [child] != parent.GetChildren():
456 ErrOut.Log('Failed GetChildren.')
457 errors += 1
459 if child != parent.GetOneOf('child'):
460 ErrOut.Log('Failed GetOneOf(child)')
461 errors += 1
463 if parent.GetOneOf('bogus'):
464 ErrOut.Log('Failed GetOneOf(bogus)')
465 errors += 1
467 if not parent.IsA('parent'):
468 ErrOut.Log('Expecting parent type')
469 errors += 1
471 parent = IDLNode('parent', 'no file', 1, 0, [child, child])
472 if [child, child] != parent.GetChildren():
473 ErrOut.Log('Failed GetChildren2.')
474 errors += 1
476 if not errors: InfoOut.Log('Passed ChildTest')
477 return errors
480 def Main():
481 errors = StringTest()
482 errors += ChildTest()
484 if errors:
485 ErrOut.Log('IDLNode failed with %d errors.' % errors)
486 return -1
487 return 0
489 if __name__ == '__main__':
490 sys.exit(Main())