def test_is_record(self):
     idl_type = IdlType('USVString')
     self.assertFalse(idl_type.is_record_type)
     idl_type = IdlSequenceType(
         IdlRecordType(IdlType('DOMString'), IdlType('byte')))
     self.assertFalse(idl_type.is_record_type)
     idl_type = IdlRecordType(IdlType('USVString'), IdlType('long'))
     self.assertTrue(idl_type.is_record_type)
     idl_type = IdlRecordType(IdlType('USVString'),
                              IdlSequenceType(IdlType('boolean')))
     self.assertTrue(idl_type.is_record_type)
Example #2
0
 def test_name(self):
     idl_type = IdlRecordType(IdlType('ByteString'), IdlType('octet'))
     self.assertEqual(idl_type.name, 'ByteStringOctetRecord')
     idl_type = IdlRecordType(IdlType('USVString'),
                              IdlSequenceType(IdlType('double')))
     self.assertEqual(idl_type.name, 'USVStringDoubleSequenceRecord')
     idl_type = IdlRecordType(
         IdlType('DOMString'),
         IdlRecordType(IdlType('ByteString'),
                       IdlSequenceType(IdlType('unsigned short'))))
     self.assertEqual(idl_type.name,
                      'StringByteStringUnsignedShortSequenceRecordRecord')
Example #3
0
def record_node_to_type(node):
    children = node.GetChildren()
    if len(children) != 2:
        raise ValueError('record<K,V> node expects exactly 2 children, got %d'
                         % (len(children)))
    key_child = children[0]
    value_child = children[1]
    if key_child.GetClass() != 'StringType':
        raise ValueError('Keys in record<K,V> nodes must be string types.')
    if value_child.GetClass() != 'Type':
        raise ValueError('Unrecognized node class for record<K,V> value: %s' %
                         value_child.GetClass())
    return IdlRecordType(
        IdlType(key_child.GetName()), type_node_to_type(value_child))
Example #4
0
    def generate_interface_code(self, definitions, interface_name, interface):
        # Store other interfaces for introspection
        interfaces.update(definitions.interfaces)

        interface_info = self.info_provider.interfaces_info[interface_name]
        full_path = interface_info.get('full_path')
        component = idl_filename_to_component(full_path)
        include_paths = interface_info.get('dependencies_include_paths')

        # Select appropriate Jinja template and contents function
        if interface.is_callback:
            header_template_filename = 'callback_interface.h'
            cpp_template_filename = 'callback_interface.cpp'
            interface_context = v8_callback_interface.callback_interface_context
        elif interface.is_partial:
            interface_context = v8_interface.interface_context
            header_template_filename = 'partial_interface.h'
            cpp_template_filename = 'partial_interface.cpp'
            interface_name += 'Partial'
            assert component == 'core'
            component = 'modules'
            include_paths = interface_info.get(
                'dependencies_other_component_include_paths')
        else:
            header_template_filename = 'interface.h'
            cpp_template_filename = 'interface.cpp'
            interface_context = v8_interface.interface_context
        header_template = self.jinja_env.get_template(header_template_filename)
        cpp_template = self.jinja_env.get_template(cpp_template_filename)

        template_context = interface_context(interface)
        if not interface.is_partial and not is_testing_target(full_path):
            template_context['header_includes'].add(
                self.info_provider.include_path_for_export)
            template_context[
                'exported'] = self.info_provider.specifier_for_export
        # Add the include for interface itself
        if IdlType(interface_name).is_typed_array:
            template_context['header_includes'].add('core/dom/DOMTypedArray.h')
        elif interface_info['include_path']:
            template_context['header_includes'].add(
                interface_info['include_path'])
        header_text, cpp_text = render_template(include_paths, header_template,
                                                cpp_template, template_context,
                                                component)
        header_path, cpp_path = self.output_paths(interface_name)
        return (
            (header_path, header_text),
            (cpp_path, cpp_text),
        )
Example #5
0
def preprocess_idl_type_and_value(idl_type, cpp_value, extended_attributes):
    """Returns IDL type and value, with preliminary type conversions applied."""
    idl_type = idl_type.preprocessed_type
    if idl_type.name == 'Promise':
        idl_type = IdlType('ScriptValue')
    if idl_type.base_type in ['long long', 'unsigned long long']:
        # long long and unsigned long long are not representable in ECMAScript;
        # we represent them as doubles.
        is_nullable = idl_type.is_nullable
        idl_type = IdlType('double')
        if is_nullable:
            idl_type = IdlNullableType(idl_type)
        cpp_value = 'static_cast<double>(%s)' % cpp_value
    # HTML5 says that unsigned reflected attributes should be in the range
    # [0, 2^31). When a value isn't in this range, a default value (or 0)
    # should be returned instead.
    extended_attributes = extended_attributes or {}
    if ('Reflect' in extended_attributes
            and idl_type.base_type in ['unsigned long', 'unsigned short']):
        cpp_value = cpp_value.replace('getUnsignedIntegralAttribute',
                                      'getIntegralAttribute')
        cpp_value = 'std::max(0, static_cast<int>(%s))' % cpp_value
    return idl_type, cpp_value
