summaryrefslogtreecommitdiffstats
path: root/tools/json_schema_compiler/compiler.py
diff options
context:
space:
mode:
authorsashab@chromium.org <sashab@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-06 01:29:31 +0000
committersashab@chromium.org <sashab@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-06 01:29:31 +0000
commit32096af1d31370bc81358a3ea90498d38ef7ceb3 (patch)
treec4f695ae70ab018a7a5b926c49329cf21c84d635 /tools/json_schema_compiler/compiler.py
parent6d65ef66a053c717dcb0dad338fd886c986679b6 (diff)
downloadchromium_src-32096af1d31370bc81358a3ea90498d38ef7ceb3.zip
chromium_src-32096af1d31370bc81358a3ea90498d38ef7ceb3.tar.gz
chromium_src-32096af1d31370bc81358a3ea90498d38ef7ceb3.tar.bz2
Initial commit of the Dart Chrome Extension APIs generators
Modified json_schema_compiler to allow a -l option to specify the language. Also allowed for a -H option to specify a hooks file, which is currently only supported for Dart. Review URL: https://chromiumcodereview.appspot.com/12041098 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@180845 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools/json_schema_compiler/compiler.py')
-rwxr-xr-xtools/json_schema_compiler/compiler.py271
1 files changed, 126 insertions, 145 deletions
diff --git a/tools/json_schema_compiler/compiler.py b/tools/json_schema_compiler/compiler.py
index a270756..4e41e38 100755
--- a/tools/json_schema_compiler/compiler.py
+++ b/tools/json_schema_compiler/compiler.py
@@ -16,18 +16,22 @@ Usage example:
--namespace extensions windows.json tabs.json
"""
-import cc_generator
-import cpp_type_generator
-import h_generator
+from cpp_generator import CppGenerator
+from cpp_type_generator import CppTypeGenerator
+from dart_generator import DartGenerator
+from cpp_bundle_generator import CppBundleGenerator
+from model import Model
import idl_schema
import json_schema
-import model
-import schema_bundle_generator
import optparse
import os.path
import sys
+# Names of supported code generators, as specified on the command-line.
+# First is default.
+GENERATORS = ['cpp', 'cpp-bundle', 'dart']
+
def load_schema(schema):
schema_filename, schema_extension = os.path.splitext(schema)
@@ -36,106 +40,98 @@ def load_schema(schema):
elif schema_extension == '.idl':
api_defs = idl_schema.Load(schema)
else:
- sys.exit("Did not recognize file extension %s for schema %s" %
+ sys.exit('Did not recognize file extension %s for schema %s' %
(schema_extension, schema))
if len(api_defs) != 1:
- sys.exit("File %s has multiple schemas. Files are only allowed to contain a"
- " single schema." % schema)
+ sys.exit('File %s has multiple schemas. Files are only allowed to contain a'
+ ' single schema.' % schema)
return api_defs
-def handle_single_schema(filename, dest_dir, root, root_namespace):
- schema = os.path.normpath(filename)
- schema_filename, schema_extension = os.path.splitext(schema)
- path, short_filename = os.path.split(schema_filename)
- api_defs = json_schema.DeleteNocompileNodes(load_schema(schema))
-
- api_model = model.Model()
-
- for target_namespace in api_defs:
- referenced_schemas = target_namespace.get('dependencies', [])
- # Load type dependencies into the model.
- # TODO(miket): do we need this in IDL?
- for referenced_schema in referenced_schemas:
- split_schema = referenced_schema.split(':', 1)
- if len(split_schema) > 1:
- if split_schema[0] != 'api':
- continue
- else:
- referenced_schema = split_schema[1]
-
- referenced_schema_path = os.path.join(
- os.path.dirname(schema), referenced_schema + '.json')
- referenced_api_defs = json_schema.Load(referenced_schema_path)
-
- for namespace in referenced_api_defs:
- api_model.AddNamespace(
- namespace,
- os.path.relpath(referenced_schema_path, opts.root))
-
- # Gets the relative path from opts.root to the schema to correctly determine
- # the include path.
- relpath = os.path.relpath(schema, opts.root)
- namespace = api_model.AddNamespace(target_namespace,
- relpath,
- include_compiler_options=True)
- if not namespace:
- continue
+if __name__ == '__main__':
+ parser = optparse.OptionParser(
+ description='Generates a C++ model of an API from JSON schema',
+ usage='usage: %prog [option]... schema')
+ parser.add_option('-r', '--root', default='.',
+ help='logical include root directory. Path to schema files from specified'
+ 'dir will be the include path.')
+ parser.add_option('-d', '--destdir',
+ help='root directory to output generated files.')
+ parser.add_option('-n', '--namespace', default='generated_api_schemas',
+ help='C++ namespace for generated files. e.g extensions::api.')
+ parser.add_option('-g', '--generator', default=GENERATORS[0],
+ choices=GENERATORS,
+ help='The generator to use to build the output code. Supported values are'
+ ' %s' % GENERATORS)
+ parser.add_option('-D', '--dart-overrides-dir', dest='dart_overrides_dir',
+ help='Adds custom dart from files in the given directory (Dart only).')
- if short_filename != namespace.unix_name:
- sys.exit("Filename %s is illegal. Name files using unix_hacker style." %
- filename)
+ (opts, filenames) = parser.parse_args()
- # The output filename must match the input filename for gyp to deal with it
- # properly.
- out_file = namespace.unix_name
- type_generator = cpp_type_generator.CppTypeGenerator(
- root_namespace, namespace, namespace.unix_name)
- for referenced_namespace in api_model.namespaces.values():
- if referenced_namespace == namespace:
- continue
- type_generator.AddNamespace(
- referenced_namespace,
- referenced_namespace.unix_name)
-
- h_code = (h_generator.HGenerator(namespace, type_generator)
- .Generate().Render())
- cc_code = (cc_generator.CCGenerator(namespace, type_generator)
- .Generate().Render())
-
- if dest_dir:
- with open(
- os.path.join(dest_dir, namespace.source_file_dir, out_file + '.cc'),
- 'w') as cc_file:
- cc_file.write(cc_code)
- with open(
- os.path.join(dest_dir, namespace.source_file_dir, out_file + '.h'),
- 'w') as h_file:
- h_file.write(h_code)
- else:
- print '%s.h' % out_file
- print
- print h_code
- print
- print '%s.cc' % out_file
- print
- print cc_code
+ if not filenames:
+ sys.exit(0) # This is OK as a no-op
+
+ # Unless in bundle mode, only one file should be specified.
+ if opts.generator != 'cpp-bundle' and len(filenames) > 1:
+ # TODO(sashab): Could also just use filenames[0] here and not complain.
+ raise Exception(
+ "Unless in bundle mode, only one file can be specified at a time.")
-def handle_bundle_schema(filenames, dest_dir, root, root_namespace):
# Merge the source files into a single list of schemas.
api_defs = []
for filename in filenames:
schema = os.path.normpath(filename)
schema_filename, schema_extension = os.path.splitext(schema)
- api_defs.extend(load_schema(schema))
-
- api_model = model.Model()
- relpath = os.path.relpath(os.path.normpath(filenames[0]), root)
-
+ path, short_filename = os.path.split(schema_filename)
+ api_def = load_schema(schema)
+
+ # If compiling the C++ model code, delete 'nocompile' nodes.
+ if opts.generator == 'cpp':
+ api_def = json_schema.DeleteNodes(api_def, 'nocompile')
+ api_defs.extend(api_def)
+
+ api_model = Model()
+
+ # Load type dependencies into the model.
+ #
+ # HACK(kalman): bundle mode doesn't work with dependencies, because not all
+ # schemas work in bundle mode.
+ #
+ # TODO(kalman): load dependencies lazily (get rid of the 'dependencies' list)
+ # and this problem will go away.
+ if opts.generator != 'cpp-bundle':
+ for target_namespace in api_defs:
+ for referenced_schema in target_namespace.get('dependencies', []):
+ split_schema = referenced_schema.split(':', 1)
+ if len(split_schema) > 1:
+ if split_schema[0] != 'api':
+ continue
+ else:
+ referenced_schema = split_schema[1]
+
+ referenced_schema_path = os.path.join(
+ os.path.dirname(schema), referenced_schema + '.json')
+ referenced_api_defs = json_schema.Load(referenced_schema_path)
+
+ for namespace in referenced_api_defs:
+ api_model.AddNamespace(
+ namespace,
+ os.path.relpath(referenced_schema_path, opts.root),
+ include_compiler_options=True)
+
+ # For single-schema compilation make sure that the first (i.e. only) schema
+ # is the default one.
+ default_namespace = None
+
+ # Load the actual namespaces into the model.
for target_namespace, schema_filename in zip(api_defs, filenames):
+ relpath = os.path.relpath(os.path.normpath(schema_filename), opts.root)
namespace = api_model.AddNamespace(target_namespace,
relpath,
include_compiler_options=True)
+ if default_namespace is None:
+ default_namespace = namespace
+
path, filename = os.path.split(schema_filename)
short_filename, extension = os.path.splitext(filename)
@@ -146,62 +142,47 @@ def handle_bundle_schema(filenames, dest_dir, root, root_namespace):
sys.exit("Filename %s is illegal. Name files using unix_hacker style." %
schema_filename)
- type_generator = cpp_type_generator.CppTypeGenerator(root_namespace)
- for referenced_namespace in api_model.namespaces.values():
- type_generator.AddNamespace(
- referenced_namespace,
- referenced_namespace.unix_name)
-
- generator = schema_bundle_generator.SchemaBundleGenerator(
- root, api_model, api_defs, type_generator)
- api_h_code = generator.GenerateAPIHeader().Render()
- schemas_h_code = generator.GenerateSchemasHeader().Render()
- schemas_cc_code = generator.GenerateSchemasCC().Render()
-
- if dest_dir:
- basedir = os.path.join(dest_dir, 'chrome/common/extensions/api')
- with open(os.path.join(basedir, 'generated_api.h'), 'w') as h_file:
- h_file.write(api_h_code)
- with open(os.path.join(basedir, 'generated_schemas.h'), 'w') as h_file:
- h_file.write(schemas_h_code)
- with open(os.path.join(basedir, 'generated_schemas.cc'), 'w') as cc_file:
- cc_file.write(schemas_cc_code)
- else:
- print 'generated_api.h'
- print
- print api_h_code
- print
- print 'generated_schemas.h'
- print
- print schemas_h_code
- print
- print 'generated_schemas.cc'
- print
- print schemas_cc_code
-
-if __name__ == '__main__':
- parser = optparse.OptionParser(
- description='Generates a C++ model of an API from JSON schema',
- usage='usage: %prog [option]... schema')
- parser.add_option('-r', '--root', default='.',
- help='logical include root directory. Path to schema files from specified'
- 'dir will be the include path.')
- parser.add_option('-d', '--destdir',
- help='root directory to output generated files.')
- parser.add_option('-n', '--namespace', default='generated_api_schemas',
- help='C++ namespace for generated files. e.g extensions::api.')
- parser.add_option('-b', '--bundle', action="store_true", help=
-'''if supplied, causes compiler to generate bundle files for the given set of
-source files.''')
-
- (opts, args) = parser.parse_args()
-
- if not args:
- sys.exit(0) # This is OK as a no-op
- dest_dir = opts.destdir
- root_namespace = opts.namespace
+ # The output filename must match the input filename for gyp to deal with it
+ # properly.
+ out_file = namespace.unix_name
- if opts.bundle:
- handle_bundle_schema(args, dest_dir, opts.root, root_namespace)
+ # Construct the type generator with all the namespaces in this model.
+ type_generator = CppTypeGenerator(api_model,
+ default_namespace=default_namespace)
+
+ if opts.generator == 'cpp-bundle':
+ cpp_bundle_generator = CppBundleGenerator(opts.root,
+ api_model,
+ api_defs,
+ type_generator,
+ opts.namespace)
+ generators = [
+ ('generated_api.h', cpp_bundle_generator.api_h_generator),
+ ('generated_schemas.cc', cpp_bundle_generator.schemas_cc_generator),
+ ('generated_schemas.h', cpp_bundle_generator.schemas_h_generator)
+ ]
+ elif opts.generator == 'cpp':
+ cpp_generator = CppGenerator(type_generator, opts.namespace)
+ generators = [
+ ('%s.h' % namespace.unix_name, cpp_generator.h_generator),
+ ('%s.cc' % namespace.unix_name, cpp_generator.cc_generator)
+ ]
+ elif opts.generator == 'dart':
+ generators = [
+ ('%s.dart' % namespace.unix_name, DartGenerator(
+ opts.dart_overrides_dir))
+ ]
else:
- handle_single_schema(args[0], dest_dir, opts.root, root_namespace)
+ raise Exception('Unrecognised generator %s' % opts.generator)
+
+ for filename, generator in generators:
+ code = generator.Generate(namespace).Render()
+ if opts.destdir:
+ with open(os.path.join(opts.destdir, namespace.source_file_dir,
+ filename), 'w') as f:
+ f.write(code)
+ else:
+ print filename
+ print
+ print code
+ print