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.
9 This file defines the behavior of the AST namespace which allows for resolving
10 a symbol as one or more AST nodes given a Release or range of Releases.
15 from idl_log
import ErrOut
, InfoOut
, WarnOut
16 from idl_option
import GetOption
, Option
, ParseOptions
18 Option('release_debug', 'Debug Release data')
19 Option('wgap', 'Ignore Release gap warning')
23 # Module level functions and data used for testing.
27 def ReportReleaseError(msg
):
31 def ReportReleaseWarning(msg
):
43 # IDLRelease is an object which stores the association of a given symbol
44 # name, with an AST node for a range of Releases for that object.
46 # A vmin value of None indicates that the object begins at the earliest
47 # available Release number. The value of vmin is always inclusive.
49 # A vmax value of None indicates that the object is never deprecated, so
50 # it exists until it is overloaded or until the latest available Release.
51 # The value of vmax is always exclusive, representing the first Release
52 # on which the object is no longer valid.
53 class IDLRelease(object):
54 def __init__(self
, rmin
, rmax
):
67 return '[%s,%s)' % (rmin
, rmax
)
69 def SetReleaseRange(self
, rmin
, rmax
):
73 # True, if Release falls within the interval [self.vmin, self.vmax)
74 def IsRelease(self
, release
):
75 if self
.rmax
and self
.rmax
<= release
:
77 if self
.rmin
and self
.rmin
> release
:
79 if GetOption('release_debug'):
80 InfoOut
.Log('%f is in %s' % (release
, self
))
83 # True, if Release falls within the interval [self.vmin, self.vmax)
84 def InReleases(self
, releases
):
85 if not releases
: return False
87 # Check last release first, since InRange does not match last item
88 if self
.IsRelease(releases
[-1]): return True
90 return self
.InRange(releases
[0], releases
[-1])
93 # True, if interval [vmin, vmax) overlaps interval [self.vmin, self.vmax)
94 def InRange(self
, rmin
, rmax
):
95 assert (rmin
== None) or rmin
< rmax
97 # An min of None always passes a min bound test
98 # An max of None always passes a max bound test
99 if rmin
is not None and self
.rmax
is not None:
100 if self
.rmax
<= rmin
:
102 if rmax
is not None and self
.rmin
is not None:
103 if self
.rmin
>= rmax
:
106 if GetOption('release_debug'):
107 InfoOut
.Log('%f to %f is in %s' % (rmin
, rmax
, self
))
110 def GetMinMax(self
, releases
= None):
112 return self
.rmin
, self
.rmax
117 rmin
= str(self
.rmin
)
121 rmax
= str(self
.rmax
)
124 def SetMin(self
, release
):
128 def Error(self
, msg
):
129 ReportReleaseError(msg
)
132 ReportReleaseWarning(msg
)
138 # IDLReleaseList is a list based container for holding IDLRelease
139 # objects in order. The IDLReleaseList can be added to, and searched by
140 # range. Objects are stored in order, and must be added in order.
142 class IDLReleaseList(object):
146 def GetReleases(self
):
149 def FindRelease(self
, release
):
150 for node
in self
._nodes
:
151 if node
.IsRelease(release
):
155 def FindRange(self
, rmin
, rmax
):
156 assert (rmin
== None) or rmin
!= rmax
159 for node
in self
._nodes
:
160 if node
.InRange(rmin
, rmax
):
164 def AddNode(self
, node
):
165 if GetOption('release_debug'):
166 InfoOut
.Log('\nAdding %s %s' % (node
.Location(), node
))
169 # Check current releases in that namespace
170 for cver
in self
._nodes
:
171 if GetOption('release_debug'): InfoOut
.Log(' Checking %s' % cver
)
173 # We should only be missing a 'release' tag for the first item.
175 node
.Error('Missing release on overload of previous %s.' %
179 # If the node has no max, then set it to this one
181 cver
.rmax
= node
.rmin
182 if GetOption('release_debug'): InfoOut
.Log(' Update %s' % cver
)
184 # if the max and min overlap, than's an error
185 if cver
.rmax
> node
.rmin
:
186 if node
.rmax
and cver
.rmin
>= node
.rmax
:
187 node
.Error('Declarations out of order.')
189 node
.Error('Overlap in releases: %s vs %s when adding %s' %
190 (cver
.rmax
, node
.rmin
, node
))
194 # Otherwise, the previous max and current min should match
195 # unless this is the unlikely case of something being only
196 # temporarily deprecated.
197 if last
and last
.rmax
!= node
.rmin
:
198 node
.Warn('Gap in release numbers.')
200 # If we made it here, this new node must be the 'newest'
201 # and does not overlap with anything previously added, so
202 # we can add it to the end of the list.
203 if GetOption('release_debug'): InfoOut
.Log('Done %s' % node
)
204 self
._nodes
.append(node
)
210 # A release map, can map from an float interface release, to a global
213 class IDLReleaseMap(object):
214 def __init__(self
, release_info
):
215 self
.version_to_release
= {}
216 self
.release_to_version
= {}
217 self
.release_to_channel
= {}
218 for release
, version
, channel
in release_info
:
219 self
.version_to_release
[version
] = release
220 self
.release_to_version
[release
] = version
221 self
.release_to_channel
[release
] = channel
222 self
.releases
= sorted(self
.release_to_version
.keys())
223 self
.versions
= sorted(self
.version_to_release
.keys())
225 def GetVersion(self
, release
):
226 return self
.release_to_version
.get(release
, None)
228 def GetVersions(self
):
231 def GetRelease(self
, version
):
232 return self
.version_to_release
.get(version
, None)
234 def GetReleases(self
):
237 def GetReleaseRange(self
):
238 return (self
.releases
[0], self
.releases
[-1])
240 def GetVersionRange(self
):
241 return (self
.versions
[0], self
.version
[-1])
243 def GetChannel(self
, release
):
244 return self
.release_to_channel
.get(release
, None)
249 def TestReleaseNode():
250 FooXX
= IDLRelease(None, None)
251 Foo1X
= IDLRelease('M14', None)
252 Foo23
= IDLRelease('M15', 'M16')
254 assert FooXX
.IsRelease('M13')
255 assert FooXX
.IsRelease('M14')
256 assert FooXX
.InRange('M13', 'M13A')
257 assert FooXX
.InRange('M14','M15')
259 assert not Foo1X
.IsRelease('M13')
260 assert Foo1X
.IsRelease('M14')
261 assert Foo1X
.IsRelease('M15')
263 assert not Foo1X
.InRange('M13', 'M14')
264 assert not Foo1X
.InRange('M13A', 'M14')
265 assert Foo1X
.InRange('M14', 'M15')
266 assert Foo1X
.InRange('M15', 'M16')
268 assert not Foo23
.InRange('M13', 'M14')
269 assert not Foo23
.InRange('M13A', 'M14')
270 assert not Foo23
.InRange('M14', 'M15')
271 assert Foo23
.InRange('M15', 'M16')
272 assert Foo23
.InRange('M14', 'M15A')
273 assert Foo23
.InRange('M15B', 'M17')
274 assert not Foo23
.InRange('M16', 'M17')
275 print "TestReleaseNode - Passed"
278 def TestReleaseListWarning():
279 FooXX
= IDLRelease(None, None)
280 Foo1X
= IDLRelease('M14', None)
281 Foo23
= IDLRelease('M15', 'M16')
282 Foo45
= IDLRelease('M17', 'M18')
284 # Add nodes out of order should fail
286 releases
= IDLReleaseList()
287 assert releases
.AddNode(Foo23
)
288 assert releases
.AddNode(Foo45
)
290 print "TestReleaseListWarning - Passed"
293 def TestReleaseListError():
294 FooXX
= IDLRelease(None, None)
295 Foo1X
= IDLRelease('M14', None)
296 Foo23
= IDLRelease('M15', 'M16')
297 Foo45
= IDLRelease('M17', 'M18')
299 # Add nodes out of order should fail
301 releases
= IDLReleaseList()
302 assert releases
.AddNode(FooXX
)
303 assert releases
.AddNode(Foo23
)
304 assert not releases
.AddNode(Foo1X
)
306 print "TestReleaseListError - Passed"
309 def TestReleaseListOK():
310 FooXX
= IDLRelease(None, None)
311 Foo1X
= IDLRelease('M14', None)
312 Foo23
= IDLRelease('M15', 'M16')
313 Foo45
= IDLRelease('M17', 'M18')
315 # Add nodes in order should work
317 releases
= IDLReleaseList()
318 assert releases
.AddNode(FooXX
)
319 assert releases
.AddNode(Foo1X
)
320 assert releases
.AddNode(Foo23
)
321 assert not error
and not warning
322 assert releases
.AddNode(Foo45
)
325 assert releases
.FindRelease('M13') == FooXX
326 assert releases
.FindRelease('M14') == Foo1X
327 assert releases
.FindRelease('M15') == Foo23
328 assert releases
.FindRelease('M16') == None
329 assert releases
.FindRelease('M17') == Foo45
330 assert releases
.FindRelease('M18') == None
332 assert releases
.FindRange('M13','M14') == [FooXX
]
333 assert releases
.FindRange('M13','M17') == [FooXX
, Foo1X
, Foo23
]
334 assert releases
.FindRange('M16','M17') == []
335 assert releases
.FindRange(None, None) == [FooXX
, Foo1X
, Foo23
, Foo45
]
337 # Verify we can find the correct versions
338 print "TestReleaseListOK - Passed"
341 def TestReleaseMap():
342 print "TestReleaseMap- Passed"
347 TestReleaseListWarning()
348 TestReleaseListError()
354 if __name__
== '__main__':
355 sys
.exit(Main(sys
.argv
[1:]))