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