Example #6
0
    def __init__(self, idl_name, node):
        """Args: node: AST root node, class == 'File'"""
        self.callback_functions = {}
        self.dictionaries = {}
        self.enumerations = {}
        self.interfaces = {}
        self.idl_name = idl_name

        node_class = node.GetClass()
        if node_class != 'File':
            raise ValueError('Unrecognized node class: %s' % node_class)

        typedefs = dict(
            (typedef_name, IdlType(type_name))
            for typedef_name, type_name in STANDARD_TYPEDEFS.iteritems())

        children = node.GetChildren()
        for child in children:
            child_class = child.GetClass()
            if child_class == 'Interface':
                interface = IdlInterface(idl_name, child)
                self.interfaces[interface.name] = interface
            elif child_class == 'Exception':
                exception = IdlException(idl_name, child)
                # For simplicity, treat exceptions as interfaces
                self.interfaces[exception.name] = exception
            elif child_class == 'Typedef':
                type_name = child.GetName()
                typedefs[type_name] = typedef_node_to_type(child)
            elif child_class == 'Enum':
                enumeration = IdlEnum(idl_name, child)
                self.enumerations[enumeration.name] = enumeration
            elif child_class == 'Callback':
                callback_function = IdlCallbackFunction(idl_name, child)
                self.callback_functions[
                    callback_function.name] = callback_function
            elif child_class == 'Implements':
                # Implements is handled at the interface merging step
                pass
            elif child_class == 'Dictionary':
                dictionary = IdlDictionary(idl_name, child)
                self.dictionaries[dictionary.name] = dictionary
            else:
                raise ValueError('Unrecognized node class: %s' % child_class)

        # Typedefs are not stored in IR:
        # Resolve typedefs with the actual types and then discard the Typedefs.
        # http://www.w3.org/TR/WebIDL/#idl-typedefs
        self.resolve_typedefs(typedefs)
Example #7
0
def type_node_inner_to_type(node, is_array=False, is_nullable=False):
    # FIXME: remove is_array and is_nullable once have IdlArrayType and IdlNullableType
    node_class = node.GetClass()
    # Note Type*r*ef, not Typedef, meaning the type is an identifier, thus
    # either a typedef shorthand (but not a Typedef declaration itself) or an
    # interface type. We do not distinguish these, and just use the type name.
    if node_class in ['PrimitiveType', 'Typeref']:
        # unrestricted syntax: unrestricted double | unrestricted float
        is_unrestricted = node.GetProperty('UNRESTRICTED') or False
        return IdlType(node.GetName(),
                       is_array=is_array,
                       is_nullable=is_nullable,
                       is_unrestricted=is_unrestricted)
    elif node_class == 'Any':
        return IdlType('any', is_array=is_array, is_nullable=is_nullable)
    elif node_class == 'Sequence':
        if is_array:
            raise ValueError('Arrays of sequences are not supported')
        return sequence_node_to_type(node, is_nullable=is_nullable)
    elif node_class == 'UnionType':
        if is_array:
            raise ValueError('Arrays of unions are not supported')
        return union_type_node_to_idl_union_type(node, is_nullable=is_nullable)
    raise ValueError('Unrecognized node class: %s' % node_class)
    def test_add_method(self):
        helper = IdlTestingHelper()
        builder = InterfaceContextBuilder(
            'test',
            TypeResolver(
                helper.make_stub_interfaces_info({
                    'foo': 'path_to_foo',
                    'bar': 'path_to_bar',
                    'garply': 'path_to_garply',
                })))

        operation = helper.make_stub_idl_operation('foo', 'bar')
        builder.add_operation(operation)
        self.assertEqual(
            {
                'code_generator': 'test',
                'cpp_includes': set(['path_to_bar']),
                'methods': [{
                    'arguments': [],
                    'name': 'Foo',
                    'type': 'bar'
                }],
            }, builder.build())

        operation = helper.make_stub_idl_operation('quux', 'garply')
        operation.arguments = [
            helper.make_stub_idl_argument('barBaz', IdlType('qux'))
        ]
        builder.add_operation(operation)
        self.assertEqual(
            {
                'code_generator':
                'test',
                'cpp_includes':
                set(['path_to_bar', 'path_to_garply']),
                'methods': [{
                    'arguments': [],
                    'name': 'Foo',
                    'type': 'bar'
                }, {
                    'arguments': [{
                        'name': 'bar_baz',
                        'type': 'qux'
                    }],
                    'name': 'Quux',
                    'type': 'garply'
                }],
            }, builder.build())
Example #9
0
def dictionary_context(dictionary, interfaces_info):
    includes.clear()
    includes.update(DICTIONARY_CPP_INCLUDES)

    if 'RuntimeEnabled' in dictionary.extended_attributes:
        raise Exception('Dictionary cannot be RuntimeEnabled: %s' %
                        dictionary.name)

    members = [
        member_context(dictionary, member)
        for member in sorted(dictionary.members,
                             key=operator.attrgetter('name'))
    ]

    for member in members:
        if member['runtime_enabled_function']:
            includes.add('platform/RuntimeEnabledFeatures.h')
            break

    cpp_class = v8_utilities.cpp_name(dictionary)
    context = {
        'cpp_class':
        cpp_class,
        'header_includes':
        set(DICTIONARY_H_INCLUDES),
        'members':
        members,
        'required_member_names':
        sorted([
            member.name for member in dictionary.members if member.is_required
        ]),
        'use_permissive_dictionary_conversion':
        'PermissiveDictionaryConversion' in dictionary.extended_attributes,
        'v8_class':
        v8_types.v8_type(cpp_class),
        'v8_original_class':
        v8_types.v8_type(dictionary.name),
    }
    if dictionary.parent:
        IdlType(dictionary.parent).add_includes_for_type()
        parent_cpp_class = v8_utilities.cpp_name_from_interfaces_info(
            dictionary.parent, interfaces_info)
        context.update({
            'parent_cpp_class': parent_cpp_class,
            'parent_v8_class': v8_types.v8_type(parent_cpp_class),
        })
    return context
