| 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 elif generator_name.endswith(".py"): |
| 62 pass | 63 pass |
| 63 else: | 64 else: |
| 64 print "Unknown generator name %s" % generator_name | 65 print "Unknown generator name %s" % generator_name |
| 65 sys.exit(1) | 66 sys.exit(1) |
| 66 generator_module = imp.load_source(os.path.basename(generator_name)[:-3], | 67 generator_module = imp.load_source(os.path.basename(generator_name)[:-3], |
| 67 generator_name) | 68 generator_name) |
| 68 generators.append(generator_module) | 69 generators[language] = generator_module |
| 69 return generators | 70 return generators |
| 70 | 71 |
| 71 | 72 |
| 72 def MakeImportStackMessage(imported_filename_stack): | 73 def MakeImportStackMessage(imported_filename_stack): |
| 73 """Make a (human-readable) message listing a chain of imports. (Returned | 74 """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.)""" | 75 string begins with a newline (if nonempty) and does not end with one.)""" |
| 75 return ''.join( | 76 return ''.join( |
| 76 reversed(["\n %s was imported by %s" % (a, b) for (a, b) in \ | 77 reversed(["\n %s was imported by %s" % (a, b) for (a, b) in \ |
| 77 zip(imported_filename_stack[1:], imported_filename_stack)])) | 78 zip(imported_filename_stack[1:], imported_filename_stack)])) |
| 78 | 79 |
| 79 | 80 |
| 80 def FindImportFile(dir_name, file_name, search_dirs): | 81 def FindImportFile(dir_name, file_name, search_dirs): |
| 81 for search_dir in [dir_name] + search_dirs: | 82 for search_dir in [dir_name] + search_dirs: |
| 82 path = os.path.join(search_dir, file_name) | 83 path = os.path.join(search_dir, file_name) |
| 83 if os.path.isfile(path): | 84 if os.path.isfile(path): |
| 84 return path | 85 return path |
| 85 return os.path.join(dir_name, file_name) | 86 return os.path.join(dir_name, file_name) |
| 86 | 87 |
| 87 class MojomProcessor(object): | 88 class MojomProcessor(object): |
| 88 def __init__(self, should_generate): | 89 def __init__(self, should_generate): |
| 89 self._should_generate = should_generate | 90 self._should_generate = should_generate |
| 90 self._processed_files = {} | 91 self._processed_files = {} |
| 91 self._parsed_files = {} | 92 self._parsed_files = {} |
| 93 self._typemap = {} |
| 94 |
| 95 def LoadTypemaps(self, typemaps): |
| 96 # Support some very simple single-line comments in typemap JSON. |
| 97 comment_expr = r"^\s*//.*$" |
| 98 def no_comments(line): |
| 99 return not re.match(comment_expr, line) |
| 100 for filename in typemaps: |
| 101 with open(filename) as f: |
| 102 typemaps = json.loads("".join(filter(no_comments, f.readlines()))) |
| 103 for language, typemap in typemaps.iteritems(): |
| 104 language_map = self._typemap.get(language, {}) |
| 105 language_map.update(typemap) |
| 106 self._typemap[language] = language_map |
| 92 | 107 |
| 93 def ProcessFile(self, args, remaining_args, generator_modules, filename): | 108 def ProcessFile(self, args, remaining_args, generator_modules, filename): |
| 94 self._ParseFileAndImports(filename, args.import_directories, []) | 109 self._ParseFileAndImports(filename, args.import_directories, []) |
| 95 | 110 |
| 96 return self._GenerateModule(args, remaining_args, generator_modules, | 111 return self._GenerateModule(args, remaining_args, generator_modules, |
| 97 filename) | 112 filename) |
| 98 | 113 |
| 99 def _GenerateModule(self, args, remaining_args, generator_modules, filename): | 114 def _GenerateModule(self, args, remaining_args, generator_modules, filename): |
| 100 # Return the already-generated module. | 115 # Return the already-generated module. |
| 101 if filename in self._processed_files: | 116 if filename in self._processed_files: |
| (...skipping 17 matching lines...) Expand all Loading... |
| 119 module = OrderedModuleFromData(mojom) | 134 module = OrderedModuleFromData(mojom) |
| 120 | 135 |
| 121 # Set the path as relative to the source root. | 136 # Set the path as relative to the source root. |
| 122 module.path = os.path.relpath(os.path.abspath(filename), | 137 module.path = os.path.relpath(os.path.abspath(filename), |
| 123 os.path.abspath(args.depth)) | 138 os.path.abspath(args.depth)) |
| 124 | 139 |
| 125 # Normalize to unix-style path here to keep the generators simpler. | 140 # Normalize to unix-style path here to keep the generators simpler. |
| 126 module.path = module.path.replace('\\', '/') | 141 module.path = module.path.replace('\\', '/') |
| 127 | 142 |
| 128 if self._should_generate(filename): | 143 if self._should_generate(filename): |
| 129 for generator_module in generator_modules: | 144 for language, generator_module in generator_modules.iteritems(): |
| 130 generator = generator_module.Generator(module, args.output_dir) | 145 generator = generator_module.Generator( |
| 146 module, args.output_dir, typemap=self._typemap.get(language, {}), |
| 147 variant=args.variant) |
| 131 filtered_args = [] | 148 filtered_args = [] |
| 132 if hasattr(generator_module, 'GENERATOR_PREFIX'): | 149 if hasattr(generator_module, 'GENERATOR_PREFIX'): |
| 133 prefix = '--' + generator_module.GENERATOR_PREFIX + '_' | 150 prefix = '--' + generator_module.GENERATOR_PREFIX + '_' |
| 134 filtered_args = [arg for arg in remaining_args | 151 filtered_args = [arg for arg in remaining_args |
| 135 if arg.startswith(prefix)] | 152 if arg.startswith(prefix)] |
| 136 generator.GenerateFiles(filtered_args) | 153 generator.GenerateFiles(filtered_args) |
| 137 | 154 |
| 138 # Save result. | 155 # Save result. |
| 139 self._processed_files[filename] = module | 156 self._processed_files[filename] = module |
| 140 return module | 157 return module |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 metavar="GENERATORS", | 205 metavar="GENERATORS", |
| 189 default="c++,javascript,java", | 206 default="c++,javascript,java", |
| 190 help="comma-separated list of generators") | 207 help="comma-separated list of generators") |
| 191 parser.add_argument("--debug_print_intermediate", action="store_true", | 208 parser.add_argument("--debug_print_intermediate", action="store_true", |
| 192 help="print the intermediate representation") | 209 help="print the intermediate representation") |
| 193 parser.add_argument("-I", dest="import_directories", action="append", | 210 parser.add_argument("-I", dest="import_directories", action="append", |
| 194 metavar="directory", default=[], | 211 metavar="directory", default=[], |
| 195 help="add a directory to be searched for import files") | 212 help="add a directory to be searched for import files") |
| 196 parser.add_argument("--use_bundled_pylibs", action="store_true", | 213 parser.add_argument("--use_bundled_pylibs", action="store_true", |
| 197 help="use Python modules bundled in the SDK") | 214 help="use Python modules bundled in the SDK") |
| 215 parser.add_argument("--typemap", action="append", metavar="TYPEMAP", |
| 216 default=[], dest="typemaps", |
| 217 help="apply TYPEMAP to generated output") |
| 218 parser.add_argument("--variant", dest="variant", default=None, |
| 219 help="output a named variant of the bindings") |
| 198 (args, remaining_args) = parser.parse_known_args() | 220 (args, remaining_args) = parser.parse_known_args() |
| 199 | 221 |
| 200 generator_modules = LoadGenerators(args.generators_string) | 222 generator_modules = LoadGenerators(args.generators_string) |
| 201 | 223 |
| 202 fileutil.EnsureDirectoryExists(args.output_dir) | 224 fileutil.EnsureDirectoryExists(args.output_dir) |
| 203 | 225 |
| 204 processor = MojomProcessor(lambda filename: filename in args.filename) | 226 processor = MojomProcessor(lambda filename: filename in args.filename) |
| 227 processor.LoadTypemaps(set(args.typemaps)) |
| 205 for filename in args.filename: | 228 for filename in args.filename: |
| 206 processor.ProcessFile(args, remaining_args, generator_modules, filename) | 229 processor.ProcessFile(args, remaining_args, generator_modules, filename) |
| 207 | 230 |
| 208 return 0 | 231 return 0 |
| 209 | 232 |
| 210 | 233 |
| 211 if __name__ == "__main__": | 234 if __name__ == "__main__": |
| 212 sys.exit(main()) | 235 sys.exit(main()) |
| OLD | NEW |