Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: ppapi/generators/idl_namespace.py

Issue 7253025: Add version aware name resolution (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 #!/usr/bin/python
2 #
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
5 # found in the LICENSE file.
6
7 """
8 IDLNamespace for PPAPI
9
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.
12 """
13
14 import sys
15
16 from idl_option import GetOption, Option, ParseOptions
17 from idl_log import ErrOut, InfoOut, WarnOut
18 from idl_version import IDLVersion
19
20 Option('label', 'Use the specifed label blocks.', default='Chrome')
21 Option('version', 'Use the specified version', default='M14')
22 Option('namespace_debug', 'Use the specified version')
23
24
25 #
26 # IDLVersionList
27 #
28 # IDLVersionList is a list based container for holding IDLVersion
29 # objects in order. The IDLVersionList can be added to, and searched by
30 # range. Objects are stored in order, and must be added in order.
31 #
32 class IDLVersionList(object):
33 def __init__(self):
34 self.nodes = []
35
36 def FindVersion(self, version):
37 assert type(version) == float
38
39 for node in self.nodes:
40 if node.IsVersion(version):
41 return node
42 return None
43
44 def FindRange(self, vmin, vmax):
45 assert type(vmin) == float
46 assert type(vmax) == float
47 assert vmin != vmax
48
49 out = []
50 for node in self.nodes:
51 if node.InRange(vmin, vmax):
52 out.append(node)
53 return out
54
55 def AddNode(self, node):
56 if GetOption('version_debug'): 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 node.Error('Missing version on overload of previous %s.' %
66 cver.Location())
67 raise RuntimeError('DSFSD')
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
109 def AddReleaseVersionMapping(self, release, version):
110 self.version_to_release[version] = release
111 self.release_to_version[release] = version
112 self.versions = sorted(self.version_to_release.keys())
113
114 def GetRelease(self, version):
115 # Check for exact match
116 if version in self.versions:
117 return self.version_to_release[version]
118
119 def GetVersion(self, release):
120 return self.release_to_version[release]
121
122
123
124 #
125 # IDLNamespace
126 #
127 # IDLNamespace provides a mapping between a symbol name and an IDLVersionList
128 # which contains IDLVersion objects. It provides an interface for fetching
129 # one or more IDLNodes based on a version or range of versions.
130 #
131 class IDLNamespace(object):
132 def __init__(self, parent):
133 self.namespace = {}
134 self.parent = parent
135
136 def Dump(self):
137 for name in self.namespace:
138 InfoOut.Log('NAME=%s' % name)
139 for cver in self.namespace[name]:
140 InfoOut.Log(' %s' % cver)
141 InfoOut.Log('')
142
143 def FindVersion(self, name, version):
144 list = self.namespace.get(name, None)
145 if list == None:
146 if self.parent:
147 return self.parent.FindVersion(name, version)
148 else:
149 return None
150 return list.FindVersion(version)
151
152 def FindRange(self, name, vmin, vmax):
153 list = self.namespace.get(name, None)
154 if list == None:
155 if self.parent:
156 return self.parent.FindRange(name, vmin, vmax)
157 else:
158 return []
159 return list.FindRange(vmin, vmax)
160
161 def FindList(self, name):
162 list = self.namespace.get(name, None)
163 if list == None:
164 if self.parent:
165 return self.parent.FindList(name)
166 return list
167
168 def AddNode(self, node):
169 name = node.GetName()
170 list = self.namespace.setdefault(name,IDLVersionList())
171 if GetOption('namespace_debug'):
172 print "Adding to namespace: %s" % node
173 return list.AddNode(node)
174
175
176
177 #
178 # Testing Code
179 #
180
181 #
182 # MockNode
183 #
184 # Mocks the IDLNode to support error, warning handling, and string functions.
185 #
186 class MockNode(IDLVersion):
187 def __init__(self, name, vmin, vmax):
188 self.name = name
189 self.vmin = vmin
190 self.vmax = vmax
191 self.errors = []
192 self.warns = []
193 self.properties = {
194 'NAME': name,
195 'version': vmin,
196 'deprecate' : vmax
197 }
198
199 def __str__(self):
200 return '%s (%s : %s)' % (self.name, self.vmin, self.vmax)
201
202 def GetName(self):
203 return self.name
204
205 def Error(self, msg):
206 if GetOption('version_debug'): print 'Error: %s' % msg
207 self.errors.append(msg)
208
209 def Warn(self, msg):
210 if GetOption('version_debug'): print 'Warn: %s' % msg
211 self.warns.append(msg)
212
213 def GetProperty(self, name):
214 return self.properties.get(name, None)
215
216 errors = 0
217 #
218 # DumpFailure
219 #
220 # Dumps all the information relevant to an add failure.
221 def DumpFailure(namespace, node, msg):
222 global errors
223 print '\n******************************'
224 print 'Failure: %s %s' % (node, msg)
225 for warn in node.warns:
226 print ' WARN: %s' % warn
227 for err in node.errors:
228 print ' ERROR: %s' % err
229 print '\n'
230 namespace.Dump()
231 print '******************************\n'
232 errors += 1
233
234 # Add expecting no errors or warnings
235 def AddOkay(namespace, node):
236 okay = namespace.AddNode(node)
237 if not okay or node.errors or node.warns:
238 DumpFailure(namespace, node, 'Expected success')
239
240 # Add expecting a specific warning
241 def AddWarn(namespace, node, msg):
242 okay = namespace.AddNode(node)
243 if not okay or node.errors or not node.warns:
244 DumpFailure(namespace, node, 'Expected warnings')
245 if msg not in node.warns:
246 DumpFailure(namespace, node, 'Expected warning: %s' % msg)
247
248 # Add expecting a specific error any any number of warnings
249 def AddError(namespace, node, msg):
250 okay = namespace.AddNode(node)
251 if okay or not node.errors:
252 DumpFailure(namespace, node, 'Expected errors')
253 if msg not in node.errors:
254 DumpFailure(namespace, node, 'Expected error: %s' % msg)
255
256 # Verify that a FindVersion call on the namespace returns the expected node.
257 def VerifyFindOne(namespace, name, version, node):
258 global errors
259 if (namespace.FindVersion(name, version) != node):
260 print "Failed to find %s as version %f of %s" % (node, version, name)
261 namespace.Dump()
262 print "\n"
263 errors += 1
264
265 # Verify that a FindRage call on the namespace returns a set of expected nodes.
266 def VerifyFindAll(namespace, name, vmin, vmax, nodes):
267 global errors
268 out = namespace.FindRange(name, vmin, vmax)
269 if (out != nodes):
270 print "Found [%s] instead of[%s] for versions %f to %f of %s" % (
271 ' '.join([str(x) for x in out]),
272 ' '.join([str(x) for x in nodes]),
273 vmin,
274 vmax,
275 name)
276 namespace.Dump()
277 print "\n"
278 errors += 1
279
280 def Main(args):
281 global errors
282 ParseOptions(args)
283
284 InfoOut.SetConsole(True)
285
286 namespace = IDLNamespace(None)
287
288 FooXX = MockNode('foo', None, None)
289 Foo1X = MockNode('foo', 1.0, None)
290 Foo2X = MockNode('foo', 2.0, None)
291 Foo3X = MockNode('foo', 3.0, None)
292
293 # Verify we succeed with undeprecated adds
294 AddOkay(namespace, FooXX)
295 AddOkay(namespace, Foo1X)
296 AddOkay(namespace, Foo3X)
297 # Verify we fail to add a node between undeprecated versions
298 AddError(namespace, Foo2X, 'Overlap in versions.')
299
300 BarXX = MockNode('bar', None, None)
301 Bar12 = MockNode('bar', 1.0, 2.0)
302 Bar23 = MockNode('bar', 2.0, 3.0)
303 Bar34 = MockNode('bar', 3.0, 4.0)
304
305 # Verify we succeed with fully qualified versions
306 namespace = IDLNamespace(namespace)
307 AddOkay(namespace, BarXX)
308 AddOkay(namespace, Bar12)
309 # Verify we warn when detecting a gap
310 AddWarn(namespace, Bar34, 'Gap in version numbers.')
311 # Verify we fail when inserting into this gap
312 # (NOTE: while this could be legal, it is sloppy so we disallow it)
313 AddError(namespace, Bar23, 'Declarations out of order.')
314
315 # Verify local namespace
316 VerifyFindOne(namespace, 'bar', 0.0, BarXX)
317 VerifyFindAll(namespace, 'bar', 0.5, 1.5, [BarXX, Bar12])
318
319 # Verify the correct version of the object is found recursively
320 VerifyFindOne(namespace, 'foo', 0.0, FooXX)
321 VerifyFindOne(namespace, 'foo', 0.5, FooXX)
322 VerifyFindOne(namespace, 'foo', 1.0, Foo1X)
323 VerifyFindOne(namespace, 'foo', 1.5, Foo1X)
324 VerifyFindOne(namespace, 'foo', 3.0, Foo3X)
325 VerifyFindOne(namespace, 'foo', 100.0, Foo3X)
326
327 # Verify the correct range of objects is found
328 VerifyFindAll(namespace, 'foo', 0.0, 1.0, [FooXX])
329 VerifyFindAll(namespace, 'foo', 0.5, 1.0, [FooXX])
330 VerifyFindAll(namespace, 'foo', 1.0, 1.1, [Foo1X])
331 VerifyFindAll(namespace, 'foo', 0.5, 1.5, [FooXX, Foo1X])
332 VerifyFindAll(namespace, 'foo', 0.0, 3.0, [FooXX, Foo1X])
333 VerifyFindAll(namespace, 'foo', 3.0, 100.0, [Foo3X])
334
335
336
337 if errors:
338 print 'Test failed with %d errors.' % errors
339 else:
340 print 'Passed.'
341 return errors
342
343 if __name__ == '__main__':
344 sys.exit(Main(sys.argv[1:]))
345
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698