diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py')
-rw-r--r-- | chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py | 1850 |
1 files changed, 0 insertions, 1850 deletions
diff --git a/chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py b/chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py deleted file mode 100644 index 60a1adb309d..00000000000 --- a/chromium/third_party/blink/renderer/bindings/scripts/v8_interface.py +++ /dev/null @@ -1,1850 +0,0 @@ -# Copyright (C) 2013 Google Inc. All rights reserved. -# coding=utf-8 -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# pylint: disable=relative-import -"""Generate template values for an interface. - -Design doc: http://www.chromium.org/developers/design-documents/idl-compiler -""" -import os -import sys -from operator import or_ - -sys.path.append( - os.path.join(os.path.dirname(__file__), '..', '..', 'build', 'scripts')) -from blinkbuild.name_style_converter import NameStyleConverter -from idl_definitions import IdlAttribute, IdlOperation, IdlArgument -from idl_types import IdlType, inherits_interface -from overload_set_algorithm import effective_overload_set_by_length -from overload_set_algorithm import method_overloads_by_name - -import v8_attributes -from v8_globals import includes -import v8_methods -import v8_types -import v8_utilities -from v8_utilities import ( - binding_header_filename, context_enabled_feature_name, cpp_name_or_partial, - cpp_name, has_extended_attribute_value, runtime_enabled_feature_name) - -INTERFACE_H_INCLUDES = frozenset([ - 'bindings/core/v8/generated_code_helper.h', - 'bindings/core/v8/native_value_traits.h', - 'platform/bindings/script_wrappable.h', - 'bindings/core/v8/to_v8_for_core.h', - 'bindings/core/v8/v8_binding_for_core.h', - 'platform/bindings/v8_dom_wrapper.h', - 'platform/bindings/wrapper_type_info.h', - 'platform/heap/handle.h', -]) -INTERFACE_CPP_INCLUDES = frozenset([ - 'base/memory/scoped_refptr.h', - 'bindings/core/v8/native_value_traits_impl.h', - 'bindings/core/v8/v8_dom_configuration.h', - 'core/execution_context/execution_context.h', - 'platform/scheduler/public/cooperative_scheduling_manager.h', - 'platform/bindings/exception_messages.h', - 'platform/bindings/exception_state.h', - 'platform/bindings/v8_object_constructor.h', - 'platform/wtf/get_ptr.h', -]) - - -def filter_has_constant_configuration(constants): - return [ - constant for constant in constants - if not constant['measure_as'] and not constant['deprecate_as'] - and not constant['runtime_enabled_feature_name'] - and not constant['origin_trial_feature_name'] - ] - - -def filter_has_special_getter(constants): - return [ - constant for constant in constants - if constant['measure_as'] or constant['deprecate_as'] - ] - - -def filter_runtime_enabled(constants): - return [ - constant for constant in constants - if constant['runtime_enabled_feature_name'] - ] - - -def filter_origin_trial_enabled(constants): - return [ - constant for constant in constants - if constant['origin_trial_feature_name'] - ] - - -def constant_filters(): - return { - 'has_constant_configuration': filter_has_constant_configuration, - 'has_special_getter': filter_has_special_getter, - 'runtime_enabled_constants': filter_runtime_enabled, - 'origin_trial_enabled_constants': filter_origin_trial_enabled - } - - -def origin_trial_features(interface, constants, attributes, methods): - """ Returns a list of the origin trial features used in this interface. - - Each element is a dictionary with keys 'name' and 'needs_instance'. - 'needs_instance' is true if any member associated with the interface needs - to be installed on every instance of the interface. This list is the union - of the sets of features used for constants, attributes and methods. - """ - KEY = 'origin_trial_feature_name' # pylint: disable=invalid-name - - def member_filter(members): - return sorted([member for member in members if member.get(KEY)]) - - def member_filter_by_name(members, name): - return [member for member in members if member[KEY] == name] - - # Collect all members visible on this interface with a defined origin trial - origin_trial_constants = member_filter(constants) - origin_trial_attributes = member_filter(attributes) - origin_trial_methods = member_filter([ - method for method in methods - if v8_methods.method_is_visible(method, interface.is_partial) - and not v8_methods.custom_registration(method) - ]) - - feature_names = set([ - member[KEY] for member in origin_trial_constants + - origin_trial_attributes + origin_trial_methods - ]) - - # Construct the list of dictionaries. 'needs_instance' will be true if any - # member for the feature has 'on_instance' defined as true. - features = [{ - 'name': - name, - 'constants': - member_filter_by_name(origin_trial_constants, name), - 'attributes': - member_filter_by_name(origin_trial_attributes, name), - 'methods': - member_filter_by_name(origin_trial_methods, name) - } for name in feature_names] - for feature in features: - members = feature['constants'] + feature['attributes'] + feature[ - 'methods'] - feature['needs_instance'] = any( - member.get('on_instance', False) for member in members) - # TODO(chasej): Need to handle method overloads? e.g. - # (method['overloads']['secure_context_test_all'] if 'overloads' in method else method['secure_context_test']) - feature['needs_secure_context'] = any( - member.get('secure_context_test', False) for member in members) - feature['needs_cross_origin_isolated'] = any( - member.get('cross_origin_isolated_test', False) - for member in members) - feature['needs_direct_socket_enabled'] = any( - member.get('direct_socket_enabled_test', False) - for member in members) - feature['needs_context'] = feature['needs_secure_context'] or feature[ - 'needs_cross_origin_isolated'] or feature[ - 'needs_direct_socket_enabled'] or any( - member.get('exposed_test', False) for member in members) - - if features: - includes.add('platform/bindings/script_state.h') - includes.add('platform/runtime_enabled_features.h') - includes.add('core/execution_context/execution_context.h') - - return features - - -def context_enabled_features(attributes): - """ Returns a list of context-enabled features from a set of attributes. - - Each element is a dictionary with the feature's |name| and lists of - |attributes| associated with the feature. - """ - KEY = 'context_enabled_feature_name' # pylint: disable=invalid-name - - def member_filter(members): - return sorted([ - member for member in members - if member.get(KEY) and not member.get('exposed_test') - ], key=lambda item: item['name']) - - def member_filter_by_name(members, name): - return [member for member in members if member[KEY] == name] - - # Collect all members visible on this interface with a defined origin trial - context_enabled_attributes = member_filter(attributes) - feature_names = set([member[KEY] for member in context_enabled_attributes]) - features = [{ - 'name': - name, - 'attributes': - member_filter_by_name(context_enabled_attributes, name), - 'needs_instance': - False - } for name in feature_names] - if features: - includes.add('platform/bindings/script_state.h') - return features - - -def runtime_call_stats_context(interface): - counter_prefix = 'Blink_' + v8_utilities.cpp_name(interface) + '_' - return { - 'constructor_counter': - counter_prefix + 'Constructor', - 'cross_origin_named_getter_counter': - counter_prefix + 'CrossOriginNamedGetter', - 'cross_origin_named_setter_counter': - counter_prefix + 'CrossOriginNamedSetter', - 'indexed_property_getter_counter': - counter_prefix + 'IndexedPropertyGetter', - 'named_property_getter_counter': - counter_prefix + 'NamedPropertyGetter', - 'named_property_query_counter': - counter_prefix + 'NamedPropertyQuery', - 'named_property_setter_counter': - counter_prefix + 'NamedPropertySetter', - } - - -def interface_context(interface, interfaces, component_info): - """Creates a Jinja template context for an interface. - - Args: - interface: An interface to create the context for - interfaces: A dict which maps an interface name to the definition - which can be referred if needed - component_info: A dict containing component wide information - - Returns: - A Jinja template context for |interface| - """ - - includes.clear() - includes.update(INTERFACE_CPP_INCLUDES) - header_includes = set(INTERFACE_H_INCLUDES) - - if interface.is_partial: - # A partial interface definition cannot specify that the interface - # inherits from another interface. Inheritance must be specified on - # the original interface definition. - parent_interface = None - is_event_target = False - # partial interface needs the definition of its original interface. - includes.add( - 'bindings/core/v8/%s' % binding_header_filename(interface.name)) - else: - parent_interface = interface.parent - if parent_interface: - header_includes.update( - v8_types.includes_for_interface(parent_interface)) - is_event_target = inherits_interface(interface.name, 'EventTarget') - - extended_attributes = interface.extended_attributes - - is_array_buffer_or_view = interface.idl_type.is_array_buffer_or_view - is_typed_array_type = interface.idl_type.is_typed_array - if is_array_buffer_or_view: - includes.update(('bindings/core/v8/v8_array_buffer.h', - 'bindings/core/v8/v8_shared_array_buffer.h')) - if interface.name == 'ArrayBufferView': - includes.update(('bindings/core/v8/v8_int8_array.h', - 'bindings/core/v8/v8_int16_array.h', - 'bindings/core/v8/v8_int32_array.h', - 'bindings/core/v8/v8_uint8_array.h', - 'bindings/core/v8/v8_uint8_clamped_array.h', - 'bindings/core/v8/v8_uint16_array.h', - 'bindings/core/v8/v8_uint32_array.h', - 'bindings/core/v8/v8_big_int_64_array.h', - 'bindings/core/v8/v8_big_uint_64_array.h', - 'bindings/core/v8/v8_float32_array.h', - 'bindings/core/v8/v8_float64_array.h', - 'bindings/core/v8/v8_data_view.h')) - - # [ActiveScriptWrappable] - active_scriptwrappable = 'ActiveScriptWrappable' in extended_attributes - - # [CheckSecurity] - is_check_security = 'CheckSecurity' in extended_attributes - if is_check_security: - includes.add('bindings/core/v8/binding_security.h') - includes.add('core/frame/local_dom_window.h') - - # [Global] - is_global = 'Global' in extended_attributes - - # [ImmutablePrototype] - # TODO(littledan): Is it possible to deduce this based on inheritance, - # as in the WebIDL spec? - is_immutable_prototype = is_global or 'ImmutablePrototype' in extended_attributes - - # interface mixin - assert not interface.is_mixin, ( - "Interface mixin {} must not be a direct target of bindings code generation." - .format(interface.name)) - - wrapper_class_id = ('kNodeClassId' if inherits_interface( - interface.name, 'Node') else 'kObjectClassId') - - # [LegacyUnenumerableNamedProperties] - # pylint: disable=C0103 - has_legacy_unenumerable_named_properties = ( - interface.has_named_property_getter - and 'LegacyUnenumerableNamedProperties' in extended_attributes) - - v8_class_name = v8_utilities.v8_class_name(interface) - cpp_class_name = cpp_name(interface) - cpp_class_name_or_partial = cpp_name_or_partial(interface) - v8_class_name_or_partial = v8_utilities.v8_class_name_or_partial(interface) - - # TODO(peria): Generate the target list from 'Window' and 'HTMLDocument'. - needs_runtime_enabled_installer = v8_class_name in [ - 'V8Window', 'V8HTMLDocument', 'V8Document', 'V8Node', 'V8EventTarget' - ] - - runtime_features = component_info['runtime_enabled_features'] - - context = { - 'active_scriptwrappable': - active_scriptwrappable, - 'context_enabled_feature_name': - context_enabled_feature_name(interface), # [ContextEnabled] - 'cpp_class': - cpp_class_name, - 'cpp_class_or_partial': - cpp_class_name_or_partial, - 'is_gc_type': - True, - # FIXME: Remove 'EventTarget' special handling, http://crbug.com/383699 - 'has_access_check_callbacks': (is_check_security - and interface.name != 'EventTarget'), - # [Custom=LegacyCallAsFunction] - 'has_custom_legacy_call_as_function': - has_extended_attribute_value(interface, 'Custom', - 'LegacyCallAsFunction'), - 'has_legacy_unenumerable_named_properties': - has_legacy_unenumerable_named_properties, - 'has_partial_interface': - len(interface.partial_interfaces) > 0, - 'header_includes': - header_includes, - 'interface_name': - interface.name, - 'internal_namespace': - internal_namespace(interface), - 'is_array_buffer_or_view': - is_array_buffer_or_view, - 'is_check_security': - is_check_security, - 'is_event_target': - is_event_target, - 'is_global': - is_global, - 'is_immutable_prototype': - is_immutable_prototype, - 'is_node': - inherits_interface(interface.name, 'Node'), - 'is_partial': - interface.is_partial, - 'is_typed_array_type': - is_typed_array_type, - # [MeasureAs] - 'measure_as': - v8_utilities.measure_as(interface, None), - 'needs_runtime_enabled_installer': - needs_runtime_enabled_installer, - 'origin_trial_feature_name': - v8_utilities.origin_trial_feature_name(interface, runtime_features), - 'parent_interface': - parent_interface, - 'pass_cpp_type': - cpp_name(interface) + '*', - 'runtime_call_stats': - runtime_call_stats_context(interface), - # [RuntimeEnabled] - 'runtime_enabled_feature_name': - runtime_enabled_feature_name(interface, runtime_features), - 'snake_case_v8_class': - NameStyleConverter(v8_class_name).to_snake_case(), - 'v8_class': - v8_class_name, - 'v8_class_or_partial': - v8_class_name_or_partial, - 'wrapper_class_id': - wrapper_class_id, - } - - # Constructors - constructors = [ - constructor_context(interface, constructor) - for constructor in interface.constructors - # FIXME: shouldn't put named constructors with constructors - # (currently needed for Perl compatibility) - # Handle named constructors separately - if constructor.name == 'Constructor' - ] - if len(constructors) > 1: - context['constructor_overloads'] = overloads_context( - interface, constructors) - - # [CustomConstructor] - custom_constructors = [{ # Only needed for computing interface length - 'number_of_required_arguments': - number_of_required_arguments(constructor), - } for constructor in interface.custom_constructors] - - # [HTMLConstructor] - has_html_constructor = 'HTMLConstructor' in extended_attributes - # https://html.spec.whatwg.org/C/#html-element-constructors - if has_html_constructor: - if ('Constructor' in extended_attributes - or 'LegacyNoInterfaceObject' in extended_attributes): - raise Exception( - '[HTMLConstructor] cannot be specified with ' - '[Constructor] or [LegacyNoInterfaceObject], or on ' - 'a mixin : %s' % interface.name) - includes.add('bindings/core/v8/v8_html_constructor.h') - - # [NamedConstructor] - named_constructor = named_constructor_context(interface) - - if constructors or custom_constructors or named_constructor: - if interface.is_partial: - raise Exception('[Constructor] and [NamedConstructor] MUST NOT be' - ' specified on partial interface definitions: ' - '%s' % interface.name) - if named_constructor: - includes.add('platform/bindings/v8_per_context_data.h') - includes.add('platform/bindings/v8_private_property.h') - - includes.add('platform/bindings/v8_object_constructor.h') - includes.add('core/frame/local_dom_window.h') - elif 'Measure' in extended_attributes or 'MeasureAs' in extended_attributes: - if not interface.is_partial: - raise Exception( - '[Measure] or [MeasureAs] specified for interface without a constructor: ' - '%s' % interface.name) - - # [ConstructorCallWith=Document] - if has_extended_attribute_value(interface, 'ConstructorCallWith', - 'Document'): - includes.add('core/dom/document.h') - - # [Unscopable] attributes and methods - unscopables = [] - for attribute in interface.attributes: - if 'Unscopable' in attribute.extended_attributes: - unscopables.append((attribute.name, - runtime_enabled_feature_name( - attribute, runtime_features))) - for method in interface.operations: - if 'Unscopable' in method.extended_attributes: - unscopables.append((method.name, - runtime_enabled_feature_name( - method, runtime_features))) - - # [CEReactions] - setter_or_deleters = ( - interface.indexed_property_setter, - interface.indexed_property_deleter, - interface.named_property_setter, - interface.named_property_deleter, - ) - has_ce_reactions = any( - setter_or_deleter - and 'CEReactions' in setter_or_deleter.extended_attributes - for setter_or_deleter in setter_or_deleters) - if has_ce_reactions: - includes.add('core/html/custom/ce_reactions_scope.h') - - context.update({ - 'constructors': - constructors, - 'has_custom_constructor': - bool(custom_constructors), - 'has_html_constructor': - has_html_constructor, - 'interface_length': - interface_length(constructors + custom_constructors), - # [RaisesException=Constructor] - 'is_constructor_raises_exception': - extended_attributes.get('RaisesException') == 'Constructor', - 'named_constructor': - named_constructor, - 'unscopables': - sorted(unscopables), - }) - - # Constants - context.update({ - 'constants': [ - constant_context(constant, interface, component_info) - for constant in interface.constants - ], - 'do_not_check_constants': - 'DoNotCheckConstants' in extended_attributes, - }) - - # Attributes - attributes = attributes_context(interface, interfaces, component_info) - - context.update({ - 'attributes': - attributes, - # Elements in attributes are broken in following members. - 'accessors': - v8_attributes.filter_accessors(attributes), - 'data_attributes': - v8_attributes.filter_data_attributes(attributes), - 'runtime_enabled_attributes': - v8_attributes.filter_runtime_enabled(attributes), - }) - - # Conditionally enabled attributes - conditionally_enabled_attributes = v8_attributes.filter_conditionally_enabled( - attributes) - conditional_attributes = [ - attr for attr in conditionally_enabled_attributes - if not attr['constructor_type'] - ] - conditional_interface_objects = [ - attr for attr in conditionally_enabled_attributes - if attr['constructor_type'] - ] - has_conditional_coi_attributes = any( # pylint: disable=invalid-name - v8_attributes.is_cross_origin_isolated(attr) - for attr in conditionally_enabled_attributes) - has_conditional_direct_socket_attributes = any( # pylint: disable=invalid-name - v8_attributes.is_direct_socket_enabled(attr) - for attr in conditionally_enabled_attributes) - has_conditional_secure_attributes = any( # pylint: disable=invalid-name - v8_attributes.is_secure_context(attr) - for attr in conditionally_enabled_attributes) - context.update({ - 'conditional_attributes': - conditional_attributes, - 'conditional_interface_objects': - conditional_interface_objects, - 'has_conditional_coi_attributes': - has_conditional_coi_attributes, - 'has_conditional_direct_socket_attributes': - has_conditional_direct_socket_attributes, - 'has_conditional_secure_attributes': - has_conditional_secure_attributes, - }) - - # Methods - context.update(methods_context(interface, component_info)) - methods = context['methods'] - - # Conditionally enabled methods - conditional_methods = v8_methods.filter_conditionally_enabled( - methods, interface.is_partial) - has_conditional_coi_methods = any( # pylint: disable=invalid-name - v8_methods.is_cross_origin_isolated(method) - for method in conditional_methods) - has_conditional_direct_socket_methods = any( # pylint: disable=invalid-name - v8_methods.is_direct_socket_enabled(method) - for method in conditional_methods) - has_conditional_secure_methods = any( # pylint: disable=invalid-name - v8_methods.is_secure_context(method) for method in conditional_methods) - context.update({ - 'has_conditional_coi_methods': has_conditional_coi_methods, - 'has_conditional_direct_socket_methods': - has_conditional_direct_socket_methods, - 'has_conditional_secure_methods': has_conditional_secure_methods, - 'conditional_methods': conditional_methods, - }) - - # Window.idl in Blink has indexed properties, but the spec says Window - # interface doesn't have indexed properties, instead the WindowProxy exotic - # object has indexed properties. Thus, Window interface must not support - # iterators. - has_array_iterator = (not interface.is_partial - and interface.has_indexed_elements - and interface.name != 'Window') - context.update({ - 'has_array_iterator': has_array_iterator, - 'iterable': interface.iterable, - }) - - # Conditionally enabled members - install_conditional_features_func = None # pylint: disable=invalid-name - if unscopables or conditional_interface_objects or conditional_attributes or conditional_methods: - install_conditional_features_func = ( # pylint: disable=invalid-name - v8_class_name_or_partial + '::InstallConditionalFeatures') - - context.update({ - 'install_conditional_features_func': - install_conditional_features_func, - }) - - context.update({ - 'indexed_property_getter': - property_getter(interface.indexed_property_getter, ['index']), - 'indexed_property_setter': - property_setter(interface.indexed_property_setter, interface), - 'indexed_property_deleter': - property_deleter(interface.indexed_property_deleter), - 'is_override_builtins': - 'LegacyOverrideBuiltIns' in extended_attributes, - 'named_property_getter': - property_getter(interface.named_property_getter, ['name']), - 'named_property_setter': - property_setter(interface.named_property_setter, interface), - 'named_property_deleter': - property_deleter(interface.named_property_deleter), - }) - context.update({ - 'has_named_properties_object': - is_global and context['named_property_getter'], - }) - - # Origin Trials and ContextEnabled features - context.update({ - 'optional_features': - sorted( - origin_trial_features(interface, context['constants'], - context['attributes'], context['methods']) + - context_enabled_features(context['attributes']), - key=lambda item: item['name']), - }) - if context['optional_features']: - includes.add('platform/bindings/v8_per_context_data.h') - - # Cross-origin interceptors - has_cross_origin_named_getter = False - has_cross_origin_named_setter = False - has_cross_origin_indexed_getter = False - - for attribute in attributes: - if attribute['has_cross_origin_getter']: - has_cross_origin_named_getter = True - if attribute['has_cross_origin_setter']: - has_cross_origin_named_setter = True - - # Methods are exposed as getter attributes on the interface: e.g. - # window.location gets the location attribute on the Window interface. For - # the cross-origin case, this attribute getter is guaranteed to only return - # a Function object, which the actual call is dispatched against. - for method in methods: - if method['is_cross_origin']: - has_cross_origin_named_getter = True - - has_cross_origin_named_enumerator = has_cross_origin_named_getter or has_cross_origin_named_setter # pylint: disable=invalid-name - - if (context['named_property_getter'] - and context['named_property_getter']['is_cross_origin']): - has_cross_origin_named_getter = True - - if context['indexed_property_getter'] and context[ - 'indexed_property_getter']['is_cross_origin']: - has_cross_origin_indexed_getter = True - - context.update({ - 'has_cross_origin_named_getter': - has_cross_origin_named_getter, - 'has_cross_origin_named_setter': - has_cross_origin_named_setter, - 'has_cross_origin_named_enumerator': - has_cross_origin_named_enumerator, - 'has_cross_origin_indexed_getter': - has_cross_origin_indexed_getter, - }) - - return context - - -def attributes_context(interface, interfaces, component_info): - """Creates a list of Jinja template contexts for attributes of an interface. - - Args: - interface: An interface to create contexts for - interfaces: A dict which maps an interface name to the definition - which can be referred if needed - - Returns: - A list of attribute contexts - """ - - attributes = [ - v8_attributes.attribute_context(interface, attribute, interfaces, - component_info) - for attribute in interface.attributes - ] - - has_conditional_attributes = any( - attribute['exposed_test'] for attribute in attributes) - if has_conditional_attributes and interface.is_partial: - raise Exception( - 'Conditional attributes between partial interfaces in modules ' - 'and the original interfaces(%s) in core are not allowed.' % - interface.name) - - # See also comment in methods_context. - if not interface.is_partial and (interface.maplike or interface.setlike): - if any(attribute['name'] == 'size' for attribute in attributes): - raise ValueError( - 'An interface cannot define an attribute called "size"; it is ' - 'implied by maplike/setlike in the IDL.') - size_attribute = IdlAttribute() - size_attribute.name = 'size' - size_attribute.idl_type = IdlType('unsigned long') - size_attribute.is_read_only = True - size_attribute.extended_attributes['NotEnumerable'] = None - attributes.append( - v8_attributes.attribute_context(interface, size_attribute, - interfaces, component_info)) - - return attributes - - -def methods_context(interface, component_info): - """Creates a list of Jinja template contexts for methods of an interface. - - Args: - interface: An interface to create contexts for - component_info: A dict containing component wide information - - Returns: - A dictionary with 3 keys: - 'iterator_method': An iterator context if available or None. - 'iterator_method_alias': A string that can also be used to refer to the - @@iterator symbol or None. - 'methods': A list of method contexts. - """ - - methods = [] - - if interface.original_interface: - methods.extend([ - v8_methods.method_context( - interface, operation, component_info, is_visible=False) - for operation in interface.original_interface.operations - if operation.name - ]) - methods.extend([ - v8_methods.method_context(interface, method, component_info) - for method in interface.operations if method.name - ]) # Skip anonymous special operations (methods) - if interface.partial_interfaces: - assert len(interface.partial_interfaces) == len( - set(interface.partial_interfaces)) - for partial_interface in interface.partial_interfaces: - methods.extend([ - v8_methods.method_context( - interface, operation, component_info, is_visible=False) - for operation in partial_interface.operations if operation.name - ]) - compute_method_overloads_context(interface, methods) - - def generated_method(return_type, - name, - arguments=None, - extended_attributes=None, - implemented_as=None): - operation = IdlOperation() - operation.idl_type = return_type - operation.name = name - if arguments: - operation.arguments = arguments - if extended_attributes: - operation.extended_attributes.update(extended_attributes) - if implemented_as is None: - implemented_as = name + 'ForBinding' - operation.extended_attributes['ImplementedAs'] = implemented_as - return v8_methods.method_context(interface, operation, component_info) - - def generated_argument(idl_type, - name, - is_optional=False, - extended_attributes=None): - argument = IdlArgument() - argument.idl_type = idl_type - argument.name = name - argument.is_optional = is_optional - if extended_attributes: - argument.extended_attributes.update(extended_attributes) - return argument - - # iterable<>, maplike<> and setlike<> - iterator_method = None - - # Depending on the declaration, @@iterator may be a synonym for e.g. - # 'entries' or 'values'. - iterator_method_alias = None - - # FIXME: support Iterable in partial interfaces. However, we don't - # need to support iterator overloads between interface and - # partial interface definitions. - # http://heycam.github.io/webidl/#idl-overloading - if (not interface.is_partial - and (interface.iterable or interface.maplike or interface.setlike - or interface.has_indexed_elements)): - - used_extended_attributes = {} - - if interface.iterable: - used_extended_attributes.update( - interface.iterable.extended_attributes) - elif interface.maplike: - used_extended_attributes.update( - interface.maplike.extended_attributes) - elif interface.setlike: - used_extended_attributes.update( - interface.setlike.extended_attributes) - - if 'RaisesException' in used_extended_attributes: - raise ValueError( - '[RaisesException] is implied for iterable<>/maplike<>/setlike<>' - ) - if 'CallWith' in used_extended_attributes: - raise ValueError( - '[CallWith=ScriptState] is implied for iterable<>/maplike<>/setlike<>' - ) - - used_extended_attributes.update({ - 'RaisesException': None, - 'CallWith': 'ScriptState', - }) - - forEach_extended_attributes = used_extended_attributes.copy() - forEach_extended_attributes.update({ - 'CallWith': ['ScriptState', 'ThisValue'], - }) - - def generated_iterator_method(name, implemented_as=None): - return generated_method( - return_type=IdlType('Iterator'), - name=name, - extended_attributes=used_extended_attributes, - implemented_as=implemented_as) - - if not interface.has_indexed_elements: - iterator_method = generated_iterator_method( - 'iterator', implemented_as='GetIterator') - - if interface.iterable or interface.maplike or interface.setlike: - non_overridable_methods = [] - overridable_methods = [] - - is_value_iterator = interface.iterable and interface.iterable.key_type is None - - # For value iterators, the |entries|, |forEach|, |keys| and |values| are originally set - # to corresponding properties in %ArrayPrototype%. - # For pair iterators and maplike declarations, |entries| is an alias for @@iterator - # itself. For setlike declarations, |values| is an alias for @@iterator. - if not is_value_iterator: - if not interface.setlike: - iterator_method_alias = 'entries' - entries_or_values_method = generated_iterator_method( - 'values') - else: - iterator_method_alias = 'values' - entries_or_values_method = generated_iterator_method( - 'entries') - - non_overridable_methods.extend([ - generated_iterator_method('keys'), - entries_or_values_method, - - # void forEach(ForEachIteratorCallback callback, [DefaultValue=Undefined] optional any thisArg) - generated_method( - IdlType('void'), - 'forEach', - arguments=[ - generated_argument( - IdlType('ForEachIteratorCallback'), - 'callback'), - generated_argument( - IdlType('any'), - 'thisArg', - is_optional=True, - extended_attributes={ - 'DefaultValue': 'Undefined' - }) - ], - extended_attributes=forEach_extended_attributes), - ]) - - if interface.maplike: - key_argument = generated_argument(interface.maplike.key_type, - 'key') - value_argument = generated_argument( - interface.maplike.value_type, 'value') - - non_overridable_methods.extend([ - generated_method( - IdlType('boolean'), - 'has', - arguments=[key_argument], - extended_attributes=used_extended_attributes), - generated_method( - IdlType('any'), - 'get', - arguments=[key_argument], - extended_attributes=used_extended_attributes), - ]) - - if not interface.maplike.is_read_only: - overridable_methods.extend([ - generated_method( - IdlType('void'), - 'clear', - extended_attributes=used_extended_attributes), - generated_method( - IdlType('boolean'), - 'delete', - arguments=[key_argument], - extended_attributes=used_extended_attributes), - generated_method( - IdlType(interface.name), - 'set', - arguments=[key_argument, value_argument], - extended_attributes=used_extended_attributes), - ]) - - if interface.setlike: - value_argument = generated_argument( - interface.setlike.value_type, 'value') - - non_overridable_methods.extend([ - generated_method( - IdlType('boolean'), - 'has', - arguments=[value_argument], - extended_attributes=used_extended_attributes), - ]) - - if not interface.setlike.is_read_only: - overridable_methods.extend([ - generated_method( - IdlType(interface.name), - 'add', - arguments=[value_argument], - extended_attributes=used_extended_attributes), - generated_method( - IdlType('void'), - 'clear', - extended_attributes=used_extended_attributes), - generated_method( - IdlType('boolean'), - 'delete', - arguments=[value_argument], - extended_attributes=used_extended_attributes), - ]) - - methods_by_name = {} - for method in methods: - methods_by_name.setdefault(method['name'], []).append(method) - - for non_overridable_method in non_overridable_methods: - if non_overridable_method['name'] in methods_by_name: - raise ValueError( - 'An interface cannot define an operation called "%s()", it ' - 'comes from the iterable, maplike or setlike declaration ' - 'in the IDL.' % non_overridable_method['name']) - methods.append(non_overridable_method) - - for overridable_method in overridable_methods: - if overridable_method['name'] in methods_by_name: - # FIXME: Check that the existing method is compatible. - continue - methods.append(overridable_method) - - # FIXME: maplike<> and setlike<> should also imply the presence of a - # 'size' attribute. - - # Stringifier - if interface.stringifier: - stringifier = interface.stringifier - stringifier_ext_attrs = stringifier.extended_attributes.copy() - if stringifier.attribute: - implemented_as = stringifier.attribute.name - elif stringifier.operation: - implemented_as = stringifier.operation.name - else: - implemented_as = 'toString' - methods.append( - generated_method( - return_type=IdlType('DOMString'), - name='toString', - extended_attributes=stringifier_ext_attrs, - implemented_as=implemented_as)) - - for method in methods: - # The value of the Function object’s “length” property is a Number - # determined as follows: - # 1. Let S be the effective overload set for regular operations (if the - # operation is a regular operation) or for static operations (if the - # operation is a static operation) with identifier id on interface I and - # with argument count 0. - # 2. Return the length of the shortest argument list of the entries in S. - # FIXME: This calculation doesn't take into account whether runtime - # enabled overloads are actually enabled, so length may be incorrect. - # E.g., [RuntimeEnabled=Foo] void f(); void f(long x); - # should have length 1 if Foo is not enabled, but length 0 if it is. - method['length'] = (method['overloads']['length'] - if 'overloads' in method else - method['number_of_required_arguments']) - - return { - 'iterator_method': iterator_method, - 'iterator_method_alias': iterator_method_alias, - 'methods': methods, - } - - -def reflected_name(constant_name): - """Returns the name to use for the matching constant name in blink code. - - Given an all-uppercase 'CONSTANT_NAME', returns a camel-case - 'kConstantName'. - """ - # Check for SHOUTY_CASE constants - if constant_name.upper() != constant_name: - return constant_name - return 'k' + ''.join(part.title() for part in constant_name.split('_')) - - -# [DeprecateAs], [Reflect], [RuntimeEnabled] -def constant_context(constant, interface, component_info): - extended_attributes = constant.extended_attributes - runtime_features = component_info['runtime_enabled_features'] - - return { - 'camel_case_name': - NameStyleConverter(constant.name).to_upper_camel_case(), - 'cpp_class': - extended_attributes.get('PartialInterfaceImplementedAs'), - 'cpp_type': - constant.idl_type.cpp_type, - 'deprecate_as': - v8_utilities.deprecate_as(constant), # [DeprecateAs] - 'idl_type': - constant.idl_type.name, - 'measure_as': - v8_utilities.measure_as(constant, interface), # [MeasureAs] - 'high_entropy': - v8_utilities.high_entropy(constant), # [HighEntropy] - 'name': - constant.name, - # [RuntimeEnabled] for origin trial - 'origin_trial_feature_name': - v8_utilities.origin_trial_feature_name(constant, runtime_features), - # FIXME: use 'reflected_name' as correct 'name' - 'rcs_counter': - 'Blink_' + v8_utilities.cpp_name(interface) + '_' + constant.name + - '_ConstantGetter', - 'reflected_name': - extended_attributes.get('Reflect', reflected_name(constant.name)), - # [RuntimeEnabled] if not in origin trial - 'runtime_enabled_feature_name': - runtime_enabled_feature_name(constant, runtime_features), - 'value': - constant.value, - } - - -################################################################################ -# Overloads -################################################################################ - - -def compute_method_overloads_context(interface, methods): - # Regular methods - compute_method_overloads_context_by_type( - interface, [method for method in methods if not method['is_static']]) - # Static methods - compute_method_overloads_context_by_type( - interface, [method for method in methods if method['is_static']]) - - -def compute_method_overloads_context_by_type(interface, methods): - """Computes |method.overload*| template values. - - Called separately for static and non-static (regular) methods, - as these are overloaded separately. - Modifies |method| in place for |method| in |methods|. - Doesn't change the |methods| list itself (only the values, i.e. individual - methods), so ok to treat these separately. - """ - # Add overload information only to overloaded methods, so template code can - # easily verify if a function is overloaded - for name, overloads in method_overloads_by_name(methods): - # Resolution function is generated after last overloaded function; - # package necessary information into |method.overloads| for that method. - overloads[-1]['overloads'] = overloads_context(interface, overloads) - overloads[-1]['overloads']['name'] = name - overloads[-1]['overloads']['camel_case_name'] = NameStyleConverter( - name).to_upper_camel_case() - - -def overloads_context(interface, overloads): - """Returns |overloads| template values for a single name. - - Sets |method.overload_index| in place for |method| in |overloads| - and returns dict of overall overload template values. - """ - assert len(overloads) > 1 # only apply to overloaded names - for index, method in enumerate(overloads, 1): - method['overload_index'] = index - - # [RuntimeEnabled] - if any(method.get('origin_trial_feature_name') for method in overloads): - raise Exception( - '[RuntimeEnabled] for origin trial cannot be specified on ' - 'overloaded methods: %s.%s' % (interface.name, - overloads[0]['name'])) - - effective_overloads_by_length = effective_overload_set_by_length(overloads) - lengths = [length for length, _ in effective_overloads_by_length] - name = overloads[0].get('name', '<constructor>') - camel_case_name = NameStyleConverter(name).to_upper_camel_case() - - runtime_determined_lengths = None - function_length = lengths[0] - runtime_determined_maxargs = None - maxarg = lengths[-1] - - # The special case handling below is not needed if all overloads are - # runtime enabled by the same feature. - if not common_value(overloads, 'runtime_enabled_feature_name'): - # Check if all overloads with the shortest acceptable arguments list are - # runtime enabled, in which case we need to have a runtime determined - # Function.length. - shortest_overloads = effective_overloads_by_length[0][1] - if (all( - method.get('runtime_enabled_feature_name') - for method, _, _ in shortest_overloads)): - # Generate a list of (length, runtime_enabled_feature_names) tuples. - runtime_determined_lengths = [] - for length, effective_overloads in effective_overloads_by_length: - runtime_enabled_feature_names = set( - method['runtime_enabled_feature_name'] - for method, _, _ in effective_overloads) - if None in runtime_enabled_feature_names: - # This "length" is unconditionally enabled, so stop here. - runtime_determined_lengths.append((length, [None])) - break - runtime_determined_lengths.append( - (length, sorted(runtime_enabled_feature_names))) - function_length = ('%s::%sMethodLength()' % ( - internal_namespace(interface), camel_case_name)) - - # Check if all overloads with the longest required arguments list are - # runtime enabled, in which case we need to have a runtime determined - # maximum distinguishing argument index. - longest_overloads = effective_overloads_by_length[-1][1] - if (not common_value(overloads, 'runtime_enabled_feature_name') - and all( - method.get('runtime_enabled_feature_name') - for method, _, _ in longest_overloads)): - # Generate a list of (length, runtime_enabled_feature_name) tuples. - runtime_determined_maxargs = [] - for length, effective_overloads in reversed( - effective_overloads_by_length): - runtime_enabled_feature_names = set( - method['runtime_enabled_feature_name'] - for method, _, _ in effective_overloads - if method.get('runtime_enabled_feature_name')) - if not runtime_enabled_feature_names: - # This "length" is unconditionally enabled, so stop here. - runtime_determined_maxargs.append((length, [None])) - break - runtime_determined_maxargs.append( - (length, sorted(runtime_enabled_feature_names))) - maxarg = ('%s::%sMethodMaxArg()' % (internal_namespace(interface), - camel_case_name)) - - # Check and fail if overloads disagree about whether the return type - # is a Promise or not. - promise_overload_count = sum( - 1 for method in overloads if method.get('returns_promise')) - if promise_overload_count not in (0, len(overloads)): - raise ValueError( - 'Overloads of %s have conflicting Promise/non-Promise types' % - (name)) - - has_overload_visible = False - has_overload_not_visible = False - for overload in overloads: - if overload.get('visible', True): - # If there exists an overload which is visible, need to generate - # overload_resolution, i.e. overlods_visible should be True. - has_overload_visible = True - else: - has_overload_not_visible = True - - # If some overloads are not visible and others are visible, - # the method is overloaded between core and modules. - has_partial_overloads = has_overload_visible and has_overload_not_visible - - return { - 'deprecate_all_as': - common_value(overloads, 'deprecate_as'), # [DeprecateAs] - 'exposed_test_all': - common_value(overloads, 'exposed_test'), # [Exposed] - 'length': - function_length, - 'length_tests_methods': - length_tests_methods(effective_overloads_by_length), - # 1. Let maxarg be the length of the longest type list of the - # entries in S. - 'maxarg': - maxarg, - 'measure_all_as': - common_value(overloads, 'measure_as'), # [MeasureAs] - 'returns_promise_all': - promise_overload_count > 0, - 'runtime_determined_lengths': - runtime_determined_lengths, - 'runtime_determined_maxargs': - runtime_determined_maxargs, - # [RuntimeEnabled] - 'runtime_enabled_all': - common_value(overloads, 'runtime_enabled_feature_name'), - # [CrossOriginIsolated] - 'cross_origin_isolated_test_all': - common_value(overloads, 'cross_origin_isolated_test'), - # [DirectSocketEnabled] - 'direct_socket_enabled_test_all': - common_value(overloads, 'direct_socket_enabled_test'), - # [SecureContext] - 'secure_context_test_all': - common_value(overloads, 'secure_context_test'), - 'valid_arities': ( - lengths - # Only need to report valid arities if there is a gap in the - # sequence of possible lengths, otherwise invalid length means - # "not enough arguments". - if lengths[-1] - lengths[0] != len(lengths) - 1 else None), - 'visible': - has_overload_visible, - 'has_partial_overloads': - has_partial_overloads, - } - - -def distinguishing_argument_index(entries): - """Returns the distinguishing argument index for a sequence of entries. - - Entries are elements of the effective overload set with the same number - of arguments (formally, same type list length), each a 3-tuple of the form - (callable, type list, optionality list). - - Spec: http://heycam.github.io/webidl/#dfn-distinguishing-argument-index - - If there is more than one entry in an effective overload set that has a - given type list length, then for those entries there must be an index i - such that for each pair of entries the types at index i are - distinguishable. - The lowest such index is termed the distinguishing argument index for the - entries of the effective overload set with the given type list length. - """ - # Only applicable “If there is more than one entry” - assert len(entries) > 1 - - def typename_without_nullable(idl_type): - if idl_type.is_nullable: - return idl_type.inner_type.name - return idl_type.name - - type_lists = [ - tuple(typename_without_nullable(idl_type) for idl_type in entry[1]) - for entry in entries - ] - type_list_length = len(type_lists[0]) - # Only applicable for entries that “[have] a given type list length” - assert all(len(type_list) == type_list_length for type_list in type_lists) - name = entries[0][0].get('name', 'Constructor') # for error reporting - - # The spec defines the distinguishing argument index by conditions it must - # satisfy, but does not give an algorithm. - # - # We compute the distinguishing argument index by first computing the - # minimum index where not all types are the same, and then checking that - # all types in this position are distinguishable (and the optionality lists - # up to this point are identical), since "minimum index where not all types - # are the same" is a *necessary* condition, and more direct to check than - # distinguishability. - types_by_index = (set(types) for types in zip(*type_lists)) - try: - # “In addition, for each index j, where j is less than the - # distinguishing argument index for a given type list length, the types - # at index j in all of the entries’ type lists must be the same” - index = next( - i for i, types in enumerate(types_by_index) if len(types) > 1) - except StopIteration: - raise ValueError('No distinguishing index found for %s, length %s:\n' - 'All entries have the same type list:\n' - '%s' % (name, type_list_length, type_lists[0])) - # Check optionality - # “and the booleans in the corresponding list indicating argument - # optionality must be the same.” - # FIXME: spec typo: optionality value is no longer a boolean - # https://www.w3.org/Bugs/Public/show_bug.cgi?id=25628 - initial_optionality_lists = set(entry[2][:index] for entry in entries) - if len(initial_optionality_lists) > 1: - raise ValueError( - 'Invalid optionality lists for %s, length %s:\n' - 'Optionality lists differ below distinguishing argument index %s:\n' - '%s' % (name, type_list_length, index, - set(initial_optionality_lists))) - - # Check distinguishability - # http://heycam.github.io/webidl/#dfn-distinguishable - # Use names to check for distinct types, since objects are distinct - # FIXME: check distinguishability more precisely, for validation - distinguishing_argument_type_names = [ - type_list[index] for type_list in type_lists - ] - if (len(set(distinguishing_argument_type_names)) != - len(distinguishing_argument_type_names)): - raise ValueError('Types in distinguishing argument are not distinct:\n' - '%s' % distinguishing_argument_type_names) - - return index - - -def length_tests_methods(effective_overloads_by_length): - """Returns sorted list of resolution tests and associated methods, by length. - - This builds the main data structure for the overload resolution loop. - For a given argument length, bindings test argument at distinguishing - argument index, in order given by spec: if it is compatible with - (optionality or) type required by an overloaded method, resolve to that - method. - - Returns: - [(length, [(test, method)])] - """ - return [(length, list(resolution_tests_methods(effective_overloads))) - for length, effective_overloads in effective_overloads_by_length] - - -def resolution_tests_methods(effective_overloads): - """Yields resolution test and associated method, in resolution order, for effective overloads of a given length. - - This is the heart of the resolution algorithm. - https://heycam.github.io/webidl/#dfn-overload-resolution-algorithm - - Note that a given method can be listed multiple times, with different tests! - This is to handle implicit type conversion. - - Returns: - [(test, method)] - """ - methods = [ - effective_overload[0] for effective_overload in effective_overloads - ] - if len(methods) == 1: - # If only one method with a given length, no test needed - yield 'true', methods[0] - return - - # 8. If there is more than one entry in S, then set d to be the - # distinguishing argument index for the entries of S. - index = distinguishing_argument_index(effective_overloads) - - # (11. is for handling |undefined| values for optional arguments - # before the distinguishing argument (as “missing”).) - # TODO(peria): We have to handle this step. Also in 15.4.2. - - # 12. If i = d, then: - # 12.1. Let V be args[i]. - cpp_value = 'info[%s]' % index - - # Extract argument and IDL type to simplify accessing these in each loop. - arguments = [method['arguments'][index] for method in methods] - arguments_methods = list(zip(arguments, methods)) - idl_types = [argument['idl_type_object'] for argument in arguments] - idl_types_methods = list(zip(idl_types, methods)) - - # We can’t do a single loop through all methods or simply sort them, because - # a method may be listed in multiple steps of the resolution algorithm, and - # which test to apply differs depending on the step. - # - # Instead, we need to go through all methods at each step, either finding - # first match (if only one test is allowed) or filtering to matches (if - # multiple tests are allowed), and generating an appropriate tests. - # - # In listing types, we put ellipsis (...) for shorthand nullable type(s), - # annotated type(s), and a (nullable/annotated) union type, which extend - # listed types. - # TODO(peria): Support handling general union types. https://crbug.com/838787 - - # 12.2. If V is undefined, and there is an entry in S whose list of - # optionality values has “optional” at index i, then remove from S all - # other entries. - try: - method = next(method for argument, method in arguments_methods - if argument['is_optional']) - test = '%s->IsUndefined()' % cpp_value - yield test, method - except StopIteration: - pass - - # 12.3. Otherwise: if V is null or undefined, and there is an entry in S that - # has one of the following types at position i of its type list, - # • a nullable type - # • a dictionary type - # ... - try: - method = next(method for idl_type, method in idl_types_methods - if idl_type.is_nullable or idl_type.is_dictionary) - test = 'IsUndefinedOrNull(%s)' % cpp_value - yield test, method - except StopIteration: - pass - - # 12.4. Otherwise: if V is a platform object, and there is an entry in S that - # has one of the following types at position i of its type list, - # • an interface type that V implements - # ... - for idl_type, method in idl_types_methods: - if idl_type.is_wrapper_type and not idl_type.is_array_buffer_or_view: - test = 'V8{idl_type}::HasInstance({cpp_value}, info.GetIsolate())'.format( - idl_type=idl_type.base_type, cpp_value=cpp_value) - yield test, method - - # 12.5. Otherwise: if V is a DOMException platform object and there is an entry - # in S that has one of the following types at position i of its type list, - # • DOMException - # • Error - # ... - # (DOMException is handled in 12.4, and we don't support Error type.) - - # 12.6. Otherwise: if Type(V) is Object, V has an [[ErrorData]] internal slot, - # and there is an entry in S that has one of the following types at position - # i of its type list, - # • Error - # ... - # (We don't support Error type.) - - # 12.7. Otherwise: if Type(V) is Object, V has an [[ArrayBufferData]] internal - # slot, and there is an entry in S that has one of the following types at - # position i of its type list, - # • ArrayBuffer - # ... - for idl_type, method in idl_types_methods: - if idl_type.is_array_buffer_or_view or idl_type.is_typed_array: - test = '{cpp_value}->Is{idl_type}()'.format( - idl_type=idl_type.base_type, cpp_value=cpp_value) - yield test, method - - # 12.8. Otherwise: if Type(V) is Object, V has a [[DataView]] internal slot, - # and there is an entry in S that has one of the following types at position - # i of its type list, - # • DataView - # ... - # (DataView is included in 12.7.) - - # 12.9. Otherwise: if Type(V) is Object, V has a [[TypedArrayName]] internal - # slot, and there is an entry in S that has one of the following types at - # position i of its type list, - # • a typed array type whose name is equal to the value of V’s - # [[TypedArrayName]] internal slot - # ... - # (TypedArrays are included in 12.7.) - - # 12.10. Otherwise: if IsCallable(V) is true, and there is an entry in S that - # has one of the following types at position i of its type list, - # • a callback function type - # ... - try: - method = next(method for idl_type, method in idl_types_methods - if idl_type.is_callback_function) - test = '%s->IsFunction()' % cpp_value - yield test, method - except StopIteration: - pass - - # 12.11. Otherwise: if Type(V) is Object and there is an entry in S that has - # one of the following types at position i of its type list, - # • a sequence type - # • a frozen array type - # ... - # and after performing the following steps, - # 12.11.1. Let method be ? GetMethod(V, @@iterator). - # method is not undefined, then remove from S all other entries. - try: - method = next(method for idl_type, method in idl_types_methods - if idl_type.native_array_element_type) - # Either condition should be fulfilled to call this |method|. - test = '%s->IsArray()' % cpp_value - yield test, method - test = 'HasCallableIteratorSymbol(info.GetIsolate(), %s, exception_state)' % cpp_value - yield test, method - except StopIteration: - pass - - # 12.12. Otherwise: if Type(V) is Object and there is an entry in S that has - # one of the following types at position i of its type list, - # • a callback interface type - # • a dictionary type - # • a record type - # ... - try: - method = next(method for idl_type, method in idl_types_methods - if idl_type.is_callback_interface - or idl_type.is_dictionary or idl_type.is_record_type) - test = '%s->IsObject()' % cpp_value - yield test, method - except StopIteration: - pass - - # 12.13. Otherwise: if Type(V) is Boolean and there is an entry in S that has - # one of the following types at position i of its type list, - # • boolean - # ... - try: - method = next(method for idl_type, method in idl_types_methods - if idl_type.name == 'Boolean') - test = '%s->IsBoolean()' % cpp_value - yield test, method - except StopIteration: - pass - - # 12.14. Otherwise: if Type(V) is Number and there is an entry in S that has - # one of the following types at position i of its type list, - # • a numeric type - # ... - try: - method = next(method for idl_type, method in idl_types_methods - if idl_type.is_numeric_type) - test = '%s->IsNumber()' % cpp_value - yield test, method - except StopIteration: - pass - - # 12.15. Otherwise: if there is an entry in S that has one of the following - # types at position i of its type list, - # • a string type - # ... - try: - method = next( - method for idl_type, method in idl_types_methods - if idl_type.is_string_type or idl_type.is_enum or ( - idl_type.is_union_type and idl_type.string_member_type)) - yield 'true', method - except StopIteration: - pass - - # 12.16. Otherwise: if there is an entry in S that has one of the following - # types at position i of its type list, - # • a numeric type - # ... - try: - method = next(method for idl_type, method in idl_types_methods - if idl_type.is_numeric_type) - yield 'true', method - except StopIteration: - pass - - # 12.17. Otherwise: if there is an entry in S that has one of the following - # types at position i of its type list, - # • boolean - # ... - try: - method = next(method for idl_type, method in idl_types_methods - if idl_type.name == 'Boolean') - yield 'true', method - except StopIteration: - pass - - -################################################################################ -# Utility functions -################################################################################ - - -def common(dicts, f): - """Returns common result of f across an iterable of dicts, or None. - - Call f for each dict and return its result if the same across all dicts. - """ - values = (f(d) for d in dicts) - first_value = next(values) - if all(value == first_value for value in values): - return first_value - return None - - -def common_key(dicts, key): - """Returns common presence of a key across an iterable of dicts, or None. - - True if all dicts have the key, False if none of the dicts have the key, - and None if some but not all dicts have the key. - """ - return common(dicts, lambda d: key in d) - - -def common_value(dicts, key): - """Returns common value of a key across an iterable of dicts, or None. - - Auxiliary function for overloads, so can consolidate an extended attribute - that appears with the same value on all items in an overload set. - """ - return common(dicts, lambda d: d.get(key)) - - -def internal_namespace(interface): - return (v8_utilities.to_snake_case(cpp_name_or_partial(interface)) + - '_v8_internal') - - -################################################################################ -# Constructors -################################################################################ - - -# [Constructor] -def constructor_context(interface, constructor): - # [RaisesException=Constructor] - is_constructor_raises_exception = \ - interface.extended_attributes.get('RaisesException') == 'Constructor' - - argument_contexts = [ - v8_methods.argument_context(interface, constructor, argument, index) - for index, argument in enumerate(constructor.arguments) - ] - - return { - 'arguments': - argument_contexts, - 'cpp_type': - cpp_name(interface) + '*', - 'cpp_value': - v8_methods.cpp_value(interface, constructor, - len(constructor.arguments)), - 'has_exception_state': - is_constructor_raises_exception - or any(argument for argument in constructor.arguments - if argument.idl_type.v8_conversion_needs_exception_state), - 'has_optional_argument_without_default_value': - any(True for argument_context in argument_contexts - if argument_context['is_optional_without_default_value']), - 'is_call_with_document': - # [ConstructorCallWith=Document] - has_extended_attribute_value(interface, 'ConstructorCallWith', - 'Document'), - 'is_call_with_execution_context': - # [ConstructorCallWith=ExecutionContext] - has_extended_attribute_value(interface, 'ConstructorCallWith', - 'ExecutionContext'), - 'is_call_with_script_state': - # [ConstructorCallWith=ScriptState] - has_extended_attribute_value(interface, 'ConstructorCallWith', - 'ScriptState'), - 'is_constructor': - True, - 'is_named_constructor': - False, - 'is_raises_exception': - is_constructor_raises_exception, - 'number_of_required_arguments': - number_of_required_arguments(constructor), - 'rcs_counter': - 'Blink_' + v8_utilities.cpp_name(interface) + '_ConstructorCallback' - } - - -# [NamedConstructor] -def named_constructor_context(interface): - extended_attributes = interface.extended_attributes - if 'NamedConstructor' not in extended_attributes: - return None - # FIXME: parser should return named constructor separately; - # included in constructors (and only name stored in extended attribute) - # for Perl compatibility - idl_constructor = interface.constructors[-1] - assert idl_constructor.name == 'NamedConstructor' - context = constructor_context(interface, idl_constructor) - context.update({ - 'name': extended_attributes['NamedConstructor'], - 'is_named_constructor': True, - }) - return context - - -def number_of_required_arguments(constructor): - return len([ - argument for argument in constructor.arguments - if not (argument.is_optional or argument.is_variadic) - ]) - - -def interface_length(constructors): - # Docs: http://heycam.github.io/webidl/#es-interface-call - if not constructors: - return 0 - return min(constructor['number_of_required_arguments'] - for constructor in constructors) - - -################################################################################ -# Special operations (methods) -# http://heycam.github.io/webidl/#idl-special-operations -################################################################################ - - -def property_getter(getter, cpp_arguments): - if not getter: - return None - - def is_null_expression(idl_type): - if idl_type.use_output_parameter_for_result or idl_type.is_string_type: - return 'result.IsNull()' - if idl_type.is_interface_type: - return '!result' - if idl_type.base_type in ('any', 'object'): - return 'result.IsEmpty()' - return '' - - extended_attributes = getter.extended_attributes - has_no_side_effect = v8_utilities.has_extended_attribute_value( - getter, 'Affects', 'Nothing') - idl_type = getter.idl_type - idl_type.add_includes_for_type(extended_attributes) - is_call_with_script_state = v8_utilities.has_extended_attribute_value( - getter, 'CallWith', 'ScriptState') - is_raises_exception = 'RaisesException' in extended_attributes - use_output_parameter_for_result = idl_type.use_output_parameter_for_result - - # FIXME: make more generic, so can use v8_methods.cpp_value - cpp_method_name = 'impl->%s' % cpp_name(getter) - - if is_call_with_script_state: - cpp_arguments.insert(0, 'script_state') - if is_raises_exception: - cpp_arguments.append('exception_state') - if use_output_parameter_for_result: - cpp_arguments.append('result') - - cpp_value = '%s(%s)' % (cpp_method_name, ', '.join(cpp_arguments)) - - return { - 'cpp_type': - idl_type.cpp_type, - 'cpp_value': - cpp_value, - 'has_no_side_effect': - has_no_side_effect, - 'is_call_with_script_state': - is_call_with_script_state, - 'is_cross_origin': - 'CrossOrigin' in extended_attributes, - 'is_custom': - 'Custom' in extended_attributes and - (not extended_attributes['Custom'] - or has_extended_attribute_value(getter, 'Custom', 'PropertyGetter')), - 'is_custom_property_enumerator': - has_extended_attribute_value(getter, 'Custom', 'PropertyEnumerator'), - 'is_custom_property_query': - has_extended_attribute_value(getter, 'Custom', 'PropertyQuery'), - # TODO(rakuco): [NotEnumerable] does not make sense here and is only - # used in non-standard IDL operations. We need to get rid of them. - 'is_enumerable': - 'NotEnumerable' not in extended_attributes, - 'is_null_expression': - is_null_expression(idl_type), - 'is_raises_exception': - is_raises_exception, - 'name': - cpp_name(getter), - 'use_output_parameter_for_result': - use_output_parameter_for_result, - 'v8_set_return_value': - idl_type.v8_set_return_value( - 'result', - extended_attributes=extended_attributes, - script_wrappable='impl'), - } - - -def property_setter(setter, interface): - if not setter: - return None - - extended_attributes = setter.extended_attributes - idl_type = setter.arguments[1].idl_type - idl_type.add_includes_for_type(extended_attributes) - is_call_with_script_state = v8_utilities.has_extended_attribute_value( - setter, 'CallWith', 'ScriptState') - is_raises_exception = 'RaisesException' in extended_attributes - is_ce_reactions = 'CEReactions' in extended_attributes - - has_type_checking_interface = idl_type.is_wrapper_type - - return { - 'has_exception_state': - (is_raises_exception or idl_type.v8_conversion_needs_exception_state), - 'has_type_checking_interface': - has_type_checking_interface, - 'idl_type': - idl_type.base_type, - 'is_call_with_script_state': - is_call_with_script_state, - 'is_ce_reactions': - is_ce_reactions, - 'is_custom': - 'Custom' in extended_attributes, - 'is_nullable': - idl_type.is_nullable, - 'is_raises_exception': - is_raises_exception, - 'name': - cpp_name(setter), - 'v8_value_to_local_cpp_value': - idl_type.v8_value_to_local_cpp_value(extended_attributes, 'v8_value', - 'property_value'), - } - - -def property_deleter(deleter): - if not deleter: - return None - - extended_attributes = deleter.extended_attributes - is_call_with_script_state = v8_utilities.has_extended_attribute_value( - deleter, 'CallWith', 'ScriptState') - is_ce_reactions = 'CEReactions' in extended_attributes - return { - 'is_call_with_script_state': is_call_with_script_state, - 'is_ce_reactions': is_ce_reactions, - 'is_custom': 'Custom' in extended_attributes, - 'is_raises_exception': 'RaisesException' in extended_attributes, - 'name': cpp_name(deleter), - } |