Chromium Code Reviews
|
| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/python | |
| 2 # | |
| 3 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 4 # Use of this source code is governed by a BSD-style license that can be | |
| 5 # found in the LICENSE file. | |
| 6 | |
| 7 """ | |
| 8 IDLNamespace for PPAPI | |
| 9 | |
| 10 This file defines the behavior of the AST namespace which allows for resolving | |
| 11 a symbol as one or more AST nodes given a version or range of versions. | |
| 12 """ | |
| 13 | |
| 14 import sys | |
| 15 | |
| 16 from idl_option import GetOption, Option, ParseOptions | |
| 17 from idl_log import ErrOut, InfoOut, WarnOut | |
| 18 from idl_version import IDLVersion | |
| 19 | |
| 20 Option('label', 'Use the specifed label blocks.', default='Chrome') | |
| 21 Option('version', 'Use the specified version', default='M14') | |
| 22 Option('namespace_debug', 'Use the specified version') | |
| 23 | |
| 24 | |
| 25 # | |
| 26 # IDLVersionList | |
| 27 # | |
| 28 # IDLVersionList is a list based container for holding IDLVersion | |
| 29 # objects. The IDLVersionList can be added to, and searched by | |
| 30 # range. | |
| 31 # | |
| 32 class IDLVersionList(object): | |
| 33 def __init__(self): | |
| 34 self.nodes = [] | |
| 35 | |
| 36 def FindVersion(self, version): | |
| 37 assert type(version) == float | |
| 38 | |
| 39 for node in self.nodes: | |
| 40 if node.IsVersion(version): | |
| 41 return node | |
| 42 return None | |
| 43 | |
| 44 def FindRange(self, vmin, vmax): | |
| 45 assert type(vmin) == float | |
| 46 assert type(vmax) == float | |
| 47 assert vmin != vmax | |
| 48 | |
| 49 out = [] | |
| 50 for node in self.nodes: | |
| 51 if node.InRange(vmin, vmax): | |
| 52 out.append(node) | |
| 53 return out | |
| 54 | |
| 55 def AddNode(self, node): | |
| 56 if GetOption('version_debug'): InfoOut.Log('\nAdding %s' % node) | |
| 57 last = None | |
| 58 | |
| 59 # Check current versions in that namespace | |
| 60 for cver in self.nodes: | |
| 61 if GetOption('version_debug'): InfoOut.Log(' Checking %s' % cver) | |
| 62 | |
| 63 # We should only be missing a 'version' tag for the first item. | |
| 64 if not node.vmin: | |
| 65 node.Error('Missing version on overload of previous %s.' % | |
| 66 cver.Location()) | |
| 67 raise RuntimeError('DSFSD') | |
| 68 return False | |
| 69 | |
| 70 # If the node has no max, then set it to this one | |
| 71 if not cver.vmax: | |
| 72 cver.vmax = node.vmin | |
| 73 if GetOption('version_debug'): InfoOut.Log(' Update %s' % cver) | |
| 74 | |
| 75 # if the max and min overlap, than's an error | |
|
sehr (please use chromium)
2011/07/01 22:58:51
This requires that versioned information appear in
noelallen1
2011/07/02 19:51:32
Done.
| |
| 76 if cver.vmax > node.vmin: | |
| 77 if node.vmax and cver.vmin >= node.vmax: | |
| 78 node.Error('Declarations out of order.') | |
| 79 else: | |
| 80 node.Error('Overlap in versions.') | |
| 81 return False | |
| 82 last = cver | |
| 83 | |
| 84 # Otherwise, the previous max and current min should match | |
| 85 # unless this is the unlikely case of something being only | |
| 86 # temporarily deprecated. | |
| 87 if last and last.vmax != node.vmin: | |
| 88 node.Warn('Gap in version numbers.') | |
| 89 | |
| 90 # If we made it here, this new node must be the 'newest' | |
| 91 # and does not overlap with anything previously added, so | |
| 92 # we can add it to the end of the list. | |
| 93 if GetOption('version_debug'): InfoOut.Log('Done %s' % node) | |
| 94 self.nodes.append(node) | |
| 95 return True | |
| 96 | |
| 97 # | |
| 98 # IDLVersionMap | |
| 99 # | |
| 100 # A version map, can map from an float interface version, to a global | |
| 101 # release string. | |
| 102 # | |
| 103 class IDLVersionMap(object): | |
| 104 def __init__(self): | |
| 105 self.version_to_release = {} | |
| 106 self.release_to_version = {} | |
| 107 self.versions = [] | |
| 108 | |
| 109 def AddReleaseVersionMapping(self, release, version): | |
| 110 self.version_to_release[version] = release | |
| 111 self.release_to_version[release] = version | |
| 112 self.versions = sorted(self.version_to_release.keys()) | |
| 113 | |
| 114 def GetRelease(self, version): | |
| 115 # Check for exact match | |
| 116 if version in self.versions: | |
| 117 return self.version_to_release[version] | |
| 118 | |
| 119 def GetVersion(self, release): | |
| 120 return self.release_to_version[release] | |
| 121 | |
| 122 | |
| 123 | |
| 124 # | |
| 125 # IDLNamespace | |
| 126 # | |
| 127 # IDLNamespace provides a mapping between a symbol name and an IDLVersionList | |
| 128 # which contains IDLVersion objects. It provides an interface for fetching | |
| 129 # one or more IDLNodes based on a version or range of versions. | |
| 130 # | |
| 131 class IDLNamespace(object): | |
| 132 def __init__(self, parent): | |
| 133 self.namespace = {} | |
| 134 self.parent = parent | |
| 135 | |
| 136 def Dump(self): | |
| 137 for name in self.namespace: | |
| 138 InfoOut.Log('NAME=%s' % name) | |
| 139 for cver in self.namespace[name]: | |
| 140 InfoOut.Log(' %s' % cver) | |
| 141 InfoOut.Log('') | |
| 142 | |
| 143 def FindVersion(self, name, version): | |
| 144 list = self.namespace.get(name, None) | |
| 145 if list == None: | |
| 146 if self.parent: | |
| 147 return self.parent.FindVersion(name, version) | |
| 148 else: | |
| 149 return None | |
| 150 return list.FindVersion(version) | |
| 151 | |
| 152 def FindRange(self, name, vmin, vmax): | |
| 153 list = self.namespace.get(name, None) | |
| 154 if list == None: | |
| 155 if self.parent: | |
| 156 return self.parent.FindRange(name, vmin, vmax) | |
| 157 else: | |
| 158 return [] | |
| 159 return list.FindRange(vmin, vmax) | |
| 160 | |
| 161 def FindList(self, name): | |
| 162 list = self.namespace.get(name, None) | |
| 163 if list == None: | |
| 164 if self.parent: | |
| 165 return self.parent.FindList(name) | |
| 166 return list | |
| 167 | |
| 168 def AddNode(self, node): | |
| 169 name = node.GetName() | |
| 170 list = self.namespace.setdefault(name,IDLVersionList()) | |
| 171 if GetOption('namespace_debug'): | |
| 172 print "Adding to namespace: %s" % node | |
| 173 return list.AddNode(node) | |
| 174 | |
| 175 | |
| 176 | |
| 177 # | |
| 178 # Testing Code | |
| 179 # | |
| 180 | |
| 181 # | |
| 182 # MockNode | |
| 183 # | |
| 184 # Mocks the IDLNode to support error, warning handling, and string functions. | |
| 185 # | |
| 186 class MockNode(IDLVersion): | |
| 187 def __init__(self, name, vmin, vmax): | |
| 188 self.name = name | |
| 189 self.vmin = vmin | |
| 190 self.vmax = vmax | |
| 191 self.errors = [] | |
| 192 self.warns = [] | |
| 193 self.properties = { | |
| 194 'NAME': name, | |
| 195 'version': vmin, | |
| 196 'deprecate' : vmax | |
| 197 } | |
| 198 | |
| 199 def __str__(self): | |
| 200 return '%s (%s : %s)' % (self.name, self.vmin, self.vmax) | |
| 201 | |
| 202 def GetName(self): | |
| 203 return self.name | |
| 204 | |
| 205 def Error(self, msg): | |
| 206 if GetOption('version_debug'): print 'Error: %s' % msg | |
| 207 self.errors.append(msg) | |
| 208 | |
| 209 def Warn(self, msg): | |
| 210 if GetOption('version_debug'): print 'Warn: %s' % msg | |
| 211 self.warns.append(msg) | |
| 212 | |
| 213 def GetProperty(self, name): | |
| 214 return self.properties.get(name, None) | |
| 215 | |
| 216 errors = 0 | |
| 217 # | |
| 218 # DumpFailure | |
| 219 # | |
| 220 # Dumps all the information relavent to an add failure. | |
|
sehr (please use chromium)
2011/07/01 22:58:51
relevant
noelallen1
2011/07/02 19:51:32
Done.
| |
| 221 def DumpFailure(namespace, node, msg): | |
| 222 global errors | |
| 223 print '\n******************************' | |
| 224 print 'Failure: %s %s' % (node, msg) | |
| 225 for warn in node.warns: | |
| 226 print ' WARN: %s' % warn | |
| 227 for err in node.errors: | |
| 228 print ' ERROR: %s' % err | |
| 229 print '\n' | |
| 230 namespace.Dump() | |
| 231 print '******************************\n' | |
| 232 errors += 1 | |
| 233 | |
| 234 # Add expecting no errors or warnings | |
| 235 def AddOkay(namespace, node): | |
| 236 okay = namespace.AddNode(node) | |
| 237 if not okay or node.errors or node.warns: | |
| 238 DumpFailure(namespace, node, 'Expected success') | |
| 239 | |
| 240 # Add expecting a specific warning | |
| 241 def AddWarn(namespace, node, msg): | |
| 242 okay = namespace.AddNode(node) | |
| 243 if not okay or node.errors or not node.warns: | |
| 244 DumpFailure(namespace, node, 'Expected warnings') | |
| 245 if msg not in node.warns: | |
| 246 DumpFailure(namespace, node, 'Expected warning: %s' % msg) | |
| 247 | |
| 248 # Add expecting a specific error any any number of warnings | |
| 249 def AddError(namespace, node, msg): | |
| 250 okay = namespace.AddNode(node) | |
| 251 if okay or not node.errors: | |
| 252 DumpFailure(namespace, node, 'Expected errors') | |
| 253 if msg not in node.errors: | |
| 254 DumpFailure(namespace, node, 'Expected error: %s' % msg) | |
| 255 | |
| 256 # Verify the namespace find the correct node based on version | |
| 257 def VerifyFindOne(namespace, name, version, node): | |
| 258 global errors | |
| 259 if (namespace.FindVersion(name, version) != node): | |
| 260 print "Failed to find %s as version %f of %s" % (node, version, name) | |
| 261 namespace.Dump() | |
| 262 print "\n" | |
| 263 errors += 1 | |
| 264 | |
| 265 # Verify the namespace find the correct nodes based on range | |
|
sehr (please use chromium)
2011/07/01 22:58:51
Can't parse this comment.
noelallen1
2011/07/02 19:51:32
Done.
| |
| 266 def VerifyFindAll(namespace, name, vmin, vmax, nodes): | |
| 267 global errors | |
| 268 out = namespace.FindRange(name, vmin, vmax) | |
| 269 if (out != nodes): | |
| 270 print "Found [%s] instead of[%s] for versions %f to %f of %s" % ( | |
| 271 ' '.join([str(x) for x in out]), | |
| 272 ' '.join([str(x) for x in nodes]), | |
| 273 vmin, | |
| 274 vmax, | |
| 275 name) | |
| 276 namespace.Dump() | |
| 277 print "\n" | |
| 278 errors += 1 | |
| 279 | |
| 280 def Main(args): | |
| 281 global errors | |
| 282 ParseOptions(args) | |
| 283 | |
| 284 InfoOut.SetConsole(True) | |
| 285 | |
| 286 namespace = IDLNamespace(None) | |
| 287 | |
| 288 FooXX = MockNode('foo', None, None) | |
| 289 Foo1X = MockNode('foo', 1.0, None) | |
| 290 Foo2X = MockNode('foo', 2.0, None) | |
| 291 Foo3X = MockNode('foo', 3.0, None) | |
| 292 | |
| 293 #Verify we succeed with undeprecated adds | |
|
sehr (please use chromium)
2011/07/01 22:58:51
s/#V/# V/
noelallen1
2011/07/02 19:51:32
Done.
| |
| 294 AddOkay(namespace, FooXX) | |
| 295 AddOkay(namespace, Foo1X) | |
| 296 AddOkay(namespace, Foo3X) | |
| 297 # Verify we fail to add a node between undeprecated versions | |
| 298 AddError(namespace, Foo2X, 'Overlap in versions.') | |
| 299 | |
| 300 BarXX = MockNode('bar', None, None) | |
| 301 Bar12 = MockNode('bar', 1.0, 2.0) | |
| 302 Bar23 = MockNode('bar', 2.0, 3.0) | |
| 303 Bar34 = MockNode('bar', 3.0, 4.0) | |
| 304 | |
| 305 # Verify we succeed with fully qualified versions | |
| 306 namespace = IDLNamespace(namespace) | |
| 307 AddOkay(namespace, BarXX) | |
| 308 AddOkay(namespace, Bar12) | |
| 309 # Verify we warn when detecting a gap | |
| 310 AddWarn(namespace, Bar34, 'Gap in version numbers.') | |
| 311 # Verify we fail when inserting into this gap | |
| 312 # (NOTE: while this could be legal, it is sloppy so we disallow it) | |
| 313 AddError(namespace, Bar23, 'Declarations out of order.') | |
| 314 | |
| 315 # Verify local namespace | |
| 316 VerifyFindOne(namespace, 'bar', 0.0, BarXX) | |
| 317 VerifyFindAll(namespace, 'bar', 0.5, 1.5, [BarXX, Bar12]) | |
| 318 | |
| 319 # Verify the correct version of the object is found recursively | |
| 320 VerifyFindOne(namespace, 'foo', 0.0, FooXX) | |
| 321 VerifyFindOne(namespace, 'foo', 0.5, FooXX) | |
| 322 VerifyFindOne(namespace, 'foo', 1.0, Foo1X) | |
| 323 VerifyFindOne(namespace, 'foo', 1.5, Foo1X) | |
| 324 VerifyFindOne(namespace, 'foo', 3.0, Foo3X) | |
| 325 VerifyFindOne(namespace, 'foo', 100.0, Foo3X) | |
| 326 | |
| 327 # Verify the correct range of objects is found | |
| 328 VerifyFindAll(namespace, 'foo', 0.0, 1.0, [FooXX]) | |
| 329 VerifyFindAll(namespace, 'foo', 0.5, 1.0, [FooXX]) | |
| 330 VerifyFindAll(namespace, 'foo', 1.0, 1.1, [Foo1X]) | |
| 331 VerifyFindAll(namespace, 'foo', 0.5, 1.5, [FooXX, Foo1X]) | |
| 332 VerifyFindAll(namespace, 'foo', 0.0, 3.0, [FooXX, Foo1X]) | |
| 333 VerifyFindAll(namespace, 'foo', 3.0, 100.0, [Foo3X]) | |
| 334 | |
| 335 | |
| 336 | |
| 337 if errors: | |
| 338 print 'Test failed with %d errors.' % errors | |
| 339 else: | |
| 340 print 'Passed.' | |
| 341 return errors | |
| 342 | |
| 343 if __name__ == '__main__': | |
| 344 sys.exit(Main(sys.argv[1:])) | |
| 345 | |
| OLD | NEW |