blob: d06defbfd2c193619875a0f98f86da0acecebd66 [file] [log] [blame]
[email protected]8c311f02012-11-17 16:01:321#!/usr/bin/env python
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.
5
6""" Generator for C++ style thunks """
7
8import glob
9import os
10import re
11import sys
12
13from idl_log import ErrOut, InfoOut, WarnOut
14from idl_node import IDLAttribute, IDLNode
15from idl_ast import IDLAst
16from idl_option import GetOption, Option, ParseOptions
17from idl_outfile import IDLOutFile
18from idl_parser import ParseFiles
19from idl_c_proto import CGen, GetNodeComments, CommentLines, Comment
20from idl_generator import Generator, GeneratorByFile
21
22Option('thunkroot', 'Base directory of output',
23 default=os.path.join('..', 'thunk'))
24
25
26class TGenError(Exception):
27 def __init__(self, msg):
28 self.value = msg
29
30 def __str__(self):
31 return repr(self.value)
32
33
[email protected]cba2c4302012-11-20 18:18:1334class ThunkBodyMetadata(object):
35 """Metadata about thunk body. Used for selecting which headers to emit."""
36 def __init__(self):
37 self._apis = set()
[email protected]2a7e8c52013-03-30 00:13:2538 self._builtin_includes = set()
[email protected]8f2a08d52012-12-08 00:10:5039 self._includes = set()
[email protected]cba2c4302012-11-20 18:18:1340
41 def AddApi(self, api):
42 self._apis.add(api)
43
44 def Apis(self):
45 return self._apis
46
[email protected]8f2a08d52012-12-08 00:10:5047 def AddInclude(self, include):
48 self._includes.add(include)
49
50 def Includes(self):
51 return self._includes
52
[email protected]2a7e8c52013-03-30 00:13:2553 def AddBuiltinInclude(self, include):
54 self._builtin_includes.add(include)
55
56 def BuiltinIncludes(self):
57 return self._builtin_includes
58
[email protected]cba2c4302012-11-20 18:18:1359
[email protected]8c311f02012-11-17 16:01:3260def _GetBaseFileName(filenode):
61 """Returns the base name for output files, given the filenode.
62
63 Examples:
[email protected]a5b6ace2013-02-08 21:09:5264 'dev/ppb_find_dev.h' -> 'ppb_find_dev'
[email protected]8c311f02012-11-17 16:01:3265 'trusted/ppb_buffer_trusted.h' -> 'ppb_buffer_trusted'
66 """
67 path, name = os.path.split(filenode.GetProperty('NAME'))
68 name = os.path.splitext(name)[0]
[email protected]8c311f02012-11-17 16:01:3269 return name
70
71
72def _GetHeaderFileName(filenode):
73 """Returns the name for the header for this file."""
74 path, name = os.path.split(filenode.GetProperty('NAME'))
75 name = os.path.splitext(name)[0]
76 if path:
77 header = "ppapi/c/%s/%s.h" % (path, name)
78 else:
79 header = "ppapi/c/%s.h" % name
80 return header
81
82
83def _GetThunkFileName(filenode, relpath):
84 """Returns the thunk file name."""
85 path = os.path.split(filenode.GetProperty('NAME'))[0]
86 name = _GetBaseFileName(filenode)
87 # We don't reattach the path for thunk.
88 if relpath: name = os.path.join(relpath, name)
89 name = '%s%s' % (name, '_thunk.cc')
90 return name
91
92
[email protected]56c49bb2013-04-26 01:24:1393def _StripFileName(filenode):
94 """Strips path and dev, trusted, and private suffixes from the file name."""
[email protected]2a7e8c52013-03-30 00:13:2595 api_basename = _GetBaseFileName(filenode)
96 if api_basename.endswith('_dev'):
97 api_basename = api_basename[:-len('_dev')]
98 if api_basename.endswith('_trusted'):
99 api_basename = api_basename[:-len('_trusted')]
[email protected]adf250c2013-04-22 18:13:47100 if api_basename.endswith('_private'):
101 api_basename = api_basename[:-len('_private')]
[email protected]56c49bb2013-04-26 01:24:13102 return api_basename
[email protected]2a7e8c52013-03-30 00:13:25103
104
[email protected]56c49bb2013-04-26 01:24:13105def _StripApiName(api_name):
106 """Strips Dev, Private, and Trusted suffixes from the API name."""
[email protected]2a7e8c52013-03-30 00:13:25107 if api_name.endswith('Trusted'):
108 api_name = api_name[:-len('Trusted')]
109 if api_name.endswith('_Dev'):
110 api_name = api_name[:-len('_Dev')]
[email protected]adf250c2013-04-22 18:13:47111 if api_name.endswith('_Private'):
112 api_name = api_name[:-len('_Private')]
[email protected]56c49bb2013-04-26 01:24:13113 return api_name
114
115
116def _MakeEnterLine(filenode, interface, member, arg, handle_errors, callback,
117 meta):
118 """Returns an EnterInstance/EnterResource string for a function."""
119 api_name = _StripApiName(interface.GetName()) + '_API'
[email protected]a3887962013-04-16 21:02:16120 if member.GetProperty('api'): # Override API name.
121 manually_provided_api = True
122 # TODO(teravest): Automatically guess the API header file.
123 api_name = member.GetProperty('api')
124 else:
125 manually_provided_api = False
[email protected]2a7e8c52013-03-30 00:13:25126
[email protected]8c311f02012-11-17 16:01:32127 if arg[0] == 'PP_Instance':
128 if callback is None:
[email protected]2a7e8c52013-03-30 00:13:25129 arg_string = arg[1]
[email protected]8c311f02012-11-17 16:01:32130 else:
[email protected]2a7e8c52013-03-30 00:13:25131 arg_string = '%s, %s' % (arg[1], callback)
[email protected]a3887962013-04-16 21:02:16132 if interface.GetProperty('singleton') or member.GetProperty('singleton'):
133 if not manually_provided_api:
[email protected]56c49bb2013-04-26 01:24:13134 meta.AddApi('ppapi/thunk/%s_api.h' % _StripFileName(filenode))
[email protected]2a7e8c52013-03-30 00:13:25135 return 'EnterInstanceAPI<%s> enter(%s);' % (api_name, arg_string)
136 else:
137 return 'EnterInstance enter(%s);' % arg_string
[email protected]8c311f02012-11-17 16:01:32138 elif arg[0] == 'PP_Resource':
[email protected]8c311f02012-11-17 16:01:32139 enter_type = 'EnterResource<%s>' % api_name
[email protected]a3887962013-04-16 21:02:16140 if not manually_provided_api:
[email protected]56c49bb2013-04-26 01:24:13141 meta.AddApi('ppapi/thunk/%s_api.h' % _StripFileName(filenode))
[email protected]8c311f02012-11-17 16:01:32142 if callback is None:
143 return '%s enter(%s, %s);' % (enter_type, arg[1],
144 str(handle_errors).lower())
145 else:
146 return '%s enter(%s, %s, %s);' % (enter_type, arg[1],
147 callback,
148 str(handle_errors).lower())
149 else:
150 raise TGenError("Unknown type for _MakeEnterLine: %s" % arg[0])
151
152
153def _GetShortName(interface, filter_suffixes):
154 """Return a shorter interface name that matches Is* and Create* functions."""
155 parts = interface.GetName().split('_')[1:]
156 tail = parts[len(parts) - 1]
157 if tail in filter_suffixes:
158 parts = parts[:-1]
159 return ''.join(parts)
160
161
[email protected]1a77d232013-05-02 01:35:06162def _IsTypeCheck(interface, node, args):
[email protected]8c311f02012-11-17 16:01:32163 """Returns true if node represents a type-checking function."""
[email protected]1a77d232013-05-02 01:35:06164 if len(args) == 0 or args[0][0] != 'PP_Resource':
165 return False
[email protected]8c311f02012-11-17 16:01:32166 return node.GetName() == 'Is%s' % _GetShortName(interface, ['Dev', 'Private'])
167
168
169def _GetCreateFuncName(interface):
170 """Returns the creation function name for an interface."""
171 return 'Create%s' % _GetShortName(interface, ['Dev'])
172
173
174def _GetDefaultFailureValue(t):
175 """Returns the default failure value for a given type.
176
177 Returns None if no default failure value exists for the type.
178 """
179 values = {
180 'PP_Bool': 'PP_FALSE',
181 'PP_Resource': '0',
182 'struct PP_Var': 'PP_MakeUndefined()',
[email protected]12b6f612013-02-13 18:17:58183 'float': '0.0f',
[email protected]8c311f02012-11-17 16:01:32184 'int32_t': 'enter.retval()',
185 'uint16_t': '0',
186 'uint32_t': '0',
187 'uint64_t': '0',
[email protected]56c49bb2013-04-26 01:24:13188 'void*': 'NULL'
[email protected]8c311f02012-11-17 16:01:32189 }
190 if t in values:
191 return values[t]
192 return None
193
194
195def _MakeCreateMemberBody(interface, member, args):
196 """Returns the body of a Create() function.
197
198 Args:
199 interface - IDLNode for the interface
200 member - IDLNode for member function
201 args - List of arguments for the Create() function
202 """
203 if args[0][0] == 'PP_Resource':
[email protected]8917a672013-02-25 17:18:04204 body = 'Resource* object =\n'
205 body += ' PpapiGlobals::Get()->GetResourceTracker()->'
[email protected]8c311f02012-11-17 16:01:32206 body += 'GetResource(%s);\n' % args[0][1]
[email protected]8917a672013-02-25 17:18:04207 body += 'if (!object)\n'
208 body += ' return 0;\n'
209 body += 'EnterResourceCreation enter(object->pp_instance());\n'
[email protected]8c311f02012-11-17 16:01:32210 elif args[0][0] == 'PP_Instance':
[email protected]8917a672013-02-25 17:18:04211 body = 'EnterResourceCreation enter(%s);\n' % args[0][1]
[email protected]8c311f02012-11-17 16:01:32212 else:
213 raise TGenError('Unknown arg type for Create(): %s' % args[0][0])
214
[email protected]8917a672013-02-25 17:18:04215 body += 'if (enter.failed())\n'
216 body += ' return 0;\n'
[email protected]8c311f02012-11-17 16:01:32217 arg_list = ', '.join([a[1] for a in args])
218 if member.GetProperty('create_func'):
219 create_func = member.GetProperty('create_func')
220 else:
221 create_func = _GetCreateFuncName(interface)
[email protected]8917a672013-02-25 17:18:04222 body += 'return enter.functions()->%s(%s);' % (create_func,
223 arg_list)
[email protected]8c311f02012-11-17 16:01:32224 return body
225
226
[email protected]b082d582013-04-18 14:02:00227def _GetOutputParams(member, release):
228 """Returns output parameters (and their types) for a member function.
229
230 Args:
231 member - IDLNode for the member function
232 release - Release to get output parameters for
233 Returns:
234 A list of name strings for all output parameters of the member
235 function.
236 """
237 out_params = []
238 callnode = member.GetOneOf('Callspec')
239 if callnode:
240 cgen = CGen()
241 for param in callnode.GetListOf('Param'):
242 mode = cgen.GetParamMode(param)
243 if mode == 'out':
244 # We use the 'store' mode when getting the parameter type, since we
245 # need to call sizeof() for memset().
246 _, pname, _, _ = cgen.GetComponents(param, release, 'store')
247 out_params.append(pname)
248 return out_params
249
250
[email protected]8917a672013-02-25 17:18:04251def _MakeNormalMemberBody(filenode, release, node, member, rtype, args,
252 include_version, meta):
[email protected]8c311f02012-11-17 16:01:32253 """Returns the body of a typical function.
254
255 Args:
256 filenode - IDLNode for the file
[email protected]8917a672013-02-25 17:18:04257 release - release to generate body for
[email protected]8c311f02012-11-17 16:01:32258 node - IDLNode for the interface
259 member - IDLNode for the member function
260 rtype - Return type for the member function
261 args - List of 4-tuple arguments for the member function
[email protected]8917a672013-02-25 17:18:04262 include_version - whether to include the version in the invocation
[email protected]cba2c4302012-11-20 18:18:13263 meta - ThunkBodyMetadata for header hints
[email protected]8c311f02012-11-17 16:01:32264 """
[email protected]56c49bb2013-04-26 01:24:13265 if len(args) == 0:
266 # Calling into the "Shared" code for the interface seems like a reasonable
267 # heuristic when we don't have any arguments; some thunk code follows this
268 # convention today.
269 meta.AddApi('ppapi/shared_impl/%s_shared.h' % _StripFileName(filenode))
270 return 'return %s::%s();' % (_StripApiName(node.GetName()) + '_Shared',
271 member.GetName())
272
[email protected]8c311f02012-11-17 16:01:32273 is_callback_func = args[len(args) - 1][0] == 'struct PP_CompletionCallback'
274
275 if is_callback_func:
276 call_args = args[:-1] + [('', 'enter.callback()', '', '')]
[email protected]8f2a08d52012-12-08 00:10:50277 meta.AddInclude('ppapi/c/pp_completion_callback.h')
[email protected]8c311f02012-11-17 16:01:32278 else:
279 call_args = args
280
281 if args[0][0] == 'PP_Instance':
282 call_arglist = ', '.join(a[1] for a in call_args)
283 function_container = 'functions'
[email protected]56c49bb2013-04-26 01:24:13284 elif args[0][0] == 'PP_Resource':
[email protected]8c311f02012-11-17 16:01:32285 call_arglist = ', '.join(a[1] for a in call_args[1:])
286 function_container = 'object'
[email protected]56c49bb2013-04-26 01:24:13287 else:
288 # Calling into the "Shared" code for the interface seems like a reasonable
289 # heuristic when the first argument isn't a PP_Instance or a PP_Resource;
290 # some thunk code follows this convention today.
291 meta.AddApi('ppapi/shared_impl/%s_shared.h' % _StripFileName(filenode))
292 return 'return %s::%s(%s);' % (_StripApiName(node.GetName()) + '_Shared',
293 member.GetName(),
294 ', '.join(a[1] for a in args))
[email protected]8c311f02012-11-17 16:01:32295
[email protected]8917a672013-02-25 17:18:04296 function_name = member.GetName()
297 if include_version:
298 version = node.GetVersion(release).replace('.', '_')
299 function_name += version
300
[email protected]8c311f02012-11-17 16:01:32301 invocation = 'enter.%s()->%s(%s)' % (function_container,
[email protected]8917a672013-02-25 17:18:04302 function_name,
[email protected]8c311f02012-11-17 16:01:32303 call_arglist)
304
305 handle_errors = not (member.GetProperty('report_errors') == 'False')
[email protected]b082d582013-04-18 14:02:00306 out_params = _GetOutputParams(member, release)
[email protected]8c311f02012-11-17 16:01:32307 if is_callback_func:
[email protected]a3887962013-04-16 21:02:16308 body = '%s\n' % _MakeEnterLine(filenode, node, member, args[0],
309 handle_errors, args[len(args) - 1][1], meta)
[email protected]135f5942013-04-19 14:25:18310 failure_value = member.GetProperty('on_failure')
311 if failure_value is None:
312 failure_value = 'enter.retval()'
313 failure_return = 'return %s;' % failure_value
314 success_return = 'return enter.SetResult(%s);' % invocation
[email protected]8c311f02012-11-17 16:01:32315 elif rtype == 'void':
[email protected]a3887962013-04-16 21:02:16316 body = '%s\n' % _MakeEnterLine(filenode, node, member, args[0],
317 handle_errors, None, meta)
[email protected]135f5942013-04-19 14:25:18318 failure_return = 'return;'
319 success_return = '%s;' % invocation # We don't return anything for void.
[email protected]8c311f02012-11-17 16:01:32320 else:
[email protected]a3887962013-04-16 21:02:16321 body = '%s\n' % _MakeEnterLine(filenode, node, member, args[0],
322 handle_errors, None, meta)
[email protected]135f5942013-04-19 14:25:18323 failure_value = member.GetProperty('on_failure')
324 if failure_value is None:
325 failure_value = _GetDefaultFailureValue(rtype)
326 if failure_value is None:
327 raise TGenError('There is no default value for rtype %s. '
328 'Maybe you should provide an on_failure attribute '
329 'in the IDL file.' % rtype)
330 failure_return = 'return %s;' % failure_value
331 success_return = 'return %s;' % invocation
332
333 if member.GetProperty('always_set_output_parameters'):
334 body += 'if (enter.failed()) {\n'
335 for param in out_params:
336 body += ' memset(%s, 0, sizeof(*%s));\n' % (param, param)
337 body += ' %s\n' % failure_return
338 body += '}\n'
339 body += '%s' % success_return
340 meta.AddBuiltinInclude('string.h')
341 else:
342 body += 'if (enter.failed())\n'
343 body += ' %s\n' % failure_return
344 body += '%s' % success_return
[email protected]8c311f02012-11-17 16:01:32345 return body
346
347
[email protected]cba2c4302012-11-20 18:18:13348def DefineMember(filenode, node, member, release, include_version, meta):
[email protected]8c311f02012-11-17 16:01:32349 """Returns a definition for a member function of an interface.
350
351 Args:
352 filenode - IDLNode for the file
353 node - IDLNode for the interface
354 member - IDLNode for the member function
355 release - release to generate
356 include_version - include the version in emitted function name.
[email protected]cba2c4302012-11-20 18:18:13357 meta - ThunkMetadata for header hints
[email protected]8c311f02012-11-17 16:01:32358 Returns:
359 A string with the member definition.
360 """
361 cgen = CGen()
362 rtype, name, arrays, args = cgen.GetComponents(member, release, 'return')
[email protected]03f8b542013-04-02 17:57:50363 body = 'VLOG(4) << \"%s::%s()\";\n' % (node.GetName(), member.GetName())
[email protected]8c311f02012-11-17 16:01:32364
[email protected]1a77d232013-05-02 01:35:06365 if _IsTypeCheck(node, member, args):
[email protected]a3887962013-04-16 21:02:16366 body += '%s\n' % _MakeEnterLine(filenode, node, member, args[0], False,
367 None, meta)
[email protected]8917a672013-02-25 17:18:04368 body += 'return PP_FromBool(enter.succeeded());'
[email protected]9590f8602013-04-23 18:55:21369 elif member.GetName() == 'Create' or member.GetName() == 'CreateTrusted':
[email protected]03f8b542013-04-02 17:57:50370 body += _MakeCreateMemberBody(node, member, args)
[email protected]8c311f02012-11-17 16:01:32371 else:
[email protected]03f8b542013-04-02 17:57:50372 body += _MakeNormalMemberBody(filenode, release, node, member, rtype, args,
373 include_version, meta)
[email protected]8c311f02012-11-17 16:01:32374
375 signature = cgen.GetSignature(member, release, 'return', func_as_ptr=False,
376 include_version=include_version)
[email protected]8917a672013-02-25 17:18:04377 return '%s\n%s\n}' % (cgen.Indent('%s {' % signature, tabs=0),
378 cgen.Indent(body, tabs=1))
379
380
381def _IsNewestMember(member, members, releases):
382 """Returns true if member is the newest node with its name in members.
383
384 Currently, every node in the AST only has one version. This means that we
385 will have two sibling nodes with the same name to represent different
386 versions.
387 See http://crbug.com/157017 .
388
389 Special handling is required for nodes which share their name with others,
390 but aren't the newest version in the IDL.
391
392 Args:
393 member - The member which is checked if it's newest
394 members - The list of members to inspect
395 releases - The set of releases to check for versions in.
396 """
397 build_list = member.GetUniqueReleases(releases)
[email protected]ba054c02013-02-26 23:27:18398 release = build_list[0] # Pick the oldest release.
[email protected]8917a672013-02-25 17:18:04399 same_name_siblings = filter(
400 lambda n: str(n) == str(member) and n != member, members)
401
402 for s in same_name_siblings:
403 sibling_build_list = s.GetUniqueReleases(releases)
[email protected]ba054c02013-02-26 23:27:18404 sibling_release = sibling_build_list[0]
[email protected]8917a672013-02-25 17:18:04405 if sibling_release > release:
406 return False
407 return True
[email protected]8c311f02012-11-17 16:01:32408
409
410class TGen(GeneratorByFile):
411 def __init__(self):
412 Generator.__init__(self, 'Thunk', 'tgen', 'Generate the C++ thunk.')
413
414 def GenerateFile(self, filenode, releases, options):
415 savename = _GetThunkFileName(filenode, GetOption('thunkroot'))
416 my_min, my_max = filenode.GetMinMax(releases)
417 if my_min > releases[-1] or my_max < releases[0]:
418 if os.path.isfile(savename):
419 print "Removing stale %s for this range." % filenode.GetName()
420 os.remove(os.path.realpath(savename))
421 return False
422 do_generate = filenode.GetProperty('generate_thunk')
423 if not do_generate:
424 return False
425
426 thunk_out = IDLOutFile(savename)
[email protected]cba2c4302012-11-20 18:18:13427 body, meta = self.GenerateBody(thunk_out, filenode, releases, options)
[email protected]a3887962013-04-16 21:02:16428 # TODO(teravest): How do we handle repeated values?
429 if filenode.GetProperty('thunk_include'):
430 meta.AddInclude(filenode.GetProperty('thunk_include'))
[email protected]cba2c4302012-11-20 18:18:13431 self.WriteHead(thunk_out, filenode, releases, options, meta)
432 thunk_out.Write('\n\n'.join(body))
433 self.WriteTail(thunk_out, filenode, releases, options)
[email protected]8c311f02012-11-17 16:01:32434 return thunk_out.Close()
435
[email protected]cba2c4302012-11-20 18:18:13436 def WriteHead(self, out, filenode, releases, options, meta):
[email protected]8c311f02012-11-17 16:01:32437 __pychecker__ = 'unusednames=options'
438 cgen = CGen()
439
440 cright_node = filenode.GetChildren()[0]
441 assert(cright_node.IsA('Copyright'))
442 out.Write('%s\n' % cgen.Copyright(cright_node, cpp_style=True))
443
444 # Wrap the From ... modified ... comment if it would be >80 characters.
445 from_text = 'From %s' % (
446 filenode.GetProperty('NAME').replace(os.sep,'/'))
447 modified_text = 'modified %s.' % (
448 filenode.GetProperty('DATETIME'))
449 if len(from_text) + len(modified_text) < 74:
450 out.Write('// %s %s\n\n' % (from_text, modified_text))
451 else:
452 out.Write('// %s,\n// %s\n\n' % (from_text, modified_text))
453
[email protected]2a7e8c52013-03-30 00:13:25454 if meta.BuiltinIncludes():
455 for include in sorted(meta.BuiltinIncludes()):
456 out.Write('#include <%s>\n' % include)
457 out.Write('\n')
[email protected]8c311f02012-11-17 16:01:32458
459 # TODO(teravest): Don't emit includes we don't need.
460 includes = ['ppapi/c/pp_errors.h',
461 'ppapi/shared_impl/tracked_callback.h',
462 'ppapi/thunk/enter.h',
[email protected]b3fcc412014-01-16 04:34:37463 'ppapi/thunk/ppapi_thunk_export.h']
[email protected]8c311f02012-11-17 16:01:32464 includes.append(_GetHeaderFileName(filenode))
[email protected]cba2c4302012-11-20 18:18:13465 for api in meta.Apis():
[email protected]56c49bb2013-04-26 01:24:13466 includes.append('%s' % api.lower())
[email protected]8f2a08d52012-12-08 00:10:50467 for i in meta.Includes():
468 includes.append(i)
[email protected]8c311f02012-11-17 16:01:32469 for include in sorted(includes):
470 out.Write('#include "%s"\n' % include)
471 out.Write('\n')
472 out.Write('namespace ppapi {\n')
473 out.Write('namespace thunk {\n')
474 out.Write('\n')
475 out.Write('namespace {\n')
476 out.Write('\n')
477
478 def GenerateBody(self, out, filenode, releases, options):
[email protected]cba2c4302012-11-20 18:18:13479 """Generates a member function lines to be written and metadata.
480
481 Returns a tuple of (body, meta) where:
482 body - a list of lines with member function bodies
483 meta - a ThunkMetadata instance for hinting which headers are needed.
484 """
[email protected]8c311f02012-11-17 16:01:32485 __pychecker__ = 'unusednames=options'
[email protected]8917a672013-02-25 17:18:04486 out_members = []
[email protected]cba2c4302012-11-20 18:18:13487 meta = ThunkBodyMetadata()
[email protected]8c311f02012-11-17 16:01:32488 for node in filenode.GetListOf('Interface'):
489 # Skip if this node is not in this release
490 if not node.InReleases(releases):
491 print "Skipping %s" % node
492 continue
493
494 # Generate Member functions
495 if node.IsA('Interface'):
[email protected]8917a672013-02-25 17:18:04496 members = node.GetListOf('Member')
497 for child in members:
[email protected]8c311f02012-11-17 16:01:32498 build_list = child.GetUniqueReleases(releases)
499 # We have to filter out releases this node isn't in.
500 build_list = filter(lambda r: child.InReleases([r]), build_list)
501 if len(build_list) == 0:
502 continue
[email protected]8917a672013-02-25 17:18:04503 release = build_list[-1]
504 include_version = not _IsNewestMember(child, members, releases)
505 member = DefineMember(filenode, node, child, release, include_version,
506 meta)
[email protected]8c311f02012-11-17 16:01:32507 if not member:
508 continue
[email protected]8917a672013-02-25 17:18:04509 out_members.append(member)
510 return (out_members, meta)
[email protected]8c311f02012-11-17 16:01:32511
[email protected]cba2c4302012-11-20 18:18:13512 def WriteTail(self, out, filenode, releases, options):
[email protected]8c311f02012-11-17 16:01:32513 __pychecker__ = 'unusednames=options'
514 cgen = CGen()
515
516 version_list = []
517 out.Write('\n\n')
518 for node in filenode.GetListOf('Interface'):
519 build_list = node.GetUniqueReleases(releases)
520 for build in build_list:
521 version = node.GetVersion(build).replace('.', '_')
522 thunk_name = 'g_' + node.GetName().lower() + '_thunk_' + \
523 version
524 thunk_type = '_'.join((node.GetName(), version))
525 version_list.append((thunk_type, thunk_name))
526
[email protected]8c71647a62013-02-26 19:32:50527 declare_line = 'const %s %s = {' % (thunk_type, thunk_name)
528 if len(declare_line) > 80:
529 declare_line = 'const %s\n %s = {' % (thunk_type, thunk_name)
530 out.Write('%s\n' % declare_line)
[email protected]cfc881d2013-01-03 19:07:46531 generated_functions = []
[email protected]8917a672013-02-25 17:18:04532 members = node.GetListOf('Member')
533 for child in members:
[email protected]8c311f02012-11-17 16:01:32534 rtype, name, arrays, args = cgen.GetComponents(
535 child, build, 'return')
[email protected]cfc881d2013-01-03 19:07:46536 if child.InReleases([build]):
[email protected]fa8543d2013-05-24 17:43:49537 if not _IsNewestMember(child, members, releases):
538 version = child.GetVersion(
539 child.first_release[build]).replace('.', '_')
540 name += '_' + version
[email protected]cfc881d2013-01-03 19:07:46541 generated_functions.append(name)
542 out.Write(',\n'.join([' &%s' % f for f in generated_functions]))
543 out.Write('\n};\n\n')
[email protected]8c311f02012-11-17 16:01:32544
545 out.Write('} // namespace\n')
546 out.Write('\n')
547 for thunk_type, thunk_name in version_list:
[email protected]b3fcc412014-01-16 04:34:37548 thunk_decl = ('PPAPI_THUNK_EXPORT const %s* Get%s_Thunk() {\n' %
549 (thunk_type, thunk_type))
[email protected]8c311f02012-11-17 16:01:32550 if len(thunk_decl) > 80:
[email protected]b3fcc412014-01-16 04:34:37551 thunk_decl = ('PPAPI_THUNK_EXPORT const %s*\n Get%s_Thunk() {\n' %
552 (thunk_type, thunk_type))
[email protected]8c311f02012-11-17 16:01:32553 out.Write(thunk_decl)
554 out.Write(' return &%s;\n' % thunk_name)
555 out.Write('}\n')
556 out.Write('\n')
557 out.Write('} // namespace thunk\n')
558 out.Write('} // namespace ppapi\n')
559
560
561tgen = TGen()
562
563
564def Main(args):
565 # Default invocation will verify the golden files are unchanged.
566 failed = 0
567 if not args:
568 args = ['--wnone', '--diff', '--test', '--thunkroot=.']
569
570 ParseOptions(args)
571
572 idldir = os.path.split(sys.argv[0])[0]
573 idldir = os.path.join(idldir, 'test_thunk', '*.idl')
574 filenames = glob.glob(idldir)
575 ast = ParseFiles(filenames)
[email protected]fa8543d2013-05-24 17:43:49576 if tgen.GenerateRange(ast, ['M13', 'M14', 'M15'], {}):
577 print "Golden file for M13-M15 failed."
[email protected]8c311f02012-11-17 16:01:32578 failed = 1
579 else:
[email protected]fa8543d2013-05-24 17:43:49580 print "Golden file for M13-M15 passed."
[email protected]8c311f02012-11-17 16:01:32581
582 return failed
583
584
585if __name__ == '__main__':
586 sys.exit(Main(sys.argv[1:]))