def methods_context()

in bindings/scripts/v8_interface.py [0:0]


def methods_context(interface):
    """Creates a list of Jinja template contexts for methods of an interface.

    Args:
        interface: An interface to create contexts for

    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, is_visible=False)
                        for operation in interface.original_interface.operations
                        if operation.name])
    methods.extend([v8_methods.method_context(interface, method)
                    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, 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)

    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(Function callback, [Default=Undefined] optional any thisArg)
                    generated_method(IdlType('void'), 'forEach',
                                     arguments=[generated_argument(IdlType('Function'), 'callback'),
                                                generated_argument(IdlType('any'), 'thisArg',
                                                                   is_optional=True,
                                                                   extended_attributes={'Default': '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.

    # Serializer
    if interface.serializer:
        serializer = interface.serializer
        serializer_ext_attrs = serializer.extended_attributes.copy()
        if serializer.operation:
            return_type = serializer.operation.idl_type
            implemented_as = serializer.operation.name
        else:
            return_type = IdlType('any')
            implemented_as = None
            if 'CallWith' not in serializer_ext_attrs:
                serializer_ext_attrs['CallWith'] = 'ScriptState'
        methods.append(generated_method(
            return_type=return_type,
            name='toJSON',
            extended_attributes=serializer_ext_attrs,
            implemented_as=implemented_as))

    # 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,
    }