Example #10
0
    def __init__(self, idl_name, node=None):
        self.attributes = []
        self.constants = []
        self.constructors = []
        self.custom_constructors = []
        self.extended_attributes = {}
        self.operations = []
        self.parent = None
        self.stringifier = None
        self.original_interface = None
        self.partial_interfaces = []
        if not node:  # Early exit for IdlException.__init__
            return

        self.is_callback = node.GetProperty('CALLBACK') or False
        self.is_exception = False
        # FIXME: uppercase 'Partial' => 'PARTIAL' in base IDL parser
        self.is_partial = node.GetProperty('Partial') or False
        self.idl_name = idl_name
        self.name = node.GetName()
        self.idl_type = IdlType(self.name)

        children = node.GetChildren()
        for child in children:
            child_class = child.GetClass()
            if child_class == 'Attribute':
                self.attributes.append(IdlAttribute(idl_name, child))
            elif child_class == 'Const':
                self.constants.append(IdlConstant(idl_name, child))
            elif child_class == 'ExtAttributes':
                extended_attributes = ext_attributes_node_to_extended_attributes(
                    idl_name, child)
                self.constructors, self.custom_constructors = (
                    extended_attributes_to_constructors(
                        idl_name, extended_attributes))
                clear_constructor_attributes(extended_attributes)
                self.extended_attributes = extended_attributes
            elif child_class == 'Operation':
                self.operations.append(IdlOperation(idl_name, child))
            elif child_class == 'Inherit':
                self.parent = child.GetName()
            elif child_class == 'Stringifier':
                self.stringifier = IdlStringifier(idl_name, child)
                self.process_stringifier()
            else:
                raise ValueError('Unrecognized node class: %s' % child_class)
Example #11
0
def preprocess_idl_type_and_value(idl_type, cpp_value, extended_attributes):
    """Returns IDL type and value, with preliminary type conversions applied."""
    idl_type = idl_type.preprocessed_type
    if idl_type.name == 'Promise':
        idl_type = IdlType('ScriptPromise')

    # FIXME(vsm): V8 maps 'long long' and 'unsigned long long' to double
    # as they are not representable in ECMAScript.  Should we do the same?

    # HTML5 says that unsigned reflected attributes should be in the range
    # [0, 2^31). When a value isn't in this range, a default value (or 0)
    # should be returned instead.
    extended_attributes = extended_attributes or {}
    if ('Reflect' in extended_attributes and
        idl_type.base_type in ['unsigned long', 'unsigned short']):
        cpp_value = cpp_value.replace('getUnsignedIntegralAttribute',
                                      'getIntegralAttribute')
        cpp_value = 'std::max(0, %s)' % cpp_value
    return idl_type, cpp_value
Example #12
0
def dictionary_context(dictionary, interfaces_info):
    includes.clear()
    includes.update(DICTIONARY_CPP_INCLUDES)
    cpp_class = v8_utilities.cpp_name(dictionary)
    context = {
        'cpp_class': cpp_class,
        'header_includes': set(DICTIONARY_H_INCLUDES),
        'members': [member_context(member)
                    for member in sorted(dictionary.members,
                                         key=operator.attrgetter('name'))],
        'use_permissive_dictionary_conversion': 'PermissiveDictionaryConversion' in dictionary.extended_attributes,
        'v8_class': v8_types.v8_type(cpp_class),
        'v8_original_class': v8_types.v8_type(dictionary.name),
    }
    if dictionary.parent:
        IdlType(dictionary.parent).add_includes_for_type()
        parent_cpp_class = v8_utilities.cpp_name_from_interfaces_info(
            dictionary.parent, interfaces_info)
        context.update({
            'parent_cpp_class': parent_cpp_class,
            'parent_v8_class': v8_types.v8_type(parent_cpp_class),
        })
    return context
Example #13
0
    def test_idl_types(self):
        idl_type = IdlRecordType(IdlType('USVString'), IdlType('long'))
        idl_types = list(idl_type.idl_types())
        self.assertEqual(len(idl_types), 3)
        self.assertIs(idl_types[0], idl_type)
        self.assertEqual(idl_types[1].name, 'USVString')
        self.assertEqual(idl_types[2].name, 'Long')
        self.assertListEqual(
            list(idl_type.idl_types()),
            [idl_type, idl_type.key_type, idl_type.value_type])

        idl_type = IdlRecordType(
            IdlType('DOMString'),
            IdlSequenceType(IdlType('unrestricted float')))
        idl_types = list(idl_type.idl_types())
        self.assertEqual(len(idl_types), 4)
        self.assertIs(idl_types[0], idl_type)
        self.assertEqual(idl_types[1].name, 'String')
        self.assertEqual(idl_types[2].name, 'UnrestrictedFloatSequence')
        self.assertEqual(idl_types[3].name, 'UnrestrictedFloat')
        self.assertListEqual(list(idl_type.idl_types()), [
            idl_type, idl_type.key_type, idl_type.value_type,
            idl_type.value_type.element_type
        ])

        idl_type = IdlRecordType(
            IdlType('ByteString'),
            IdlRecordType(IdlType('DOMString'), IdlType('octet')))
        idl_types = list(idl_type.idl_types())
        self.assertEqual(len(idl_types), 5)
        self.assertIs(idl_types[0], idl_type)
        self.assertEqual(idl_types[1].name, 'ByteString')
        self.assertEqual(idl_types[2].name, 'StringOctetRecord')
        self.assertEqual(idl_types[3].name, 'String')
        self.assertEqual(idl_types[4].name, 'Octet')
        self.assertListEqual(list(idl_type.idl_types()), [
            idl_type, idl_type.key_type, idl_type.value_type,
            idl_type.value_type.key_type, idl_type.value_type.value_type
        ])
