"""
IDLRelease for PPAPI
This file defines the behavior of the AST namespace which allows for resolving
a symbol as one or more AST nodes given a Release or range of Releases.
"""
from __future__ import print_function
import sys
from idl_log import ErrOut, InfoOut, WarnOut
from idl_option import GetOption, Option, ParseOptions
Option('release_debug', 'Debug Release data')
Option('wgap', 'Ignore Release gap warning')
error = None
warning = None
def ReportReleaseError(msg):
global error
error = msg
def ReportReleaseWarning(msg):
global warning
warning = msg
def ReportClear():
global error, warning
error = None
warning = None
class IDLRelease(object):
def __init__(self, rmin, rmax):
self.rmin = rmin
self.rmax = rmax
def __str__(self):
if not self.rmin:
rmin = '0'
else:
rmin = str(self.rmin)
if not self.rmax:
rmax = '+oo'
else:
rmax = str(self.rmax)
return '[%s,%s)' % (rmin, rmax)
def SetReleaseRange(self, rmin, rmax):
self.rmin = rmin
self.rmax = rmax
def IsRelease(self, release):
if self.rmax and self.rmax <= release:
return False
if self.rmin and self.rmin > release:
return False
if GetOption('release_debug'):
InfoOut.Log('%f is in %s' % (release, self))
return True
def InReleases(self, releases):
if not releases: return False
if self.IsRelease(releases[-1]): return True
if len(releases) > 1:
return self.InRange(releases[0], releases[-1])
return False
def InRange(self, rmin, rmax):
assert (rmin == None) or rmin < rmax
if rmin is not None and self.rmax is not None:
if self.rmax <= rmin:
return False
if rmax is not None and self.rmin is not None:
if self.rmin >= rmax:
return False
if GetOption('release_debug'):
InfoOut.Log('%f to %f is in %s' % (rmin, rmax, self))
return True
def GetMinMax(self, releases = None):
if not releases:
return self.rmin, self.rmax
if not self.rmin:
rmin = releases[0]
else:
rmin = str(self.rmin)
if not self.rmax:
rmax = releases[-1]
else:
rmax = str(self.rmax)
return (rmin, rmax)
def SetMin(self, release):
assert not self.rmin
self.rmin = release
def Error(self, msg):
ReportReleaseError(msg)
def Warn(self, msg):
ReportReleaseWarning(msg)
class IDLReleaseList(object):
def __init__(self):
self._nodes = []
def GetReleases(self):
return self._nodes
def FindRelease(self, release):
for node in self._nodes:
if node.IsRelease(release):
return node
return None
def FindRange(self, rmin, rmax):
assert (rmin == None) or rmin != rmax
out = []
for node in self._nodes:
if node.InRange(rmin, rmax):
out.append(node)
return out
def AddNode(self, node):
if GetOption('release_debug'):
InfoOut.Log('\nAdding %s %s' % (node.Location(), node))
last = None
for cver in self._nodes:
if GetOption('release_debug'): InfoOut.Log(' Checking %s' % cver)
if not node.rmin:
node.Error('Missing release on overload of previous %s.' %
cver.Location())
return False
if not cver.rmax:
cver.rmax = node.rmin
if GetOption('release_debug'): InfoOut.Log(' Update %s' % cver)
if cver.rmax > node.rmin:
if node.rmax and cver.rmin >= node.rmax:
node.Error('Declarations out of order.')
else:
node.Error('Overlap in releases: %s vs %s when adding %s' %
(cver.rmax, node.rmin, node))
return False
last = cver
if last and last.rmax != node.rmin:
node.Warn('Gap in release numbers.')
if GetOption('release_debug'): InfoOut.Log('Done %s' % node)
self._nodes.append(node)
return True
class IDLReleaseMap(object):
def __init__(self, release_info):
self.version_to_release = {}
self.release_to_version = {}
self.release_to_channel = {}
for release, version, channel in release_info:
self.version_to_release[version] = release
self.release_to_version[release] = version
self.release_to_channel[release] = channel
self.releases = sorted(self.release_to_version.keys())
self.versions = sorted(self.version_to_release.keys())
def GetVersion(self, release):
return self.release_to_version.get(release, None)
def GetVersions(self):
return self.versions
def GetRelease(self, version):
return self.version_to_release.get(version, None)
def GetReleases(self):
return self.releases
def GetReleaseRange(self):
return (self.releases[0], self.releases[-1])
def GetVersionRange(self):
return (self.versions[0], self.version[-1])
def GetChannel(self, release):
return self.release_to_channel.get(release, None)
def TestReleaseNode():
FooXX = IDLRelease(None, None)
Foo1X = IDLRelease('M14', None)
Foo23 = IDLRelease('M15', 'M16')
assert FooXX.IsRelease('M13')
assert FooXX.IsRelease('M14')
assert FooXX.InRange('M13', 'M13A')
assert FooXX.InRange('M14','M15')
assert not Foo1X.IsRelease('M13')
assert Foo1X.IsRelease('M14')
assert Foo1X.IsRelease('M15')
assert not Foo1X.InRange('M13', 'M14')
assert not Foo1X.InRange('M13A', 'M14')
assert Foo1X.InRange('M14', 'M15')
assert Foo1X.InRange('M15', 'M16')
assert not Foo23.InRange('M13', 'M14')
assert not Foo23.InRange('M13A', 'M14')
assert not Foo23.InRange('M14', 'M15')
assert Foo23.InRange('M15', 'M16')
assert Foo23.InRange('M14', 'M15A')
assert Foo23.InRange('M15B', 'M17')
assert not Foo23.InRange('M16', 'M17')
print("TestReleaseNode - Passed")
def TestReleaseListWarning():
FooXX = IDLRelease(None, None)
Foo1X = IDLRelease('M14', None)
Foo23 = IDLRelease('M15', 'M16')
Foo45 = IDLRelease('M17', 'M18')
ReportClear()
releases = IDLReleaseList()
assert releases.AddNode(Foo23)
assert releases.AddNode(Foo45)
assert warning
print("TestReleaseListWarning - Passed")
def TestReleaseListError():
FooXX = IDLRelease(None, None)
Foo1X = IDLRelease('M14', None)
Foo23 = IDLRelease('M15', 'M16')
Foo45 = IDLRelease('M17', 'M18')
ReportClear()
releases = IDLReleaseList()
assert releases.AddNode(FooXX)
assert releases.AddNode(Foo23)
assert not releases.AddNode(Foo1X)
assert error
print("TestReleaseListError - Passed")
def TestReleaseListOK():
FooXX = IDLRelease(None, None)
Foo1X = IDLRelease('M14', None)
Foo23 = IDLRelease('M15', 'M16')
Foo45 = IDLRelease('M17', 'M18')
ReportClear()
releases = IDLReleaseList()
assert releases.AddNode(FooXX)
assert releases.AddNode(Foo1X)
assert releases.AddNode(Foo23)
assert not error and not warning
assert releases.AddNode(Foo45)
assert warning
assert releases.FindRelease('M13') == FooXX
assert releases.FindRelease('M14') == Foo1X
assert releases.FindRelease('M15') == Foo23
assert releases.FindRelease('M16') == None
assert releases.FindRelease('M17') == Foo45
assert releases.FindRelease('M18') == None
assert releases.FindRange('M13','M14') == [FooXX]
assert releases.FindRange('M13','M17') == [FooXX, Foo1X, Foo23]
assert releases.FindRange('M16','M17') == []
assert releases.FindRange(None, None) == [FooXX, Foo1X, Foo23, Foo45]
print("TestReleaseListOK - Passed")
def TestReleaseMap():
print("TestReleaseMap- Passed")
def Main(args):
TestReleaseNode()
TestReleaseListWarning()
TestReleaseListError()
TestReleaseListOK()
print("Passed")
return 0
if __name__ == '__main__':
sys.exit(Main(sys.argv[1:]))