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: 7IdlType 8IdlUnionType 9""" 10 11from collections import defaultdict 12 13 14################################################################################ 15# IDL types 16################################################################################ 17 18INTEGER_TYPES = frozenset([ 19 # http://www.w3.org/TR/WebIDL/#dfn-integer-type 20 'byte', 21 'octet', 22 'short', 23 'unsigned short', 24 # int and unsigned are not IDL types 25 'long', 26 'unsigned long', 27 'long long', 28 'unsigned long long', 29]) 30NUMERIC_TYPES = (INTEGER_TYPES | frozenset([ 31 # http://www.w3.org/TR/WebIDL/#dfn-numeric-type 32 'float', 33 'unrestricted float', 34 'double', 35 'unrestricted double', 36])) 37# http://www.w3.org/TR/WebIDL/#dfn-primitive-type 38PRIMITIVE_TYPES = (frozenset(['boolean']) | NUMERIC_TYPES) 39BASIC_TYPES = (PRIMITIVE_TYPES | frozenset([ 40 # Built-in, non-composite, non-object data types 41 # http://heycam.github.io/webidl/#idl-types 42 'DOMString', 43 'ByteString', 44 'Date', 45 # http://heycam.github.io/webidl/#es-type-mapping 46 'void', 47 # http://encoding.spec.whatwg.org/#type-scalarvaluestring 48 'ScalarValueString', 49])) 50TYPE_NAMES = { 51 # http://heycam.github.io/webidl/#dfn-type-name 52 'any': 'Any', 53 'boolean': 'Boolean', 54 'byte': 'Byte', 55 'octet': 'Octet', 56 'short': 'Short', 57 'unsigned short': 'UnsignedShort', 58 'long': 'Long', 59 'unsigned long': 'UnsignedLong', 60 'long long': 'LongLong', 61 'unsigned long long': 'UnsignedLongLong', 62 'float': 'Float', 63 'unrestricted float': 'UnrestrictedFloat', 64 'double': 'Double', 65 'unrestricted double': 'UnrestrictedDouble', 66 'DOMString': 'String', 67 'ByteString': 'ByteString', 68 'ScalarValueString': 'ScalarValueString', 69 'object': 'Object', 70 'Date': 'Date', 71} 72 73 74################################################################################ 75# Inheritance 76################################################################################ 77 78ancestors = defaultdict(list) # interface_name -> ancestors 79 80def inherits_interface(interface_name, ancestor_name): 81 return (interface_name == ancestor_name or 82 ancestor_name in ancestors[interface_name]) 83 84 85def set_ancestors(new_ancestors): 86 ancestors.update(new_ancestors) 87 88 89################################################################################ 90# IdlType 91################################################################################ 92 93class IdlType(object): 94 # FIXME: incorporate Nullable, etc. 95 # FIXME: use nested types: IdlArrayType, IdlNullableType, IdlSequenceType 96 # to support types like short?[] vs. short[]?, instead of treating these 97 # as orthogonal properties (via flags). 98 callback_functions = set() 99 callback_interfaces = set() 100 enums = {} # name -> values 101 102 def __init__(self, base_type, is_array=False, is_sequence=False, is_nullable=False, is_unrestricted=False): 103 if is_array and is_sequence: 104 raise ValueError('Array of Sequences are not allowed.') 105 if is_unrestricted: 106 self.base_type = 'unrestricted %s' % base_type 107 else: 108 self.base_type = base_type 109 self.is_array = is_array 110 self.is_sequence = is_sequence 111 self.is_nullable = is_nullable 112 113 def __str__(self): 114 type_string = self.base_type 115 if self.is_array: 116 return type_string + '[]' 117 if self.is_sequence: 118 return 'sequence<%s>' % type_string 119 if self.is_nullable: 120 # FIXME: Dictionary::ConversionContext::setConversionType can't 121 # handle the '?' in nullable types (passes nullability separately). 122 # Update that function to handle nullability from the type name, 123 # simplifying its signature. 124 # return type_string + '?' 125 return type_string 126 return type_string 127 128 # FIXME: rename to native_array_element_type and move to v8_types.py 129 @property 130 def array_or_sequence_type(self): 131 return self.array_type or self.sequence_type 132 133 # FIXME: rename to array_element_type 134 @property 135 def array_type(self): 136 return self.is_array and IdlType(self.base_type) 137 138 # FIXME: rename to sequence_element_type 139 @property 140 def sequence_type(self): 141 return self.is_sequence and IdlType(self.base_type) 142 143 @property 144 def is_basic_type(self): 145 return self.base_type in BASIC_TYPES and not self.array_or_sequence_type 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_composite_type(self): 157 return (self.name == 'Any' or 158 self.array_type or 159 self.sequence_type or 160 self.is_union_type) 161 162 @property 163 def is_enum(self): 164 # FIXME: add an IdlEnumType class and a resolve_enums step at end of 165 # IdlDefinitions constructor 166 return self.name in IdlType.enums 167 168 @property 169 def enum_values(self): 170 return IdlType.enums[self.name] 171 172 @property 173 def is_integer_type(self): 174 return self.base_type in INTEGER_TYPES and not self.array_or_sequence_type 175 176 @property 177 def is_numeric_type(self): 178 return self.base_type in NUMERIC_TYPES and not self.array_or_sequence_type 179 180 @property 181 def is_primitive_type(self): 182 return self.base_type in PRIMITIVE_TYPES and not self.array_or_sequence_type 183 184 @property 185 def is_interface_type(self): 186 # Anything that is not another type is an interface type. 187 # http://www.w3.org/TR/WebIDL/#idl-types 188 # http://www.w3.org/TR/WebIDL/#idl-interface 189 # In C++ these are RefPtr or PassRefPtr types. 190 return not(self.is_basic_type or 191 self.is_composite_type or 192 self.is_callback_function or 193 self.is_enum or 194 self.name == 'Object' or 195 self.name == 'Promise') # Promise will be basic in future 196 197 @property 198 def is_union_type(self): 199 return isinstance(self, IdlUnionType) 200 201 @property 202 def name(self): 203 """Return type name. 204 205 http://heycam.github.io/webidl/#dfn-type-name 206 """ 207 base_type = self.base_type 208 base_type_name = TYPE_NAMES.get(base_type, base_type) 209 if self.is_array: 210 return base_type_name + 'Array' 211 if self.is_sequence: 212 return base_type_name + 'Sequence' 213 if self.is_nullable: 214 return base_type_name + 'OrNull' 215 return base_type_name 216 217 @classmethod 218 def set_callback_functions(cls, new_callback_functions): 219 cls.callback_functions.update(new_callback_functions) 220 221 @classmethod 222 def set_callback_interfaces(cls, new_callback_interfaces): 223 cls.callback_interfaces.update(new_callback_interfaces) 224 225 @classmethod 226 def set_enums(cls, new_enums): 227 cls.enums.update(new_enums) 228 229 def resolve_typedefs(self, typedefs): 230 if self.base_type not in typedefs: 231 return self 232 new_type = typedefs[self.base_type] 233 if type(new_type) != type(self): 234 # If type changes, need to return a different object, 235 # since can't change type(self) 236 return new_type 237 # If type doesn't change, just mutate self to avoid a new object 238 # FIXME: a bit ugly; use __init__ instead of setting flags 239 self.base_type = new_type.base_type 240 # handle array both in use and in typedef itself: 241 # typedef Type TypeDef; 242 # TypeDef[] ... 243 # and: 244 # typedef Type[] TypeArray 245 # TypeArray ... 246 self.is_array |= new_type.is_array 247 self.is_sequence |= new_type.is_sequence 248 return self 249 250 251################################################################################ 252# IdlUnionType 253################################################################################ 254 255class IdlUnionType(object): 256 # http://heycam.github.io/webidl/#idl-union 257 # FIXME: derive from IdlType, instead of stand-alone class, to reduce 258 # duplication. 259 def __init__(self, member_types, is_nullable=False): 260 self.member_types = member_types 261 self.is_nullable = is_nullable 262 263 @property 264 def array_or_sequence_type(self): 265 return False 266 267 @property 268 def array_type(self): 269 return False 270 271 @property 272 def is_array(self): 273 # We do not support arrays of union types 274 return False 275 276 @property 277 def base_type(self): 278 return None 279 280 @property 281 def is_basic_type(self): 282 return False 283 284 @property 285 def is_callback_function(self): 286 return False 287 288 @property 289 def is_enum(self): 290 return False 291 292 @property 293 def is_integer_type(self): 294 return False 295 296 @property 297 def is_numeric_type(self): 298 return False 299 300 @property 301 def is_primitivee_type(self): 302 return False 303 304 @property 305 def is_sequence(self): 306 # We do not support sequences of union types 307 return False 308 309 @property 310 def is_union_type(self): 311 return True 312 313 @property 314 def name(self): 315 return 'Or'.join(member_type.name for member_type in self.member_types) 316 317 def resolve_typedefs(self, typedefs): 318 self.member_types = [ 319 typedefs.get(member_type, member_type) 320 for member_type in self.member_types] 321 return self 322