Example #14
0
    def __init__(self, node):
        self.attributes = []
        self.constants = []
        self.constructors = []
        self.custom_constructors = []
        self.extended_attributes = {}
        self.operations = []
        self.parent = None
        self.serializer = None
        self.stringifier = None
        self.iterable = None
        self.has_indexed_elements = False
        self.has_named_property_getter = False
        self.maplike = None
        self.setlike = None
        self.original_interface = None
        self.partial_interfaces = []

        self.is_callback = bool(node.GetProperty('CALLBACK'))
        self.is_partial = bool(node.GetProperty('PARTIAL'))
        self.name = node.GetName()
        self.idl_type = IdlType(self.name)

        has_indexed_property_getter = False
        has_integer_typed_length = False

        def is_blacklisted_attribute_type(idl_type):
            return idl_type.is_callback_function or \
                idl_type.is_dictionary or \
                idl_type.is_record_type or \
                idl_type.is_sequence_type

        children = node.GetChildren()
        for child in children:
            child_class = child.GetClass()
            if child_class == 'Attribute':
                attr = IdlAttribute(child)
                if is_blacklisted_attribute_type(attr.idl_type):
                    raise ValueError('Type "%s" cannot be used as an attribute.' % attr.idl_type)
                if attr.idl_type.is_integer_type and attr.name == 'length':
                    has_integer_typed_length = True
                self.attributes.append(attr)
            elif child_class == 'Const':
                self.constants.append(IdlConstant(child))
            elif child_class == 'ExtAttributes':
                extended_attributes = ext_attributes_node_to_extended_attributes(child)
                self.constructors, self.custom_constructors = (
                    extended_attributes_to_constructors(extended_attributes))
                clear_constructor_attributes(extended_attributes)
                self.extended_attributes = extended_attributes
            elif child_class == 'Operation':
                op = IdlOperation(child)
                if 'getter' in op.specials:
                    if str(op.arguments[0].idl_type) == 'unsigned long':
                        has_indexed_property_getter = True
                    elif str(op.arguments[0].idl_type) == 'DOMString':
                        self.has_named_property_getter = True
                self.operations.append(op)
            elif child_class == 'Inherit':
                self.parent = child.GetName()
            elif child_class == 'Serializer':
                self.serializer = IdlSerializer(child)
                self.process_serializer()
            elif child_class == 'Stringifier':
                self.stringifier = IdlStringifier(child)
                self.process_stringifier()
            elif child_class == 'Iterable':
                self.iterable = IdlIterable(child)
            elif child_class == 'Maplike':
                self.maplike = IdlMaplike(child)
            elif child_class == 'Setlike':
                self.setlike = IdlSetlike(child)
            else:
                raise ValueError('Unrecognized node class: %s' % child_class)

        if len(filter(None, [self.iterable, self.maplike, self.setlike])) > 1:
            raise ValueError('Interface can only have one of iterable<>, maplike<> and setlike<>.')

        # TODO(rakuco): This validation logic should be in v8_interface according to bashi@.
        # At the moment, doing so does not work because several IDL files are partial Window
        # interface definitions, and interface_dependency_resolver.py doesn't seem to have any logic
        # to prevent these partial interfaces from resetting has_named_property to False.
        if 'LegacyUnenumerableNamedProperties' in self.extended_attributes and \
           not self.has_named_property_getter:
            raise ValueError('[LegacyUnenumerableNamedProperties] can be used only in interfaces '
                             'that support named properties.')

        if has_integer_typed_length and has_indexed_property_getter:
            self.has_indexed_elements = True
        else:
            if self.iterable is not None and self.iterable.key_type is None:
                raise ValueError('Value iterators (iterable<V>) must be accompanied by an indexed '
                                 'property getter and an integer-typed length attribute.')
