Chromium Code Reviews| Index: tools/json_to_struct/json_to_struct.py |
| diff --git a/tools/json_to_struct/json_to_struct.py b/tools/json_to_struct/json_to_struct.py |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..70ae1a9b8014486676eb9cf9ff7532db2d56fd6f |
| --- /dev/null |
| +++ b/tools/json_to_struct/json_to_struct.py |
| @@ -0,0 +1,204 @@ |
| +#!/usr/bin/env python |
| +# Copyright 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. |
| + |
| +# Format for the JSON schema file: |
| +# { |
| +# "type_name": "DesiredCStructName", |
| +# "headers": [ // Optional list of headers to be included by the .h. |
| +# "path/to/header.h" |
| +# ], |
| +# "schema": [ // Fields of the generated structure. |
| +# { |
| +# "field": "my_enum_field", |
| +# "type": "enum", // Either: int, string, string16, enum, array. |
| +# "default": "RED", // Optional. Cannot be used for array. |
| +# "ctype": "Color" // Only for enum, specify the C type. |
| +# }, |
| +# { |
| +# "field": "my_int_array_field", // my_int_array_field_size will also |
| +# "type": "array", // be generated. |
| +# "contents": { |
| +# "type": "int" // Either: int, string, string16, enum, array. |
| +# } |
| +# }, |
| +# ... |
| +# ] |
| +# } |
| +# |
| +# Format for the JSON description file: |
| +# { |
| +# "int_variables": { // An optional list of constant int variables. |
| +# "kDesiredConstantName": 45 |
| +# }, |
| +# "elements": { // All the elements for which to create static |
| +# // initialization code in the .cc file. |
| +# "my_const_variable": { |
| +# "my_int_field": 10, |
| +# "my_string_field": "foo bar", |
| +# "my_enum_field": "BLACK", |
| +# "my_int_array_field": [ 1, 2, 3, 5, 7 ], |
| +# }, |
| +# "my_other_const_variable": { |
| +# ... |
| +# } |
| +# } |
| +# } |
| + |
| +import json |
| +from datetime import datetime |
| +import os.path |
| +import sys |
| +import optparse |
| +import copy |
| +_script_path = os.path.realpath(__file__) |
| +_old_path = copy.copy(sys.path) |
| + |
| +sys.path.insert(0, os.path.normpath(_script_path + "/../../")) |
| +try: |
| + import json_comment_eater |
| +finally: |
| + sys.path = _old_path |
|
not at google - send to devlin
2012/11/13 20:28:07
nit: rather than storing _old_path use sys.path.po
beaudoin
2012/11/13 21:42:04
/facepalm :)
Done.
|
| + |
| +import struct_generator |
| +import element_generator |
| + |
| +HEAD = """// Copyright %d 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. |
| + |
| +// GENERATED FROM THE SCHEMA DEFINITION AND DESCRIPTION IN |
| +// %s |
| +// %s |
| +// DO NOT EDIT. |
| + |
| +""" |
| + |
| +def _GenerateHeaderGuard(h_filename): |
| + """Generates the string used in #ifndef guarding the header file. |
| + """ |
| + return (('%s_' % h_filename) |
| + .upper().replace(os.sep, '_').replace('/', '_').replace('.', '_')) |
| + |
| +def _GenerateH(fileroot, head, namespace, schema, description): |
| + """Generates the .h file containing the definition of the structure specified |
| + by the schema. |
| + |
| + Args: |
| + fileroot: The filename and path of the file to create, without an extension. |
| + head: The string to output as the header of the .h file. |
| + namespace: A string corresponding to the C++ namespace to use. |
| + schema: A dict containing the schema. See comment at the top of this file. |
| + description: A dict containing the description. See comment at the top of |
| + this file. |
| + """ |
| + |
| + h_filename = fileroot + '.h' |
| + with open(h_filename, 'w') as f: |
| + f.write(head) |
| + header_guard = _GenerateHeaderGuard(h_filename) |
| + f.write('#ifndef %s\n' % header_guard) |
| + f.write('#define %s\n' % header_guard) |
| + f.write('\n') |
| + |
| + try: |
| + for header in schema['headers']: |
| + f.write('#include "%s"\n' % header) |
| + except KeyError: |
|
not at google - send to devlin
2012/11/13 20:28:07
use schema.get('headers', []) rather than keyerror
beaudoin
2012/11/13 21:42:04
Done.
|
| + pass |
| + f.write('\n') |
| + |
| + if namespace: |
| + f.write('namespace %s {\n' % namespace) |
| + f.write('\n') |
| + |
| + f.write(struct_generator.GenerateStruct( |
| + schema['type_name'], schema['schema'])) |
| + f.write('\n') |
| + |
| + try: |
| + for var_name, value in description['int_variables'].items(): |
| + f.write('extern const int %s;\n' % var_name) |
| + f.write('\n') |
| + except KeyError: |
|
not at google - send to devlin
2012/11/13 20:28:07
use description.get('int_variables', []) rather th
beaudoin
2012/11/13 21:42:04
Done.
|
| + pass |
| + |
| + for element_name, element in description['elements'].items(): |
| + f.write('extern const %s %s;\n' % (schema['type_name'], element_name)) |
| + |
| + if namespace: |
| + f.write('\n') |
| + f.write('} // namespace %s\n' % namespace) |
| + |
| + f.write('\n') |
| + f.write( '#endif // %s\n' % header_guard) |
| + |
| +def _GenerateCC(fileroot, head, namespace, schema, description): |
| + """Generates the .cc file containing the static initializers for the |
| + of the elements specified in the description. |
| + |
| + Args: |
| + fileroot: The filename and path of the file to create, without an extension. |
| + head: The string to output as the header of the .cc file. |
| + namespace: A string corresponding to the C++ namespace to use. |
| + schema: A dict containing the schema. See comment at the top of this file. |
| + description: A dict containing the description. See comment at the top of |
| + this file. |
| + """ |
| + with open(fileroot + '.cc', 'w') as f: |
| + f.write(head) |
| + |
| + f.write('#include <stdio.h>\n') |
| + f.write('\n') |
| + f.write('#include "%s"\n' % (fileroot + '.h')) |
| + f.write('\n') |
| + |
| + if namespace: |
| + f.write('namespace %s {\n' % namespace) |
| + f.write('\n') |
| + |
| + f.write(element_generator.GenerateElements(schema['type_name'], |
|
not at google - send to devlin
2012/11/13 20:28:07
This distinction between the "struct generator" an
beaudoin
2012/11/13 21:42:04
Following chat discussion: we'll keep it like this
|
| + schema['schema'], description)) |
| + |
| + if namespace: |
| + f.write('\n') |
| + f.write('} // namespace %s\n' % namespace) |
| + |
| +def _Load(filename): |
| + """Loads a JSON file int a Python object and return this object. |
| + """ |
| + # TODO(beaudoin): When moving to Python 2.7 use object_pairs_hook=OrderedDict. |
| + with open(filename, 'r') as handle: |
| + result = json.loads(json_comment_eater.Nom(handle.read())) |
| + return result |
| + |
| +if __name__ == '__main__': |
| + parser = optparse.OptionParser( |
| + description='Generates an C++ array of struct from a JSON description.', |
| + usage='usage: %prog [option] -s schema description') |
| + parser.add_option('-d', '--destdir', |
| + help='root directory to output generated files.') |
| + parser.add_option('-n', '--namespace', |
| + help='C++ namespace for generated files. e.g search_providers.') |
| + parser.add_option('-s', '--schema', help='path to the schema file, ' |
| + 'mandatory.') |
| + (opts, args) = parser.parse_args() |
| + |
| + if not opts.schema: |
| + parser.error('You must specify a --schema.') |
| + |
| + description_filename = os.path.normpath(args[0]) |
| + root, ext = os.path.splitext(description_filename) |
| + shortroot = os.path.split(root)[1] |
| + if opts.destdir: |
| + output_root = os.path.join(os.path.normpath(opts.destdir), shortroot) |
| + else: |
| + output_root = shortroot |
| + |
| + schema = _Load(opts.schema) |
| + description = _Load(description_filename) |
| + |
| + head = HEAD % (datetime.now().year, opts.schema, description_filename) |
| + _GenerateH(output_root, head, opts.namespace, schema, description) |
| + _GenerateCC(output_root, head, opts.namespace, schema, description) |