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 Error(self
, msg
):
111 ReportReleaseError(msg
)
114 ReportReleaseWarning(msg
)
120 # IDLReleaseList is a list based container for holding IDLRelease
121 # objects in order. The IDLReleaseList can be added to, and searched by
122 # range. Objects are stored in order, and must be added in order.
124 class IDLReleaseList(object):
128 def FindRelease(self
, release
):
129 for node
in self
.nodes
:
130 if node
.IsRelease(release
):
134 def FindRange(self
, rmin
, rmax
):
135 assert (rmin
== None) or rmin
!= rmax
138 for node
in self
.nodes
:
139 if node
.InRange(rmin
, rmax
):
143 def AddNode(self
, node
):
144 if GetOption('release_debug'):
145 InfoOut
.Log('\nAdding %s %s' % (node
.Location(), node
))
148 # Check current releases in that namespace
149 for cver
in self
.nodes
:
150 if GetOption('release_debug'): InfoOut
.Log(' Checking %s' % cver
)
152 # We should only be missing a 'release' tag for the first item.
154 node
.Error('Missing release on overload of previous %s.' %
158 # If the node has no max, then set it to this one
160 cver
.rmax
= node
.rmin
161 if GetOption('release_debug'): InfoOut
.Log(' Update %s' % cver
)
163 # if the max and min overlap, than's an error
164 if cver
.rmax
> node
.rmin
:
165 if node
.rmax
and cver
.rmin
>= node
.rmax
:
166 node
.Error('Declarations out of order.')
168 node
.Error('Overlap in releases: %s vs %s when adding %s' %
169 (cver
.rmax
, node
.rmin
, node
))
173 # Otherwise, the previous max and current min should match
174 # unless this is the unlikely case of something being only
175 # temporarily deprecated.
176 if last
and last
.rmax
!= node
.rmin
:
177 node
.Warn('Gap in release numbers.')
179 # If we made it here, this new node must be the 'newest'
180 # and does not overlap with anything previously added, so
181 # we can add it to the end of the list.
182 if GetOption('release_debug'): InfoOut
.Log('Done %s' % node
)
183 self
.nodes
.append(node
)
189 # A release map, can map from an float interface release, to a global
192 class IDLReleaseMap(object):
193 def __init__(self
, release_info
):
194 self
.version_to_release
= {}
195 self
.release_to_version
= {}
196 for release
, version
in release_info
:
197 self
.version_to_release
[version
] = release
198 self
.release_to_version
[release
] = version
199 self
.releases
= sorted(self
.release_to_version
.keys())
200 self
.versions
= sorted(self
.version_to_release
.keys())
202 def GetVersion(self
, release
):
203 return self
.release_to_version
.get(release
, None)
205 def GetVersions(self
):
208 def GetRelease(self
, version
):
209 return self
.version_to_release
.get(version
, None)
211 def GetReleases(self
):
217 def TestReleaseNode():
218 FooXX
= IDLRelease(None, None)
219 Foo1X
= IDLRelease('M14', None)
220 Foo23
= IDLRelease('M15', 'M16')
222 assert FooXX
.IsRelease('M13')
223 assert FooXX
.IsRelease('M14')
224 assert FooXX
.InRange('M13', 'M13A')
225 assert FooXX
.InRange('M14','M15')
227 assert not Foo1X
.IsRelease('M13')
228 assert Foo1X
.IsRelease('M14')
229 assert Foo1X
.IsRelease('M15')
231 assert not Foo1X
.InRange('M13', 'M14')
232 assert not Foo1X
.InRange('M13A', 'M14')
233 assert Foo1X
.InRange('M14', 'M15')
234 assert Foo1X
.InRange('M15', 'M16')
236 assert not Foo23
.InRange('M13', 'M14')
237 assert not Foo23
.InRange('M13A', 'M14')
238 assert not Foo23
.InRange('M14', 'M15')
239 assert Foo23
.InRange('M15', 'M16')
240 assert Foo23
.InRange('M14', 'M15A')
241 assert Foo23
.InRange('M15B', 'M17')
242 assert not Foo23
.InRange('M16', 'M17')
243 print "TestReleaseNode - Passed"
246 def TestReleaseListWarning():
247 FooXX
= IDLRelease(None, None)
248 Foo1X
= IDLRelease('M14', None)
249 Foo23
= IDLRelease('M15', 'M16')
250 Foo45
= IDLRelease('M17', 'M18')
252 # Add nodes out of order should fail
254 releases
= IDLReleaseList()
255 assert releases
.AddNode(Foo23
)
256 assert releases
.AddNode(Foo45
)
258 print "TestReleaseListWarning - Passed"
261 def TestReleaseListError():
262 FooXX
= IDLRelease(None, None)
263 Foo1X
= IDLRelease('M14', None)
264 Foo23
= IDLRelease('M15', 'M16')
265 Foo45
= IDLRelease('M17', 'M18')
267 # Add nodes out of order should fail
269 releases
= IDLReleaseList()
270 assert releases
.AddNode(FooXX
)
271 assert releases
.AddNode(Foo23
)
272 assert not releases
.AddNode(Foo1X
)
274 print "TestReleaseListError - Passed"
277 def TestReleaseListOK():
278 FooXX
= IDLRelease(None, None)
279 Foo1X
= IDLRelease('M14', None)
280 Foo23
= IDLRelease('M15', 'M16')
281 Foo45
= IDLRelease('M17', 'M18')
283 # Add nodes in order should work
285 releases
= IDLReleaseList()
286 assert releases
.AddNode(FooXX
)
287 assert releases
.AddNode(Foo1X
)
288 assert releases
.AddNode(Foo23
)
289 assert not error
and not warning
290 assert releases
.AddNode(Foo45
)
293 assert releases
.FindRelease('M13') == FooXX
294 assert releases
.FindRelease('M14') == Foo1X
295 assert releases
.FindRelease('M15') == Foo23
296 assert releases
.FindRelease('M16') == None
297 assert releases
.FindRelease('M17') == Foo45
298 assert releases
.FindRelease('M18') == None
300 assert releases
.FindRange('M13','M14') == [FooXX
]
301 assert releases
.FindRange('M13','M17') == [FooXX
, Foo1X
, Foo23
]
302 assert releases
.FindRange('M16','M17') == []
303 assert releases
.FindRange(None, None) == [FooXX
, Foo1X
, Foo23
, Foo45
]
305 # Verify we can find the correct versions
306 print "TestReleaseListOK - Passed"
309 def TestReleaseMap():
310 print "TestReleaseMap- Passed"
315 TestReleaseListWarning()
316 TestReleaseListError()
322 if __name__
== '__main__':
323 sys
.exit(Main(sys
.argv
[1:]))