"""
IDLNamespace 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_option import GetOption, Option, ParseOptions
from idl_log import ErrOut, InfoOut, WarnOut
from idl_release import IDLRelease, IDLReleaseList
Option('label', 'Use the specifed label blocks.', default='Chrome')
Option('namespace_debug', 'Use the specified release')
class IDLNamespace(object):
def __init__(self, parent):
self._name_to_releases = {}
self._parent = parent
def Dump(self):
for name in self._name_to_releases:
InfoOut.Log('NAME=%s' % name)
for cver in self._name_to_releases[name].GetReleases():
InfoOut.Log(' %s' % cver)
InfoOut.Log('')
def FindRelease(self, name, release):
verlist = self._name_to_releases.get(name, None)
if verlist == None:
if self._parent:
return self._parent.FindRelease(name, release)
else:
return None
return verlist.FindRelease(release)
def FindRange(self, name, rmin, rmax):
verlist = self._name_to_releases.get(name, None)
if verlist == None:
if self._parent:
return self._parent.FindRange(name, rmin, rmax)
else:
return []
return verlist.FindRange(rmin, rmax)
def FindList(self, name):
verlist = self._name_to_releases.get(name, None)
if verlist == None:
if self._parent:
return self._parent.FindList(name)
return verlist
def AddNode(self, node):
name = node.GetName()
verlist = self._name_to_releases.setdefault(name,IDLReleaseList())
if GetOption('namespace_debug'):
print("Adding to namespace: %s" % node)
return verlist.AddNode(node)
class MockNode(IDLRelease):
def __init__(self, name, rmin, rmax):
self.name = name
self.rmin = rmin
self.rmax = rmax
self.errors = []
self.warns = []
self.properties = {
'NAME': name,
'release': rmin,
'deprecate' : rmax
}
def __str__(self):
return '%s (%s : %s)' % (self.name, self.rmin, self.rmax)
def GetName(self):
return self.name
def Error(self, msg):
if GetOption('release_debug'):
print('Error: %s' % msg)
self.errors.append(msg)
def Warn(self, msg):
if GetOption('release_debug'):
print('Warn: %s' % msg)
self.warns.append(msg)
def GetProperty(self, name):
return self.properties.get(name, None)
errors = 0
def DumpFailure(namespace, node, msg):
global errors
print('\n******************************')
print('Failure: %s %s' % (node, msg))
for warn in node.warns:
print(' WARN: %s' % warn)
for err in node.errors:
print(' ERROR: %s' % err)
print('\n')
namespace.Dump()
print('******************************\n')
errors += 1
def AddOkay(namespace, node):
okay = namespace.AddNode(node)
if not okay or node.errors or node.warns:
DumpFailure(namespace, node, 'Expected success')
def AddWarn(namespace, node, msg):
okay = namespace.AddNode(node)
if not okay or node.errors or not node.warns:
DumpFailure(namespace, node, 'Expected warnings')
if msg not in node.warns:
DumpFailure(namespace, node, 'Expected warning: %s' % msg)
def AddError(namespace, node, msg):
okay = namespace.AddNode(node)
if okay or not node.errors:
DumpFailure(namespace, node, 'Expected errors')
if msg not in node.errors:
DumpFailure(namespace, node, 'Expected error: %s' % msg)
print(">>%s<<\n>>%s<<\n" % (node.errors[0], msg))
def VerifyFindOne(namespace, name, release, node):
global errors
if (namespace.FindRelease(name, release) != node):
print("Failed to find %s as release %f of %s" % (node, release, name))
namespace.Dump()
print("\n")
errors += 1
def VerifyFindAll(namespace, name, rmin, rmax, nodes):
global errors
out = namespace.FindRange(name, rmin, rmax)
if (out != nodes):
print("Found [%s] instead of[%s] for releases %f to %f of %s" % (' '.join([
str(x) for x in out
]), ' '.join([str(x) for x in nodes]), rmin, rmax, name))
namespace.Dump()
print("\n")
errors += 1
def Main(args):
global errors
ParseOptions(args)
InfoOut.SetConsole(True)
namespace = IDLNamespace(None)
FooXX = MockNode('foo', None, None)
Foo1X = MockNode('foo', 1.0, None)
Foo2X = MockNode('foo', 2.0, None)
Foo3X = MockNode('foo', 3.0, None)
AddOkay(namespace, FooXX)
AddOkay(namespace, Foo1X)
AddOkay(namespace, Foo3X)
AddError(namespace, Foo2X,
'Overlap in releases: 3.0 vs 2.0 when adding foo (2.0 : None)')
BarXX = MockNode('bar', None, None)
Bar12 = MockNode('bar', 1.0, 2.0)
Bar23 = MockNode('bar', 2.0, 3.0)
Bar34 = MockNode('bar', 3.0, 4.0)
namespace = IDLNamespace(namespace)
AddOkay(namespace, BarXX)
AddOkay(namespace, Bar12)
AddWarn(namespace, Bar34, 'Gap in release numbers.')
AddError(namespace, Bar23, 'Declarations out of order.')
VerifyFindOne(namespace, 'bar', 0.0, BarXX)
VerifyFindAll(namespace, 'bar', 0.5, 1.5, [BarXX, Bar12])
VerifyFindOne(namespace, 'foo', 0.0, FooXX)
VerifyFindOne(namespace, 'foo', 0.5, FooXX)
VerifyFindOne(namespace, 'foo', 1.0, Foo1X)
VerifyFindOne(namespace, 'foo', 1.5, Foo1X)
VerifyFindOne(namespace, 'foo', 3.0, Foo3X)
VerifyFindOne(namespace, 'foo', 100.0, Foo3X)
VerifyFindAll(namespace, 'foo', 0.0, 1.0, [FooXX])
VerifyFindAll(namespace, 'foo', 0.5, 1.0, [FooXX])
VerifyFindAll(namespace, 'foo', 1.0, 1.1, [Foo1X])
VerifyFindAll(namespace, 'foo', 0.5, 1.5, [FooXX, Foo1X])
VerifyFindAll(namespace, 'foo', 0.0, 3.0, [FooXX, Foo1X])
VerifyFindAll(namespace, 'foo', 3.0, 100.0, [Foo3X])
FooBar = MockNode('foobar', 1.0, 2.0)
namespace = IDLNamespace(namespace)
AddOkay(namespace, FooBar)
if errors:
print('Test failed with %d errors.' % errors)
else:
print('Passed.')
return errors
if __name__ == '__main__':
sys.exit(Main(sys.argv[1:]))