| Index: third_party/chrome/ppapi/generators/idl_generator.py
|
| diff --git a/third_party/chrome/ppapi/generators/idl_generator.py b/third_party/chrome/ppapi/generators/idl_generator.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..028a233435b903bf3419865573b7ad37837e59ce
|
| --- /dev/null
|
| +++ b/third_party/chrome/ppapi/generators/idl_generator.py
|
| @@ -0,0 +1,277 @@
|
| +#!/usr/bin/env python
|
| +# Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +import sys
|
| +
|
| +from idl_log import ErrOut, InfoOut, WarnOut
|
| +from idl_option import GetOption, Option, ParseOptions
|
| +from idl_parser import ParseFiles
|
| +
|
| +GeneratorList = []
|
| +
|
| +Option('out', 'List of output files', default='')
|
| +Option('release', 'Which release to generate.', default='')
|
| +Option('range', 'Which ranges in the form of MIN,MAX.', default='start,end')
|
| +
|
| +class Generator(object):
|
| + """Base class for generators.
|
| +
|
| + This class provides a mechanism for adding new generator objects to the IDL
|
| + driver. To use this class override the GenerateRelease and GenerateRange
|
| + members, and instantiate one copy of the class in the same module which
|
| + defines it to register the generator. After the AST is generated, call the
|
| + static Run member which will check every registered generator to see which
|
| + ones have been enabled through command-line options. To enable a generator
|
| + use the switches:
|
| + --<sname> : To enable with defaults
|
| + --<sname>_opt=<XXX,YYY=y> : To enable with generator specific options.
|
| +
|
| + NOTE: Generators still have access to global options
|
| + """
|
| +
|
| + def __init__(self, name, sname, desc):
|
| + self.name = name
|
| + self.run_switch = Option(sname, desc)
|
| + self.opt_switch = Option(sname + '_opt', 'Options for %s.' % sname,
|
| + default='')
|
| + GeneratorList.append(self)
|
| + self.errors = 0
|
| + self.skip_list = []
|
| +
|
| + def Error(self, msg):
|
| + ErrOut.Log('Error %s : %s' % (self.name, msg))
|
| + self.errors += 1
|
| +
|
| + def GetRunOptions(self):
|
| + options = {}
|
| + option_list = self.opt_switch.Get()
|
| + if option_list:
|
| + option_list = option_list.split(',')
|
| + for opt in option_list:
|
| + offs = opt.find('=')
|
| + if offs > 0:
|
| + options[opt[:offs]] = opt[offs+1:]
|
| + else:
|
| + options[opt] = True
|
| + return options
|
| + if self.run_switch.Get():
|
| + return options
|
| + return None
|
| +
|
| + def Generate(self, ast, options):
|
| + self.errors = 0
|
| +
|
| + rangestr = GetOption('range')
|
| + releasestr = GetOption('release')
|
| +
|
| + print "Found releases: %s" % ast.releases
|
| +
|
| + # Generate list of files to ignore due to errors
|
| + for filenode in ast.GetListOf('File'):
|
| + # If this file has errors, skip it
|
| + if filenode.GetProperty('ERRORS') > 0:
|
| + self.skip_list.append(filenode)
|
| + continue
|
| +
|
| + # Check for a range option which over-rides a release option
|
| + if not releasestr and rangestr:
|
| + range_list = rangestr.split(',')
|
| + if len(range_list) != 2:
|
| + self.Error('Failed to generate for %s, incorrect range: "%s"' %
|
| + (self.name, rangestr))
|
| + else:
|
| + vmin = range_list[0]
|
| + vmax = range_list[1]
|
| +
|
| + # Generate 'start' and 'end' represent first and last found.
|
| + if vmin == 'start':
|
| + vmin = ast.releases[0]
|
| + if vmax == 'end':
|
| + vmax = ast.releases[-1]
|
| +
|
| + vmin = ast.releases.index(vmin)
|
| + vmax = ast.releases.index(vmax) + 1
|
| + releases = ast.releases[vmin:vmax]
|
| + InfoOut.Log('Generate range %s of %s.' % (rangestr, self.name))
|
| + ret = self.GenerateRange(ast, releases, options)
|
| + if ret < 0:
|
| + self.Error('Failed to generate range %s : %s.' %(vmin, vmax))
|
| + else:
|
| + InfoOut.Log('%s wrote %d files.' % (self.name, ret))
|
| + # Otherwise this should be a single release generation
|
| + else:
|
| + if releasestr == 'start':
|
| + releasestr = ast.releases[0]
|
| + if releasestr == 'end':
|
| + releasestr = ast.releases[-1]
|
| +
|
| + if releasestr > ast.releases[-1]:
|
| + InfoOut.Log('There is no unique release for %s, using last release.' %
|
| + releasestr)
|
| + releasestr = ast.releases[-1]
|
| +
|
| + if releasestr not in ast.releases:
|
| + self.Error('Release %s not in [%s].' %
|
| + (releasestr, ', '.join(ast.releases)))
|
| +
|
| + if releasestr:
|
| + InfoOut.Log('Generate release %s of %s.' % (releasestr, self.name))
|
| + ret = self.GenerateRelease(ast, releasestr, options)
|
| + if ret < 0:
|
| + self.Error('Failed to generate release %s.' % releasestr)
|
| + else:
|
| + InfoOut.Log('%s wrote %d files.' % (self.name, ret))
|
| +
|
| + else:
|
| + self.Error('No range or release specified for %s.' % releasestr)
|
| + return self.errors
|
| +
|
| + def GenerateRelease(self, ast, release, options):
|
| + __pychecker__ = 'unusednames=ast,release,options'
|
| + self.Error("Undefined release generator.")
|
| + return 0
|
| +
|
| + def GenerateRange(self, ast, releases, options):
|
| + __pychecker__ = 'unusednames=ast,releases,options'
|
| + self.Error("Undefined range generator.")
|
| + return 0
|
| +
|
| + @staticmethod
|
| + def Run(ast):
|
| + fail_count = 0
|
| +
|
| + # Check all registered generators if they should run.
|
| + for gen in GeneratorList:
|
| + options = gen.GetRunOptions()
|
| + if options is not None:
|
| + if gen.Generate(ast, options):
|
| + fail_count += 1
|
| + return fail_count
|
| +
|
| +
|
| +class GeneratorByFile(Generator):
|
| + """A simplified generator that generates one output file per IDL source file.
|
| +
|
| + A subclass of Generator for use of generators which have a one to one
|
| + mapping between IDL sources and output files.
|
| +
|
| + Derived classes should define GenerateFile.
|
| + """
|
| +
|
| + def GenerateFile(self, filenode, releases, options):
|
| + """Generates an output file from the IDL source.
|
| +
|
| + Returns true if the generated file is different than the previously
|
| + generated file.
|
| + """
|
| + __pychecker__ = 'unusednames=filenode,releases,options'
|
| + self.Error("Undefined release generator.")
|
| + return 0
|
| +
|
| + def GenerateRelease(self, ast, release, options):
|
| + return self.GenerateRange(ast, [release], options)
|
| +
|
| + def GenerateRange(self, ast, releases, options):
|
| + # Get list of out files
|
| + outlist = GetOption('out')
|
| + if outlist: outlist = outlist.split(',')
|
| +
|
| + skipList = []
|
| + cnt = 0
|
| + for filenode in ast.GetListOf('File'):
|
| + # Ignore files with errors
|
| + if filenode in self.skip_list:
|
| + continue
|
| +
|
| + # Skip this file if not required
|
| + if outlist and filenode.GetName() not in outlist:
|
| + continue
|
| +
|
| + # Create the output file and increment out count if there was a delta
|
| + if self.GenerateFile(filenode, releases, options):
|
| + cnt = cnt + 1
|
| +
|
| + for filenode in skipList:
|
| + errcnt = filenode.GetProperty('ERRORS')
|
| + ErrOut.Log('%s : Skipped because of %d errors.' % (
|
| + filenode.GetName(), errcnt))
|
| +
|
| + if skipList:
|
| + return -len(skipList)
|
| +
|
| + if GetOption('diff'):
|
| + return -cnt
|
| + return cnt
|
| +
|
| +
|
| +check_release = 0
|
| +check_range = 0
|
| +
|
| +class GeneratorReleaseTest(Generator):
|
| + def GenerateRelease(self, ast, release, options = {}):
|
| + __pychecker__ = 'unusednames=ast,release,options'
|
| + global check_release
|
| + check_map = {
|
| + 'so_long': True,
|
| + 'MyOpt': 'XYZ',
|
| + 'goodbye': True
|
| + }
|
| + check_release = 1
|
| + for item in check_map:
|
| + check_item = check_map[item]
|
| + option_item = options.get(item, None)
|
| + if check_item != option_item:
|
| + print 'Option %s is %s, expecting %s' % (item, option_item, check_item)
|
| + check_release = 0
|
| +
|
| + if release != 'M14':
|
| + check_release = 0
|
| + return check_release == 1
|
| +
|
| + def GenerateRange(self, ast, releases, options):
|
| + __pychecker__ = 'unusednames=ast,releases,options'
|
| + global check_range
|
| + check_range = 1
|
| + return True
|
| +
|
| +def Test():
|
| + __pychecker__ = 'unusednames=args'
|
| + global check_release
|
| + global check_range
|
| +
|
| + ParseOptions(['--testgen_opt=so_long,MyOpt=XYZ,goodbye'])
|
| + if Generator.Run('AST') != 0:
|
| + print 'Generate release: Failed.\n'
|
| + return -1
|
| +
|
| + if check_release != 1 or check_range != 0:
|
| + print 'Gererate release: Failed to run.\n'
|
| + return -1
|
| +
|
| + check_release = 0
|
| + ParseOptions(['--testgen_opt="HELLO"', '--range=M14,M16'])
|
| + if Generator.Run('AST') != 0:
|
| + print 'Generate range: Failed.\n'
|
| + return -1
|
| +
|
| + if check_release != 0 or check_range != 1:
|
| + print 'Gererate range: Failed to run.\n'
|
| + return -1
|
| +
|
| + print 'Generator test: Pass'
|
| + return 0
|
| +
|
| +
|
| +def Main(args):
|
| + if not args: return Test()
|
| + filenames = ParseOptions(args)
|
| + ast = ParseFiles(filenames)
|
| +
|
| + return Generator.Run(ast)
|
| +
|
| +
|
| +if __name__ == '__main__':
|
| + GeneratorReleaseTest('Test Gen', 'testgen', 'Generator Class Test.')
|
| + sys.exit(Main(sys.argv[1:]))
|
|
|