| # Copyright 2019 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from .code_generator_info import CodeGeneratorInfoMutable |
| from .composition_parts import Identifier |
| from .composition_parts import WithCodeGeneratorInfo |
| from .composition_parts import WithComponent |
| from .composition_parts import WithDebugInfo |
| from .composition_parts import WithIdentifier |
| from .idl_type import IdlType |
| from .typedef import Typedef |
| |
| |
| # NewUnion is a tentative name and will be renamed to Union. |
| class NewUnion(WithIdentifier, WithCodeGeneratorInfo, WithComponent, |
| WithDebugInfo): |
| """ |
| Union class makes a group of union types with the same flattened member |
| types and the same result whether it includes a nullable type or not. |
| |
| For example, the following union types will be grouped into one Union |
| instance. |
| (A? or B or C), (A or B? or C), ((A or B) or C?), (A or (B or C?)), ... |
| All these unions have the same set of flattened member types (A, B, C) and |
| include a nullable type. |
| |
| However, all following union types will be grouped into separate Union |
| instances. |
| (A or B), ([X] A or B), ([Y] A or B) |
| IdlType(A), IdlType([X] A), and IdlType([Y] A) are all distinguished from |
| each other as they behave differently. Bindings code generators are |
| expected to define an implementation class for each Union instance. |
| """ |
| |
| _null_token = "Null" |
| |
| @classmethod |
| def unique_token(cls, union_type): |
| """ |
| Returns an unique token per a set of union types that are considered |
| as the same group. |
| """ |
| assert union_type.is_union |
| |
| token_pieces = [] |
| |
| def collect_token_pieces(idl_type): |
| idl_type = idl_type.unwrap() |
| if idl_type.is_union: |
| for member_type in idl_type.member_types: |
| collect_token_pieces(member_type) |
| else: |
| # Typename is not guaranteed to be unique, however it's |
| # unlikely that a conflict happens. |
| token_pieces.append( |
| idl_type.type_name_with_extended_attribute_key_values) |
| |
| collect_token_pieces(union_type) |
| token_pieces.sort() |
| if union_type.does_include_nullable_type: |
| token_pieces.append(cls._null_token) |
| return tuple(token_pieces) |
| |
| class IR(object): |
| # Note that Union.IR is, despite of its name, very different from other |
| # IDL definitions' IR classes. This class is not meant to be stored in |
| # IRMap nor managed with 'compilation phase'. |
| |
| def __init__(self, token, union_types): |
| assert all(union_type.is_union for union_type in union_types) |
| |
| self.token = token |
| self._member_set = set(token) |
| self.union_types = union_types |
| self.typedefs = [] |
| self.sub_union_irs = [] |
| self.public_object = None |
| |
| def __lt__(self, other): |
| if len(self.token) == len(other.token): |
| return self.token < other.token |
| else: |
| return len(self.token) < len(other.token) |
| |
| def contains(self, other): |
| assert isinstance(other, NewUnion.IR) |
| return (self.token != other.token |
| and self._member_set.issuperset(other._member_set)) |
| |
| def __init__(self, ir): |
| assert isinstance(ir, NewUnion.IR) |
| assert ir.public_object is None |
| |
| identifier = Identifier('Union_{}'.format('_'.join(ir.token))) |
| union_type = ir.union_types[0] |
| flattened_member_types = union_type.flattened_member_types |
| does_include_nullable_type = union_type.does_include_nullable_type |
| does_include_nullable_or_dict = ( |
| union_type.does_include_nullable_or_dict) |
| |
| typedef_members = set() |
| union_members = set() |
| for union_type in ir.union_types: |
| assert union_type.flattened_member_types == flattened_member_types |
| assert (union_type.does_include_nullable_type == |
| does_include_nullable_type) |
| for member_type in union_type.member_types: |
| if member_type.is_typedef: |
| typedef_members.add(member_type.typedef_object) |
| for sub_union_ir in ir.sub_union_irs: |
| assert isinstance(sub_union_ir.public_object, NewUnion) |
| typedef_members.update(sub_union_ir.typedefs) |
| union_members.add(sub_union_ir.public_object) |
| |
| components = set() |
| for_testing = [False] |
| |
| def collect_primary_component(idl_type): |
| type_definition_object = idl_type.type_definition_object |
| if type_definition_object and type_definition_object.components: |
| components.add(type_definition_object.components[0]) |
| if (type_definition_object and |
| type_definition_object.code_generator_info.for_testing): |
| for_testing[0] = True |
| |
| for idl_type in flattened_member_types: |
| idl_type.apply_to_all_composing_elements(collect_primary_component) |
| code_generator_info = CodeGeneratorInfoMutable() |
| code_generator_info.set_for_testing(for_testing[0]) |
| |
| WithIdentifier.__init__(self, identifier) |
| WithCodeGeneratorInfo.__init__(self, |
| code_generator_info, |
| readonly=True) |
| WithComponent.__init__(self, sorted(components), readonly=True) |
| WithDebugInfo.__init__(self) |
| |
| sort_key_typename = lambda idl_type: ( |
| idl_type.type_name_with_extended_attribute_key_values) |
| sort_key_identifier = lambda x: x.identifier |
| |
| self._idl_types = tuple(ir.union_types) |
| self._member_tokens = ir.token |
| self._flattened_member_types = tuple( |
| sorted(flattened_member_types, key=sort_key_typename)) |
| self._does_include_nullable_type = does_include_nullable_type |
| self._does_include_nullable_or_dict = does_include_nullable_or_dict |
| self._typedef_members = tuple( |
| sorted(typedef_members, key=sort_key_identifier)) |
| self._union_members = tuple( |
| sorted(union_members, key=sort_key_identifier)) |
| self._aliasing_typedefs = tuple( |
| sorted(ir.typedefs, key=sort_key_identifier)) |
| |
| ir.public_object = self |
| |
| for idl_type in self._idl_types: |
| idl_type.set_new_union_definition_object(self) |
| |
| @property |
| def idl_types(self): |
| """Returns a list of IdlTypes which this object represents.""" |
| return self._idl_types |
| |
| @property |
| def member_tokens(self): |
| """Returns a list of unique names of union member types.""" |
| return self._member_tokens |
| |
| @property |
| def flattened_member_types(self): |
| """ |
| Returns the same list of flattened member types as |
| IdlType.flattened_member_types. |
| """ |
| return self._flattened_member_types |
| |
| @property |
| def does_include_nullable_type(self): |
| """ |
| Returns True if any of member type is nullable or a member union |
| includes a nullable type. |
| """ |
| return self._does_include_nullable_type |
| |
| @property |
| def does_include_nullable_or_dict(self): |
| """ |
| Returns True if this type includes a nullable type or a dictionary |
| type. |
| """ |
| return self._does_include_nullable_or_dict |
| |
| @property |
| def typedef_members(self): |
| """ |
| Returns a list of typedef types which are direct members of union types |
| which this object represents. |
| |
| Given the following union types, |
| (AT or B), (A or BT) where typedef A AT, and typedef B BT |
| typedef_members returns a list of IdlType(AT) and IdlType(BT). |
| """ |
| return self._typedef_members |
| |
| @property |
| def union_members(self): |
| """ |
| Returns a list of union types which are direct members of union types |
| which this object represents. |
| |
| Given the following union types, |
| ((A or B) or C), (A or (B or C)) |
| union_members returns a list of IdlType(A or B) and IdlType(B or C). |
| """ |
| return self._union_members |
| |
| @property |
| def aliasing_typedefs(self): |
| """ |
| Returns a list of typedef types which are aliases to union types which |
| this object represents. |
| |
| Given the following typedef definitions, |
| typedef ((A or B) or C) T1; |
| typedef (A or (B or C)) T2; |
| aliasing_typedefs returns a list of IdlType(T1) and IdlType(T2). |
| """ |
| return self._aliasing_typedefs |
| |
| |
| class BackwardCompatibleUnion(WithIdentifier, WithCodeGeneratorInfo, |
| WithComponent, WithDebugInfo): |
| """ |
| Union class makes a group of union types with the same flattened member |
| types and the same result whether it includes a nullable type or not. |
| |
| For example, the following union types will be grouped into one Union |
| instance. |
| (A? or B or C), (A or B? or C), ((A or B) or C?), (A or (B or C?)), ... |
| All these unions have the same set of flattened member types (A, B, C) and |
| include a nullable type. |
| |
| However, all following union types will be grouped into separate Union |
| instances. |
| (A or B), ([X] A or B), ([Y] A or B) |
| IdlType(A), IdlType([X] A), and IdlType([Y] A) are all distinguished from |
| each other as they behave differently. Bindings code generators are |
| expected to define an implementation class for each Union instance. |
| """ |
| |
| def __init__(self, union_types, typedef_backrefs): |
| """ |
| Args: |
| union_types: Union types of which this object consists. All types |
| in |union_types| must have the same flattened_member_types and |
| the same value of does_include_nullable_type. |
| typedef_backrefs: Typedef instances whose typedef'ed type is this |
| union. |
| """ |
| assert isinstance(union_types, (list, tuple)) |
| assert len(union_types) > 0 |
| assert all( |
| isinstance(union_type, IdlType) and union_type.is_union |
| for union_type in union_types) |
| assert isinstance(typedef_backrefs, (list, tuple)) |
| assert all( |
| isinstance(typedef, Typedef) for typedef in typedef_backrefs) |
| |
| flattened_members = union_types[0].flattened_member_types |
| does_include_nullable_type = union_types[0].does_include_nullable_type |
| |
| nullable_members = set() |
| typedef_members = set() |
| union_members = set() |
| for union_type in union_types: |
| assert union_type.flattened_member_types == flattened_members |
| assert (union_type.does_include_nullable_type == |
| does_include_nullable_type) |
| union_type.set_union_definition_object(self) |
| for direct_member in union_type.member_types: |
| if direct_member.is_nullable: |
| nullable_members.add(direct_member) |
| if direct_member.is_typedef: |
| typedef_members.add(direct_member) |
| if direct_member.is_union: |
| union_members.add(direct_member) |
| |
| sort_key = lambda x: x.syntactic_form |
| |
| components = set() |
| |
| def collect_primary_component(idl_type): |
| type_definition_object = idl_type.type_definition_object |
| if type_definition_object and type_definition_object.components: |
| components.add(type_definition_object.components[0]) |
| |
| for idl_type in flattened_members: |
| idl_type.apply_to_all_composing_elements(collect_primary_component) |
| # Make this union type look defined in 'modules' if the union type is |
| # used in 'modules' in order to keep the backward compatibility with |
| # the old bindings generator. |
| is_defined_in_core = False |
| is_defined_in_modules = False |
| for idl_type in union_types: |
| filepath = idl_type.debug_info.location.filepath |
| if filepath.startswith('third_party/blink/renderer/core/'): |
| is_defined_in_core = True |
| if filepath.startswith('third_party/blink/renderer/modules/'): |
| is_defined_in_modules = True |
| if not is_defined_in_core and is_defined_in_modules: |
| from .composition_parts import Component |
| components.add(Component('modules')) |
| |
| # TODO(peria, yukishiino): Produce unique union names. Trying to |
| # produce the names compatible to the old bindings generator for the |
| # time being. |
| # |
| # type_names = sorted( |
| # [idl_type.type_name for idl_type in flattened_members]) |
| def backward_compatible_member_name(idl_type): |
| name = idl_type.unwrap().type_name |
| if name == 'StringTreatNullAs': |
| return 'StringTreatNullAsEmptyString' |
| else: |
| return name |
| |
| identifier = Identifier('Or'.join([ |
| backward_compatible_member_name(idl_type) |
| for idl_type in union_types[0].member_types |
| ])) |
| |
| WithIdentifier.__init__(self, identifier) |
| WithCodeGeneratorInfo.__init__(self, readonly=True) |
| WithComponent.__init__(self, sorted(components), readonly=True) |
| WithDebugInfo.__init__(self) |
| |
| # Sort improves reproducibility. |
| self._flattened_members = tuple( |
| sorted(flattened_members, key=sort_key)) |
| self._does_include_nullable_type = does_include_nullable_type |
| self._nullable_members = tuple(sorted(nullable_members, key=sort_key)) |
| self._typedef_members = tuple(sorted(typedef_members, key=sort_key)) |
| self._union_members = tuple(sorted(union_members, key=sort_key)) |
| self._typedef_backrefs = tuple(typedef_backrefs) |
| |
| @property |
| def flattened_member_types(self): |
| """ |
| Returns the same list of flattened member types as |
| IdlType.flattened_member_types. |
| """ |
| return self._flattened_members |
| |
| @property |
| def does_include_nullable_type(self): |
| """ |
| Returns True if any of member type is nullable or a member union |
| includes a nullable type. |
| """ |
| return self._does_include_nullable_type |
| |
| @property |
| def nullable_member_types(self): |
| """ |
| Returns a list of nullable types which are direct members of union types |
| of which this object consists. |
| |
| Given the following unions, |
| (A? or B or C), (A or B? or C), (A or B or CN) where typedef C? CN; |
| nullable_member_types returns a list of IdlType(A?) and IdlType(B?). |
| """ |
| return self._nullable_members |
| |
| @property |
| def typedef_member_types(self): |
| """ |
| Returns a list of typedef types which are direct members of union types |
| of which this object consists. |
| |
| Given the following unions, |
| (AT or B), (A or BT) where typedef A AT, and typedef B BT; |
| typedef_member_types returns a list of IdlType(AT) and IdlType(BT). |
| """ |
| return self._typedef_members |
| |
| @property |
| def union_member_types(self): |
| """ |
| Returns a list of union types which are direct members of union types of |
| which this object consists. |
| |
| Given the following unions, |
| ((A or B) or C), (A or (B or C)) |
| union_member_types returns a list of IdlType(A or B) and |
| IdlType(B or C). |
| """ |
| return self._union_members |
| |
| @property |
| def aliasing_typedefs(self): |
| """ |
| Returns a list of typedefs which are aliases to this union type. |
| """ |
| return self._typedef_backrefs |
| |
| |
| Union = BackwardCompatibleUnion |