OLD | NEW |
(Empty) | |
| 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 functions. |
| 30 |
| 31 FIXME: rename "parameter/parameters": |
| 32 "template parameters" is easily confused with "function parameters" |
| 33 Also, "parameter*s*", not "parameter". |
| 34 """ |
| 35 |
| 36 |
| 37 from code_generator_idl_reader import implemented_as_from_implemented_by |
| 38 from v8_includes import * |
| 39 from v8_types import * |
| 40 from v8_utilities import extended_attribute_contains, generate_conditional_strin
g, get_raises_exception, runtime_enable_function_name, implemented_as_cpp_name |
| 41 from v8_values import get_js_value_to_native_statement, get_native_to_js_value_s
tatement, get_pass_owner_expression |
| 42 |
| 43 from v8_utilities import ACTIVITY_LOGGING_INCLUDES, get_call_with_parameter, get
_custom_element_invocation_scope_parameter, get_deprecation_notification_paramet
er, get_function_mandatory_parameters, get_feature_observation_parameter, has_ac
tivity_logging |
| 44 |
| 45 |
| 46 def generate_functions(interface): |
| 47 # FIXME: clearer with a list comprehension + nested function to handle inclu
des |
| 48 functions = [] |
| 49 includes = [] |
| 50 for function in interface.operations: |
| 51 function_contents, function_includes = generate_function(interface, func
tion) |
| 52 # print '[FUNC]', function_contents |
| 53 functions.append(function_contents) |
| 54 includes += function_includes |
| 55 return functions, includes |
| 56 |
| 57 |
| 58 def generate_function(interface, function): |
| 59 includes = [] |
| 60 name = function.name |
| 61 cpp_class_name = implemented_as_cpp_name(interface) |
| 62 is_normal_function = function.name and 'EnabledPerContext' not in function.e
xtended_attributes |
| 63 is_standard_function = get_is_standard_function(interface, function) |
| 64 is_custom = has_custom_implementation(function) |
| 65 |
| 66 per_world_bindings = 'PerWorldBindings' in function.extended_attributes |
| 67 for_main_world_suffixes = [''] |
| 68 if per_world_bindings: |
| 69 for_main_world_suffixes.append('ForMainWorld') |
| 70 |
| 71 activity_logging = set() |
| 72 setter_function_call_parameter = {} |
| 73 for for_main_world_suffix in for_main_world_suffixes: |
| 74 if has_activity_logging(for_main_world_suffix, function.extended_attribu
tes, 'Method'): |
| 75 activity_logging.add(for_main_world_suffix) |
| 76 includes += ACTIVITY_LOGGING_INCLUDES |
| 77 |
| 78 check_security_for_node = 'CheckSecurityForNode' in function.extended_attrib
utes |
| 79 if check_security_for_node: |
| 80 includes.append('bindings/v8/BindingSecurity.h') |
| 81 |
| 82 method_for_main_world = '0' |
| 83 if 'PerWorldBindings' in function.extended_attributes: |
| 84 method_for_main_world = '%sV8Internal::%sMethodCallbackForMainWorld' % (
implemented_as_cpp_name(interface), function.name) |
| 85 mandatory_parameters = get_function_mandatory_parameters(function) |
| 86 |
| 87 if len(function.overloads) > 1: |
| 88 name = '%s%d' % (name, function.overload_index) |
| 89 is_representative = function.overload_index == 1 |
| 90 conditional_runtime = '' |
| 91 enable_function = '' |
| 92 if 'EnabledAtRuntime' in function.extended_attributes: |
| 93 # Only call Set()/SetAccessor() if this method should be enabled |
| 94 enable_function = runtime_enable_function_name(function) |
| 95 conditional_runtime = 'if (%s())\n ' % enable_function |
| 96 if function.extended_attributes.get('EnabledPerContext'): |
| 97 # Only call Set()/SetAccessor() if this method should be enabled |
| 98 enable_function = get_context_enable_function(function) |
| 99 conditional_runtime = 'if (%s(impl->document()))' % enable_function |
| 100 |
| 101 template = 'proto' |
| 102 if 'Unforgeable' in function.extended_attributes: |
| 103 template = 'instance' |
| 104 if function.is_static: |
| 105 template = 'desc' |
| 106 |
| 107 setter = '%sV8Internal::%sDomainSafeFunctionSetter' % (cpp_class_name, cpp_c
lass_name) if 'ReadOnly' not in function.extended_attributes else '0' |
| 108 |
| 109 signature = 'defaultSignature' |
| 110 if 'DoNotCheckSignature' in function.extended_attributes or function.is_stat
ic: |
| 111 signature = 'v8::Local<v8::Signature>()' |
| 112 requires_custom_signature = get_requires_custom_signature(function) |
| 113 if requires_custom_signature: |
| 114 signature = function.name + 'Signature' |
| 115 |
| 116 # FIXME: simplify: additional_property_attributes_list, ' | '.join(...) |
| 117 property_attributes = 'v8::DontDelete' |
| 118 if 'NotEnumerable' in function.extended_attributes: |
| 119 property_attributes += ' | v8::DontEnum' |
| 120 if 'ReadOnly' in function.extended_attributes: |
| 121 property_attributes += ' | v8::ReadOnly' |
| 122 |
| 123 if property_attributes == 'v8::DontDelete': |
| 124 property_attributes = '' |
| 125 else: |
| 126 property_attributes = ', static_cast<v8::PropertyAttribute>(%s)' % prope
rty_attributes |
| 127 |
| 128 custom_signatures = [] |
| 129 if requires_custom_signature: |
| 130 for parameter in function.arguments: |
| 131 if is_wrapper_type(parameter.data_type): |
| 132 if parameter.data_type == 'XPathNSResolver': |
| 133 # Special case for XPathNSResolver. All other browsers acce
pts a callable, |
| 134 # so, even though it's against IDL, accept objects here. |
| 135 custom_signatures.append('v8::Handle<v8::FunctionTemplate>()
') |
| 136 else: |
| 137 array_or_sequence_type = get_array_or_sequence_type(paramete
r.data_type) |
| 138 |
| 139 if array_or_sequence_type: |
| 140 if is_ref_ptr_type(array_or_sequence_type): |
| 141 includes += get_includes_for_type(array_or_sequence_
type) |
| 142 else: |
| 143 custom_signatures.append('v8::Handle<v8::FunctionTem
plate>()') |
| 144 continue |
| 145 else: |
| 146 # print '[FOO]', parameter.data_type, 'AS', array_or
_sequence_type |
| 147 includes += get_includes_for_type(parameter.data_type) |
| 148 custom_signatures.append('V8PerIsolateData::from(isolate)->r
awTemplate(&V8%s::info, currentWorldType)' % parameter.data_type) |
| 149 else: |
| 150 custom_signatures.append('v8::Handle<v8::FunctionTemplate>()') |
| 151 custom_signature = ', '.join(custom_signatures) |
| 152 function_call_parameters = {} |
| 153 raises_exception = get_raises_exception(function) |
| 154 if any(['IsIndex' in parameter.extended_attributes |
| 155 for parameter in function.arguments]): |
| 156 raises_exception = True |
| 157 feature_observation_parameter = {} |
| 158 deprecation_notification_parameter = {} |
| 159 custom_element_invocation_scope_parameter = {} |
| 160 parameter_check_parameters = {} |
| 161 |
| 162 if not is_custom and name: |
| 163 if raises_exception: |
| 164 includes.append('bindings/v8/ExceptionState.h') |
| 165 |
| 166 parameter_check_parameters, parameter_check_includes, replacements = get
_parameter_check_parameters(interface, function) |
| 167 includes += parameter_check_includes |
| 168 |
| 169 for for_main_world_suffix in for_main_world_suffixes: |
| 170 function_call_parameter, function_call_includes = get_function_call_
parameter(interface, function, len(function.arguments), for_main_world_suffix=fo
r_main_world_suffix, replacements=replacements) |
| 171 function_call_parameters[for_main_world_suffix] = function_call_para
meter |
| 172 includes += function_call_includes |
| 173 |
| 174 comment_info = 'Function "%s" (ExtAttr: "%s")' % (function.name, ' '.joi
n(function.extended_attributes.keys())) |
| 175 |
| 176 # if template == 'proto' and conditional_runtime == '' and signature ==
'defaultSignature' and property_attributes == '': |
| 177 # raise Exception('This shouldn't happen: Class '%s' %s' % (cpp_clas
s_name, comment_info)) |
| 178 |
| 179 custom_element_invocation_scope_parameter, custom_element_invocation_sco
pe_includes = get_custom_element_invocation_scope_parameter(function) |
| 180 includes += custom_element_invocation_scope_includes |
| 181 |
| 182 feature_observation_parameter, feature_observation_includes = get_featur
e_observation_parameter(function) |
| 183 includes += feature_observation_includes |
| 184 |
| 185 deprecation_notification_parameter, deprecation_notification_includes =
get_deprecation_notification_parameter(function) |
| 186 includes += deprecation_notification_includes |
| 187 |
| 188 # print |
| 189 # print '#'*30 |
| 190 # print '[get_function_parameter] ', function.data_type, name |
| 191 contents = { |
| 192 'name': name, |
| 193 'is_static': function.is_static, |
| 194 'is_custom': is_custom, |
| 195 'create_callback': is_representative and is_normal_function and is_stand
ard_function, |
| 196 'is_representative': is_representative, |
| 197 'conditional_runtime': conditional_runtime, |
| 198 'template': template, |
| 199 'setter': setter, |
| 200 'signature': signature, |
| 201 'property_attributes': property_attributes, |
| 202 'requires_custom_signature': requires_custom_signature, |
| 203 'custom_signature': custom_signature, |
| 204 'conditional_string': generate_conditional_string(function), |
| 205 'mandatory_parameters': mandatory_parameters, |
| 206 'length': get_function_mandatory_parameters(function, count_variadic=Tru
e), |
| 207 'parameters': parameter_check_parameters, |
| 208 'function_call_parameter': function_call_parameters, |
| 209 'method_for_main_world': method_for_main_world, |
| 210 'is_normal_function': is_normal_function, |
| 211 'is_standard_function': is_standard_function, |
| 212 'is_enabled_per_context_function': function.name and 'EnabledPerContext'
in function.extended_attributes, |
| 213 'raises_exception': raises_exception, |
| 214 'do_not_check_security': 'DoNotCheckSecurity' in function.extended_attri
butes, |
| 215 'for_main_world_suffixes': for_main_world_suffixes, |
| 216 'cpp_name': implemented_as_cpp_name(function), |
| 217 'check_security_for_node': check_security_for_node, |
| 218 'enable_function': enable_function, |
| 219 'activity_logging': activity_logging, |
| 220 } |
| 221 contents.update(feature_observation_parameter) |
| 222 contents.update(deprecation_notification_parameter) |
| 223 contents.update(custom_element_invocation_scope_parameter) |
| 224 return contents, includes |
| 225 |
| 226 |
| 227 def get_function_call_parameter(interface, function, number_of_parameters=None,
for_main_world_suffix='', replacements=None): |
| 228 # return parameter for function_call macro, includes |
| 229 replacements = replacements or {} |
| 230 if number_of_parameters is None: |
| 231 number_of_parameters = len(function.arguments) |
| 232 |
| 233 includes = [] |
| 234 arguments = [] |
| 235 cpp_class_name = implemented_as_cpp_name(interface) |
| 236 implemented_by = function.extended_attributes.get('ImplementedBy') |
| 237 ### TODO Similar to attribute. merge! |
| 238 if implemented_by: |
| 239 implemented_by_cpp_name = implemented_as_from_implemented_by(implemented
_by) |
| 240 includes += header_files_for_interface(implemented_by, implemented_by_cp
p_name) |
| 241 function_name = '%s::%s' % (implemented_by_cpp_name, implemented_as_cpp_
name(function)) |
| 242 if not function.is_static: |
| 243 arguments.append('imp') |
| 244 elif function.is_static: |
| 245 function_name = '%s::%s' % (cpp_class_name, implemented_as_cpp_name(func
tion)) |
| 246 else: |
| 247 function_name = 'imp->%s' % implemented_as_cpp_name(function) |
| 248 |
| 249 call_with = function.extended_attributes.get('CallWith') |
| 250 call_with_arguments, call_with_parameter, call_with_includes = get_call_with
_parameter(call_with, return_void=True, function=function) |
| 251 includes += call_with_includes |
| 252 arguments = call_with_arguments + arguments |
| 253 |
| 254 parameters = [] |
| 255 for index, parameter in enumerate(function.arguments): |
| 256 svg_tear_off_and_not_list = False |
| 257 if index == number_of_parameters: |
| 258 break |
| 259 if replacements.get(parameter.name): |
| 260 arguments.append(replacements.get(parameter.name)) |
| 261 elif parameter.data_type == 'NodeFilter' or parameter.data_type == 'XPat
hNSResolver': |
| 262 arguments.append('%s.get()' % parameter.name) |
| 263 elif get_svg_type_needing_tear_off(parameter.data_type) and not interfac
e.name.endswith('List'): |
| 264 includes.append('core/dom/ExceptionCode.h') |
| 265 arguments.append('%s->propertyReference()' % parameter.name) |
| 266 svg_tear_off_and_not_list = True |
| 267 elif parameter.data_type == 'SVGMatrix' and interface.name == 'SVGTransf
ormList': |
| 268 arguments.append('%s.get()' % parameter.name) |
| 269 else: |
| 270 arguments.append(parameter.name) |
| 271 parameter = { |
| 272 'svg_tear_off_and_not_list': svg_tear_off_and_not_list, |
| 273 'name': parameter.name, |
| 274 } |
| 275 parameters.append(parameter) |
| 276 |
| 277 if get_raises_exception(function): |
| 278 arguments.append('es') |
| 279 |
| 280 function_call_expression = '%s(%s)' % (function_name, ', '.join(arguments)) |
| 281 native_value_expression = get_pass_owner_expression(function.data_type, 'res
ult') |
| 282 function_call_statement = '' |
| 283 if function.data_type == 'void': |
| 284 function_call_statement = '%s;' % function_call_expression |
| 285 elif extended_attribute_contains(function.extended_attributes.get('CallWith'
), 'ScriptState') or get_raises_exception(function): |
| 286 function_call_statement = '%s result = %s;' % (get_native_type(function.
data_type, extended_attributes=function.extended_attributes), function_call_expr
ession) |
| 287 else: |
| 288 native_value_expression = function_call_expression |
| 289 |
| 290 extended_attribute_contains_script_state = extended_attribute_contains(call_
with, 'ScriptState') |
| 291 |
| 292 script_wrappable = is_dom_node_type(interface.name) and 'imp' or 0 |
| 293 return_js_value_statement = '' |
| 294 return_js_value_statement, native_to_js_value_includes = get_native_to_js_va
lue_statement(function.data_type, function.extended_attributes, native_value_exp
ression, creation_context='args.Holder()', isolate='args.GetIsolate()', callback
_info='args', script_wrappable=script_wrappable, for_main_world_suffix=for_main_
world_suffix, used_as_return_value=True) |
| 295 includes += native_to_js_value_includes |
| 296 # print '[----]', function.name |
| 297 |
| 298 svg_native_type = svg_tear_off = get_svg_type_needing_tear_off(function.data
_type) |
| 299 svg_tear_off_and_not_list = svg_tear_off and not interface.name.endswith('Li
st') |
| 300 dom_node_type = is_dom_node_type(interface.name) |
| 301 if svg_tear_off_and_not_list: |
| 302 includes.append('V8%s.h' % function.data_type) |
| 303 includes.append('core/svg/properties/SVGPropertyTearOff.h') |
| 304 |
| 305 parameter = { |
| 306 'statement': function_call_statement, |
| 307 'raises_exception': get_raises_exception(function), |
| 308 'return_js_value_statement': return_js_value_statement, |
| 309 'extended_attribute_contains_script_state': extended_attribute_contains_
script_state, |
| 310 'call_with': call_with_parameter, |
| 311 'parameters': parameters, |
| 312 'svg_tear_off_and_not_list': svg_tear_off_and_not_list, |
| 313 'svg_tear_off': svg_tear_off, |
| 314 'is_dom_node_type': dom_node_type, |
| 315 'for_main_world_suffix': for_main_world_suffix, |
| 316 'svg_native_type': svg_native_type, |
| 317 'native_value_expression': native_value_expression, |
| 318 } |
| 319 return parameter, includes |
| 320 |
| 321 |
| 322 def get_function_mandatory_parameters(function, count_variadic=False): |
| 323 allow_non_optional = True |
| 324 for parameter in function.arguments: |
| 325 if parameter.is_optional or parameter.is_variadic: |
| 326 allow_non_optional = False |
| 327 else: |
| 328 if not allow_non_optional: |
| 329 raise Exception() |
| 330 mandatory_parameters = 0 |
| 331 for parameter in function.arguments: |
| 332 if parameter.is_optional: |
| 333 break |
| 334 if parameter.is_variadic and not count_variadic: |
| 335 break |
| 336 mandatory_parameters += 1 |
| 337 # print '[]', function.name, mandatory_parameters |
| 338 return mandatory_parameters |
| 339 |
| 340 |
| 341 def get_parameter_check_parameters(interface, function, for_main_world_suffix=''
): |
| 342 # GenerateParametersCheck in perl |
| 343 includes = [] |
| 344 parameters_check_parameter = [] |
| 345 for parameter_index in range(len(function.arguments)): |
| 346 parameter_check_parameter, parameter_check_includes = get_parameter_chec
k_parameter(interface, function, parameter_index) |
| 347 parameters_check_parameter.append(parameter_check_parameter) |
| 348 includes += parameter_check_includes |
| 349 replacements = {} # TODO |
| 350 return parameters_check_parameter, includes, replacements |
| 351 |
| 352 |
| 353 def get_parameter_check_parameter(interface, function, parameter_index, for_main
_world_suffix=''): |
| 354 # corresponds to for loop in GenerateParametersCheck in perl |
| 355 includes = ['bindings/v8/ExceptionState.h'] |
| 356 parameter = function.arguments[parameter_index] |
| 357 is_callback_interface = is_callback_interface_etc(parameter.data_type) |
| 358 if is_callback_interface: |
| 359 includes.append('V8%s.h' % parameter.data_type) |
| 360 if parameter.data_type == 'SerializedScriptValue': |
| 361 includes.append('bindings/v8/SerializedScriptValue.h') |
| 362 is_index = 'IsIndex' in parameter.extended_attributes |
| 363 if is_index: |
| 364 includes.append('core/dom/ExceptionCode.h') |
| 365 |
| 366 native_type = get_native_type(parameter.data_type, extended_attributes=param
eter.extended_attributes, used_to_assign_js_value=True) |
| 367 native_element_type = get_native_type(parameter.data_type) |
| 368 if native_element_type.endswith('>'): |
| 369 native_element_type += ' ' |
| 370 |
| 371 # print '[[]]', native_type |
| 372 default = '' |
| 373 if 'Default' in parameter.extended_attributes: |
| 374 default = parameter.extended_attributes.get('Default') |
| 375 |
| 376 if parameter.is_optional and default == 'NullString': |
| 377 js_value = 'argumentOrNull(args, %d)' % parameter_index |
| 378 else: |
| 379 js_value = 'args[%d]' % parameter_index |
| 380 |
| 381 js_to_native_statement, js_value_to_native_includes = get_js_value_to_native
_statement(parameter.data_type, parameter.extended_attributes, js_value, paramet
er.name, 'args.GetIsolate()') |
| 382 includes += js_value_to_native_includes |
| 383 |
| 384 enum_values = get_enum_values(parameter.data_type) |
| 385 enum_validation_terms = ['string == "%s"' % enum_value for enum_value in enu
m_values] |
| 386 enum_validation_expression = ' || '.join(enum_validation_terms) |
| 387 |
| 388 # Optional arguments without [Default=...] should generate an early call wit
h fewer arguments. |
| 389 # Optional arguments with [Optional=...] should not generate the early call. |
| 390 # Optional Dictionary arguments always considered to have default of empty d
ictionary. |
| 391 early_call = parameter.is_optional and 'Default' not in parameter.extended_a
ttributes and native_type != 'Dictionary' and not is_callback_interface |
| 392 early_call_multi_line = False |
| 393 early_call_statements = {} |
| 394 if early_call: |
| 395 # TODO |
| 396 early_call_statements, early_call_includes = get_function_call_parameter
(interface, function, parameter_index, for_main_world_suffix=for_main_world_suff
ix) |
| 397 includes += early_call_includes |
| 398 early_call_multi_line = len([c for c in early_call_statements if c == '\
n']) > 1 |
| 399 |
| 400 parameter_check_parameter = { |
| 401 'index': parameter_index, |
| 402 'name': parameter.name, |
| 403 'type': parameter.data_type, |
| 404 'early_call': early_call, |
| 405 'early_call_statement_parameter': early_call_statements, |
| 406 'early_call_multi_line': early_call_multi_line, |
| 407 'is_callback_interface': is_callback_interface, |
| 408 'is_optional': parameter.is_optional, |
| 409 'is_variadic': parameter.is_variadic, |
| 410 'is_index': is_index, |
| 411 'is_wrapper_type': is_wrapper_type(parameter.data_type), |
| 412 'clamp': parameter.extended_attributes.get('Clamp'), |
| 413 'strict_type_checking': parameter.extended_attributes.get('StrictTypeChe
cking'), |
| 414 'enforce_range': 'EnforceRange' in parameter.extended_attributes, |
| 415 'js_to_native_statement': js_to_native_statement, |
| 416 'native_type': native_type, |
| 417 'native_element_type': native_element_type, |
| 418 'enum_validation_expression': enum_validation_expression, |
| 419 'is_enum_type': is_enum_type(parameter.data_type), |
| 420 } |
| 421 return parameter_check_parameter, includes |
OLD | NEW |