Example #15
0
    def __init__(self, node):
        self.attributes = []
        self.constants = []
        self.constructors = []
        self.custom_constructors = []
        self.extended_attributes = {}
        self.operations = []
        self.parent = None
        self.stringifier = None
        self.iterable = None
        self.has_indexed_elements = False
        self.has_named_property_getter = False
        self.maplike = None
        self.setlike = None
        self.original_interface = None
        self.partial_interfaces = []

        self.is_callback = bool(node.GetProperty('CALLBACK'))
        self.is_partial = bool(node.GetProperty('PARTIAL'))
        self.is_mixin = bool(node.GetProperty('MIXIN'))
        self.name = node.GetName()
        self.idl_type = IdlType(self.name)

        has_indexed_property_getter = False
        has_integer_typed_length = False

        # These are used to support both constructor operations and old style
        # [Constructor] extended attributes. Ideally we should do refactoring
        # for constructor code generation but we will use a new code generator
        # soon so this kind of workaround should be fine.
        constructor_operations = []
        custom_constructor_operations = []
        constructor_operations_extended_attributes = {}

        def is_blacklisted_attribute_type(idl_type):
            return idl_type.is_callback_function or \
                idl_type.is_dictionary or \
                idl_type.is_record_type or \
                idl_type.is_sequence_type

        children = node.GetChildren()
        for child in children:
            child_class = child.GetClass()
            if child_class == 'Attribute':
                attr = IdlAttribute(child)
                if is_blacklisted_attribute_type(attr.idl_type):
                    raise ValueError(
                        'Type "%s" cannot be used as an attribute.' %
                        attr.idl_type)
                if attr.idl_type.is_integer_type and attr.name == 'length':
                    has_integer_typed_length = True
                self.attributes.append(attr)
            elif child_class == 'Const':
                self.constants.append(IdlConstant(child))
            elif child_class == 'ExtAttributes':
                extended_attributes = ext_attributes_node_to_extended_attributes(
                    child)
                self.constructors, self.custom_constructors = (
                    extended_attributes_to_constructors(extended_attributes))
                clear_constructor_attributes(extended_attributes)
                self.extended_attributes = extended_attributes
            elif child_class == 'Operation':
                op = IdlOperation(child)
                if 'getter' in op.specials:
                    if str(op.arguments[0].idl_type) == 'unsigned long':
                        has_indexed_property_getter = True
                    elif str(op.arguments[0].idl_type) == 'DOMString':
                        self.has_named_property_getter = True
                self.operations.append(op)
            elif child_class == 'Constructor':
                operation = constructor_operation_from_node(child)
                if operation.is_custom:
                    custom_constructor_operations.append(operation.constructor)
                else:
                    # Check extended attributes consistency when we previously
                    # handle constructor operations.
                    if constructor_operations:
                        check_constructor_operations_extended_attributes(
                            constructor_operations_extended_attributes,
                            operation.extended_attributes)
                    constructor_operations.append(operation.constructor)
                    constructor_operations_extended_attributes.update(
                        operation.extended_attributes)
            elif child_class == 'Inherit':
                self.parent = child.GetName()
            elif child_class == 'Stringifier':
                self.stringifier = IdlStringifier(child)
                self.process_stringifier()
            elif child_class == 'Iterable':
                self.iterable = IdlIterable(child)
            elif child_class == 'Maplike':
                self.maplike = IdlMaplike(child)
            elif child_class == 'Setlike':
                self.setlike = IdlSetlike(child)
            else:
                raise ValueError('Unrecognized node class: %s' % child_class)

        if len(filter(None, [self.iterable, self.maplike, self.setlike])) > 1:
            raise ValueError(
                'Interface can only have one of iterable<>, maplike<> and setlike<>.'
            )

        # TODO(rakuco): This validation logic should be in v8_interface according to bashi@.
        # At the moment, doing so does not work because several IDL files are partial Window
        # interface definitions, and interface_dependency_resolver.py doesn't seem to have any logic
        # to prevent these partial interfaces from resetting has_named_property to False.
        if 'LegacyUnenumerableNamedProperties' in self.extended_attributes and \
           not self.has_named_property_getter:
            raise ValueError(
                '[LegacyUnenumerableNamedProperties] can be used only in interfaces '
                'that support named properties.')

        if has_integer_typed_length and has_indexed_property_getter:
            self.has_indexed_elements = True
        else:
            if self.iterable is not None and self.iterable.key_type is None:
                raise ValueError(
                    'Value iterators (iterable<V>) must be accompanied by an indexed '
                    'property getter and an integer-typed length attribute.')

        if 'Unforgeable' in self.extended_attributes:
            raise ValueError('[Unforgeable] cannot appear on interfaces.')

        if constructor_operations or custom_constructor_operations:
            if self.constructors or self.custom_constructors:
                raise ValueError('Detected mixed [Constructor] and consructor '
                                 'operations. Do not use both in a single '
                                 'interface.')
            extended_attributes = (
                convert_constructor_operations_extended_attributes(
                    constructor_operations_extended_attributes))
            if any(name in extended_attributes.keys()
                   for name in self.extended_attributes.keys()):
                raise ValueError('Detected mixed extended attributes for '
                                 'both [Constructor] and constructor '
                                 'operations. Do not use both in a single '
                                 'interface')
            self.constructors = constructor_operations
            self.custom_constructors = custom_constructor_operations
            self.extended_attributes.update(extended_attributes)
 def test_invalid_inner_type_any(self):
     inner_type = IdlType('any')
     with self.assertRaises(ValueError):
         IdlNullableType(inner_type)
Example #17
0
    def __init__(self, node=None):
        self.attributes = []
        self.constants = []
        self.constructors = []
        self.custom_constructors = []
        self.extended_attributes = {}
        self.operations = []
        self.parent = None
        self.serializer = None
        self.stringifier = None
        self.iterable = None
        self.has_indexed_elements = False
        self.maplike = None
        self.setlike = None
        self.original_interface = None
        self.partial_interfaces = []
        if not node:  # Early exit for IdlException.__init__
            return

        self.is_callback = bool(node.GetProperty('CALLBACK'))
        self.is_exception = False
        # FIXME: uppercase 'Partial' => 'PARTIAL' in base IDL parser
        self.is_partial = bool(node.GetProperty('Partial'))
        self.name = node.GetName()
        self.idl_type = IdlType(self.name)

        has_indexed_property_getter = False
        has_integer_typed_length = False

        children = node.GetChildren()
        for child in children:
            child_class = child.GetClass()
            if child_class == 'Attribute':
                attr = IdlAttribute(child)
                if attr.idl_type.is_integer_type and attr.name == 'length':
                    has_integer_typed_length = True
                self.attributes.append(attr)
            elif child_class == 'Const':
                self.constants.append(IdlConstant(child))
            elif child_class == 'ExtAttributes':
                extended_attributes = ext_attributes_node_to_extended_attributes(
                    child)
                self.constructors, self.custom_constructors = (
                    extended_attributes_to_constructors(extended_attributes))
                clear_constructor_attributes(extended_attributes)
                self.extended_attributes = extended_attributes
            elif child_class == 'Operation':
                op = IdlOperation(child)
                if 'getter' in op.specials and str(
                        op.arguments[0].idl_type) == 'unsigned long':
                    has_indexed_property_getter = True
                self.operations.append(op)
            elif child_class == 'Inherit':
                self.parent = child.GetName()
            elif child_class == 'Serializer':
                self.serializer = IdlSerializer(child)
                self.process_serializer()
            elif child_class == 'Stringifier':
                self.stringifier = IdlStringifier(child)
                self.process_stringifier()
            elif child_class == 'Iterable':
                self.iterable = IdlIterable(child)
            elif child_class == 'Maplike':
                self.maplike = IdlMaplike(child)
            elif child_class == 'Setlike':
                self.setlike = IdlSetlike(child)
            else:
                raise ValueError('Unrecognized node class: %s' % child_class)

        if len(filter(None, [self.iterable, self.maplike, self.setlike])) > 1:
            raise ValueError(
                'Interface can only have one of iterable<>, maplike<> and setlike<>.'
            )

        if has_integer_typed_length and has_indexed_property_getter:
            self.has_indexed_elements = True
        else:
            if self.iterable is not None and self.iterable.key_type is None:
                raise ValueError(
                    'Value iterators (iterable<V>) must be accompanied by an indexed '
                    'property getter and an integer-typed length attribute.')
 def make_stub_idl_type(self, base_type):
     return IdlType(base_type)
 def make_stub_idl_operation(self, name, return_type):
     idl_operation_stub = IdlOperation()
     idl_operation_stub.name = name
     idl_operation_stub.idl_type = IdlType(return_type)
     return idl_operation_stub
 def test_invalid_inner_type_nullable(self):
     inner_type = IdlNullableType(IdlType('long'))
     with self.assertRaises(ValueError):
         IdlNullableType(inner_type)
