blob: 6018753580de0e64bcf193285e8ad288f68140b2 [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]2a7e8c52013-03-30 00:13:2593def _AddApiHeader(filenode, meta):
94 """Adds an API header for the given file to the ThunkBodyMetadata."""
95 # The API header matches the file name, not the interface name.
96 api_basename = _GetBaseFileName(filenode)
97 if api_basename.endswith('_dev'):
98 api_basename = api_basename[:-len('_dev')]
99 if api_basename.endswith('_trusted'):
100 api_basename = api_basename[:-len('_trusted')]
101 meta.AddApi(api_basename + '_api')
102
103
[email protected]a3887962013-04-16 21:02:16104def _MakeEnterLine(filenode, interface, member, arg, handle_errors, callback,
105 meta):
[email protected]8c311f02012-11-17 16:01:32106 """Returns an EnterInstance/EnterResource string for a function."""
[email protected]2a7e8c52013-03-30 00:13:25107 api_name = interface.GetName()
108 if api_name.endswith('Trusted'):
109 api_name = api_name[:-len('Trusted')]
110 if api_name.endswith('_Dev'):
111 api_name = api_name[:-len('_Dev')]
112 api_name += '_API'
[email protected]a3887962013-04-16 21:02:16113 if member.GetProperty('api'): # Override API name.
114 manually_provided_api = True
115 # TODO(teravest): Automatically guess the API header file.
116 api_name = member.GetProperty('api')
117 else:
118 manually_provided_api = False
[email protected]2a7e8c52013-03-30 00:13:25119
[email protected]8c311f02012-11-17 16:01:32120 if arg[0] == 'PP_Instance':
121 if callback is None:
[email protected]2a7e8c52013-03-30 00:13:25122 arg_string = arg[1]
[email protected]8c311f02012-11-17 16:01:32123 else:
[email protected]2a7e8c52013-03-30 00:13:25124 arg_string = '%s, %s' % (arg[1], callback)
[email protected]a3887962013-04-16 21:02:16125 if interface.GetProperty('singleton') or member.GetProperty('singleton'):
126 if not manually_provided_api:
127 _AddApiHeader(filenode, meta)
[email protected]2a7e8c52013-03-30 00:13:25128 return 'EnterInstanceAPI<%s> enter(%s);' % (api_name, arg_string)
129 else:
130 return 'EnterInstance enter(%s);' % arg_string
[email protected]8c311f02012-11-17 16:01:32131 elif arg[0] == 'PP_Resource':
[email protected]8c311f02012-11-17 16:01:32132 enter_type = 'EnterResource<%s>' % api_name
[email protected]a3887962013-04-16 21:02:16133 if not manually_provided_api:
134 _AddApiHeader(filenode, meta)
[email protected]8c311f02012-11-17 16:01:32135 if callback is None:
136 return '%s enter(%s, %s);' % (enter_type, arg[1],
137 str(handle_errors).lower())
138 else:
139 return '%s enter(%s, %s, %s);' % (enter_type, arg[1],
140 callback,
141 str(handle_errors).lower())
142 else:
143 raise TGenError("Unknown type for _MakeEnterLine: %s" % arg[0])
144
145
146def _GetShortName(interface, filter_suffixes):
147 """Return a shorter interface name that matches Is* and Create* functions."""
148 parts = interface.GetName().split('_')[1:]
149 tail = parts[len(parts) - 1]
150 if tail in filter_suffixes:
151 parts = parts[:-1]
152 return ''.join(parts)
153
154
155def _IsTypeCheck(interface, node):
156 """Returns true if node represents a type-checking function."""
157 return node.GetName() == 'Is%s' % _GetShortName(interface, ['Dev', 'Private'])
158
159
160def _GetCreateFuncName(interface):
161 """Returns the creation function name for an interface."""
162 return 'Create%s' % _GetShortName(interface, ['Dev'])
163
164
165def _GetDefaultFailureValue(t):
166 """Returns the default failure value for a given type.
167
168 Returns None if no default failure value exists for the type.
169 """
170 values = {
171 'PP_Bool': 'PP_FALSE',
172 'PP_Resource': '0',
173 'struct PP_Var': 'PP_MakeUndefined()',
[email protected]12b6f612013-02-13 18:17:58174 'float': '0.0f',
[email protected]8c311f02012-11-17 16:01:32175 'int32_t': 'enter.retval()',
176 'uint16_t': '0',
177 'uint32_t': '0',
178 'uint64_t': '0',
179 }
180 if t in values:
181 return values[t]
182 return None
183
184
185def _MakeCreateMemberBody(interface, member, args):
186 """Returns the body of a Create() function.
187
188 Args:
189 interface - IDLNode for the interface
190 member - IDLNode for member function
191 args - List of arguments for the Create() function
192 """
193 if args[0][0] == 'PP_Resource':
[email protected]8917a672013-02-25 17:18:04194 body = 'Resource* object =\n'
195 body += ' PpapiGlobals::Get()->GetResourceTracker()->'
[email protected]8c311f02012-11-17 16:01:32196 body += 'GetResource(%s);\n' % args[0][1]
[email protected]8917a672013-02-25 17:18:04197 body += 'if (!object)\n'
198 body += ' return 0;\n'
199 body += 'EnterResourceCreation enter(object->pp_instance());\n'
[email protected]8c311f02012-11-17 16:01:32200 elif args[0][0] == 'PP_Instance':
[email protected]8917a672013-02-25 17:18:04201 body = 'EnterResourceCreation enter(%s);\n' % args[0][1]
[email protected]8c311f02012-11-17 16:01:32202 else:
203 raise TGenError('Unknown arg type for Create(): %s' % args[0][0])
204
[email protected]8917a672013-02-25 17:18:04205 body += 'if (enter.failed())\n'
206 body += ' return 0;\n'
[email protected]8c311f02012-11-17 16:01:32207 arg_list = ', '.join([a[1] for a in args])
208 if member.GetProperty('create_func'):
209 create_func = member.GetProperty('create_func')
210 else:
211 create_func = _GetCreateFuncName(interface)
[email protected]8917a672013-02-25 17:18:04212 body += 'return enter.functions()->%s(%s);' % (create_func,
213 arg_list)
[email protected]8c311f02012-11-17 16:01:32214 return body
215
216
[email protected]8917a672013-02-25 17:18:04217def _MakeNormalMemberBody(filenode, release, node, member, rtype, args,
218 include_version, meta):
[email protected]8c311f02012-11-17 16:01:32219 """Returns the body of a typical function.
220
221 Args:
222 filenode - IDLNode for the file
[email protected]8917a672013-02-25 17:18:04223 release - release to generate body for
[email protected]8c311f02012-11-17 16:01:32224 node - IDLNode for the interface
225 member - IDLNode for the member function
226 rtype - Return type for the member function
227 args - List of 4-tuple arguments for the member function
[email protected]8917a672013-02-25 17:18:04228 include_version - whether to include the version in the invocation
[email protected]cba2c4302012-11-20 18:18:13229 meta - ThunkBodyMetadata for header hints
[email protected]8c311f02012-11-17 16:01:32230 """
231 is_callback_func = args[len(args) - 1][0] == 'struct PP_CompletionCallback'
232
233 if is_callback_func:
234 call_args = args[:-1] + [('', 'enter.callback()', '', '')]
[email protected]8f2a08d52012-12-08 00:10:50235 meta.AddInclude('ppapi/c/pp_completion_callback.h')
[email protected]8c311f02012-11-17 16:01:32236 else:
237 call_args = args
238
239 if args[0][0] == 'PP_Instance':
240 call_arglist = ', '.join(a[1] for a in call_args)
241 function_container = 'functions'
242 else:
243 call_arglist = ', '.join(a[1] for a in call_args[1:])
244 function_container = 'object'
245
[email protected]8917a672013-02-25 17:18:04246 function_name = member.GetName()
247 if include_version:
248 version = node.GetVersion(release).replace('.', '_')
249 function_name += version
250
[email protected]8c311f02012-11-17 16:01:32251 invocation = 'enter.%s()->%s(%s)' % (function_container,
[email protected]8917a672013-02-25 17:18:04252 function_name,
[email protected]8c311f02012-11-17 16:01:32253 call_arglist)
254
255 handle_errors = not (member.GetProperty('report_errors') == 'False')
256 if is_callback_func:
[email protected]a3887962013-04-16 21:02:16257 body = '%s\n' % _MakeEnterLine(filenode, node, member, args[0],
258 handle_errors, args[len(args) - 1][1], meta)
[email protected]8917a672013-02-25 17:18:04259 body += 'if (enter.failed())\n'
[email protected]8c311f02012-11-17 16:01:32260 value = member.GetProperty('on_failure')
261 if value is None:
262 value = 'enter.retval()'
[email protected]8917a672013-02-25 17:18:04263 body += ' return %s;\n' % value
264 body += 'return enter.SetResult(%s);' % invocation
[email protected]8c311f02012-11-17 16:01:32265 elif rtype == 'void':
[email protected]2a7e8c52013-03-30 00:13:25266 # On failure, zero out all output parameters.
267 out_params = []
268 callnode = member.GetOneOf('Callspec')
269 if callnode:
270 cgen = CGen()
271 for param in callnode.GetListOf('Param'):
272 mode = cgen.GetParamMode(param)
273 if mode == 'out':
274 # We use the 'store' mode when getting the parameter type, since we
275 # need to call sizeof() for memset().
276 ptype, pname, _, _ = cgen.GetComponents(param, release, 'store')
277 out_params.append((pname, ptype))
278
[email protected]a3887962013-04-16 21:02:16279 body = '%s\n' % _MakeEnterLine(filenode, node, member, args[0],
280 handle_errors, None, meta)
[email protected]2a7e8c52013-03-30 00:13:25281 if not out_params:
282 body += 'if (enter.succeeded())\n'
283 body += ' %s;' % invocation
284 else:
285 body += 'if (enter.succeeded()) {\n'
286 body += ' %s;\n' % invocation
287 body += ' return;\n'
288 body += '}'
289 for param in out_params:
290 body += '\nmemset(%s, 0, sizeof(%s));' % param
291 meta.AddBuiltinInclude('string.h')
292
[email protected]8c311f02012-11-17 16:01:32293 else:
294 value = member.GetProperty('on_failure')
295 if value is None:
296 value = _GetDefaultFailureValue(rtype)
297 if value is None:
298 raise TGenError('No default value for rtype %s' % rtype)
299
[email protected]a3887962013-04-16 21:02:16300 body = '%s\n' % _MakeEnterLine(filenode, node, member, args[0],
301 handle_errors, None, meta)
[email protected]8917a672013-02-25 17:18:04302 body += 'if (enter.failed())\n'
303 body += ' return %s;\n' % value
304 body += 'return %s;' % invocation
[email protected]8c311f02012-11-17 16:01:32305 return body
306
307
[email protected]cba2c4302012-11-20 18:18:13308def DefineMember(filenode, node, member, release, include_version, meta):
[email protected]8c311f02012-11-17 16:01:32309 """Returns a definition for a member function of an interface.
310
311 Args:
312 filenode - IDLNode for the file
313 node - IDLNode for the interface
314 member - IDLNode for the member function
315 release - release to generate
316 include_version - include the version in emitted function name.
[email protected]cba2c4302012-11-20 18:18:13317 meta - ThunkMetadata for header hints
[email protected]8c311f02012-11-17 16:01:32318 Returns:
319 A string with the member definition.
320 """
321 cgen = CGen()
322 rtype, name, arrays, args = cgen.GetComponents(member, release, 'return')
[email protected]03f8b542013-04-02 17:57:50323 body = 'VLOG(4) << \"%s::%s()\";\n' % (node.GetName(), member.GetName())
[email protected]8c311f02012-11-17 16:01:32324
325 if _IsTypeCheck(node, member):
[email protected]a3887962013-04-16 21:02:16326 body += '%s\n' % _MakeEnterLine(filenode, node, member, args[0], False,
327 None, meta)
[email protected]8917a672013-02-25 17:18:04328 body += 'return PP_FromBool(enter.succeeded());'
[email protected]8c311f02012-11-17 16:01:32329 elif member.GetName() == 'Create':
[email protected]03f8b542013-04-02 17:57:50330 body += _MakeCreateMemberBody(node, member, args)
[email protected]8c311f02012-11-17 16:01:32331 else:
[email protected]03f8b542013-04-02 17:57:50332 body += _MakeNormalMemberBody(filenode, release, node, member, rtype, args,
333 include_version, meta)
[email protected]8c311f02012-11-17 16:01:32334
335 signature = cgen.GetSignature(member, release, 'return', func_as_ptr=False,
336 include_version=include_version)
[email protected]8917a672013-02-25 17:18:04337 return '%s\n%s\n}' % (cgen.Indent('%s {' % signature, tabs=0),
338 cgen.Indent(body, tabs=1))
339
340
341def _IsNewestMember(member, members, releases):
342 """Returns true if member is the newest node with its name in members.
343
344 Currently, every node in the AST only has one version. This means that we
345 will have two sibling nodes with the same name to represent different
346 versions.
347 See http://crbug.com/157017 .
348
349 Special handling is required for nodes which share their name with others,
350 but aren't the newest version in the IDL.
351
352 Args:
353 member - The member which is checked if it's newest
354 members - The list of members to inspect
355 releases - The set of releases to check for versions in.
356 """
357 build_list = member.GetUniqueReleases(releases)
[email protected]ba054c02013-02-26 23:27:18358 release = build_list[0] # Pick the oldest release.
[email protected]8917a672013-02-25 17:18:04359 same_name_siblings = filter(
360 lambda n: str(n) == str(member) and n != member, members)
361
362 for s in same_name_siblings:
363 sibling_build_list = s.GetUniqueReleases(releases)
[email protected]ba054c02013-02-26 23:27:18364 sibling_release = sibling_build_list[0]
[email protected]8917a672013-02-25 17:18:04365 if sibling_release > release:
366 return False
367 return True
[email protected]8c311f02012-11-17 16:01:32368
369
370class TGen(GeneratorByFile):
371 def __init__(self):
372 Generator.__init__(self, 'Thunk', 'tgen', 'Generate the C++ thunk.')
373
374 def GenerateFile(self, filenode, releases, options):
375 savename = _GetThunkFileName(filenode, GetOption('thunkroot'))
376 my_min, my_max = filenode.GetMinMax(releases)
377 if my_min > releases[-1] or my_max < releases[0]:
378 if os.path.isfile(savename):
379 print "Removing stale %s for this range." % filenode.GetName()
380 os.remove(os.path.realpath(savename))
381 return False
382 do_generate = filenode.GetProperty('generate_thunk')
383 if not do_generate:
384 return False
385
386 thunk_out = IDLOutFile(savename)
[email protected]cba2c4302012-11-20 18:18:13387 body, meta = self.GenerateBody(thunk_out, filenode, releases, options)
[email protected]a3887962013-04-16 21:02:16388 # TODO(teravest): How do we handle repeated values?
389 if filenode.GetProperty('thunk_include'):
390 meta.AddInclude(filenode.GetProperty('thunk_include'))
[email protected]cba2c4302012-11-20 18:18:13391 self.WriteHead(thunk_out, filenode, releases, options, meta)
392 thunk_out.Write('\n\n'.join(body))
393 self.WriteTail(thunk_out, filenode, releases, options)
[email protected]8c311f02012-11-17 16:01:32394 return thunk_out.Close()
395
[email protected]cba2c4302012-11-20 18:18:13396 def WriteHead(self, out, filenode, releases, options, meta):
[email protected]8c311f02012-11-17 16:01:32397 __pychecker__ = 'unusednames=options'
398 cgen = CGen()
399
400 cright_node = filenode.GetChildren()[0]
401 assert(cright_node.IsA('Copyright'))
402 out.Write('%s\n' % cgen.Copyright(cright_node, cpp_style=True))
403
404 # Wrap the From ... modified ... comment if it would be >80 characters.
405 from_text = 'From %s' % (
406 filenode.GetProperty('NAME').replace(os.sep,'/'))
407 modified_text = 'modified %s.' % (
408 filenode.GetProperty('DATETIME'))
409 if len(from_text) + len(modified_text) < 74:
410 out.Write('// %s %s\n\n' % (from_text, modified_text))
411 else:
412 out.Write('// %s,\n// %s\n\n' % (from_text, modified_text))
413
[email protected]2a7e8c52013-03-30 00:13:25414 if meta.BuiltinIncludes():
415 for include in sorted(meta.BuiltinIncludes()):
416 out.Write('#include <%s>\n' % include)
417 out.Write('\n')
[email protected]8c311f02012-11-17 16:01:32418
419 # TODO(teravest): Don't emit includes we don't need.
420 includes = ['ppapi/c/pp_errors.h',
421 'ppapi/shared_impl/tracked_callback.h',
422 'ppapi/thunk/enter.h',
423 'ppapi/thunk/ppb_instance_api.h',
424 'ppapi/thunk/resource_creation_api.h',
425 'ppapi/thunk/thunk.h']
426 includes.append(_GetHeaderFileName(filenode))
[email protected]cba2c4302012-11-20 18:18:13427 for api in meta.Apis():
428 includes.append('ppapi/thunk/%s.h' % api.lower())
[email protected]8f2a08d52012-12-08 00:10:50429 for i in meta.Includes():
430 includes.append(i)
[email protected]8c311f02012-11-17 16:01:32431 for include in sorted(includes):
432 out.Write('#include "%s"\n' % include)
433 out.Write('\n')
434 out.Write('namespace ppapi {\n')
435 out.Write('namespace thunk {\n')
436 out.Write('\n')
437 out.Write('namespace {\n')
438 out.Write('\n')
439
440 def GenerateBody(self, out, filenode, releases, options):
[email protected]cba2c4302012-11-20 18:18:13441 """Generates a member function lines to be written and metadata.
442
443 Returns a tuple of (body, meta) where:
444 body - a list of lines with member function bodies
445 meta - a ThunkMetadata instance for hinting which headers are needed.
446 """
[email protected]8c311f02012-11-17 16:01:32447 __pychecker__ = 'unusednames=options'
[email protected]8917a672013-02-25 17:18:04448 out_members = []
[email protected]cba2c4302012-11-20 18:18:13449 meta = ThunkBodyMetadata()
[email protected]8c311f02012-11-17 16:01:32450 for node in filenode.GetListOf('Interface'):
451 # Skip if this node is not in this release
452 if not node.InReleases(releases):
453 print "Skipping %s" % node
454 continue
455
456 # Generate Member functions
457 if node.IsA('Interface'):
[email protected]8917a672013-02-25 17:18:04458 members = node.GetListOf('Member')
459 for child in members:
[email protected]8c311f02012-11-17 16:01:32460 build_list = child.GetUniqueReleases(releases)
461 # We have to filter out releases this node isn't in.
462 build_list = filter(lambda r: child.InReleases([r]), build_list)
463 if len(build_list) == 0:
464 continue
[email protected]8917a672013-02-25 17:18:04465 assert(len(build_list) == 1)
466 release = build_list[-1]
467 include_version = not _IsNewestMember(child, members, releases)
468 member = DefineMember(filenode, node, child, release, include_version,
469 meta)
[email protected]8c311f02012-11-17 16:01:32470 if not member:
471 continue
[email protected]8917a672013-02-25 17:18:04472 out_members.append(member)
473 return (out_members, meta)
[email protected]8c311f02012-11-17 16:01:32474
[email protected]cba2c4302012-11-20 18:18:13475 def WriteTail(self, out, filenode, releases, options):
[email protected]8c311f02012-11-17 16:01:32476 __pychecker__ = 'unusednames=options'
477 cgen = CGen()
478
479 version_list = []
480 out.Write('\n\n')
481 for node in filenode.GetListOf('Interface'):
482 build_list = node.GetUniqueReleases(releases)
483 for build in build_list:
484 version = node.GetVersion(build).replace('.', '_')
485 thunk_name = 'g_' + node.GetName().lower() + '_thunk_' + \
486 version
487 thunk_type = '_'.join((node.GetName(), version))
488 version_list.append((thunk_type, thunk_name))
489
[email protected]8c71647a62013-02-26 19:32:50490 declare_line = 'const %s %s = {' % (thunk_type, thunk_name)
491 if len(declare_line) > 80:
492 declare_line = 'const %s\n %s = {' % (thunk_type, thunk_name)
493 out.Write('%s\n' % declare_line)
[email protected]cfc881d2013-01-03 19:07:46494 generated_functions = []
[email protected]8917a672013-02-25 17:18:04495 members = node.GetListOf('Member')
496 for child in members:
[email protected]8c311f02012-11-17 16:01:32497 rtype, name, arrays, args = cgen.GetComponents(
498 child, build, 'return')
[email protected]8917a672013-02-25 17:18:04499 if not _IsNewestMember(child, members, releases):
500 version = node.GetVersion(build).replace('.', '_')
501 name += '_' + version
[email protected]cfc881d2013-01-03 19:07:46502 if child.InReleases([build]):
503 generated_functions.append(name)
504 out.Write(',\n'.join([' &%s' % f for f in generated_functions]))
505 out.Write('\n};\n\n')
[email protected]8c311f02012-11-17 16:01:32506
507 out.Write('} // namespace\n')
508 out.Write('\n')
509 for thunk_type, thunk_name in version_list:
510 thunk_decl = 'const %s* Get%s_Thunk() {\n' % (thunk_type, thunk_type)
511 if len(thunk_decl) > 80:
512 thunk_decl = 'const %s*\n Get%s_Thunk() {\n' % (thunk_type,
513 thunk_type)
514 out.Write(thunk_decl)
515 out.Write(' return &%s;\n' % thunk_name)
516 out.Write('}\n')
517 out.Write('\n')
518 out.Write('} // namespace thunk\n')
519 out.Write('} // namespace ppapi\n')
520
521
522tgen = TGen()
523
524
525def Main(args):
526 # Default invocation will verify the golden files are unchanged.
527 failed = 0
528 if not args:
529 args = ['--wnone', '--diff', '--test', '--thunkroot=.']
530
531 ParseOptions(args)
532
533 idldir = os.path.split(sys.argv[0])[0]
534 idldir = os.path.join(idldir, 'test_thunk', '*.idl')
535 filenames = glob.glob(idldir)
536 ast = ParseFiles(filenames)
537 if tgen.GenerateRange(ast, ['M13', 'M14'], {}):
538 print "Golden file for M13-M14 failed."
539 failed = 1
540 else:
541 print "Golden file for M13-M14 passed."
542
543 return failed
544
545
546if __name__ == '__main__':
547 sys.exit(Main(sys.argv[1:]))