Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(228)

Side by Side Diff: tools/json_schema_compiler/compiler.py

Issue 12041098: Initial commit of the Dart Chrome Extension APIs generators (Closed) Base URL: http://git.chromium.org/chromium/src.git@file_path_bugfix
Patch Set: Cleaned up dart_generator, and added wrappers for callbacks Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 """Generator for C++ structs from api json files. 5 """Generator for C++ structs from api json files.
6 6
7 The purpose of this tool is to remove the need for hand-written code that 7 The purpose of this tool is to remove the need for hand-written code that
8 converts to and from base::Value types when receiving javascript api calls. 8 converts to and from base::Value types when receiving javascript api calls.
9 Originally written for generating code for extension apis. Reference schemas 9 Originally written for generating code for extension apis. Reference schemas
10 are in chrome/common/extensions/api. 10 are in chrome/common/extensions/api.
11 11
12 Usage example: 12 Usage example:
13 compiler.py --root /home/Work/src --namespace extensions windows.json 13 compiler.py --root /home/Work/src --namespace extensions windows.json
14 tabs.json 14 tabs.json
15 compiler.py --destdir gen --root /home/Work/src 15 compiler.py --destdir gen --root /home/Work/src
16 --namespace extensions windows.json tabs.json 16 --namespace extensions windows.json tabs.json
17 """ 17 """
18 18
19 import cc_generator 19 import cc_generator
20 import cpp_type_generator 20 import cpp_type_generator
21 import h_generator 21 import h_generator
22 import dart_generator
22 import idl_schema 23 import idl_schema
23 import json_schema 24 import json_schema
24 import model 25 import model
25 import schema_bundle_generator 26 import schema_bundle_generator
26 27
27 import optparse 28 import optparse
28 import os.path 29 import os.path
29 import sys 30 import sys
30 31
32 # List of supported languages to build; first is default.
33 SUPPORTED_LANGS = ['c++', 'dart']
34
35 # For each language, the corresponding "ignore string" to remove that node from
36 # the returned namespace.
37 NODE_IGNORE_STR = {
38 'c++': 'nocompile',
39 }
40
31 def load_schema(schema): 41 def load_schema(schema):
32 schema_filename, schema_extension = os.path.splitext(schema) 42 schema_filename, schema_extension = os.path.splitext(schema)
33 43
34 if schema_extension == '.json': 44 if schema_extension == '.json':
35 api_defs = json_schema.Load(schema) 45 api_defs = json_schema.Load(schema)
36 elif schema_extension == '.idl': 46 elif schema_extension == '.idl':
37 api_defs = idl_schema.Load(schema) 47 api_defs = idl_schema.Load(schema)
38 else: 48 else:
39 sys.exit("Did not recognize file extension %s for schema %s" % 49 sys.exit('Did not recognize file extension %s for schema %s' %
40 (schema_extension, schema)) 50 (schema_extension, schema))
41 if len(api_defs) != 1: 51 if len(api_defs) != 1:
42 sys.exit("File %s has multiple schemas. Files are only allowed to contain a" 52 sys.exit('File %s has multiple schemas. Files are only allowed to contain a'
43 " single schema." % schema) 53 ' single schema.' % schema)
44 54
45 return api_defs 55 return api_defs
46 56
47 def handle_single_schema(filename, dest_dir, root, root_namespace): 57 def handle_single_schema(filename, dest_dir, root, root_namespace, lang,
58 dart_overrides_dir):
48 schema = os.path.normpath(filename) 59 schema = os.path.normpath(filename)
49 schema_filename, schema_extension = os.path.splitext(schema) 60 schema_filename, schema_extension = os.path.splitext(schema)
50 path, short_filename = os.path.split(schema_filename) 61 path, short_filename = os.path.split(schema_filename)
51 api_defs = json_schema.DeleteNocompileNodes(load_schema(schema)) 62 api_defs = load_schema(schema)
63 if lang in NODE_IGNORE_STR:
64 api_defs = json_schema.DeleteNodes(api_defs, NODE_IGNORE_STR[lang])
52 65
53 api_model = model.Model() 66 api_model = model.Model()
54 67
55 for target_namespace in api_defs: 68 for target_namespace in api_defs:
56 referenced_schemas = target_namespace.get('dependencies', []) 69 referenced_schemas = target_namespace.get('dependencies', [])
57 # Load type dependencies into the model. 70 # Load type dependencies into the model.
58 # TODO(miket): do we need this in IDL? 71 # TODO(miket): do we need this in IDL?
59 for referenced_schema in referenced_schemas: 72 for referenced_schema in referenced_schemas:
60 split_schema = referenced_schema.split(':', 1) 73 split_schema = referenced_schema.split(':', 1)
61 if len(split_schema) > 1: 74 if len(split_schema) > 1:
(...skipping 14 matching lines...) Expand all
76 # Gets the relative path from opts.root to the schema to correctly determine 89 # Gets the relative path from opts.root to the schema to correctly determine
77 # the include path. 90 # the include path.
78 relpath = os.path.relpath(schema, opts.root) 91 relpath = os.path.relpath(schema, opts.root)
79 namespace = api_model.AddNamespace(target_namespace, 92 namespace = api_model.AddNamespace(target_namespace,
80 relpath, 93 relpath,
81 include_compiler_options=True) 94 include_compiler_options=True)
82 if not namespace: 95 if not namespace:
83 continue 96 continue
84 97
85 if short_filename != namespace.unix_name: 98 if short_filename != namespace.unix_name:
86 sys.exit("Filename %s is illegal. Name files using unix_hacker style." % 99 sys.exit('Filename %s is illegal. Name files using unix_hacker style.' %
87 filename) 100 filename)
88 101
89 # The output filename must match the input filename for gyp to deal with it 102 # The output filename must match the input filename for gyp to deal with it
90 # properly. 103 # properly.
91 out_file = namespace.unix_name 104 out_file = namespace.unix_name
92 type_generator = cpp_type_generator.CppTypeGenerator(
93 root_namespace, namespace, namespace.unix_name)
94 for referenced_namespace in api_model.namespaces.values():
95 if referenced_namespace == namespace:
96 continue
97 type_generator.AddNamespace(
98 referenced_namespace,
99 referenced_namespace.unix_name)
100 105
101 h_code = (h_generator.HGenerator(namespace, type_generator) 106 if lang.lower() == 'c++':
102 .Generate().Render()) 107 type_generator = cpp_type_generator.CppTypeGenerator(
103 cc_code = (cc_generator.CCGenerator(namespace, type_generator) 108 root_namespace, namespace, namespace.unix_name)
104 .Generate().Render()) 109 for referenced_namespace in api_model.namespaces.values():
110 if referenced_namespace == namespace:
111 continue
112 type_generator.AddNamespace(
113 referenced_namespace,
114 referenced_namespace.unix_name)
105 115
106 if dest_dir: 116 h_code = (h_generator.HGenerator(namespace, type_generator)
107 with open( 117 .Generate().Render())
108 os.path.join(dest_dir, namespace.source_file_dir, out_file + '.cc'), 118 cc_code = (cc_generator.CCGenerator(namespace, type_generator)
109 'w') as cc_file: 119 .Generate().Render())
110 cc_file.write(cc_code) 120
111 with open( 121 if dest_dir:
112 os.path.join(dest_dir, namespace.source_file_dir, out_file + '.h'), 122 with open(
113 'w') as h_file: 123 os.path.join(dest_dir, namespace.source_file_dir, out_file + '.cc'),
114 h_file.write(h_code) 124 'w') as cc_file:
125 cc_file.write(cc_code)
126 with open(
127 os.path.join(dest_dir, namespace.source_file_dir, out_file + '.h'),
128 'w') as h_file:
129 h_file.write(h_code)
130 else:
131 print '%s.h' % out_file
132 print
133 print h_code
134 print
135 print '%s.cc' % out_file
136 print
137 print cc_code
138
139 elif lang.lower() == 'dart':
140 dart_code = (dart_generator.DartGenerator(namespace, dart_overrides_dir)
141 .Generate().Render())
142
143 if dest_dir:
144 with open(os.path.join(dest_dir, out_file + '.dart'), 'w') as dart_file:
145 dart_file.write(dart_code)
146 else:
147 print '%s.dart' % out_file
148 print
149 print dart_code
150
115 else: 151 else:
116 print '%s.h' % out_file 152 raise Exception('Unrecognised language %s. Supported languages are %s.' %
117 print 153 (lang, SUPPORTED_LANGS))
118 print h_code
119 print
120 print '%s.cc' % out_file
121 print
122 print cc_code
123 154
124 def handle_bundle_schema(filenames, dest_dir, root, root_namespace): 155 def handle_bundle_schema(filenames, dest_dir, root, root_namespace, lang):
125 # Merge the source files into a single list of schemas. 156 # Merge the source files into a single list of schemas.
126 api_defs = [] 157 api_defs = []
127 for filename in filenames: 158 for filename in filenames:
128 schema = os.path.normpath(filename) 159 schema = os.path.normpath(filename)
129 schema_filename, schema_extension = os.path.splitext(schema) 160 schema_filename, schema_extension = os.path.splitext(schema)
130 api_defs.extend(load_schema(schema)) 161 api_defs.extend(load_schema(schema))
131 162
132 api_model = model.Model() 163 api_model = model.Model()
133 relpath = os.path.relpath(os.path.normpath(filenames[0]), root) 164 relpath = os.path.relpath(os.path.normpath(filenames[0]), root)
134 165
135 for target_namespace, schema_filename in zip(api_defs, filenames): 166 for target_namespace, schema_filename in zip(api_defs, filenames):
136 namespace = api_model.AddNamespace(target_namespace, 167 namespace = api_model.AddNamespace(target_namespace,
137 relpath, 168 relpath,
138 include_compiler_options=True) 169 include_compiler_options=True)
139 path, filename = os.path.split(schema_filename) 170 path, filename = os.path.split(schema_filename)
140 short_filename, extension = os.path.splitext(filename) 171 short_filename, extension = os.path.splitext(filename)
141 172
142 # Filenames are checked against the unix_names of the namespaces they 173 # Filenames are checked against the unix_names of the namespaces they
143 # generate because the gyp uses the names of the JSON files to generate 174 # generate because the gyp uses the names of the JSON files to generate
144 # the names of the .cc and .h files. We want these to be using unix_names. 175 # the names of the .cc and .h files. We want these to be using unix_names.
145 if namespace.unix_name != short_filename: 176 if namespace.unix_name != short_filename:
146 sys.exit("Filename %s is illegal. Name files using unix_hacker style." % 177 sys.exit('Filename %s is illegal. Name files using unix_hacker style.' %
147 schema_filename) 178 schema_filename)
148 179
149 type_generator = cpp_type_generator.CppTypeGenerator(root_namespace) 180 if lang == 'c++':
150 for referenced_namespace in api_model.namespaces.values(): 181 type_generator = cpp_type_generator.CppTypeGenerator(root_namespace)
151 type_generator.AddNamespace( 182 for referenced_namespace in api_model.namespaces.values():
152 referenced_namespace, 183 type_generator.AddNamespace(
153 referenced_namespace.unix_name) 184 referenced_namespace,
185 referenced_namespace.unix_name)
154 186
155 generator = schema_bundle_generator.SchemaBundleGenerator( 187 generator = schema_bundle_generator.SchemaBundleGenerator(
156 root, api_model, api_defs, type_generator) 188 root, api_model, api_defs, type_generator)
157 api_h_code = generator.GenerateAPIHeader().Render() 189 api_h_code = generator.GenerateAPIHeader().Render()
158 schemas_h_code = generator.GenerateSchemasHeader().Render() 190 schemas_h_code = generator.GenerateSchemasHeader().Render()
159 schemas_cc_code = generator.GenerateSchemasCC().Render() 191 schemas_cc_code = generator.GenerateSchemasCC().Render()
160 192
161 if dest_dir: 193 if dest_dir:
162 basedir = os.path.join(dest_dir, 'chrome/common/extensions/api') 194 basedir = os.path.join(dest_dir, 'chrome/common/extensions/api')
163 with open(os.path.join(basedir, 'generated_api.h'), 'w') as h_file: 195 with open(os.path.join(basedir, 'generated_api.h'), 'w') as h_file:
164 h_file.write(api_h_code) 196 h_file.write(api_h_code)
165 with open(os.path.join(basedir, 'generated_schemas.h'), 'w') as h_file: 197 with open(os.path.join(basedir, 'generated_schemas.h'), 'w') as h_file:
166 h_file.write(schemas_h_code) 198 h_file.write(schemas_h_code)
167 with open(os.path.join(basedir, 'generated_schemas.cc'), 'w') as cc_file: 199 with open(os.path.join(basedir, 'generated_schemas.cc'), 'w') as cc_file:
168 cc_file.write(schemas_cc_code) 200 cc_file.write(schemas_cc_code)
201 else:
202 print 'generated_api.h'
203 print
204 print api_h_code
205 print
206 print 'generated_schemas.h'
207 print
208 print schemas_h_code
209 print
210 print 'generated_schemas.cc'
211 print
212 print schemas_cc_code
213
214 elif lang == 'dart':
215 raise Exception('Dart is not supported in bundle mode.')
216
169 else: 217 else:
170 print 'generated_api.h' 218 raise Exception("Unrecognised language %s. Supported languages are %s." %
171 print 219 (lang, SUPPORTED_LANG))
172 print api_h_code
173 print
174 print 'generated_schemas.h'
175 print
176 print schemas_h_code
177 print
178 print 'generated_schemas.cc'
179 print
180 print schemas_cc_code
181 220
182 if __name__ == '__main__': 221 if __name__ == '__main__':
183 parser = optparse.OptionParser( 222 parser = optparse.OptionParser(
184 description='Generates a C++ model of an API from JSON schema', 223 description='Generates a C++ model of an API from JSON schema',
185 usage='usage: %prog [option]... schema') 224 usage='usage: %prog [option]... schema')
186 parser.add_option('-r', '--root', default='.', 225 parser.add_option('-r', '--root', default='.',
187 help='logical include root directory. Path to schema files from specified' 226 help='logical include root directory. Path to schema files from specified'
188 'dir will be the include path.') 227 'dir will be the include path.')
189 parser.add_option('-d', '--destdir', 228 parser.add_option('-d', '--destdir',
190 help='root directory to output generated files.') 229 help='root directory to output generated files.')
191 parser.add_option('-n', '--namespace', default='generated_api_schemas', 230 parser.add_option('-n', '--namespace', default='generated_api_schemas',
192 help='C++ namespace for generated files. e.g extensions::api.') 231 help='C++ namespace for generated files. e.g extensions::api.')
193 parser.add_option('-b', '--bundle', action="store_true", help= 232 parser.add_option('-b', '--bundle', action='store_true', help=
194 '''if supplied, causes compiler to generate bundle files for the given set of 233 '''if supplied, causes compiler to generate bundle files for the given set of
195 source files.''') 234 source files.''')
235 parser.add_option('-l', '--lang', default=SUPPORTED_LANGS[0],
236 help=
237 '''The language to generate the output in. Currently supported options are
238 %s.''' % SUPPORTED_LANGS)
239 parser.add_option('-D', '--custom-dart-folder', dest='dart_overrides_dir',
240 help='Adds custom dart from files in the given folder (Dart only).')
196 241
197 (opts, args) = parser.parse_args() 242 (opts, args) = parser.parse_args()
198 243
199 if not args: 244 if not args:
200 sys.exit(0) # This is OK as a no-op 245 sys.exit(0) # This is OK as a no-op
201 dest_dir = opts.destdir 246 dest_dir = opts.destdir
202 root_namespace = opts.namespace 247 root_namespace = opts.namespace
203 248
204 if opts.bundle: 249 if opts.bundle:
205 handle_bundle_schema(args, dest_dir, opts.root, root_namespace) 250 handle_bundle_schema(args, dest_dir, opts.root, root_namespace, opts.lang)
206 else: 251 else:
207 handle_single_schema(args[0], dest_dir, opts.root, root_namespace) 252 handle_single_schema(args[0], dest_dir, opts.root, root_namespace,
253 opts.lang, opts.dart_overrides_dir)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698