Example #21
0
    def generate_interface_code(self, definitions, interface_name, interface):
        interface_info = self.info_provider.interfaces_info[interface_name]
        full_path = interface_info.get('full_path')
        component = idl_filename_to_component(full_path)
        include_paths = interface_info.get('dependencies_include_paths')

        # Select appropriate Jinja template and contents function
        #
        # A callback interface with constants needs a special handling.
        # https://heycam.github.io/webidl/#legacy-callback-interface-object
        if interface.is_callback and len(interface.constants) > 0:
            header_template_filename = 'legacy_callback_interface.h.tmpl'
            cpp_template_filename = 'legacy_callback_interface.cpp.tmpl'
            interface_context = v8_callback_interface.legacy_callback_interface_context
        elif interface.is_callback:
            header_template_filename = 'callback_interface.h.tmpl'
            cpp_template_filename = 'callback_interface.cpp.tmpl'
            interface_context = v8_callback_interface.callback_interface_context
        elif interface.is_partial:
            interface_context = v8_interface.interface_context
            header_template_filename = 'partial_interface.h.tmpl'
            cpp_template_filename = 'partial_interface.cpp.tmpl'
            interface_name += 'Partial'
            assert component == 'core'
            component = 'modules'
            include_paths = interface_info.get(
                'dependencies_other_component_include_paths')
        else:
            header_template_filename = 'interface.h.tmpl'
            cpp_template_filename = 'interface.cpp.tmpl'
            interface_context = v8_interface.interface_context

        template_context = interface_context(interface, definitions.interfaces)
        includes.update(
            interface_info.get('cpp_includes', {}).get(component, set()))
        if not interface.is_partial and not is_testing_target(full_path):
            template_context['header_includes'].add(
                self.info_provider.include_path_for_export)
            template_context[
                'exported'] = self.info_provider.specifier_for_export
        # Add the include for interface itself
        if IdlType(interface_name).is_typed_array:
            template_context['header_includes'].add(
                'core/typed_arrays/DOMTypedArray.h')
        else:
            template_context['header_includes'].add(
                interface_info['include_path'])
        template_context['header_includes'].update(
            interface_info.get('additional_header_includes', []))
        header_template = self.jinja_env.get_template(header_template_filename)
        cpp_template = self.jinja_env.get_template(cpp_template_filename)
        header_text, cpp_text = self.render_template(include_paths,
                                                     header_template,
                                                     cpp_template,
                                                     template_context,
                                                     component)
        header_path, cpp_path = self.output_paths(interface_name)
        return (
            (header_path, header_text),
            (cpp_path, cpp_text),
        )
Example #22
0
    def generate_interface_code(self, definitions, interface_name, interface):
        interface_info = self.info_provider.interfaces_info[interface_name]
        full_path = interface_info.get('full_path')
        component = idl_filename_to_component(full_path)
        include_paths = interface_info.get('dependencies_include_paths')

        # Select appropriate Jinja template and contents function
        if interface.is_callback:
            header_template_filename = 'callback_interface.h.tmpl'
            cpp_template_filename = 'callback_interface.cc.tmpl'
            interface_context = v8_callback_interface.callback_interface_context
        elif interface.is_partial:
            interface_context = v8_interface.interface_context
            header_template_filename = 'partial_interface.h.tmpl'
            cpp_template_filename = 'partial_interface.cc.tmpl'
            interface_name += 'Partial'
            assert component == 'core'
            component = 'modules'
            include_paths = interface_info.get(
                'dependencies_other_component_include_paths')
        else:
            header_template_filename = 'interface.h.tmpl'
            cpp_template_filename = 'interface.cc.tmpl'
            interface_context = v8_interface.interface_context

        component_info = self.info_provider.component_info
        template_context = interface_context(interface, definitions.interfaces,
                                             component_info)
        includes.update(
            interface_info.get('cpp_includes', {}).get(component, set()))
        if not interface.is_partial and not is_testing_target(full_path):
            template_context['header_includes'].add(
                self.info_provider.include_path_for_export)
            template_context['exported'] = \
                self.info_provider.specifier_for_export
        # Add the include for interface itself
        if IdlType(interface_name).is_typed_array:
            template_context['header_includes'].add(
                'core/typed_arrays/dom_typed_array.h')
        elif interface.is_callback:
            pass
        else:
            template_context['header_includes'].add(
                interface_info['include_path'])
        template_context['header_includes'].update(
            interface_info.get('additional_header_includes', []))
        header_path, cpp_path = self.output_paths(interface_name)
        this_include_header_path = self.normalize_this_header_path(header_path)
        template_context['this_include_header_path'] = this_include_header_path
        template_context['header_guard'] = to_header_guard(
            this_include_header_path)
        header_template = self.jinja_env.get_template(header_template_filename)
        cpp_template = self.jinja_env.get_template(cpp_template_filename)
        header_text, cpp_text = self.render_templates(include_paths,
                                                      header_template,
                                                      cpp_template,
                                                      template_context,
                                                      component)
        return (
            (header_path, header_text),
            (cpp_path, cpp_text),
        )
 def test_invalid_inner_type_union_nullable_member(self):
     inner_type = IdlUnionType([IdlNullableType(IdlType('long'))])
     with self.assertRaises(ValueError):
         IdlNullableType(inner_type)
Example #24
0
 def test_is_void(self):
     idl_type = IdlType('void')
     self.assertTrue(idl_type.is_void)
     idl_type = IdlType('somethingElse')
     self.assertFalse(idl_type.is_void)
