OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2013 The Chromium Authors. All rights reserved. | 2 # Copyright 2013 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 | 5 |
6 """The frontend for the Mojo bindings system.""" | 6 """The frontend for the Mojo bindings system.""" |
7 | 7 |
8 | 8 |
9 import argparse | 9 import argparse |
10 import imp | 10 import imp |
| 11 import json |
11 import os | 12 import os |
12 import pprint | 13 import pprint |
| 14 import re |
13 import sys | 15 import sys |
14 | 16 |
15 # Disable lint check for finding modules: | 17 # Disable lint check for finding modules: |
16 # pylint: disable=F0401 | 18 # pylint: disable=F0401 |
17 | 19 |
18 def _GetDirAbove(dirname): | 20 def _GetDirAbove(dirname): |
19 """Returns the directory "above" this file containing |dirname| (which must | 21 """Returns the directory "above" this file containing |dirname| (which must |
20 also be "above" this file).""" | 22 also be "above" this file).""" |
21 path = os.path.abspath(__file__) | 23 path = os.path.abspath(__file__) |
22 while True: | 24 while True: |
(...skipping 10 matching lines...) Expand all Loading... |
33 sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), | 35 sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), |
34 "pylib")) | 36 "pylib")) |
35 | 37 |
36 from mojom.error import Error | 38 from mojom.error import Error |
37 import mojom.fileutil as fileutil | 39 import mojom.fileutil as fileutil |
38 from mojom.generate.data import OrderedModuleFromData | 40 from mojom.generate.data import OrderedModuleFromData |
39 from mojom.parse.parser import Parse | 41 from mojom.parse.parser import Parse |
40 from mojom.parse.translate import Translate | 42 from mojom.parse.translate import Translate |
41 | 43 |
42 | 44 |
| 45 _BUILTIN_GENERATORS = { |
| 46 "c++": "mojom_cpp_generator.py", |
| 47 "javascript": "mojom_js_generator.py", |
| 48 "java": "mojom_java_generator.py", |
| 49 } |
| 50 |
43 def LoadGenerators(generators_string): | 51 def LoadGenerators(generators_string): |
44 if not generators_string: | 52 if not generators_string: |
45 return [] # No generators. | 53 return [] # No generators. |
46 | 54 |
47 script_dir = os.path.dirname(os.path.abspath(__file__)) | 55 script_dir = os.path.dirname(os.path.abspath(__file__)) |
48 generators = [] | 56 generators = {} |
49 for generator_name in [s.strip() for s in generators_string.split(",")]: | 57 for generator_name in [s.strip() for s in generators_string.split(",")]: |
50 # "Built-in" generators: | 58 language = generator_name.lower() |
51 if generator_name.lower() == "c++": | 59 if language in _BUILTIN_GENERATORS: |
52 generator_name = os.path.join(script_dir, "generators", | 60 generator_name = os.path.join(script_dir, "generators", |
53 "mojom_cpp_generator.py") | 61 _BUILTIN_GENERATORS[language]) |
54 elif generator_name.lower() == "javascript": | |
55 generator_name = os.path.join(script_dir, "generators", | |
56 "mojom_js_generator.py") | |
57 elif generator_name.lower() == "java": | |
58 generator_name = os.path.join(script_dir, "generators", | |
59 "mojom_java_generator.py") | |
60 # Specified generator python module: | |
61 elif generator_name.endswith(".py"): | |
62 pass | |
63 else: | 62 else: |
64 print "Unknown generator name %s" % generator_name | 63 print "Unknown generator name %s" % generator_name |
65 sys.exit(1) | 64 sys.exit(1) |
66 generator_module = imp.load_source(os.path.basename(generator_name)[:-3], | 65 generator_module = imp.load_source(os.path.basename(generator_name)[:-3], |
67 generator_name) | 66 generator_name) |
68 generators.append(generator_module) | 67 generators[language] = generator_module |
69 return generators | 68 return generators |
70 | 69 |
71 | 70 |
72 def MakeImportStackMessage(imported_filename_stack): | 71 def MakeImportStackMessage(imported_filename_stack): |
73 """Make a (human-readable) message listing a chain of imports. (Returned | 72 """Make a (human-readable) message listing a chain of imports. (Returned |
74 string begins with a newline (if nonempty) and does not end with one.)""" | 73 string begins with a newline (if nonempty) and does not end with one.)""" |
75 return ''.join( | 74 return ''.join( |
76 reversed(["\n %s was imported by %s" % (a, b) for (a, b) in \ | 75 reversed(["\n %s was imported by %s" % (a, b) for (a, b) in \ |
77 zip(imported_filename_stack[1:], imported_filename_stack)])) | 76 zip(imported_filename_stack[1:], imported_filename_stack)])) |
78 | 77 |
79 | 78 |
80 def FindImportFile(dir_name, file_name, search_dirs): | 79 def FindImportFile(dir_name, file_name, search_dirs): |
81 for search_dir in [dir_name] + search_dirs: | 80 for search_dir in [dir_name] + search_dirs: |
82 path = os.path.join(search_dir, file_name) | 81 path = os.path.join(search_dir, file_name) |
83 if os.path.isfile(path): | 82 if os.path.isfile(path): |
84 return path | 83 return path |
85 return os.path.join(dir_name, file_name) | 84 return os.path.join(dir_name, file_name) |
86 | 85 |
87 class MojomProcessor(object): | 86 class MojomProcessor(object): |
88 def __init__(self, should_generate): | 87 def __init__(self, should_generate): |
89 self._should_generate = should_generate | 88 self._should_generate = should_generate |
90 self._processed_files = {} | 89 self._processed_files = {} |
91 self._parsed_files = {} | 90 self._parsed_files = {} |
| 91 self._typemap = {} |
| 92 |
| 93 def LoadTypemaps(self, typemaps): |
| 94 # Support some very simple single-line comments in typemap JSON. |
| 95 comment_expr = r"^\s*//.*$" |
| 96 def no_comments(line): |
| 97 return not re.match(comment_expr, line) |
| 98 for filename in typemaps: |
| 99 with open(filename) as f: |
| 100 typemaps = json.loads("".join(filter(no_comments, f.readlines()))) |
| 101 for language, typemap in typemaps.iteritems(): |
| 102 language_map = self._typemap.get(language, {}) |
| 103 language_map.update(typemap) |
| 104 self._typemap[language] = language_map |
92 | 105 |
93 def ProcessFile(self, args, remaining_args, generator_modules, filename): | 106 def ProcessFile(self, args, remaining_args, generator_modules, filename): |
94 self._ParseFileAndImports(filename, args.import_directories, []) | 107 self._ParseFileAndImports(filename, args.import_directories, []) |
95 | 108 |
96 return self._GenerateModule(args, remaining_args, generator_modules, | 109 return self._GenerateModule(args, remaining_args, generator_modules, |
97 filename) | 110 filename) |
98 | 111 |
99 def _GenerateModule(self, args, remaining_args, generator_modules, filename): | 112 def _GenerateModule(self, args, remaining_args, generator_modules, filename): |
100 # Return the already-generated module. | 113 # Return the already-generated module. |
101 if filename in self._processed_files: | 114 if filename in self._processed_files: |
(...skipping 17 matching lines...) Expand all Loading... |
119 module = OrderedModuleFromData(mojom) | 132 module = OrderedModuleFromData(mojom) |
120 | 133 |
121 # Set the path as relative to the source root. | 134 # Set the path as relative to the source root. |
122 module.path = os.path.relpath(os.path.abspath(filename), | 135 module.path = os.path.relpath(os.path.abspath(filename), |
123 os.path.abspath(args.depth)) | 136 os.path.abspath(args.depth)) |
124 | 137 |
125 # Normalize to unix-style path here to keep the generators simpler. | 138 # Normalize to unix-style path here to keep the generators simpler. |
126 module.path = module.path.replace('\\', '/') | 139 module.path = module.path.replace('\\', '/') |
127 | 140 |
128 if self._should_generate(filename): | 141 if self._should_generate(filename): |
129 for generator_module in generator_modules: | 142 for language, generator_module in generator_modules.iteritems(): |
130 generator = generator_module.Generator(module, args.output_dir) | 143 generator = generator_module.Generator( |
| 144 module, args.output_dir, typemap=self._typemap.get(language, {}), |
| 145 variant=args.variant) |
131 filtered_args = [] | 146 filtered_args = [] |
132 if hasattr(generator_module, 'GENERATOR_PREFIX'): | 147 if hasattr(generator_module, 'GENERATOR_PREFIX'): |
133 prefix = '--' + generator_module.GENERATOR_PREFIX + '_' | 148 prefix = '--' + generator_module.GENERATOR_PREFIX + '_' |
134 filtered_args = [arg for arg in remaining_args | 149 filtered_args = [arg for arg in remaining_args |
135 if arg.startswith(prefix)] | 150 if arg.startswith(prefix)] |
136 generator.GenerateFiles(filtered_args) | 151 generator.GenerateFiles(filtered_args) |
137 | 152 |
138 # Save result. | 153 # Save result. |
139 self._processed_files[filename] = module | 154 self._processed_files[filename] = module |
140 return module | 155 return module |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 metavar="GENERATORS", | 203 metavar="GENERATORS", |
189 default="c++,javascript,java", | 204 default="c++,javascript,java", |
190 help="comma-separated list of generators") | 205 help="comma-separated list of generators") |
191 parser.add_argument("--debug_print_intermediate", action="store_true", | 206 parser.add_argument("--debug_print_intermediate", action="store_true", |
192 help="print the intermediate representation") | 207 help="print the intermediate representation") |
193 parser.add_argument("-I", dest="import_directories", action="append", | 208 parser.add_argument("-I", dest="import_directories", action="append", |
194 metavar="directory", default=[], | 209 metavar="directory", default=[], |
195 help="add a directory to be searched for import files") | 210 help="add a directory to be searched for import files") |
196 parser.add_argument("--use_bundled_pylibs", action="store_true", | 211 parser.add_argument("--use_bundled_pylibs", action="store_true", |
197 help="use Python modules bundled in the SDK") | 212 help="use Python modules bundled in the SDK") |
| 213 parser.add_argument("--typemap", action="append", metavar="TYPEMAP", |
| 214 default=[], dest="typemaps", |
| 215 help="apply TYPEMAP to generated output") |
| 216 parser.add_argument("--variant", dest="variant", default=None, |
| 217 help="output a named variant of the bindings") |
198 (args, remaining_args) = parser.parse_known_args() | 218 (args, remaining_args) = parser.parse_known_args() |
199 | 219 |
| 220 if args.variant == "none": |
| 221 args.variant = None |
| 222 |
200 generator_modules = LoadGenerators(args.generators_string) | 223 generator_modules = LoadGenerators(args.generators_string) |
201 | 224 |
202 fileutil.EnsureDirectoryExists(args.output_dir) | 225 fileutil.EnsureDirectoryExists(args.output_dir) |
203 | 226 |
204 processor = MojomProcessor(lambda filename: filename in args.filename) | 227 processor = MojomProcessor(lambda filename: filename in args.filename) |
| 228 processor.LoadTypemaps(set(args.typemaps)) |
205 for filename in args.filename: | 229 for filename in args.filename: |
206 processor.ProcessFile(args, remaining_args, generator_modules, filename) | 230 processor.ProcessFile(args, remaining_args, generator_modules, filename) |
207 | 231 |
208 return 0 | 232 return 0 |
209 | 233 |
210 | 234 |
211 if __name__ == "__main__": | 235 if __name__ == "__main__": |
212 sys.exit(main()) | 236 sys.exit(main()) |
OLD | NEW |