Replace WTF::move with WTFMove
[WebKit-https.git] / Source / JavaScriptCore / inspector / scripts / codegen / generate_cpp_backend_dispatcher_implementation.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
28 import logging
29 import string
30 from string import Template
31
32 from cpp_generator import CppGenerator
33 from cpp_generator_templates import CppGeneratorTemplates as CppTemplates
34 from generator import Generator, ucfirst
35 from models import ObjectType, ArrayType
36
37 log = logging.getLogger('global')
38
39
40 class CppBackendDispatcherImplementationGenerator(Generator):
41     def __init__(self, model, input_filepath):
42         Generator.__init__(self, model, input_filepath)
43
44     def output_filename(self):
45         return "InspectorBackendDispatchers.cpp"
46
47     def domains_to_generate(self):
48         return filter(lambda domain: len(domain.commands) > 0, Generator.domains_to_generate(self))
49
50     def generate_output(self):
51         secondary_headers = [
52             '<inspector/InspectorFrontendRouter.h>',
53             '<inspector/InspectorValues.h>',
54             '<wtf/NeverDestroyed.h>',
55             '<wtf/text/CString.h>']
56
57         secondary_includes = ['#include %s' % header for header in secondary_headers]
58         secondary_includes.append('')
59         secondary_includes.append('#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)')
60         secondary_includes.append('#include "InspectorAlternateBackendDispatchers.h"')
61         secondary_includes.append('#endif')
62
63         header_args = {
64             'primaryInclude': '"InspectorBackendDispatchers.h"',
65             'secondaryIncludes': '\n'.join(secondary_includes),
66         }
67
68         sections = []
69         sections.append(self.generate_license())
70         sections.append(Template(CppTemplates.ImplementationPrelude).substitute(None, **header_args))
71         sections.append("\n".join(map(self._generate_handler_class_destructor_for_domain, self.domains_to_generate())))
72         sections.extend(map(self._generate_dispatcher_implementations_for_domain, self.domains_to_generate()))
73         sections.append(Template(CppTemplates.ImplementationPostlude).substitute(None, **header_args))
74         return "\n\n".join(sections)
75
76     # Private methods.
77
78     def _generate_handler_class_destructor_for_domain(self, domain):
79         destructor_args = {
80             'domainName': domain.domain_name
81         }
82         destructor = '%(domainName)sBackendDispatcherHandler::~%(domainName)sBackendDispatcherHandler() { }' % destructor_args
83         return self.wrap_with_guard_for_domain(domain, destructor)
84
85     def _generate_dispatcher_implementations_for_domain(self, domain):
86         implementations = []
87
88         constructor_args = {
89             'domainName': domain.domain_name,
90         }
91         implementations.append(Template(CppTemplates.BackendDispatcherImplementationDomainConstructor).substitute(None, **constructor_args))
92
93         if len(domain.commands) <= 5:
94             implementations.append(self._generate_small_dispatcher_switch_implementation_for_domain(domain))
95         else:
96             implementations.append(self._generate_large_dispatcher_switch_implementation_for_domain(domain))
97
98         for command in domain.commands:
99             if command.is_async:
100                 implementations.append(self._generate_async_dispatcher_class_for_domain(command, domain))
101             implementations.append(self._generate_dispatcher_implementation_for_command(command, domain))
102
103         return self.wrap_with_guard_for_domain(domain, '\n\n'.join(implementations))
104
105     def _generate_small_dispatcher_switch_implementation_for_domain(self, domain):
106         cases = []
107         cases.append('    if (method == "%s")' % domain.commands[0].command_name)
108         cases.append('        %s(requestId, WTFMove(parameters));' % domain.commands[0].command_name)
109         for command in domain.commands[1:]:
110             cases.append('    else if (method == "%s")' % command.command_name)
111             cases.append('        %s(requestId, WTFMove(parameters));' % command.command_name)
112
113         switch_args = {
114             'domainName': domain.domain_name,
115             'dispatchCases': "\n".join(cases)
116         }
117
118         return Template(CppTemplates.BackendDispatcherImplementationSmallSwitch).substitute(None, **switch_args)
119
120     def _generate_large_dispatcher_switch_implementation_for_domain(self, domain):
121         cases = []
122         for command in domain.commands:
123             args = {
124                 'domainName': domain.domain_name,
125                 'commandName': command.command_name
126             }
127             cases.append('            { "%(commandName)s", &%(domainName)sBackendDispatcher::%(commandName)s },' % args)
128
129         switch_args = {
130             'domainName': domain.domain_name,
131             'dispatchCases': "\n".join(cases)
132         }
133
134         return Template(CppTemplates.BackendDispatcherImplementationLargeSwitch).substitute(None, **switch_args)
135
136     def _generate_async_dispatcher_class_for_domain(self, command, domain):
137         out_parameter_assignments = []
138         formal_parameters = []
139
140         for parameter in command.return_parameters:
141             param_args = {
142                 'keyedSetMethod': CppGenerator.cpp_setter_method_for_type(parameter.type),
143                 'parameterKey': parameter.parameter_name,
144                 'parameterName': parameter.parameter_name,
145                 'parameterType': CppGenerator.cpp_type_for_stack_in_parameter(parameter),
146             }
147
148             formal_parameters.append('%s %s' % (CppGenerator.cpp_type_for_formal_async_parameter(parameter), parameter.parameter_name))
149
150             if parameter.is_optional:
151                 if CppGenerator.should_use_wrapper_for_return_type(parameter.type):
152                     out_parameter_assignments.append('    if (%(parameterName)s.isAssigned())' % param_args)
153                     out_parameter_assignments.append('        jsonMessage->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), %(parameterName)s.getValue());' % param_args)
154                 else:
155                     out_parameter_assignments.append('    if (%(parameterName)s)' % param_args)
156                     out_parameter_assignments.append('        jsonMessage->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), %(parameterName)s);' % param_args)
157             elif parameter.type.is_enum():
158                 out_parameter_assignments.append('    jsonMessage->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), Inspector::Protocol::getEnumConstantValue(%(parameterName)s));' % param_args)
159             else:
160                 out_parameter_assignments.append('    jsonMessage->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), %(parameterName)s);' % param_args)
161
162         async_args = {
163             'domainName': domain.domain_name,
164             'callbackName': ucfirst(command.command_name) + 'Callback',
165             'formalParameters': ", ".join(formal_parameters),
166             'outParameterAssignments': "\n".join(out_parameter_assignments)
167         }
168         return Template(CppTemplates.BackendDispatcherImplementationAsyncCommand).substitute(None, **async_args)
169
170     def _generate_dispatcher_implementation_for_command(self, command, domain):
171         in_parameter_declarations = []
172         out_parameter_declarations = []
173         out_parameter_assignments = []
174         alternate_dispatcher_method_parameters = ['requestId']
175         method_parameters = ['error']
176
177         for parameter in command.call_parameters:
178             parameter_name = 'in_' + parameter.parameter_name
179             if parameter.is_optional:
180                 parameter_name = 'opt_' + parameter_name
181
182             out_success_argument = 'nullptr'
183             if parameter.is_optional:
184                 out_success_argument = '&%s_valueFound' % parameter_name
185                 in_parameter_declarations.append('    bool %s_valueFound = false;' % parameter_name)
186
187             # Now add appropriate operators.
188             parameter_expression = parameter_name
189
190             if CppGenerator.should_use_references_for_type(parameter.type):
191                 if parameter.is_optional:
192                     parameter_expression = '%s.get()' % parameter_expression
193                 else:
194                     # This assumes that we have already proved the object is non-null.
195                     # If a required property is missing, InspectorBackend::getObject will
196                     # append a protocol error, and the method dispatcher will return without
197                     # invoking the backend method (and dereferencing the object).
198                     parameter_expression = '*%s' % parameter_expression
199             elif parameter.is_optional:
200                 parameter_expression = '&%s' % parameter_expression
201
202             param_args = {
203                 'parameterType': CppGenerator.cpp_type_for_stack_in_parameter(parameter),
204                 'parameterKey': parameter.parameter_name,
205                 'parameterName': parameter_name,
206                 'parameterExpression': parameter_expression,
207                 'keyedGetMethod': CppGenerator.cpp_getter_method_for_type(parameter.type),
208                 'successOutParam': out_success_argument
209             }
210
211             in_parameter_declarations.append('    %(parameterType)s %(parameterName)s = m_backendDispatcher->%(keyedGetMethod)s(parameters.get(), ASCIILiteral("%(parameterKey)s"), %(successOutParam)s);' % param_args)
212
213             if parameter.is_optional:
214                 optional_in_parameter_string = '%(parameterName)s_valueFound ? %(parameterExpression)s : nullptr' % param_args
215                 alternate_dispatcher_method_parameters.append(optional_in_parameter_string)
216                 method_parameters.append(optional_in_parameter_string)
217             else:
218                 alternate_dispatcher_method_parameters.append(parameter_expression)
219                 method_parameters.append(parameter_expression)
220
221         if command.is_async:
222             async_args = {
223                 'domainName': domain.domain_name,
224                 'callbackName': ucfirst(command.command_name) + 'Callback'
225             }
226
227             out_parameter_assignments.append('        callback->disable();')
228             out_parameter_assignments.append('        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, error);')
229             out_parameter_assignments.append('        return;')
230             method_parameters.append('callback.copyRef()')
231
232         else:
233             for parameter in command.return_parameters:
234                 param_args = {
235                     'parameterType': CppGenerator.cpp_type_for_stack_out_parameter(parameter),
236                     'parameterKey': parameter.parameter_name,
237                     'parameterName': parameter.parameter_name,
238                     'keyedSetMethod': CppGenerator.cpp_setter_method_for_type(parameter.type),
239
240                 }
241
242                 out_parameter_declarations.append('    %(parameterType)s out_%(parameterName)s;' % param_args)
243                 if parameter.is_optional:
244                     if CppGenerator.should_use_wrapper_for_return_type(parameter.type):
245                         out_parameter_assignments.append('        if (out_%(parameterName)s.isAssigned())' % param_args)
246                         out_parameter_assignments.append('            result->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), out_%(parameterName)s.getValue());' % param_args)
247                     else:
248                         out_parameter_assignments.append('        if (out_%(parameterName)s)' % param_args)
249                         out_parameter_assignments.append('            result->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), out_%(parameterName)s);' % param_args)
250                 elif parameter.type.is_enum():
251                     out_parameter_assignments.append('        result->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), Inspector::Protocol::getEnumConstantValue(out_%(parameterName)s));' % param_args)
252                 else:
253                     out_parameter_assignments.append('        result->%(keyedSetMethod)s(ASCIILiteral("%(parameterKey)s"), out_%(parameterName)s);' % param_args)
254
255                 if CppGenerator.should_pass_by_copy_for_return_type(parameter.type):
256                     method_parameters.append('out_' + parameter.parameter_name)
257                 else:
258                     method_parameters.append('&out_' + parameter.parameter_name)
259
260         command_args = {
261             'domainName': domain.domain_name,
262             'callbackName': '%sCallback' % ucfirst(command.command_name),
263             'commandName': command.command_name,
264             'inParameterDeclarations': '\n'.join(in_parameter_declarations),
265             'invocationParameters': ', '.join(method_parameters),
266             'alternateInvocationParameters': ', '.join(alternate_dispatcher_method_parameters),
267         }
268
269         lines = []
270         if len(command.call_parameters) == 0:
271             lines.append('void %(domainName)sBackendDispatcher::%(commandName)s(long requestId, RefPtr<InspectorObject>&&)' % command_args)
272         else:
273             lines.append('void %(domainName)sBackendDispatcher::%(commandName)s(long requestId, RefPtr<InspectorObject>&& parameters)' % command_args)
274         lines.append('{')
275
276         if len(command.call_parameters) > 0:
277             lines.append(Template(CppTemplates.BackendDispatcherImplementationPrepareCommandArguments).substitute(None, **command_args))
278
279         lines.append('#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)')
280         lines.append('    if (m_alternateDispatcher) {')
281         lines.append('        m_alternateDispatcher->%(commandName)s(%(alternateInvocationParameters)s);' % command_args)
282         lines.append('        return;')
283         lines.append('    }')
284         lines.append('#endif')
285         lines.append('')
286
287         lines.append('    ErrorString error;')
288         lines.append('    Ref<InspectorObject> result = InspectorObject::create();')
289         if command.is_async:
290             lines.append('    Ref<%(domainName)sBackendDispatcherHandler::%(callbackName)s> callback = adoptRef(*new %(domainName)sBackendDispatcherHandler::%(callbackName)s(m_backendDispatcher.copyRef(), requestId));' % command_args)
291         if len(command.return_parameters) > 0:
292             lines.extend(out_parameter_declarations)
293         lines.append('    m_agent->%(commandName)s(%(invocationParameters)s);' % command_args)
294         lines.append('')
295         if command.is_async:
296             lines.append('    if (error.length()) {')
297             lines.extend(out_parameter_assignments)
298             lines.append('    }')
299         elif len(command.return_parameters) > 1:
300             lines.append('    if (!error.length()) {')
301             lines.extend(out_parameter_assignments)
302             lines.append('    }')
303         elif len(command.return_parameters) == 1:
304             lines.append('    if (!error.length())')
305             lines.extend(out_parameter_assignments)
306             lines.append('')
307
308         if not command.is_async:
309             lines.append('    if (!error.length())')
310             lines.append('        m_backendDispatcher->sendResponse(requestId, WTFMove(result));')
311             lines.append('    else')
312             lines.append('        m_backendDispatcher->reportProtocolError(BackendDispatcher::ServerError, WTFMove(error));')
313         lines.append('}')
314         return "\n".join(lines)