Example #25
0
def interface_context(interface):
    includes.clear()
    includes.update(INTERFACE_CPP_INCLUDES)
    header_includes = set(INTERFACE_H_INCLUDES)

    parent_interface = interface.parent
    if parent_interface:
        header_includes.update(
            v8_types.includes_for_interface(parent_interface))
    extended_attributes = interface.extended_attributes

    # [ActiveDOMObject]
    is_active_dom_object = 'ActiveDOMObject' in extended_attributes

    # [DependentLifetime]
    is_dependent_lifetime = 'DependentLifetime' in extended_attributes

    # [Iterable]
    iterator_method = None
    if 'Iterable' in extended_attributes:
        iterator_operation = IdlOperation(interface.idl_name)
        iterator_operation.name = 'iterator'
        iterator_operation.idl_type = IdlType('Iterator')
        iterator_operation.extended_attributes['RaisesException'] = None
        iterator_operation.extended_attributes['CallWith'] = 'ScriptState'
        iterator_method = v8_methods.method_context(interface,
                                                    iterator_operation)

    # [SetWrapperReferenceFrom]
    reachable_node_function = extended_attributes.get(
        'SetWrapperReferenceFrom')
    if reachable_node_function:
        includes.update(['core/dom/Element.h'])

    # [SetWrapperReferenceTo]
    set_wrapper_reference_to_list = [
        {
            'name': argument.name,
            # FIXME: properly should be:
            # 'cpp_type': argument.idl_type.cpp_type_args(raw_type=True),
            # (if type is non-wrapper type like NodeFilter, normally RefPtr)
            # Raw pointers faster though, and NodeFilter hacky anyway.
            'cpp_type': argument.idl_type.implemented_as + '*',
            'idl_type': argument.idl_type,
        } for argument in extended_attributes.get('SetWrapperReferenceTo', [])
    ]
    for set_wrapper_reference_to in set_wrapper_reference_to_list:
        set_wrapper_reference_to['idl_type'].add_includes_for_type()

    # [NotScriptWrappable]
    is_script_wrappable = 'NotScriptWrappable' not in extended_attributes

    # [SpecialWrapFor]
    if 'SpecialWrapFor' in extended_attributes:
        special_wrap_for = extended_attribute_value_as_list(
            interface, 'SpecialWrapFor')
    else:
        special_wrap_for = []
    for special_wrap_interface in special_wrap_for:
        v8_types.add_includes_for_interface(special_wrap_interface)

    # [Custom=Wrap], [SetWrapperReferenceFrom]
    has_visit_dom_wrapper = (has_extended_attribute_value(
        interface, 'Custom', 'VisitDOMWrapper') or reachable_node_function
                             or set_wrapper_reference_to_list)

    wrapper_class_id = ('NodeClassId' if inherits_interface(
        interface.name, 'Node') else 'ObjectClassId')

    context = {
        'cpp_class':
        cpp_name(interface),
        'has_custom_wrap':
        has_extended_attribute_value(interface, 'Custom',
                                     'Wrap'),  # [Custom=Wrap]
        'has_visit_dom_wrapper':
        has_visit_dom_wrapper,
        'header_includes':
        header_includes,
        'interface_name':
        interface.name,
        'is_active_dom_object':
        is_active_dom_object,
        'is_dependent_lifetime':
        is_dependent_lifetime,
        'is_exception':
        interface.is_exception,
        'is_script_wrappable':
        is_script_wrappable,
        'iterator_method':
        iterator_method,
        'lifetime':
        'Dependent' if (has_visit_dom_wrapper or is_active_dom_object
                        or is_dependent_lifetime) else 'Independent',
        'parent_interface':
        parent_interface,
        'reachable_node_function':
        reachable_node_function,
        'set_wrapper_reference_to_list':
        set_wrapper_reference_to_list,
        'special_wrap_for':
        special_wrap_for,
        '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(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]

    # [EventConstructor]
    has_event_constructor = 'EventConstructor' in extended_attributes
    any_type_attributes = [
        attribute for attribute in interface.attributes
        if attribute.idl_type.name == 'Any'
    ]

    # [NamedConstructor]
    named_constructor = named_constructor_context(interface)

    if (constructors or custom_constructors or has_event_constructor
            or named_constructor):
        includes.add('core/frame/LocalDOMWindow.h')

    context.update({
        'any_type_attributes':
        any_type_attributes,
        'constructors':
        constructors,
        'has_custom_constructor':
        bool(custom_constructors),
        'has_event_constructor':
        has_event_constructor,
        'interface_length':
        interface_length(interface, constructors + custom_constructors),
        'is_constructor_raises_exception':
        extended_attributes.get('RaisesException') ==
        'Constructor',  # [RaisesException=Constructor]
        'named_constructor':
        named_constructor,
    })

    constants = [
        constant_context(constant) for constant in interface.constants
    ]

    # Constants
    context.update({
        'constants': constants,
        'has_constant_configuration': True,
    })

    # Attributes
    attributes = [
        v8_attributes.attribute_context(interface, attribute)
        for attribute in interface.attributes
    ]
    context.update({
        'attributes':
        attributes,
        'has_conditional_attributes':
        any(attribute['exposed_test'] for attribute in attributes),
        'has_constructor_attributes':
        any(attribute['constructor_type'] for attribute in attributes),
        'has_replaceable_attributes':
        any(attribute['is_replaceable'] for attribute in attributes),
    })

    # Methods
    methods = [
        v8_methods.method_context(interface, method)
        for method in interface.operations if method.name
    ]  # Skip anonymous special operations (methods)
    compute_method_overloads_context(methods)

    # Stringifier
    if interface.stringifier:
        stringifier = interface.stringifier
        method = IdlOperation(interface.idl_name)
        method.name = 'toString'
        method.idl_type = IdlType('DOMString')
        method.extended_attributes.update(stringifier.extended_attributes)
        if stringifier.attribute:
            method.extended_attributes[
                'ImplementedAs'] = stringifier.attribute.name
        elif stringifier.operation:
            method.extended_attributes[
                'ImplementedAs'] = stringifier.operation.name
        methods.append(v8_methods.method_context(interface, method))

    conditionally_enabled_methods = []
    custom_registration_methods = []
    method_configuration_methods = []

    for method in methods:
        # Skip all but one method in each set of overloaded methods.
        if 'overload_index' in method and 'overloads' not in method:
            continue

        if 'overloads' in method:
            overloads = method['overloads']
            conditionally_exposed_function = overloads['exposed_test_all']
            has_custom_registration = overloads['has_custom_registration_all']
        else:
            conditionally_exposed_function = method['exposed_test']
            has_custom_registration = method['has_custom_registration']

        if conditionally_exposed_function:
            conditionally_enabled_methods.append(method)
            continue
        if has_custom_registration:
            custom_registration_methods.append(method)
            continue
        method_configuration_methods.append(method)

    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']['minarg']
                            if 'overloads' in method else
                            method['number_of_required_arguments'])

    context.update({
        'conditionally_enabled_methods': conditionally_enabled_methods,
        'custom_registration_methods': custom_registration_methods,
        'method_configuration_methods': method_configuration_methods,
        'methods': methods,
    })

    context.update({
        'indexed_property_getter':
        indexed_property_getter(interface),
        'indexed_property_setter':
        indexed_property_setter(interface),
        'indexed_property_deleter':
        indexed_property_deleter(interface),
        'is_override_builtins':
        'OverrideBuiltins' in extended_attributes,
        'named_property_getter':
        named_property_getter(interface),
        'named_property_setter':
        named_property_setter(interface),
        'named_property_deleter':
        named_property_deleter(interface),
    })

    return context
 def test_invalid_inner_type_promise(self):
     inner_type = IdlType('Promise')
     with self.assertRaises(ValueError):
         IdlNullableType(inner_type)
