Remove extra line from unit_tests.isolate
[chromium-blink-merge.git] / ppapi / generators / idl_gen_wrapper.py
blobee1fe687a0766afad18ce6d97f149eef62b9def8
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Base class for generating wrapper functions for PPAPI methods.
6 """
8 from datetime import datetime
9 import os
10 import sys
12 from idl_c_proto import CGen
13 from idl_generator import Generator
14 from idl_log import ErrOut, InfoOut, WarnOut
15 from idl_outfile import IDLOutFile
18 class PPKind(object):
19 @staticmethod
20 def ChoosePPFunc(iface, ppb_func, ppp_func):
21 name = iface.node.GetName()
22 if name.startswith("PPP"):
23 return ppp_func
24 elif name.startswith("PPB"):
25 return ppb_func
26 else:
27 raise Exception('Unknown PPKind for ' + name)
30 class Interface(object):
31 """Tracks information about a particular interface version.
33 - struct_name: the struct type used by the ppapi headers to hold the
34 method pointers (the vtable).
35 - needs_wrapping: True if a method in the interface needs wrapping.
36 - header_file: the name of the header file that defined this interface.
37 """
38 def __init__(self, interface_node, release, version,
39 struct_name, needs_wrapping, header_file):
40 self.node = interface_node
41 self.release = release
42 self.version = version
43 self.struct_name = struct_name
44 # We may want finer grained filtering (method level), but it is not
45 # yet clear how to actually do that.
46 self.needs_wrapping = needs_wrapping
47 self.header_file = header_file
50 class WrapperGen(Generator):
51 """WrapperGen - An abstract class that generates wrappers for PPAPI methods.
53 This generates a wrapper PPB and PPP GetInterface, which directs users
54 to wrapper PPAPI methods. Wrapper PPAPI methods may perform arbitrary
55 work before invoking the real PPAPI method (supplied by the original
56 GetInterface functions).
58 Subclasses must implement GenerateWrapperForPPBMethod (and PPP).
59 Optionally, subclasses can implement InterfaceNeedsWrapper to
60 filter out interfaces that do not actually need wrappers (those
61 interfaces can jump directly to the original interface functions).
62 """
64 def __init__(self, wrapper_prefix, s1, s2, s3):
65 Generator.__init__(self, s1, s2, s3)
66 self.wrapper_prefix = wrapper_prefix
67 self._skip_opt = False
68 self.output_file = None
69 self.cgen = CGen()
71 def SetOutputFile(self, fname):
72 self.output_file = fname
75 def GenerateRelease(self, ast, release, options):
76 return self.GenerateRange(ast, [release], options)
79 @staticmethod
80 def GetHeaderName(name):
81 """Get the corresponding ppapi .h file from each IDL filename.
82 """
83 name = os.path.splitext(name)[0] + '.h'
84 name = name.replace(os.sep, '/')
85 return 'ppapi/c/' + name
88 def WriteCopyrightGeneratedTime(self, out):
89 now = datetime.now()
90 c = """/* Copyright (c) %s The Chromium Authors. All rights reserved.
91 * Use of this source code is governed by a BSD-style license that can be
92 * found in the LICENSE file.
95 /* Last generated from IDL: %s. */
96 """ % (now.year, datetime.ctime(now))
97 out.Write(c)
99 def GetWrapperMetadataName(self):
100 return '__%sWrapperInfo' % self.wrapper_prefix
103 def GenerateHelperFunctions(self, out):
104 """Generate helper functions to avoid dependencies on libc.
106 out.Write("""/* Use local strcmp to avoid dependency on libc. */
107 static int mystrcmp(const char* s1, const char *s2) {
108 while((*s1 && *s2) && (*s1++ == *s2++));
109 return *(--s1) - *(--s2);
111 """)
114 def GenerateFixedFunctions(self, out):
115 """Write out the set of constant functions (those that do not depend on
116 the current Pepper IDL).
118 out.Write("""
120 static PPB_GetInterface __real_PPBGetInterface;
121 static PPP_GetInterface_Type __real_PPPGetInterface;
123 void __set_real_%(wrapper_prefix)s_PPBGetInterface(PPB_GetInterface real) {
124 __real_PPBGetInterface = real;
127 void __set_real_%(wrapper_prefix)s_PPPGetInterface(PPP_GetInterface_Type real) {
128 __real_PPPGetInterface = real;
131 /* Map interface string -> wrapper metadata */
132 static struct %(wrapper_struct)s *%(wrapper_prefix)sPPBShimIface(
133 const char *name) {
134 struct %(wrapper_struct)s **next = s_ppb_wrappers;
135 while (*next != NULL) {
136 if (mystrcmp(name, (*next)->iface_macro) == 0) return *next;
137 ++next;
139 return NULL;
142 /* Map interface string -> wrapper metadata */
143 static struct %(wrapper_struct)s *%(wrapper_prefix)sPPPShimIface(
144 const char *name) {
145 struct %(wrapper_struct)s **next = s_ppp_wrappers;
146 while (*next != NULL) {
147 if (mystrcmp(name, (*next)->iface_macro) == 0) return *next;
148 ++next;
150 return NULL;
153 const void *__%(wrapper_prefix)s_PPBGetInterface(const char *name) {
154 struct %(wrapper_struct)s *wrapper = %(wrapper_prefix)sPPBShimIface(name);
155 if (wrapper == NULL) {
156 /* We don't have an IDL for this, for some reason. Take our chances. */
157 return (*__real_PPBGetInterface)(name);
160 /* Initialize the real_iface if it hasn't been. The wrapper depends on it. */
161 if (wrapper->real_iface == NULL) {
162 const void *iface = (*__real_PPBGetInterface)(name);
163 if (NULL == iface) return NULL;
164 wrapper->real_iface = iface;
167 if (wrapper->wrapped_iface) {
168 return wrapper->wrapped_iface;
169 } else {
170 return wrapper->real_iface;
174 const void *__%(wrapper_prefix)s_PPPGetInterface(const char *name) {
175 struct %(wrapper_struct)s *wrapper = %(wrapper_prefix)sPPPShimIface(name);
176 if (wrapper == NULL) {
177 /* We don't have an IDL for this, for some reason. Take our chances. */
178 return (*__real_PPPGetInterface)(name);
181 /* Initialize the real_iface if it hasn't been. The wrapper depends on it. */
182 if (wrapper->real_iface == NULL) {
183 const void *iface = (*__real_PPPGetInterface)(name);
184 if (NULL == iface) return NULL;
185 wrapper->real_iface = iface;
188 if (wrapper->wrapped_iface) {
189 return wrapper->wrapped_iface;
190 } else {
191 return wrapper->real_iface;
194 """ % { 'wrapper_struct' : self.GetWrapperMetadataName(),
195 'wrapper_prefix' : self.wrapper_prefix,
199 ############################################################
201 def InterfaceNeedsWrapper(self, iface, releases):
202 """Return true if the interface has ANY methods that need wrapping.
204 return True
207 def OwnHeaderFile(self):
208 """Return the header file that specifies the API of this wrapper.
209 We do not generate the header files. """
210 raise Exception('Child class must implement this')
213 ############################################################
215 def DetermineInterfaces(self, ast, releases):
216 """Get a list of interfaces along with whatever metadata we need.
218 iface_releases = []
219 for filenode in ast.GetListOf('File'):
220 # If this file has errors, skip it
221 if filenode in self.skip_list:
222 InfoOut.Log('WrapperGen: Skipping %s due to errors\n' %
223 filenode.GetName())
224 continue
226 file_name = self.GetHeaderName(filenode.GetName())
227 ifaces = filenode.GetListOf('Interface')
228 for iface in ifaces:
229 releases_for_iface = iface.GetUniqueReleases(releases)
230 for release in releases_for_iface:
231 version = iface.GetVersion(release)
232 struct_name = self.cgen.GetStructName(iface, release,
233 include_version=True)
234 needs_wrap = self.InterfaceVersionNeedsWrapping(iface, version)
235 if not needs_wrap:
236 InfoOut.Log('Interface %s ver %s does not need wrapping' %
237 (struct_name, version))
238 iface_releases.append(
239 Interface(iface, release, version,
240 struct_name, needs_wrap, file_name))
241 return iface_releases
244 def GenerateIncludes(self, iface_releases, out):
245 """Generate the list of #include that define the original interfaces.
247 self.WriteCopyrightGeneratedTime(out)
248 # First include own header.
249 out.Write('#include "%s"\n\n' % self.OwnHeaderFile())
251 # Get typedefs for PPB_GetInterface.
252 out.Write('#include "%s"\n' % self.GetHeaderName('ppb.h'))
254 # Get a conservative list of all #includes that are needed,
255 # whether it requires wrapping or not. We currently depend on the macro
256 # string for comparison, even when it is not wrapped, to decide when
257 # to use the original/real interface.
258 header_files = set()
259 for iface in iface_releases:
260 header_files.add(iface.header_file)
261 for header in sorted(header_files):
262 out.Write('#include "%s"\n' % header)
263 out.Write('\n')
266 def WrapperMethodPrefix(self, iface, release):
267 return '%s_%s_%s_' % (self.wrapper_prefix, release, iface.GetName())
270 def GetReturnArgs(self, ret_type, args_spec):
271 if ret_type != 'void':
272 ret = 'return '
273 else:
274 ret = ''
275 if args_spec:
276 args = []
277 for arg in args_spec:
278 args.append(arg[1])
279 args = ', '.join(args)
280 else:
281 args = ''
282 return (ret, args)
285 def GenerateWrapperForPPBMethod(self, iface, member):
286 result = []
287 func_prefix = self.WrapperMethodPrefix(iface.node, iface.release)
288 sig = self.cgen.GetSignature(member, iface.release, 'store',
289 func_prefix, False)
290 result.append('static %s {\n' % sig)
291 result.append(' while(1) { /* Not implemented */ } \n')
292 result.append('}\n')
293 return result
296 def GenerateWrapperForPPPMethod(self, iface, member):
297 result = []
298 func_prefix = self.WrapperMethodPrefix(iface.node, iface.release)
299 sig = self.cgen.GetSignature(member, iface.release, 'store',
300 func_prefix, False)
301 result.append('static %s {\n' % sig)
302 result.append(' while(1) { /* Not implemented */ } \n')
303 result.append('}\n')
304 return result
307 def GenerateWrapperForMethods(self, iface_releases, comments=True):
308 """Return a string representing the code for each wrapper method
309 (using a string rather than writing to the file directly for testing.)
311 result = []
312 for iface in iface_releases:
313 if not iface.needs_wrapping:
314 if comments:
315 result.append('/* Not generating wrapper methods for %s */\n\n' %
316 iface.struct_name)
317 continue
318 if comments:
319 result.append('/* Begin wrapper methods for %s */\n\n' %
320 iface.struct_name)
321 generator = PPKind.ChoosePPFunc(iface,
322 self.GenerateWrapperForPPBMethod,
323 self.GenerateWrapperForPPPMethod)
324 for member in iface.node.GetListOf('Member'):
325 # Skip the method if it's not actually in the release.
326 if not member.InReleases([iface.release]):
327 continue
328 result.extend(generator(iface, member))
329 if comments:
330 result.append('/* End wrapper methods for %s */\n\n' %
331 iface.struct_name)
332 return ''.join(result)
335 def GenerateWrapperInterfaces(self, iface_releases, out):
336 for iface in iface_releases:
337 if not iface.needs_wrapping:
338 out.Write('/* Not generating wrapper interface for %s */\n\n' %
339 iface.struct_name)
340 continue
342 out.Write('struct %s %s_Wrappers_%s = {\n' % (iface.struct_name,
343 self.wrapper_prefix,
344 iface.struct_name))
345 methods = []
346 for member in iface.node.GetListOf('Member'):
347 # Skip the method if it's not actually in the release.
348 if not member.InReleases([iface.release]):
349 continue
350 prefix = self.WrapperMethodPrefix(iface.node, iface.release)
351 cast = self.cgen.GetSignature(member, iface.release, 'return',
352 prefix='',
353 func_as_ptr=True,
354 ptr_prefix='',
355 include_name=False)
356 methods.append(' .%s = (%s)&%s%s' % (member.GetName(),
357 cast,
358 prefix,
359 member.GetName()))
360 out.Write(' ' + ',\n '.join(methods) + '\n')
361 out.Write('};\n\n')
364 def GetWrapperInfoName(self, iface):
365 return '%s_WrapperInfo_%s' % (self.wrapper_prefix, iface.struct_name)
368 def GenerateWrapperInfoAndCollection(self, iface_releases, out):
369 for iface in iface_releases:
370 iface_macro = self.cgen.GetInterfaceMacro(iface.node, iface.version)
371 if iface.needs_wrapping:
372 wrap_iface = '(void *) &%s_Wrappers_%s' % (self.wrapper_prefix,
373 iface.struct_name)
374 else:
375 wrap_iface = 'NULL /* Still need slot for real_iface */'
376 out.Write("""static struct %s %s = {
377 .iface_macro = %s,
378 .wrapped_iface = %s,
379 .real_iface = NULL
380 };\n\n""" % (self.GetWrapperMetadataName(),
381 self.GetWrapperInfoName(iface),
382 iface_macro,
383 wrap_iface))
385 # Now generate NULL terminated arrays of the above wrapper infos.
386 ppb_wrapper_infos = []
387 ppp_wrapper_infos = []
388 for iface in iface_releases:
389 appender = PPKind.ChoosePPFunc(iface,
390 ppb_wrapper_infos.append,
391 ppp_wrapper_infos.append)
392 appender(' &%s' % self.GetWrapperInfoName(iface))
393 ppb_wrapper_infos.append(' NULL')
394 ppp_wrapper_infos.append(' NULL')
395 out.Write(
396 'static struct %s *s_ppb_wrappers[] = {\n%s\n};\n\n' %
397 (self.GetWrapperMetadataName(), ',\n'.join(ppb_wrapper_infos)))
398 out.Write(
399 'static struct %s *s_ppp_wrappers[] = {\n%s\n};\n\n' %
400 (self.GetWrapperMetadataName(), ',\n'.join(ppp_wrapper_infos)))
403 def DeclareWrapperInfos(self, iface_releases, out):
404 """The wrapper methods usually need access to the real_iface, so we must
405 declare these wrapper infos ahead of time (there is a circular dependency).
407 out.Write('/* BEGIN Declarations for all Wrapper Infos */\n\n')
408 for iface in iface_releases:
409 out.Write('static struct %s %s;\n' %
410 (self.GetWrapperMetadataName(), self.GetWrapperInfoName(iface)))
411 out.Write('/* END Declarations for all Wrapper Infos. */\n\n')
414 def GenerateRange(self, ast, releases, options):
415 """Generate shim code for a range of releases.
418 # Remember to set the output filename before running this.
419 out_filename = self.output_file
420 if out_filename is None:
421 ErrOut.Log('Did not set filename for writing out wrapper\n')
422 return 1
424 InfoOut.Log("Generating %s for %s" % (out_filename, self.wrapper_prefix))
426 out = IDLOutFile(out_filename)
428 # Get a list of all the interfaces along with metadata.
429 iface_releases = self.DetermineInterfaces(ast, releases)
431 # Generate the includes.
432 self.GenerateIncludes(iface_releases, out)
434 out.Write(self.GetGuardStart())
436 # Write out static helper functions (mystrcmp).
437 self.GenerateHelperFunctions(out)
439 # Declare list of WrapperInfo before actual wrapper methods, since
440 # they reference each other.
441 self.DeclareWrapperInfos(iface_releases, out)
443 # Generate wrapper functions for each wrapped method in the interfaces.
444 result = self.GenerateWrapperForMethods(iface_releases)
445 out.Write(result)
447 # Collect all the wrapper functions into interface structs.
448 self.GenerateWrapperInterfaces(iface_releases, out)
450 # Generate a table of the wrapped interface structs that can be looked up.
451 self.GenerateWrapperInfoAndCollection(iface_releases, out)
453 # Write out the IDL-invariant functions.
454 self.GenerateFixedFunctions(out)
456 out.Write(self.GetGuardEnd())
457 out.Close()
458 return 0