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 6Classes: 7IdlTypeBase 8 IdlType 9 IdlUnionType 10 IdlArrayOrSequenceType 11 IdlArrayType 12 IdlSequenceType 13 IdlNullableType 14""" 15 16from collections import defaultdict 17 18 19################################################################################ 20# IDL types 21################################################################################ 22 23INTEGER_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]) 35NUMERIC_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 43PRIMITIVE_TYPES = (frozenset(['boolean']) | NUMERIC_TYPES) 44BASIC_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])) 55TYPE_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 78STRING_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 91ancestors = defaultdict(list) # interface_name -> ancestors 92 93def inherits_interface(interface_name, ancestor_name): 94 return (interface_name == ancestor_name or 95 ancestor_name in ancestors[interface_name]) 96 97 98def set_ancestors(new_ancestors): 99 ancestors.update(new_ancestors) 100 101 102class 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 124class 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 238class 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 267class 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 279class 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 291class 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 307class 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