1# Copyright (C) 2013 Google Inc. All rights reserved.
2#
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions are
5# met:
6#
7#     * Redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer.
9#     * Redistributions in binary form must reproduce the above
10# copyright notice, this list of conditions and the following disclaimer
11# in the documentation and/or other materials provided with the
12# distribution.
13#     * Neither the name of Google Inc. nor the names of its
14# contributors may be used to endorse or promote products derived from
15# this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29"""Generate template values for methods.
30
31FIXME: Not currently used in build.
32This is a rewrite of the Perl IDL compiler in Python, but is not complete.
33Once it is complete, we will switch all IDL files over to Python at once.
34Until then, please work on the Perl IDL compiler.
35For details, see bug http://crbug.com/239771
36"""
37
38from v8_globals import includes
39import v8_types
40import v8_utilities
41from v8_utilities import has_extended_attribute_value
42
43
44def generate_method(interface, method):
45    arguments = method.arguments
46    extended_attributes = method.extended_attributes
47    idl_type = method.idl_type
48    is_static = method.is_static
49    name = method.name
50
51    this_cpp_value = cpp_value(interface, method, len(arguments))
52    this_custom_signature = custom_signature(method, arguments)
53
54    def function_template():
55        if is_static:
56            return 'functionTemplate'
57        if 'Unforgeable' in extended_attributes:
58            return 'instanceTemplate'
59        return 'prototypeTemplate'
60
61    def signature():
62        if this_custom_signature:
63            return name + 'Signature'
64        if is_static or 'DoNotCheckSignature' in extended_attributes:
65            return 'v8::Local<v8::Signature>()'
66        return 'defaultSignature'
67
68    is_call_with_script_arguments = has_extended_attribute_value(method, 'CallWith', 'ScriptArguments')
69    if is_call_with_script_arguments:
70        includes.update(['bindings/v8/ScriptCallStackFactory.h',
71                         'core/inspector/ScriptArguments.h'])
72    is_call_with_script_state = has_extended_attribute_value(method, 'CallWith', 'ScriptState')
73    if is_call_with_script_state:
74        includes.add('bindings/v8/ScriptState.h')
75    is_check_security_for_node = 'CheckSecurity' in extended_attributes
76    if is_check_security_for_node:
77        includes.add('bindings/v8/BindingSecurity.h')
78    is_custom_element_callbacks = 'CustomElementCallbacks' in extended_attributes
79    if is_custom_element_callbacks:
80        includes.add('core/dom/custom/CustomElementCallbackDispatcher.h')
81
82    contents = {
83        'activity_logging_world_list': v8_utilities.activity_logging_world_list(method),  # [ActivityLogging]
84        'arguments': [generate_argument(interface, method, argument, index)
85                      for index, argument in enumerate(arguments)],
86        'conditional_string': v8_utilities.conditional_string(method),
87        'cpp_type': v8_types.cpp_type(idl_type),
88        'cpp_value': this_cpp_value,
89        'custom_signature': this_custom_signature,
90        'deprecate_as': v8_utilities.deprecate_as(method),  # [DeprecateAs]
91        'do_not_check_signature': not(this_custom_signature or is_static or
92            v8_utilities.has_extended_attribute(method,
93                ['DoNotCheckSecurity', 'DoNotCheckSignature', 'NotEnumerable',
94                 'ReadOnly', 'RuntimeEnabled', 'Unforgeable'])),
95        'function_template': function_template(),
96        'idl_type': idl_type,
97        'is_call_with_execution_context': has_extended_attribute_value(method, 'CallWith', 'ExecutionContext'),
98        'is_call_with_script_arguments': is_call_with_script_arguments,
99        'is_call_with_script_state': is_call_with_script_state,
100        'is_check_security_for_frame': (
101            'CheckSecurity' in interface.extended_attributes and
102            'DoNotCheckSecurity' not in extended_attributes),
103        'is_check_security_for_node': is_check_security_for_node,
104        'is_custom': 'Custom' in extended_attributes,
105        'is_custom_element_callbacks': is_custom_element_callbacks,
106        'is_do_not_check_security': 'DoNotCheckSecurity' in extended_attributes,
107        'is_per_world_bindings': 'PerWorldBindings' in extended_attributes,
108        'is_raises_exception': 'RaisesException' in extended_attributes,
109        'is_read_only': 'ReadOnly' in extended_attributes,
110        'is_static': is_static,
111        'is_strict_type_checking': 'StrictTypeChecking' in extended_attributes,
112        'is_variadic': arguments and arguments[-1].is_variadic,
113        'measure_as': v8_utilities.measure_as(method),  # [MeasureAs]
114        'name': name,
115        'number_of_arguments': len(arguments),
116        'number_of_required_arguments': len([
117            argument for argument in arguments
118            if not (argument.is_optional or argument.is_variadic)]),
119        'number_of_required_or_variadic_arguments': len([
120            argument for argument in arguments
121            if not argument.is_optional]),
122        'per_context_enabled_function': v8_utilities.per_context_enabled_function_name(method),  # [PerContextEnabled]
123        'property_attributes': property_attributes(method),
124        'runtime_enabled_function': v8_utilities.runtime_enabled_function_name(method),  # [RuntimeEnabled]
125        'signature': signature(),
126        'v8_set_return_value': v8_set_return_value(method, this_cpp_value),
127        'world_suffixes': ['', 'ForMainWorld'] if 'PerWorldBindings' in extended_attributes else [''],  # [PerWorldBindings]
128    }
129    return contents
130
131
132def generate_argument(interface, method, argument, index):
133    extended_attributes = argument.extended_attributes
134    idl_type = argument.idl_type
135    this_cpp_value = cpp_value(interface, method, index)
136    return {
137        'cpp_type': v8_types.cpp_type(idl_type),
138        'cpp_value': this_cpp_value,
139        'enum_validation_expression': v8_utilities.enum_validation_expression(idl_type),
140        'has_default': 'Default' in extended_attributes,
141        'idl_type': idl_type,
142        'index': index,
143        'is_clamp': 'Clamp' in extended_attributes,
144        'is_nullable': argument.is_nullable,
145        'is_optional': argument.is_optional,
146        'is_strict_type_checking': 'StrictTypeChecking' in extended_attributes,
147        'is_variadic_wrapper_type': argument.is_variadic and v8_types.is_wrapper_type(idl_type),
148        'is_wrapper_type': v8_types.is_wrapper_type(idl_type),
149        'name': argument.name,
150        'v8_set_return_value': v8_set_return_value(method, this_cpp_value),
151        'v8_value_to_local_cpp_value': v8_value_to_local_cpp_value(argument, index),
152    }
153
154
155def cpp_value(interface, method, number_of_arguments):
156    def cpp_argument(argument):
157        if argument.idl_type in ['NodeFilter', 'XPathNSResolver']:
158            # FIXME: remove this special case
159            return '%s.release()' % argument.name
160        return argument.name
161
162    # Truncate omitted optional arguments
163    arguments = method.arguments[:number_of_arguments]
164    cpp_arguments = v8_utilities.call_with_arguments(method)
165    cpp_arguments.extend(cpp_argument(argument) for argument in arguments)
166    if 'RaisesException' in method.extended_attributes:
167        cpp_arguments.append('exceptionState')
168
169    cpp_method_name = v8_utilities.scoped_name(interface, method, v8_utilities.cpp_name(method))
170    return '%s(%s)' % (cpp_method_name, ', '.join(cpp_arguments))
171
172
173def v8_set_return_value(method, cpp_value):
174    idl_type = method.idl_type
175    if idl_type == 'void':
176        return None
177    # [CallWith=ScriptState]
178    if has_extended_attribute_value(method, 'CallWith', 'ScriptState'):
179        cpp_value = 'result'  # use local variable for value
180    return v8_types.v8_set_return_value(idl_type, cpp_value, method.extended_attributes)
181
182
183def custom_signature(method, arguments):
184    def argument_template(argument):
185        idl_type = argument.idl_type
186        if (v8_types.is_wrapper_type(idl_type) and
187            not v8_types.is_typed_array_type(idl_type) and
188            # Compatibility: all other browsers accepts a callable for
189            # XPathNSResolver, despite it being against spec.
190            not idl_type == 'XPathNSResolver'):
191            return 'V8PerIsolateData::from(isolate)->rawDOMTemplate(&V8{idl_type}::wrapperTypeInfo, currentWorldType)'.format(idl_type=idl_type)
192        return 'v8::Handle<v8::FunctionTemplate>()'
193
194    if (any(argument.is_optional and
195            'Default' not in argument.extended_attributes
196            for argument in arguments) or
197        all(not v8_types.is_wrapper_type(argument.idl_type)
198            for argument in arguments) or
199        # For [StrictTypeChecking], type checking is done in the generated code
200        'StrictTypeChecking' in method.extended_attributes):
201        return None
202    return ', '.join([argument_template(argument) for argument in arguments])
203
204
205# [NotEnumerable]
206def property_attributes(method):
207    extended_attributes = method.extended_attributes
208    property_attributes_list = []
209    if 'NotEnumerable' in extended_attributes:
210        property_attributes_list.append('v8::DontEnum')
211    if 'ReadOnly' in extended_attributes:
212        property_attributes_list.append('v8::ReadOnly')
213    if property_attributes_list:
214        property_attributes_list.insert(0, 'v8::DontDelete')
215    return property_attributes_list
216
217
218def v8_value_to_local_cpp_value(argument, index):
219    extended_attributes = argument.extended_attributes
220    idl_type = argument.idl_type
221    name = argument.name
222    if argument.is_variadic:
223        return 'V8TRYCATCH_VOID(Vector<{cpp_type}>, {name}, toNativeArguments<{cpp_type}>(info, {index}))'.format(
224                cpp_type=v8_types.cpp_type(idl_type), name=name, index=index)
225    # [Default=NullString]
226    if (argument.is_optional and idl_type == 'DOMString' and
227        extended_attributes.get('Default') == 'NullString'):
228        v8_value = 'argumentOrNull(info, %s)' % index
229    else:
230        v8_value = 'info[%s]' % index
231    return v8_types.v8_value_to_local_cpp_value(
232        idl_type, argument.extended_attributes, v8_value, name, index=index)
233