Home | History | Annotate | Download | only in scripts
      1 # Copyright 2014 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 """IDL type handling.
      5 
      6 Classes:
      7 IdlTypeBase
      8  IdlType
      9  IdlUnionType
     10  IdlArrayOrSequenceType
     11   IdlArrayType
     12   IdlSequenceType
     13  IdlNullableType
     14 """
     15 
     16 from collections import defaultdict
     17 
     18 
     19 ################################################################################
     20 # IDL types
     21 ################################################################################
     22 
     23 INTEGER_TYPES = frozenset([
     24     # http://www.w3.org/TR/WebIDL/#dfn-integer-type
     25     'byte',
     26     'octet',
     27     'short',
     28     'unsigned short',
     29     # int and unsigned are not IDL types
     30     'long',
     31     'unsigned long',
     32     'long long',
     33     'unsigned long long',
     34 ])
     35 NUMERIC_TYPES = (INTEGER_TYPES | frozenset([
     36     # http://www.w3.org/TR/WebIDL/#dfn-numeric-type
     37     'float',
     38     'unrestricted float',
     39     'double',
     40     'unrestricted double',
     41 ]))
     42 # http://www.w3.org/TR/WebIDL/#dfn-primitive-type
     43 PRIMITIVE_TYPES = (frozenset(['boolean']) | NUMERIC_TYPES)
     44 BASIC_TYPES = (PRIMITIVE_TYPES | frozenset([
     45     # Built-in, non-composite, non-object data types
     46     # http://heycam.github.io/webidl/#idl-types
     47     'DOMString',
     48     'ByteString',
     49     'Date',
     50     # http://heycam.github.io/webidl/#es-type-mapping
     51     'void',
     52     # http://encoding.spec.whatwg.org/#type-scalarvaluestring
     53     'ScalarValueString',
     54 ]))
     55 TYPE_NAMES = {
     56     # http://heycam.github.io/webidl/#dfn-type-name
     57     'any': 'Any',
     58     'boolean': 'Boolean',
     59     'byte': 'Byte',
     60     'octet': 'Octet',
     61     'short': 'Short',
     62     'unsigned short': 'UnsignedShort',
     63     'long': 'Long',
     64     'unsigned long': 'UnsignedLong',
     65     'long long': 'LongLong',
     66     'unsigned long long': 'UnsignedLongLong',
     67     'float': 'Float',
     68     'unrestricted float': 'UnrestrictedFloat',
     69     'double': 'Double',
     70     'unrestricted double': 'UnrestrictedDouble',
     71     'DOMString': 'String',
     72     'ByteString': 'ByteString',
     73     'ScalarValueString': 'ScalarValueString',
     74     'object': 'Object',
     75     'Date': 'Date',
     76 }
     77 
     78 STRING_TYPES = frozenset([
     79     # http://heycam.github.io/webidl/#es-interface-call (step 10.11)
     80     # (Interface object [[Call]] method's string types.)
     81     'String',
     82     'ByteString',
     83     'ScalarValueString',
     84 ])
     85 
     86 
     87 ################################################################################
     88 # Inheritance
     89 ################################################################################
     90 
     91 ancestors = defaultdict(list)  # interface_name -> ancestors
     92 
     93 def inherits_interface(interface_name, ancestor_name):
     94     return (interface_name == ancestor_name or
     95             ancestor_name in ancestors[interface_name])
     96 
     97 
     98 def set_ancestors(new_ancestors):
     99     ancestors.update(new_ancestors)
    100 
    101 
    102 class IdlTypeBase(object):
    103     """Base class for IdlType, IdlUnionType, IdlArrayOrSequenceType and IdlNullableType."""
    104 
    105     def __str__(self):
    106         raise NotImplementedError(
    107             '__str__() should be defined in subclasses')
    108 
    109     def __getattr__(self, name):
    110         # Default undefined attributes to None (analogous to Jinja variables).
    111         # This allows us to not define default properties in the base class, and
    112         # allows us to relay __getattr__ in IdlNullableType to the inner type.
    113         return None
    114 
    115     def resolve_typedefs(self, typedefs):
    116         raise NotImplementedError(
    117             'resolve_typedefs should be defined in subclasses')
    118 
    119 
    120 ################################################################################
    121 # IdlType
    122 ################################################################################
    123 
    124 class IdlType(IdlTypeBase):
    125     # FIXME: incorporate Nullable, etc.
    126     # to support types like short?[] vs. short[]?, instead of treating these
    127     # as orthogonal properties (via flags).
    128     callback_functions = set()
    129     callback_interfaces = set()
    130     dictionaries = set()
    131     enums = {}  # name -> values
    132 
    133     def __init__(self, base_type, is_unrestricted=False):
    134         super(IdlType, self).__init__()
    135         if is_unrestricted:
    136             self.base_type = 'unrestricted %s' % base_type
    137         else:
    138             self.base_type = base_type
    139 
    140     def __str__(self):
    141         return self.base_type
    142 
    143     @property
    144     def is_basic_type(self):
    145         return self.base_type in BASIC_TYPES
    146 
    147     @property
    148     def is_callback_function(self):
    149         return self.base_type in IdlType.callback_functions
    150 
    151     @property
    152     def is_callback_interface(self):
    153         return self.base_type in IdlType.callback_interfaces
    154 
    155     @property
    156     def is_dictionary(self):
    157         return self.base_type in IdlType.dictionaries
    158 
    159     @property
    160     def is_enum(self):
    161         # FIXME: add an IdlEnumType class and a resolve_enums step at end of
    162         # IdlDefinitions constructor
    163         return self.name in IdlType.enums
    164 
    165     @property
    166     def enum_values(self):
    167         return IdlType.enums[self.name]
    168 
    169     @property
    170     def is_integer_type(self):
    171         return self.base_type in INTEGER_TYPES
    172 
    173     @property
    174     def is_numeric_type(self):
    175         return self.base_type in NUMERIC_TYPES
    176 
    177     @property
    178     def is_primitive_type(self):
    179         return self.base_type in PRIMITIVE_TYPES
    180 
    181     @property
    182     def is_interface_type(self):
    183         # Anything that is not another type is an interface type.
    184         # http://www.w3.org/TR/WebIDL/#idl-types
    185         # http://www.w3.org/TR/WebIDL/#idl-interface
    186         # In C++ these are RefPtr or PassRefPtr types.
    187         return not(self.is_basic_type or
    188                    self.is_callback_function or
    189                    self.is_dictionary or
    190                    self.is_enum or
    191                    self.name == 'Any' or
    192                    self.name == 'Object' or
    193                    self.name == 'Promise')  # Promise will be basic in future
    194 
    195     @property
    196     def is_string_type(self):
    197         return self.name in STRING_TYPES
    198 
    199     @property
    200     def is_union_type(self):
    201         return isinstance(self, IdlUnionType)
    202 
    203     @property
    204     def name(self):
    205         """Return type name
    206 
    207         http://heycam.github.io/webidl/#dfn-type-name
    208         """
    209         base_type = self.base_type
    210         return TYPE_NAMES.get(base_type, base_type)
    211 
    212     @classmethod
    213     def set_callback_functions(cls, new_callback_functions):
    214         cls.callback_functions.update(new_callback_functions)
    215 
    216     @classmethod
    217     def set_callback_interfaces(cls, new_callback_interfaces):
    218         cls.callback_interfaces.update(new_callback_interfaces)
    219 
    220     @classmethod
    221     def set_dictionaries(cls, new_dictionaries):
    222         cls.dictionaries.update(new_dictionaries)
    223 
    224     @classmethod
    225     def set_enums(cls, new_enums):
    226         cls.enums.update(new_enums)
    227 
    228     def resolve_typedefs(self, typedefs):
    229         # This function either returns |self| or a different object.
    230         # FIXME: Rename typedefs_resolved().
    231         return typedefs.get(self.base_type, self)
    232 
    233 
    234 ################################################################################
    235 # IdlUnionType
    236 ################################################################################
    237 
    238 class IdlUnionType(IdlTypeBase):
    239     # http://heycam.github.io/webidl/#idl-union
    240     def __init__(self, member_types):
    241         super(IdlUnionType, self).__init__()
    242         self.member_types = member_types
    243 
    244     @property
    245     def is_union_type(self):
    246         return True
    247 
    248     @property
    249     def name(self):
    250         """Return type name (or inner type name if nullable)
    251 
    252         http://heycam.github.io/webidl/#dfn-type-name
    253         """
    254         return 'Or'.join(member_type.name for member_type in self.member_types)
    255 
    256     def resolve_typedefs(self, typedefs):
    257         self.member_types = [
    258             typedefs.get(member_type, member_type)
    259             for member_type in self.member_types]
    260         return self
    261 
    262 
    263 ################################################################################
    264 # IdlArrayOrSequenceType, IdlArrayType, IdlSequenceType
    265 ################################################################################
    266 
    267 class IdlArrayOrSequenceType(IdlTypeBase):
    268     """Base class for IdlArrayType and IdlSequenceType."""
    269 
    270     def __init__(self, element_type):
    271         super(IdlArrayOrSequenceType, self).__init__()
    272         self.element_type = element_type
    273 
    274     def resolve_typedefs(self, typedefs):
    275         self.element_type = self.element_type.resolve_typedefs(typedefs)
    276         return self
    277 
    278 
    279 class IdlArrayType(IdlArrayOrSequenceType):
    280     def __init__(self, element_type):
    281         super(IdlArrayType, self).__init__(element_type)
    282 
    283     def __str__(self):
    284         return '%s[]' % self.element_type
    285 
    286     @property
    287     def name(self):
    288         return self.element_type.name + 'Array'
    289 
    290 
    291 class IdlSequenceType(IdlArrayOrSequenceType):
    292     def __init__(self, element_type):
    293         super(IdlSequenceType, self).__init__(element_type)
    294 
    295     def __str__(self):
    296         return 'sequence<%s>' % self.element_type
    297 
    298     @property
    299     def name(self):
    300         return self.element_type.name + 'Sequence'
    301 
    302 
    303 ################################################################################
    304 # IdlNullableType
    305 ################################################################################
    306 
    307 class IdlNullableType(IdlTypeBase):
    308     def __init__(self, inner_type):
    309         super(IdlNullableType, self).__init__()
    310         self.inner_type = inner_type
    311 
    312     def __str__(self):
    313         # FIXME: Dictionary::ConversionContext::setConversionType can't
    314         # handle the '?' in nullable types (passes nullability separately).
    315         # Update that function to handle nullability from the type name,
    316         # simplifying its signature.
    317         # return str(self.inner_type) + '?'
    318         return str(self.inner_type)
    319 
    320     def __getattr__(self, name):
    321         return getattr(self.inner_type, name)
    322 
    323     @property
    324     def is_nullable(self):
    325         return True
    326 
    327     @property
    328     def name(self):
    329         return self.inner_type.name + 'OrNull'
    330 
    331     def resolve_typedefs(self, typedefs):
    332         self.inner_type = self.inner_type.resolve_typedefs(typedefs)
    333         return self
    334