]> git.saurik.com Git - apple/javascriptcore.git/blame - inspector/scripts/generate-inspector-protocol-bindings.py
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / inspector / scripts / generate-inspector-protocol-bindings.py
CommitLineData
ed1e77d3
A
1#!/usr/bin/env python
2#
3# Copyright (c) 2014 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 JS, Objective C, and C++ bindings for the inspector protocol.
28# Generators for individual files are located in the codegen/ directory.
29
30import os.path
31import re
32import sys
33import string
34from string import Template
35import optparse
36import logging
37
38try:
39 import json
40except ImportError:
41 import simplejson as json
42
43logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.ERROR)
44log = logging.getLogger('global')
45
46try:
47 from codegen import *
48
49# When copying generator files to JavaScriptCore's private headers on Mac,
50# the codegen/ module directory is flattened. So, import directly.
51except ImportError, e:
52 # log.error(e) # Uncomment this to debug early import errors.
53 import models
54 from models import *
55 from generator import *
56 from cpp_generator import *
57 from objc_generator import *
58
59 from generate_cpp_alternate_backend_dispatcher_header import *
60 from generate_cpp_backend_dispatcher_header import *
61 from generate_cpp_backend_dispatcher_implementation import *
62 from generate_cpp_frontend_dispatcher_header import *
63 from generate_cpp_frontend_dispatcher_implementation import *
64 from generate_cpp_protocol_types_header import *
65 from generate_cpp_protocol_types_implementation import *
66 from generate_js_backend_commands import *
67 from generate_objc_backend_dispatcher_header import *
68 from generate_objc_backend_dispatcher_implementation import *
69 from generate_objc_configuration_header import *
70 from generate_objc_configuration_implementation import *
71 from generate_objc_conversion_helpers import *
72 from generate_objc_frontend_dispatcher_implementation import *
73 from generate_objc_header import *
74 from generate_objc_internal_header import *
75 from generate_objc_protocol_types_implementation import *
76
77
78# A writer that only updates file if it actually changed.
79class IncrementalFileWriter:
80 def __init__(self, filepath, force_output):
81 self._filepath = filepath
82 self._output = ""
83 self.force_output = force_output
84
85 def write(self, text):
86 self._output += text
87
88 def close(self):
89 text_changed = True
90 self._output = self._output.rstrip() + "\n"
91
92 try:
93 if self.force_output:
94 raise
95
96 read_file = open(self._filepath, "r")
97 old_text = read_file.read()
98 read_file.close()
99 text_changed = old_text != self._output
100 except:
101 # Ignore, just overwrite by default
102 pass
103
104 if text_changed or self.force_output:
105 out_file = open(self._filepath, "w")
106 out_file.write(self._output)
107 out_file.close()
108
109
110def generate_from_specification(primary_specification_filepath=None,
111 supplemental_specification_filepaths=[],
112 concatenate_output=False,
113 output_dirpath=None,
114 force_output=False,
115 framework_name=""):
116
117 def load_specification(protocol, filepath, isSupplemental=False):
118 try:
119 with open(filepath, "r") as input_file:
120 parsed_json = json.load(input_file)
121 protocol.parse_specification(parsed_json, isSupplemental)
122 except ValueError as e:
123 raise Exception("Error parsing valid JSON in file: " + filepath)
124
125 protocol = models.Protocol(framework_name)
126 for specification in supplemental_specification_filepaths:
127 load_specification(protocol, specification, isSupplemental=True)
128 load_specification(protocol, primary_specification_filepath, isSupplemental=False)
129
130 protocol.resolve_types()
131
132 generators = []
133 is_test = protocol.framework is Frameworks.Test
134 if is_test or protocol.framework is not Frameworks.WebInspector:
135 generators.append(CppAlternateBackendDispatcherHeaderGenerator(protocol, primary_specification_filepath))
136 generators.append(JSBackendCommandsGenerator(protocol, primary_specification_filepath))
137 generators.append(CppBackendDispatcherHeaderGenerator(protocol, primary_specification_filepath))
138 generators.append(CppBackendDispatcherImplementationGenerator(protocol, primary_specification_filepath))
139 generators.append(CppFrontendDispatcherHeaderGenerator(protocol, primary_specification_filepath))
140 generators.append(CppFrontendDispatcherImplementationGenerator(protocol, primary_specification_filepath))
141 generators.append(CppProtocolTypesHeaderGenerator(protocol, primary_specification_filepath))
142 generators.append(CppProtocolTypesImplementationGenerator(protocol, primary_specification_filepath))
143 if is_test or protocol.framework is Frameworks.WebInspector:
144 generators.append(ObjCBackendDispatcherHeaderGenerator(protocol, primary_specification_filepath))
145 generators.append(ObjCBackendDispatcherImplementationGenerator(protocol, primary_specification_filepath))
146 generators.append(ObjCConfigurationHeaderGenerator(protocol, primary_specification_filepath))
147 generators.append(ObjCConfigurationImplementationGenerator(protocol, primary_specification_filepath))
148 generators.append(ObjCConversionHelpersGenerator(protocol, primary_specification_filepath))
149 generators.append(ObjCFrontendDispatcherImplementationGenerator(protocol, primary_specification_filepath))
150 generators.append(ObjCHeaderGenerator(protocol, primary_specification_filepath))
151 generators.append(ObjCProtocolTypesImplementationGenerator(protocol, primary_specification_filepath))
152 generators.append(ObjCInternalHeaderGenerator(protocol, primary_specification_filepath))
153
154 single_output_file_contents = []
155
156 for generator in generators:
157 output = generator.generate_output()
158 if concatenate_output:
159 single_output_file_contents.append('### Begin File: %s' % generator.output_filename())
160 single_output_file_contents.append(output)
161 single_output_file_contents.append('### End File: %s' % generator.output_filename())
162 single_output_file_contents.append('')
163 else:
164 output_file = IncrementalFileWriter(os.path.join(output_dirpath, generator.output_filename()), force_output)
165 output_file.write(output)
166 output_file.close()
167
168 if concatenate_output:
169 filename = os.path.join(os.path.basename(primary_specification_filepath) + '-result')
170 output_file = IncrementalFileWriter(os.path.join(output_dirpath, filename), force_output)
171 output_file.write('\n'.join(single_output_file_contents))
172 output_file.close()
173
174
175if __name__ == '__main__':
176 allowed_framework_names = ['JavaScriptCore', 'WebInspector', 'Test']
177 cli_parser = optparse.OptionParser(usage="usage: %prog [options] PrimaryProtocol.json [SupplementalProtocol.json ...]")
178 cli_parser.add_option("-o", "--outputDir", help="Directory where generated files should be written.")
179 cli_parser.add_option("--framework", type="choice", choices=allowed_framework_names, help="The framework that the primary specification belongs to.")
180 cli_parser.add_option("--force", action="store_true", help="Force output of generated scripts, even if nothing changed.")
181 cli_parser.add_option("-v", "--debug", action="store_true", help="Log extra output for debugging the generator itself.")
182 cli_parser.add_option("-t", "--test", action="store_true", help="Enable test mode. Use unique output filenames created by prepending the input filename.")
183
184 options = None
185
186 arg_options, arg_values = cli_parser.parse_args()
187 if (len(arg_values) < 1):
188 raise ParseException("At least one plain argument expected")
189
190 if not arg_options.outputDir:
191 raise ParseException("Missing output directory")
192
193 if arg_options.debug:
194 log.setLevel(logging.DEBUG)
195
196 options = {
197 'primary_specification_filepath': arg_values[0],
198 'supplemental_specification_filepaths': arg_values[1:],
199 'output_dirpath': arg_options.outputDir,
200 'concatenate_output': arg_options.test,
201 'framework_name': arg_options.framework,
202 'force_output': arg_options.force
203 }
204
205 try:
206 generate_from_specification(**options)
207 except (ParseException, TypecheckException) as e:
208 if arg_options.test:
209 log.error(e.message)
210 else:
211 raise # Force the build to fail.