builtins directory causes name conflict on Python 3
[WebKit-https.git] / Source / JavaScriptCore / Scripts / generate-js-builtins.py
1 #!/usr/bin/env python
2 #
3 # Copyright (c) 2014, 2015 Apple Inc. All rights reserved.
4 # Copyright (c) 2014 University of Washington. All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 # 1. Redistributions of source code must retain the above copyright
10 #    notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 #    notice, this list of conditions and the following disclaimer in the
13 #    documentation and/or other materials provided with the distribution.
14 #
15 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
16 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
19 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25 # THE POSSIBILITY OF SUCH DAMAGE.
26
27 # This script generates C++ bindings for JavaScript builtins.
28 # Generators for individual files are located in the builtins/ directory.
29
30 import fnmatch
31 import logging
32 import optparse
33 import os
34
35 logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.ERROR)
36 log = logging.getLogger('global')
37
38 from lazywriter import LazyFileWriter
39
40 from wkbuiltins import *
41
42
43 def concatenated_output_filename(builtins_files, framework_name, generate_only_wrapper_files):
44     if generate_only_wrapper_files:
45         return framework_name + 'JSBuiltins.h-result'
46     return os.path.basename(builtins_files[0]) + '-result'
47
48
49 def generate_bindings_for_builtins_files(builtins_files=[],
50                                          output_path=None,
51                                          concatenate_output=False,
52                                          combined_output=False,
53                                          generate_only_wrapper_files=False,
54                                          framework_name="",
55                                          force_output=False):
56
57     generators = []
58
59     model = BuiltinsCollection(framework_name=framework_name)
60
61     for filepath in builtins_files:
62         with open(filepath, "r") as file:
63             file_text = file.read()
64             file_name = os.path.basename(filepath)
65
66             # If this is a test file, then rewrite the filename to remove the
67             # test running options encoded into the filename.
68             if file_name.startswith(framework_name):
69                 (_, object_name, _) = file_name.split('-')
70                 file_name = object_name + '.js'
71             model.parse_builtins_file(file_name, file_text)
72
73     if combined_output:
74         log.debug("Using generator style: combined files for all builtins.")
75         generators.append(BuiltinsCombinedHeaderGenerator(model))
76         generators.append(BuiltinsCombinedImplementationGenerator(model))
77     else:
78         log.debug("Using generator style: single files for each builtin.")
79         if generate_only_wrapper_files:
80             generators.append(BuiltinsWrapperHeaderGenerator(model))
81             generators.append(BuiltinsWrapperImplementationGenerator(model))
82
83             generators.append(BuiltinsInternalsWrapperHeaderGenerator(model))
84             generators.append(BuiltinsInternalsWrapperImplementationGenerator(model))
85         else:
86             for object in model.objects:
87                 generators.append(BuiltinsSeparateHeaderGenerator(model, object))
88                 generators.append(BuiltinsSeparateImplementationGenerator(model, object))
89
90     log.debug("")
91     log.debug("Generating bindings for builtins.")
92
93     test_result_file_contents = []
94
95     for generator in generators:
96         output_filepath = os.path.join(output_path, generator.output_filename())
97         log.debug("Generating output file: %s" % generator.output_filename())
98         output = generator.generate_output()
99
100         log.debug("---")
101         log.debug("\n" + output)
102         log.debug("---")
103         if concatenate_output:
104             test_result_file_contents.append('### Begin File: %s' % generator.output_filename())
105             test_result_file_contents.append(output)
106             test_result_file_contents.append('### End File: %s' % generator.output_filename())
107             test_result_file_contents.append('')
108         else:
109             log.debug("Writing file: %s" % output_filepath)
110             output_file = LazyFileWriter(output_filepath, force_output)
111             output_file.write(output)
112             output_file.close()
113
114     if concatenate_output:
115         filename = concatenated_output_filename(builtins_files, framework_name, generate_only_wrapper_files)
116         output_filepath = os.path.join(output_path, filename)
117         log.debug("Writing file: %s" % output_filepath)
118         output_file = LazyFileWriter(output_filepath, force_output)
119         output_file.write('\n'.join(test_result_file_contents))
120         output_file.close()
121
122 if __name__ == '__main__':
123     allowed_framework_names = ['JavaScriptCore', 'WebCore']
124     cli_parser = optparse.OptionParser(usage="usage: %prog [options] Builtin1.js [, Builtin2.js, ...]")
125     cli_parser.add_option("-i", "--input-directory", help="If specified, generates builtins from all JavaScript files in the specified directory in addition to specific files passed as arguments.")
126     cli_parser.add_option("-o", "--output-directory", help="Directory where generated files should be written.")
127     cli_parser.add_option("--framework", type="choice", choices=allowed_framework_names, help="Destination framework for generated files.")
128     cli_parser.add_option("--force", action="store_true", help="Force output of generated scripts, even if nothing changed.")
129     cli_parser.add_option("--combined", action="store_true", help="Produce one .h/.cpp file instead of producing one per builtin object.")
130     cli_parser.add_option("--wrappers-only", action="store_true", help="Produce .h/.cpp wrapper files to ease integration of the builtins.")
131     cli_parser.add_option("-v", "--debug", action="store_true", help="Log extra output for debugging the generator itself.")
132     cli_parser.add_option("-t", "--test", action="store_true", help="Enable test mode.")
133
134     arg_options, arg_values = cli_parser.parse_args()
135     if len(arg_values) is 0 and not arg_options.input_directory:
136         raise ParseException("At least one input file or directory expected.")
137
138     if not arg_options.output_directory:
139         raise ParseException("Missing output directory.")
140
141     if arg_options.debug:
142         log.setLevel(logging.DEBUG)
143
144     input_filepaths = arg_values[:]
145     if arg_options.input_directory:
146         for filepath in os.listdir(arg_options.input_directory):
147             input_filepaths.append(os.path.join(arg_options.input_directory, filepath))
148
149     input_filepaths = sorted(filter(lambda name: fnmatch.fnmatch(name, '*.js'), input_filepaths))
150
151     options = {
152         'output_path': arg_options.output_directory,
153         'framework_name': arg_options.framework,
154         'combined_output': arg_options.combined,
155         'generate_only_wrapper_files': arg_options.wrappers_only,
156         'force_output': arg_options.force,
157         'concatenate_output': arg_options.test,
158     }
159
160     log.debug("Generating code for builtins.")
161     log.debug("Parsed options:")
162     for option, value in options.items():
163         log.debug("    %s: %s" % (option, value))
164     log.debug("")
165     log.debug("Input files:")
166     for filepath in input_filepaths:
167         log.debug("    %s" % filepath)
168     log.debug("")
169
170     try:
171         generate_bindings_for_builtins_files(builtins_files=input_filepaths, **options)
172     except ParseException as e:
173         if arg_options.test:
174             log.error(e.message)
175         else:
176             raise  # Force the build to fail.