Example #27
0
    def test_flattened_member_types(self):
        # We are only testing the algorithm here, so we do create some ambiguous union types.

        def compare_flattened_members(actual, expected):
            """Compare a set of IDL types by name, as the objects are different"""
            actual_names = set([member.name for member in actual])
            expected_names = set([member.name for member in expected])
            self.assertEqual(actual_names, expected_names)

        idl_type = IdlUnionType([IdlType('long'), IdlType('SomeInterface')])
        compare_flattened_members(
            idl_type.flattened_member_types,
            set([IdlType('long'), IdlType('SomeInterface')]))

        idl_type = IdlUnionType([
            IdlUnionType([IdlType('ByteString'),
                          IdlType('float')]),
            IdlType('boolean')
        ])
        compare_flattened_members(
            idl_type.flattened_member_types,
            set([IdlType('float'),
                 IdlType('boolean'),
                 IdlType('ByteString')]))

        idl_type = IdlUnionType([
            IdlUnionType([IdlType('ByteString'),
                          IdlType('DOMString')]),
            IdlType('DOMString')
        ])
        compare_flattened_members(
            idl_type.flattened_member_types,
            set([IdlType('DOMString'),
                 IdlType('ByteString')]))

        idl_type = IdlUnionType(
            [IdlNullableType(IdlType('ByteString')),
             IdlType('byte')])
        compare_flattened_members(
            idl_type.flattened_member_types,
            set([IdlType('ByteString'), IdlType('byte')]))

        idl_type = IdlUnionType([
            IdlNullableType(IdlType('ByteString')),
            IdlType('byte'),
            IdlUnionType([IdlType('ByteString'),
                          IdlType('float')])
        ])
        self.assertEqual(len(idl_type.flattened_member_types), 3)
        compare_flattened_members(
            idl_type.flattened_member_types,
            set([IdlType('ByteString'),
                 IdlType('byte'),
                 IdlType('float')]))

        # From the example in the spec: "the flattened member types of the union type (Node or (sequence<long> or Event) or
        # (XMLHttpRequest or DOMString)? or sequence<(sequence<double> or NodeList)>) are the six types Node, sequence<long>,
        # Event, XMLHttpRequest, DOMString and sequence<(sequence<double> or NodeList)>"
        idl_type = IdlUnionType([
            IdlType('Node'),
            IdlUnionType([IdlSequenceType(IdlType('long')),
                          IdlType('Event')]),
            IdlNullableType(
                IdlUnionType([IdlType('XMLHttpRequest'),
                              IdlType('DOMString')])),
            IdlSequenceType(
                IdlUnionType(
                    [IdlSequenceType(IdlType('double')),
                     IdlType('NodeList')]))
        ])
        self.assertEqual(len(idl_type.flattened_member_types), 6)
        compare_flattened_members(
            idl_type.flattened_member_types,
            set([
                IdlType('Node'),
                IdlSequenceType(IdlType('long')),
                IdlType('Event'),
                IdlType('XMLHttpRequest'),
                IdlType('DOMString'),
                IdlSequenceType(
                    IdlUnionType([
                        IdlSequenceType(IdlType('double')),
                        IdlType('NodeList')
                    ]))
            ]))
Example #28
0
def includes_for_interface(interface_name):
    return IdlType(interface_name).includes_for_type
 def test_invalid_inner_type_union_dictionary_member(self):
     inner_type = IdlUnionType([IdlType(self._TEST_DICTIONARY)])
     with self.assertRaises(ValueError):
         IdlNullableType(inner_type)
 def make_stub_idl_attribute(self, name, return_type):
     idl_attribute_stub = IdlAttribute()
     idl_attribute_stub.name = name
     idl_attribute_stub.idl_type = IdlType(return_type)
     return idl_attribute_stub