| 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 an interface. | |
| 30 | |
| 31 FIXME: Not currently used in build. | |
| 32 This is a rewrite of the Perl IDL compiler in Python, but is not complete. | |
| 33 Once it is complete, we will switch all IDL files over to Python at once. | |
| 34 Until then, please work on the Perl IDL compiler. | |
| 35 For details, see bug http://crbug.com/239771 | |
| 36 """ | |
| 37 | |
| 38 import v8_attributes | |
| 39 from v8_globals import includes | |
| 40 import v8_methods | |
| 41 import v8_types | |
| 42 from v8_types import inherits_interface, is_interface_type | |
| 43 import v8_utilities | |
| 44 from v8_utilities import capitalize, conditional_string, cpp_name, has_extended_
attribute_value, runtime_enabled_function_name | |
| 45 | |
| 46 | |
| 47 INTERFACE_H_INCLUDES = frozenset([ | |
| 48 'bindings/v8/V8Binding.h', | |
| 49 'bindings/v8/V8DOMWrapper.h', | |
| 50 'bindings/v8/WrapperTypeInfo.h', | |
| 51 'heap/Handle.h', | |
| 52 ]) | |
| 53 INTERFACE_CPP_INCLUDES = frozenset([ | |
| 54 'RuntimeEnabledFeatures.h', | |
| 55 'bindings/v8/ExceptionState.h', | |
| 56 'bindings/v8/V8DOMConfiguration.h', | |
| 57 'bindings/v8/V8ObjectConstructor.h', | |
| 58 'core/dom/ContextFeatures.h', | |
| 59 'core/dom/Document.h', | |
| 60 'platform/TraceEvent.h', | |
| 61 'wtf/GetPtr.h', # FIXME: remove if can eliminate WTF::getPtr | |
| 62 'wtf/RefPtr.h', | |
| 63 ]) | |
| 64 | |
| 65 | |
| 66 def generate_interface(interface): | |
| 67 includes.clear() | |
| 68 includes.update(INTERFACE_CPP_INCLUDES) | |
| 69 header_includes = set(INTERFACE_H_INCLUDES) | |
| 70 | |
| 71 parent_interface = interface.parent | |
| 72 if parent_interface: | |
| 73 header_includes.update(v8_types.includes_for_type(parent_interface)) | |
| 74 extended_attributes = interface.extended_attributes | |
| 75 | |
| 76 is_audio_buffer = inherits_interface(interface.name, 'AudioBuffer') | |
| 77 if is_audio_buffer: | |
| 78 includes.add('modules/webaudio/AudioBuffer.h') | |
| 79 | |
| 80 is_document = inherits_interface(interface.name, 'Document') | |
| 81 if is_document: | |
| 82 includes.update(['bindings/v8/ScriptController.h', | |
| 83 'bindings/v8/V8WindowShell.h', | |
| 84 'core/frame/LocalFrame.h']) | |
| 85 | |
| 86 # [CheckSecurity] | |
| 87 is_check_security = 'CheckSecurity' in extended_attributes | |
| 88 if is_check_security: | |
| 89 includes.add('bindings/v8/BindingSecurity.h') | |
| 90 | |
| 91 # [MeasureAs] | |
| 92 is_measure_as = 'MeasureAs' in extended_attributes | |
| 93 if is_measure_as: | |
| 94 includes.add('core/frame/UseCounter.h') | |
| 95 | |
| 96 # [SetWrapperReferenceFrom] | |
| 97 reachable_node_function = extended_attributes.get('SetWrapperReferenceFrom') | |
| 98 reachable_node_reference_function = extended_attributes.get('SetWrapperRefer
enceFromReference') | |
| 99 if reachable_node_function or reachable_node_reference_function: | |
| 100 includes.update(['bindings/v8/V8GCController.h', | |
| 101 'core/dom/Element.h']) | |
| 102 | |
| 103 # [SetWrapperReferenceTo] | |
| 104 set_wrapper_reference_to_list = [{ | |
| 105 'name': argument.name, | |
| 106 # FIXME: properly should be: | |
| 107 # 'cpp_type': v8_types.cpp_type(argument.idl_type, used_as_argument=True
), | |
| 108 # (if type is non-wrapper type like NodeFilter, normally RefPtr) | |
| 109 # Raw pointers faster though, and NodeFilter hacky anyway. | |
| 110 'cpp_type': v8_types.implemented_as(argument.idl_type) + '*', | |
| 111 'idl_type': argument.idl_type, | |
| 112 'v8_type': v8_types.v8_type(argument.idl_type), | |
| 113 } for argument in extended_attributes.get('SetWrapperReferenceTo', [])] | |
| 114 for set_wrapper_reference_to in set_wrapper_reference_to_list: | |
| 115 v8_types.add_includes_for_type(set_wrapper_reference_to['idl_type']) | |
| 116 | |
| 117 # [SpecialWrapFor] | |
| 118 if 'SpecialWrapFor' in extended_attributes: | |
| 119 special_wrap_for = extended_attributes['SpecialWrapFor'].split('|') | |
| 120 else: | |
| 121 special_wrap_for = [] | |
| 122 for special_wrap_interface in special_wrap_for: | |
| 123 v8_types.add_includes_for_type(special_wrap_interface) | |
| 124 | |
| 125 # [WillBeGarbageCollected] | |
| 126 is_will_be_garbage_collected = 'WillBeGarbageCollected' in extended_attribut
es | |
| 127 | |
| 128 template_contents = { | |
| 129 'conditional_string': conditional_string(interface), # [Conditional] | |
| 130 'cpp_class': cpp_name(interface), | |
| 131 'has_custom_legacy_call_as_function': has_extended_attribute_value(inter
face, 'Custom', 'LegacyCallAsFunction'), # [Custom=LegacyCallAsFunction] | |
| 132 'has_custom_to_v8': has_extended_attribute_value(interface, 'Custom', 'T
oV8'), # [Custom=ToV8] | |
| 133 'has_custom_wrap': has_extended_attribute_value(interface, 'Custom', 'Wr
ap'), # [Custom=Wrap] | |
| 134 'has_visit_dom_wrapper': ( | |
| 135 # [Custom=Wrap], [SetWrapperReferenceFrom] | |
| 136 has_extended_attribute_value(interface, 'Custom', 'VisitDOMWrapper')
or | |
| 137 reachable_node_function or | |
| 138 reachable_node_reference_function or | |
| 139 set_wrapper_reference_to_list), | |
| 140 'header_includes': header_includes, | |
| 141 'interface_name': interface.name, | |
| 142 'is_active_dom_object': 'ActiveDOMObject' in extended_attributes, # [Ac
tiveDOMObject] | |
| 143 'is_audio_buffer': is_audio_buffer, | |
| 144 'is_check_security': is_check_security, | |
| 145 'is_dependent_lifetime': 'DependentLifetime' in extended_attributes, #
[DependentLifetime] | |
| 146 'is_document': is_document, | |
| 147 'is_event_target': inherits_interface(interface.name, 'EventTarget'), | |
| 148 'is_exception': interface.is_exception, | |
| 149 'is_will_be_garbage_collected': is_will_be_garbage_collected, | |
| 150 'is_node': inherits_interface(interface.name, 'Node'), | |
| 151 'measure_as': v8_utilities.measure_as(interface), # [MeasureAs] | |
| 152 'parent_interface': parent_interface, | |
| 153 'pass_ref_ptr': 'PassRefPtrWillBeRawPtr' | |
| 154 if is_will_be_garbage_collected else 'PassRefPtr', | |
| 155 'reachable_node_function': reachable_node_function, | |
| 156 'reachable_node_reference_function': reachable_node_reference_function, | |
| 157 'ref_ptr': 'RefPtrWillBeRawPtr' | |
| 158 if is_will_be_garbage_collected else 'RefPtr', | |
| 159 'runtime_enabled_function': runtime_enabled_function_name(interface), #
[RuntimeEnabled] | |
| 160 'set_wrapper_reference_to_list': set_wrapper_reference_to_list, | |
| 161 'special_wrap_for': special_wrap_for, | |
| 162 'v8_class': v8_utilities.v8_class_name(interface), | |
| 163 } | |
| 164 | |
| 165 # Constructors | |
| 166 constructors = [generate_constructor(interface, constructor) | |
| 167 for constructor in interface.constructors | |
| 168 # FIXME: shouldn't put named constructors with constructors | |
| 169 # (currently needed for Perl compatibility) | |
| 170 # Handle named constructors separately | |
| 171 if constructor.name == 'Constructor'] | |
| 172 generate_constructor_overloads(constructors) | |
| 173 | |
| 174 # [CustomConstructor] | |
| 175 custom_constructors = [{ # Only needed for computing interface length | |
| 176 'number_of_required_arguments': | |
| 177 number_of_required_arguments(constructor), | |
| 178 } for constructor in interface.custom_constructors] | |
| 179 | |
| 180 # [EventConstructor] | |
| 181 has_event_constructor = 'EventConstructor' in extended_attributes | |
| 182 any_type_attributes = [attribute for attribute in interface.attributes | |
| 183 if attribute.idl_type == 'any'] | |
| 184 if has_event_constructor: | |
| 185 includes.add('bindings/v8/Dictionary.h') | |
| 186 if any_type_attributes: | |
| 187 includes.add('bindings/v8/SerializedScriptValue.h') | |
| 188 | |
| 189 # [NamedConstructor] | |
| 190 named_constructor = generate_named_constructor(interface) | |
| 191 | |
| 192 if (constructors or custom_constructors or has_event_constructor or | |
| 193 named_constructor): | |
| 194 includes.add('bindings/v8/V8ObjectConstructor.h') | |
| 195 | |
| 196 template_contents.update({ | |
| 197 'any_type_attributes': any_type_attributes, | |
| 198 'constructors': constructors, | |
| 199 'has_custom_constructor': bool(custom_constructors), | |
| 200 'has_event_constructor': has_event_constructor, | |
| 201 'interface_length': | |
| 202 interface_length(interface, constructors + custom_constructors), | |
| 203 'is_constructor_call_with_document': has_extended_attribute_value( | |
| 204 interface, 'ConstructorCallWith', 'Document'), # [ConstructorCallWi
th=Document] | |
| 205 'is_constructor_call_with_execution_context': has_extended_attribute_val
ue( | |
| 206 interface, 'ConstructorCallWith', 'ExecutionContext'), # [Construct
orCallWith=ExeuctionContext] | |
| 207 'is_constructor_raises_exception': extended_attributes.get('RaisesExcept
ion') == 'Constructor', # [RaisesException=Constructor] | |
| 208 'named_constructor': named_constructor, | |
| 209 }) | |
| 210 | |
| 211 # Constants | |
| 212 template_contents.update({ | |
| 213 'constants': [generate_constant(constant) for constant in interface.cons
tants], | |
| 214 'do_not_check_constants': 'DoNotCheckConstants' in extended_attributes, | |
| 215 }) | |
| 216 | |
| 217 # Attributes | |
| 218 attributes = [v8_attributes.generate_attribute(interface, attribute) | |
| 219 for attribute in interface.attributes] | |
| 220 template_contents.update({ | |
| 221 'attributes': attributes, | |
| 222 'has_accessors': any(attribute['is_expose_js_accessors'] for attribute i
n attributes), | |
| 223 'has_attribute_configuration': any( | |
| 224 not (attribute['is_expose_js_accessors'] or | |
| 225 attribute['is_static'] or | |
| 226 attribute['runtime_enabled_function'] or | |
| 227 attribute['per_context_enabled_function']) | |
| 228 for attribute in attributes), | |
| 229 'has_constructor_attributes': any(attribute['constructor_type'] for attr
ibute in attributes), | |
| 230 'has_per_context_enabled_attributes': any(attribute['per_context_enabled
_function'] for attribute in attributes), | |
| 231 'has_replaceable_attributes': any(attribute['is_replaceable'] for attrib
ute in attributes), | |
| 232 }) | |
| 233 | |
| 234 # Methods | |
| 235 methods = [v8_methods.generate_method(interface, method) | |
| 236 for method in interface.operations | |
| 237 if method.name] # Skip anonymous special operations (methods) | |
| 238 generate_overloads(methods) | |
| 239 for method in methods: | |
| 240 method['do_generate_method_configuration'] = ( | |
| 241 method['do_not_check_signature'] and | |
| 242 not method['per_context_enabled_function'] and | |
| 243 # For overloaded methods, only generate one accessor | |
| 244 ('overload_index' not in method or method['overload_index'] == 1)) | |
| 245 | |
| 246 template_contents.update({ | |
| 247 'has_origin_safe_method_setter': any( | |
| 248 method['is_check_security_for_frame'] and not method['is_read_only'] | |
| 249 for method in methods), | |
| 250 'has_method_configuration': any(method['do_generate_method_configuration
'] for method in methods), | |
| 251 'has_per_context_enabled_methods': any(method['per_context_enabled_funct
ion'] for method in methods), | |
| 252 'methods': methods, | |
| 253 }) | |
| 254 | |
| 255 template_contents.update({ | |
| 256 'indexed_property_getter': indexed_property_getter(interface), | |
| 257 'indexed_property_setter': indexed_property_setter(interface), | |
| 258 'indexed_property_deleter': indexed_property_deleter(interface), | |
| 259 'is_override_builtins': 'OverrideBuiltins' in extended_attributes, | |
| 260 'named_property_getter': named_property_getter(interface), | |
| 261 'named_property_setter': named_property_setter(interface), | |
| 262 'named_property_deleter': named_property_deleter(interface), | |
| 263 }) | |
| 264 | |
| 265 return template_contents | |
| 266 | |
| 267 | |
| 268 # [DeprecateAs], [Reflect], [RuntimeEnabled] | |
| 269 def generate_constant(constant): | |
| 270 # (Blink-only) string literals are unquoted in tokenizer, must be re-quoted | |
| 271 # in C++. | |
| 272 if constant.idl_type == 'DOMString': | |
| 273 value = '"%s"' % constant.value | |
| 274 else: | |
| 275 value = constant.value | |
| 276 | |
| 277 extended_attributes = constant.extended_attributes | |
| 278 return { | |
| 279 'cpp_class': extended_attributes.get('ImplementedBy'), | |
| 280 'name': constant.name, | |
| 281 # FIXME: use 'reflected_name' as correct 'name' | |
| 282 'reflected_name': extended_attributes.get('Reflect', constant.name), | |
| 283 'runtime_enabled_function': runtime_enabled_function_name(constant), | |
| 284 'value': value, | |
| 285 } | |
| 286 | |
| 287 | |
| 288 ################################################################################ | |
| 289 # Overloads | |
| 290 ################################################################################ | |
| 291 | |
| 292 def generate_overloads(methods): | |
| 293 generate_overloads_by_type(methods, is_static=False) # Regular methods | |
| 294 generate_overloads_by_type(methods, is_static=True) | |
| 295 | |
| 296 | |
| 297 def generate_overloads_by_type(methods, is_static): | |
| 298 # Generates |overloads| template values and modifies |methods| in place; | |
| 299 # |is_static| flag used (instead of partitioning list in 2) because need to | |
| 300 # iterate over original list of methods to modify in place | |
| 301 method_counts = {} | |
| 302 for method in methods: | |
| 303 if method['is_static'] != is_static: | |
| 304 continue | |
| 305 name = method['name'] | |
| 306 method_counts.setdefault(name, 0) | |
| 307 method_counts[name] += 1 | |
| 308 | |
| 309 # Filter to only methods that are actually overloaded | |
| 310 overloaded_method_counts = dict((name, count) | |
| 311 for name, count in method_counts.iteritems() | |
| 312 if count > 1) | |
| 313 | |
| 314 # Add overload information only to overloaded methods, so template code can | |
| 315 # easily verify if a function is overloaded | |
| 316 method_overloads = {} | |
| 317 for method in methods: | |
| 318 name = method['name'] | |
| 319 if (method['is_static'] != is_static or | |
| 320 name not in overloaded_method_counts): | |
| 321 continue | |
| 322 # Overload index includes self, so first append, then compute index | |
| 323 method_overloads.setdefault(name, []).append(method) | |
| 324 method.update({ | |
| 325 'overload_index': len(method_overloads[name]), | |
| 326 'overload_resolution_expression': overload_resolution_expression(met
hod), | |
| 327 }) | |
| 328 | |
| 329 # Resolution function is generated after last overloaded function; | |
| 330 # package necessary information into |method.overloads| for that method. | |
| 331 for method in methods: | |
| 332 if (method['is_static'] != is_static or | |
| 333 'overload_index' not in method): | |
| 334 continue | |
| 335 name = method['name'] | |
| 336 if method['overload_index'] != overloaded_method_counts[name]: | |
| 337 continue | |
| 338 overloads = method_overloads[name] | |
| 339 minimum_number_of_required_arguments = min( | |
| 340 overload['number_of_required_arguments'] | |
| 341 for overload in overloads) | |
| 342 method['overloads'] = { | |
| 343 'has_exception_state': bool(minimum_number_of_required_arguments), | |
| 344 'methods': overloads, | |
| 345 'minimum_number_of_required_arguments': minimum_number_of_required_a
rguments, | |
| 346 'name': name, | |
| 347 } | |
| 348 | |
| 349 | |
| 350 def overload_resolution_expression(method): | |
| 351 # Expression is an OR of ANDs: each term in the OR corresponds to a | |
| 352 # possible argument count for a given method, with type checks. | |
| 353 # FIXME: Blink's overload resolution algorithm is incorrect, per: | |
| 354 # Implement WebIDL overload resolution algorithm. | |
| 355 # https://code.google.com/p/chromium/issues/detail?id=293561 | |
| 356 # | |
| 357 # Currently if distinguishing non-primitive type from primitive type, | |
| 358 # (e.g., sequence<DOMString> from DOMString or Dictionary from double) | |
| 359 # the method with a non-primitive type argument must appear *first* in the | |
| 360 # IDL file, since we're not adding a check to primitive types. | |
| 361 # FIXME: Once fixed, check IDLs, as usually want methods with primitive | |
| 362 # types to appear first (style-wise). | |
| 363 # | |
| 364 # Properly: | |
| 365 # 1. Compute effective overload set. | |
| 366 # 2. First check type list length. | |
| 367 # 3. If multiple entries for given length, compute distinguishing argument | |
| 368 # index and have check for that type. | |
| 369 arguments = method['arguments'] | |
| 370 overload_checks = [overload_check_expression(method, index) | |
| 371 # check *omitting* optional arguments at |index| and up: | |
| 372 # index 0 => argument_count 0 (no arguments) | |
| 373 # index 1 => argument_count 1 (index 0 argument only) | |
| 374 for index, argument in enumerate(arguments) | |
| 375 if argument['is_optional']] | |
| 376 # FIXME: this is wrong if a method has optional arguments and a variadic | |
| 377 # one, though there are not yet any examples of this | |
| 378 if not method['is_variadic']: | |
| 379 # Includes all optional arguments (len = last index + 1) | |
| 380 overload_checks.append(overload_check_expression(method, len(arguments))
) | |
| 381 return ' || '.join('(%s)' % check for check in overload_checks) | |
| 382 | |
| 383 | |
| 384 def overload_check_expression(method, argument_count): | |
| 385 overload_checks = ['info.Length() == %s' % argument_count] | |
| 386 arguments = method['arguments'][:argument_count] | |
| 387 overload_checks.extend(overload_check_argument(index, argument) | |
| 388 for index, argument in | |
| 389 enumerate(arguments)) | |
| 390 return ' && '.join('(%s)' % check for check in overload_checks if check) | |
| 391 | |
| 392 | |
| 393 def overload_check_argument(index, argument): | |
| 394 def null_or_optional_check(): | |
| 395 # If undefined is passed for an optional argument, the argument should | |
| 396 # be treated as missing; otherwise undefined is not allowed. | |
| 397 if argument['is_nullable']: | |
| 398 if argument['is_optional']: | |
| 399 return 'isUndefinedOrNull(%s)' | |
| 400 return '%s->IsNull()' | |
| 401 if argument['is_optional']: | |
| 402 return '%s->IsUndefined()' | |
| 403 return None | |
| 404 | |
| 405 cpp_value = 'info[%s]' % index | |
| 406 idl_type = argument['idl_type'] | |
| 407 # FIXME: proper type checking, sharing code with attributes and methods | |
| 408 if idl_type == 'DOMString' and argument['is_strict_type_checking']: | |
| 409 return ' || '.join(['isUndefinedOrNull(%s)' % cpp_value, | |
| 410 '%s->IsString()' % cpp_value, | |
| 411 '%s->IsObject()' % cpp_value]) | |
| 412 if v8_types.array_or_sequence_type(idl_type): | |
| 413 return '%s->IsArray()' % cpp_value | |
| 414 if v8_types.is_callback_interface(idl_type): | |
| 415 return ' || '.join(['%s->IsNull()' % cpp_value, | |
| 416 '%s->IsFunction()' % cpp_value]) | |
| 417 if v8_types.is_wrapper_type(idl_type): | |
| 418 type_check = 'V8{idl_type}::hasInstance({cpp_value}, info.GetIsolate())'
.format(idl_type=idl_type, cpp_value=cpp_value) | |
| 419 if argument['is_nullable']: | |
| 420 type_check = ' || '.join(['%s->IsNull()' % cpp_value, type_check]) | |
| 421 return type_check | |
| 422 if is_interface_type(idl_type): | |
| 423 # Non-wrapper types are just objects: we don't distinguish type | |
| 424 # We only allow undefined for non-wrapper types (notably Dictionary), | |
| 425 # as we need it for optional Dictionary arguments, but we don't want to | |
| 426 # change behavior of existing bindings for other types. | |
| 427 type_check = '%s->IsObject()' % cpp_value | |
| 428 added_check_template = null_or_optional_check() | |
| 429 if added_check_template: | |
| 430 type_check = ' || '.join([added_check_template % cpp_value, | |
| 431 type_check]) | |
| 432 return type_check | |
| 433 return None | |
| 434 | |
| 435 | |
| 436 ################################################################################ | |
| 437 # Constructors | |
| 438 ################################################################################ | |
| 439 | |
| 440 # [Constructor] | |
| 441 def generate_constructor(interface, constructor): | |
| 442 return { | |
| 443 'argument_list': constructor_argument_list(interface, constructor), | |
| 444 'arguments': [constructor_argument(argument, index) | |
| 445 for index, argument in enumerate(constructor.arguments)], | |
| 446 'has_exception_state': | |
| 447 # [RaisesException=Constructor] | |
| 448 interface.extended_attributes.get('RaisesException') == 'Constructor
' or | |
| 449 any(argument for argument in constructor.arguments | |
| 450 if argument.idl_type == 'SerializedScriptValue' or | |
| 451 v8_types.is_integer_type(argument.idl_type)), | |
| 452 'is_constructor': True, | |
| 453 'is_variadic': False, # Required for overload resolution | |
| 454 'number_of_required_arguments': | |
| 455 number_of_required_arguments(constructor), | |
| 456 } | |
| 457 | |
| 458 | |
| 459 def constructor_argument_list(interface, constructor): | |
| 460 arguments = [] | |
| 461 # [ConstructorCallWith=ExecutionContext] | |
| 462 if has_extended_attribute_value(interface, 'ConstructorCallWith', 'Execution
Context'): | |
| 463 arguments.append('context') | |
| 464 # [ConstructorCallWith=Document] | |
| 465 if has_extended_attribute_value(interface, 'ConstructorCallWith', 'Document'
): | |
| 466 arguments.append('document') | |
| 467 | |
| 468 arguments.extend([argument.name for argument in constructor.arguments]) | |
| 469 | |
| 470 # [RaisesException=Constructor] | |
| 471 if interface.extended_attributes.get('RaisesException') == 'Constructor': | |
| 472 arguments.append('exceptionState') | |
| 473 | |
| 474 return arguments | |
| 475 | |
| 476 | |
| 477 def constructor_argument(argument, index): | |
| 478 return { | |
| 479 'has_default': 'Default' in argument.extended_attributes, | |
| 480 'idl_type': argument.idl_type, | |
| 481 'index': index, | |
| 482 'is_nullable': False, # Required for overload resolution | |
| 483 'is_optional': argument.is_optional, | |
| 484 'is_strict_type_checking': False, # Required for overload resolution | |
| 485 'name': argument.name, | |
| 486 'v8_value_to_local_cpp_value': | |
| 487 v8_methods.v8_value_to_local_cpp_value(argument, index), | |
| 488 } | |
| 489 | |
| 490 | |
| 491 def generate_constructor_overloads(constructors): | |
| 492 if len(constructors) <= 1: | |
| 493 return | |
| 494 for overload_index, constructor in enumerate(constructors): | |
| 495 constructor.update({ | |
| 496 'overload_index': overload_index + 1, | |
| 497 'overload_resolution_expression': | |
| 498 overload_resolution_expression(constructor), | |
| 499 }) | |
| 500 | |
| 501 | |
| 502 # [NamedConstructor] | |
| 503 def generate_named_constructor(interface): | |
| 504 extended_attributes = interface.extended_attributes | |
| 505 if 'NamedConstructor' not in extended_attributes: | |
| 506 return None | |
| 507 # FIXME: parser should return named constructor separately; | |
| 508 # included in constructors (and only name stored in extended attribute) | |
| 509 # for Perl compatibility | |
| 510 idl_constructor = interface.constructors[0] | |
| 511 constructor = generate_constructor(interface, idl_constructor) | |
| 512 constructor['argument_list'].insert(0, '*document') | |
| 513 constructor['name'] = extended_attributes['NamedConstructor'] | |
| 514 return constructor | |
| 515 | |
| 516 | |
| 517 def number_of_required_arguments(constructor): | |
| 518 return len([argument for argument in constructor.arguments | |
| 519 if not argument.is_optional]) | |
| 520 | |
| 521 | |
| 522 def interface_length(interface, constructors): | |
| 523 # Docs: http://heycam.github.io/webidl/#es-interface-call | |
| 524 if 'EventConstructor' in interface.extended_attributes: | |
| 525 return 1 | |
| 526 if not constructors: | |
| 527 return 0 | |
| 528 return min(constructor['number_of_required_arguments'] | |
| 529 for constructor in constructors) | |
| 530 | |
| 531 | |
| 532 ################################################################################ | |
| 533 # Special operations (methods) | |
| 534 # http://heycam.github.io/webidl/#idl-special-operations | |
| 535 ################################################################################ | |
| 536 | |
| 537 def property_getter(getter, cpp_arguments): | |
| 538 def is_null_expression(idl_type): | |
| 539 if v8_types.is_union_type(idl_type): | |
| 540 return ' && '.join('!result%sEnabled' % i | |
| 541 for i, _ in | |
| 542 enumerate(idl_type.union_member_types)) | |
| 543 if idl_type == 'DOMString': | |
| 544 return 'result.isNull()' | |
| 545 if is_interface_type(idl_type): | |
| 546 return '!result' | |
| 547 return '' | |
| 548 | |
| 549 idl_type = getter.idl_type | |
| 550 extended_attributes = getter.extended_attributes | |
| 551 is_raises_exception = 'RaisesException' in extended_attributes | |
| 552 | |
| 553 if v8_types.is_union_type(idl_type): | |
| 554 release = [v8_types.is_interface_type(union_member_type) | |
| 555 for union_member_type in idl_type.union_member_types] | |
| 556 else: | |
| 557 release = v8_types.is_interface_type(idl_type) | |
| 558 | |
| 559 # FIXME: make more generic, so can use v8_methods.cpp_value | |
| 560 cpp_method_name = 'imp->%s' % cpp_name(getter) | |
| 561 | |
| 562 if is_raises_exception: | |
| 563 cpp_arguments.append('exceptionState') | |
| 564 this_union_arguments = v8_methods.union_arguments(idl_type) | |
| 565 if this_union_arguments: | |
| 566 cpp_arguments.extend(this_union_arguments) | |
| 567 | |
| 568 cpp_value = '%s(%s)' % (cpp_method_name, ', '.join(cpp_arguments)) | |
| 569 | |
| 570 return { | |
| 571 'cpp_type': v8_types.cpp_type(idl_type), | |
| 572 'cpp_value': cpp_value, | |
| 573 'is_custom': | |
| 574 'Custom' in extended_attributes and | |
| 575 (not extended_attributes['Custom'] or | |
| 576 has_extended_attribute_value(getter, 'Custom', 'PropertyGetter')), | |
| 577 'is_custom_property_enumerator': has_extended_attribute_value( | |
| 578 getter, 'Custom', 'PropertyEnumerator'), | |
| 579 'is_custom_property_query': has_extended_attribute_value( | |
| 580 getter, 'Custom', 'PropertyQuery'), | |
| 581 'is_enumerable': 'NotEnumerable' not in extended_attributes, | |
| 582 'is_null_expression': is_null_expression(idl_type), | |
| 583 'is_raises_exception': is_raises_exception, | |
| 584 'name': cpp_name(getter), | |
| 585 'union_arguments': v8_methods.union_arguments(idl_type), | |
| 586 'v8_set_return_value': v8_types.v8_set_return_value(idl_type, 'result',
extended_attributes=extended_attributes, script_wrappable='imp', release=release
), | |
| 587 } | |
| 588 | |
| 589 | |
| 590 def property_setter(setter): | |
| 591 idl_type = setter.arguments[1].idl_type | |
| 592 extended_attributes = setter.extended_attributes | |
| 593 is_raises_exception = 'RaisesException' in extended_attributes | |
| 594 return { | |
| 595 'has_strict_type_checking': | |
| 596 'StrictTypeChecking' in extended_attributes and | |
| 597 v8_types.is_wrapper_type(idl_type), | |
| 598 'idl_type': idl_type, | |
| 599 'is_custom': 'Custom' in extended_attributes, | |
| 600 'has_exception_state': is_raises_exception or | |
| 601 v8_types.is_integer_type(idl_type), | |
| 602 'is_raises_exception': is_raises_exception, | |
| 603 'name': cpp_name(setter), | |
| 604 'v8_value_to_local_cpp_value': v8_types.v8_value_to_local_cpp_value( | |
| 605 idl_type, extended_attributes, 'jsValue', 'propertyValue'), | |
| 606 } | |
| 607 | |
| 608 | |
| 609 def property_deleter(deleter): | |
| 610 idl_type = deleter.idl_type | |
| 611 if idl_type != 'boolean': | |
| 612 raise Exception( | |
| 613 'Only deleters with boolean type are allowed, but type is "%s"' % | |
| 614 idl_type) | |
| 615 extended_attributes = deleter.extended_attributes | |
| 616 return { | |
| 617 'is_custom': 'Custom' in extended_attributes, | |
| 618 'is_raises_exception': 'RaisesException' in extended_attributes, | |
| 619 'name': cpp_name(deleter), | |
| 620 } | |
| 621 | |
| 622 | |
| 623 ################################################################################ | |
| 624 # Indexed properties | |
| 625 # http://heycam.github.io/webidl/#idl-indexed-properties | |
| 626 ################################################################################ | |
| 627 | |
| 628 def indexed_property_getter(interface): | |
| 629 try: | |
| 630 # Find indexed property getter, if present; has form: | |
| 631 # getter TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1) | |
| 632 getter = next( | |
| 633 method | |
| 634 for method in interface.operations | |
| 635 if ('getter' in method.specials and | |
| 636 len(method.arguments) == 1 and | |
| 637 method.arguments[0].idl_type == 'unsigned long')) | |
| 638 except StopIteration: | |
| 639 return None | |
| 640 | |
| 641 return property_getter(getter, ['index']) | |
| 642 | |
| 643 | |
| 644 def indexed_property_setter(interface): | |
| 645 try: | |
| 646 # Find indexed property setter, if present; has form: | |
| 647 # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG1, ARG_TYPE
ARG2) | |
| 648 setter = next( | |
| 649 method | |
| 650 for method in interface.operations | |
| 651 if ('setter' in method.specials and | |
| 652 len(method.arguments) == 2 and | |
| 653 method.arguments[0].idl_type == 'unsigned long')) | |
| 654 except StopIteration: | |
| 655 return None | |
| 656 | |
| 657 return property_setter(setter) | |
| 658 | |
| 659 | |
| 660 def indexed_property_deleter(interface): | |
| 661 try: | |
| 662 # Find indexed property deleter, if present; has form: | |
| 663 # deleter TYPE [OPTIONAL_IDENTIFIER](unsigned long ARG) | |
| 664 deleter = next( | |
| 665 method | |
| 666 for method in interface.operations | |
| 667 if ('deleter' in method.specials and | |
| 668 len(method.arguments) == 1 and | |
| 669 method.arguments[0].idl_type == 'unsigned long')) | |
| 670 except StopIteration: | |
| 671 return None | |
| 672 | |
| 673 return property_deleter(deleter) | |
| 674 | |
| 675 | |
| 676 ################################################################################ | |
| 677 # Named properties | |
| 678 # http://heycam.github.io/webidl/#idl-named-properties | |
| 679 ################################################################################ | |
| 680 | |
| 681 def named_property_getter(interface): | |
| 682 try: | |
| 683 # Find named property getter, if present; has form: | |
| 684 # getter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1) | |
| 685 getter = next( | |
| 686 method | |
| 687 for method in interface.operations | |
| 688 if ('getter' in method.specials and | |
| 689 len(method.arguments) == 1 and | |
| 690 method.arguments[0].idl_type == 'DOMString')) | |
| 691 except StopIteration: | |
| 692 return None | |
| 693 | |
| 694 getter.name = getter.name or 'anonymousNamedGetter' | |
| 695 return property_getter(getter, ['propertyName']) | |
| 696 | |
| 697 | |
| 698 def named_property_setter(interface): | |
| 699 try: | |
| 700 # Find named property setter, if present; has form: | |
| 701 # setter RETURN_TYPE [OPTIONAL_IDENTIFIER](DOMString ARG1, ARG_TYPE ARG2
) | |
| 702 setter = next( | |
| 703 method | |
| 704 for method in interface.operations | |
| 705 if ('setter' in method.specials and | |
| 706 len(method.arguments) == 2 and | |
| 707 method.arguments[0].idl_type == 'DOMString')) | |
| 708 except StopIteration: | |
| 709 return None | |
| 710 | |
| 711 return property_setter(setter) | |
| 712 | |
| 713 | |
| 714 def named_property_deleter(interface): | |
| 715 try: | |
| 716 # Find named property deleter, if present; has form: | |
| 717 # deleter TYPE [OPTIONAL_IDENTIFIER](DOMString ARG) | |
| 718 deleter = next( | |
| 719 method | |
| 720 for method in interface.operations | |
| 721 if ('deleter' in method.specials and | |
| 722 len(method.arguments) == 1 and | |
| 723 method.arguments[0].idl_type == 'DOMString')) | |
| 724 except StopIteration: | |
| 725 return None | |
| 726 | |
| 727 return property_deleter(deleter) | |
| OLD | NEW |