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)
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')
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))
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), )
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
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)
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())
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
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)
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
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
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 ])
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.')
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)
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)
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), )
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)
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)
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)
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') ])) ]))
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