OLD | NEW |
1 # Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 """IDL type handling. | 4 """IDL type handling. |
5 | 5 |
6 Classes: | 6 Classes: |
7 IdlType | 7 IdlTypeBase |
8 IdlUnionType | 8 IdlType |
| 9 IdlUnionType |
| 10 IdlArrayOrSequenceType |
| 11 IdlArrayType |
| 12 IdlSequenceType |
9 """ | 13 """ |
10 | 14 |
11 from collections import defaultdict | 15 from collections import defaultdict |
12 | 16 |
13 | 17 |
14 ################################################################################ | 18 ################################################################################ |
15 # IDL types | 19 # IDL types |
16 ################################################################################ | 20 ################################################################################ |
17 | 21 |
18 INTEGER_TYPES = frozenset([ | 22 INTEGER_TYPES = frozenset([ |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 'unrestricted float': 'UnrestrictedFloat', | 67 'unrestricted float': 'UnrestrictedFloat', |
64 'double': 'Double', | 68 'double': 'Double', |
65 'unrestricted double': 'UnrestrictedDouble', | 69 'unrestricted double': 'UnrestrictedDouble', |
66 'DOMString': 'String', | 70 'DOMString': 'String', |
67 'ByteString': 'ByteString', | 71 'ByteString': 'ByteString', |
68 'ScalarValueString': 'ScalarValueString', | 72 'ScalarValueString': 'ScalarValueString', |
69 'object': 'Object', | 73 'object': 'Object', |
70 'Date': 'Date', | 74 'Date': 'Date', |
71 } | 75 } |
72 | 76 |
| 77 STRING_TYPES = frozenset([ |
| 78 # http://heycam.github.io/webidl/#es-interface-call (step 10.11) |
| 79 # (Interface object [[Call]] method's string types.) |
| 80 'String', |
| 81 'ByteString', |
| 82 'ScalarValueString', |
| 83 ]) |
| 84 |
73 | 85 |
74 ################################################################################ | 86 ################################################################################ |
75 # Inheritance | 87 # Inheritance |
76 ################################################################################ | 88 ################################################################################ |
77 | 89 |
78 ancestors = defaultdict(list) # interface_name -> ancestors | 90 ancestors = defaultdict(list) # interface_name -> ancestors |
79 | 91 |
80 def inherits_interface(interface_name, ancestor_name): | 92 def inherits_interface(interface_name, ancestor_name): |
81 return (interface_name == ancestor_name or | 93 return (interface_name == ancestor_name or |
82 ancestor_name in ancestors[interface_name]) | 94 ancestor_name in ancestors[interface_name]) |
83 | 95 |
84 | 96 |
85 def set_ancestors(new_ancestors): | 97 def set_ancestors(new_ancestors): |
86 ancestors.update(new_ancestors) | 98 ancestors.update(new_ancestors) |
87 | 99 |
88 | 100 |
| 101 class IdlTypeBase(object): |
| 102 """Base class for IdlType, IdlUnionType and IdlArrayOrSequenceType.""" |
| 103 |
| 104 def __init__(self, is_nullable): |
| 105 self.base_type = None |
| 106 self.is_nullable = is_nullable |
| 107 |
| 108 def __str__(self): |
| 109 inner_string = self.inner_string |
| 110 if self.is_nullable: |
| 111 # FIXME: Dictionary::ConversionContext::setConversionType can't |
| 112 # handle the '?' in nullable types (passes nullability separately). |
| 113 # Update that function to handle nullability from the type name, |
| 114 # simplifying its signature. |
| 115 # return inner_string + '?' |
| 116 return inner_string |
| 117 return inner_string |
| 118 |
| 119 @property |
| 120 def inner_string(self): |
| 121 raise NotImplementedError( |
| 122 'inner_string property should be defined in subclasses') |
| 123 |
| 124 @property |
| 125 def is_basic_type(self): |
| 126 return False |
| 127 |
| 128 @property |
| 129 def is_callback_function(self): |
| 130 return False |
| 131 |
| 132 @property |
| 133 def is_callback_interface(self): |
| 134 return False |
| 135 |
| 136 @property |
| 137 def is_dictionary(self): |
| 138 return False |
| 139 |
| 140 @property |
| 141 def is_enum(self): |
| 142 return False |
| 143 |
| 144 @property |
| 145 def is_integer_type(self): |
| 146 return False |
| 147 |
| 148 @property |
| 149 def is_numeric_type(self): |
| 150 return False |
| 151 |
| 152 @property |
| 153 def is_primitive_type(self): |
| 154 return False |
| 155 |
| 156 @property |
| 157 def is_interface_type(self): |
| 158 return False |
| 159 |
| 160 @property |
| 161 def is_string_type(self): |
| 162 return False |
| 163 |
| 164 @property |
| 165 def is_union_type(self): |
| 166 return False |
| 167 |
| 168 @property |
| 169 def may_raise_exception_on_conversion(self): |
| 170 return False |
| 171 |
| 172 @property |
| 173 def name(self): |
| 174 if self.is_nullable: |
| 175 return self.inner_name + 'OrNull' |
| 176 return self.inner_name |
| 177 |
| 178 @property |
| 179 def inner_name(self): |
| 180 raise NotImplementedError( |
| 181 'inner_name property should be defined in subclasses') |
| 182 |
| 183 def resolve_typedefs(self, typedefs): |
| 184 raise NotImplementedError( |
| 185 'resolve_typedefs should be defined in subclasses') |
| 186 |
| 187 |
89 ################################################################################ | 188 ################################################################################ |
90 # IdlType | 189 # IdlType |
91 ################################################################################ | 190 ################################################################################ |
92 | 191 |
93 class IdlType(object): | 192 class IdlType(IdlTypeBase): |
94 # FIXME: incorporate Nullable, etc. | 193 # FIXME: incorporate Nullable, etc. |
95 # FIXME: use nested types: IdlArrayType, IdlNullableType, IdlSequenceType | |
96 # to support types like short?[] vs. short[]?, instead of treating these | 194 # to support types like short?[] vs. short[]?, instead of treating these |
97 # as orthogonal properties (via flags). | 195 # as orthogonal properties (via flags). |
98 callback_functions = set() | 196 callback_functions = set() |
99 callback_interfaces = set() | 197 callback_interfaces = set() |
| 198 dictionaries = set() |
100 enums = {} # name -> values | 199 enums = {} # name -> values |
101 | 200 |
102 def __init__(self, base_type, is_array=False, is_sequence=False, is_nullable
=False, is_unrestricted=False): | 201 def __init__(self, base_type, is_nullable=False, is_unrestricted=False): |
103 if is_array and is_sequence: | 202 super(IdlType, self).__init__(is_nullable) |
104 raise ValueError('Array of Sequences are not allowed.') | |
105 if is_unrestricted: | 203 if is_unrestricted: |
106 self.base_type = 'unrestricted %s' % base_type | 204 self.base_type = 'unrestricted %s' % base_type |
107 else: | 205 else: |
108 self.base_type = base_type | 206 self.base_type = base_type |
109 self.is_array = is_array | |
110 self.is_sequence = is_sequence | |
111 self.is_nullable = is_nullable | |
112 | 207 |
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 | 208 @property |
130 def array_or_sequence_type(self): | 209 def inner_string(self): |
131 return self.array_type or self.sequence_type | 210 return self.base_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 | 211 |
143 @property | 212 @property |
144 def is_basic_type(self): | 213 def is_basic_type(self): |
145 return self.base_type in BASIC_TYPES and not self.array_or_sequence_type | 214 return self.base_type in BASIC_TYPES |
146 | 215 |
147 @property | 216 @property |
148 def is_callback_function(self): | 217 def is_callback_function(self): |
149 return self.base_type in IdlType.callback_functions | 218 return self.base_type in IdlType.callback_functions |
150 | 219 |
151 @property | 220 @property |
152 def is_callback_interface(self): | 221 def is_callback_interface(self): |
153 return self.base_type in IdlType.callback_interfaces | 222 return self.base_type in IdlType.callback_interfaces |
154 | 223 |
155 @property | 224 @property |
156 def is_composite_type(self): | 225 def is_dictionary(self): |
157 return (self.name == 'Any' or | 226 return self.base_type in IdlType.dictionaries |
158 self.array_type or | |
159 self.sequence_type or | |
160 self.is_union_type) | |
161 | 227 |
162 @property | 228 @property |
163 def is_enum(self): | 229 def is_enum(self): |
164 # FIXME: add an IdlEnumType class and a resolve_enums step at end of | 230 # FIXME: add an IdlEnumType class and a resolve_enums step at end of |
165 # IdlDefinitions constructor | 231 # IdlDefinitions constructor |
166 return self.name in IdlType.enums | 232 return self.name in IdlType.enums |
167 | 233 |
168 @property | 234 @property |
169 def enum_values(self): | 235 def enum_values(self): |
170 return IdlType.enums[self.name] | 236 return IdlType.enums[self.name] |
171 | 237 |
172 @property | 238 @property |
173 def is_integer_type(self): | 239 def is_integer_type(self): |
174 return self.base_type in INTEGER_TYPES and not self.array_or_sequence_ty
pe | 240 return self.base_type in INTEGER_TYPES |
175 | 241 |
176 @property | 242 @property |
177 def is_numeric_type(self): | 243 def is_numeric_type(self): |
178 return self.base_type in NUMERIC_TYPES and not self.array_or_sequence_ty
pe | 244 return self.base_type in NUMERIC_TYPES |
179 | 245 |
180 @property | 246 @property |
181 def is_primitive_type(self): | 247 def is_primitive_type(self): |
182 return self.base_type in PRIMITIVE_TYPES and not self.array_or_sequence_
type | 248 return self.base_type in PRIMITIVE_TYPES |
183 | 249 |
184 @property | 250 @property |
185 def is_interface_type(self): | 251 def is_interface_type(self): |
186 # Anything that is not another type is an interface type. | 252 # Anything that is not another type is an interface type. |
187 # http://www.w3.org/TR/WebIDL/#idl-types | 253 # http://www.w3.org/TR/WebIDL/#idl-types |
188 # http://www.w3.org/TR/WebIDL/#idl-interface | 254 # http://www.w3.org/TR/WebIDL/#idl-interface |
189 # In C++ these are RefPtr or PassRefPtr types. | 255 # In C++ these are RefPtr or PassRefPtr types. |
190 return not(self.is_basic_type or | 256 return not(self.is_basic_type or |
191 self.is_composite_type or | |
192 self.is_callback_function or | 257 self.is_callback_function or |
| 258 self.is_dictionary or |
193 self.is_enum or | 259 self.is_enum or |
| 260 self.name == 'Any' or |
194 self.name == 'Object' or | 261 self.name == 'Object' or |
195 self.name == 'Promise') # Promise will be basic in future | 262 self.name == 'Promise') # Promise will be basic in future |
196 | 263 |
197 @property | 264 @property |
| 265 def is_string_type(self): |
| 266 return self.inner_name in STRING_TYPES |
| 267 |
| 268 @property |
| 269 def may_raise_exception_on_conversion(self): |
| 270 return (self.is_integer_type or |
| 271 self.name in ('ByteString', 'ScalarValueString')) |
| 272 |
| 273 @property |
198 def is_union_type(self): | 274 def is_union_type(self): |
199 return isinstance(self, IdlUnionType) | 275 return isinstance(self, IdlUnionType) |
200 | 276 |
201 @property | 277 @property |
202 def name(self): | 278 def inner_name(self): |
203 """Return type name. | 279 """Return type name (or inner type name if nullable) |
204 | 280 |
205 http://heycam.github.io/webidl/#dfn-type-name | 281 http://heycam.github.io/webidl/#dfn-type-name |
206 """ | 282 """ |
207 base_type = self.base_type | 283 base_type = self.base_type |
208 base_type_name = TYPE_NAMES.get(base_type, base_type) | 284 return 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 | 285 |
217 @classmethod | 286 @classmethod |
218 def set_callback_functions(cls, new_callback_functions): | 287 def set_callback_functions(cls, new_callback_functions): |
219 cls.callback_functions.update(new_callback_functions) | 288 cls.callback_functions.update(new_callback_functions) |
220 | 289 |
221 @classmethod | 290 @classmethod |
222 def set_callback_interfaces(cls, new_callback_interfaces): | 291 def set_callback_interfaces(cls, new_callback_interfaces): |
223 cls.callback_interfaces.update(new_callback_interfaces) | 292 cls.callback_interfaces.update(new_callback_interfaces) |
224 | 293 |
225 @classmethod | 294 @classmethod |
| 295 def set_dictionaries(cls, new_dictionaries): |
| 296 cls.dictionaries.update(new_dictionaries) |
| 297 |
| 298 @classmethod |
226 def set_enums(cls, new_enums): | 299 def set_enums(cls, new_enums): |
227 cls.enums.update(new_enums) | 300 cls.enums.update(new_enums) |
228 | 301 |
229 def resolve_typedefs(self, typedefs): | 302 def resolve_typedefs(self, typedefs): |
| 303 # This function either returns |self|, possibly mutated, or leaves this |
| 304 # object unmodified and returns a different object. |
| 305 # FIXME: Change to never mutate |self|, and rename typedefs_resolved(). |
230 if self.base_type not in typedefs: | 306 if self.base_type not in typedefs: |
231 return self | 307 return self |
232 new_type = typedefs[self.base_type] | 308 new_type = typedefs[self.base_type] |
233 if type(new_type) != type(self): | 309 if type(new_type) != type(self): |
234 # If type changes, need to return a different object, | 310 # If type changes, need to return a different object, |
235 # since can't change type(self) | 311 # since can't change type(self) |
236 return new_type | 312 return new_type |
237 # If type doesn't change, just mutate self to avoid a new object | 313 # If type doesn't change, just mutate self to avoid a new object |
238 # FIXME: a bit ugly; use __init__ instead of setting flags | 314 self.__init__(new_type.base_type, self.is_nullable or new_type.is_nullab
le) |
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 | 315 return self |
249 | 316 |
250 | 317 |
251 ################################################################################ | 318 ################################################################################ |
252 # IdlUnionType | 319 # IdlUnionType |
253 ################################################################################ | 320 ################################################################################ |
254 | 321 |
255 class IdlUnionType(object): | 322 class IdlUnionType(IdlTypeBase): |
256 # http://heycam.github.io/webidl/#idl-union | 323 # 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): | 324 def __init__(self, member_types, is_nullable=False): |
| 325 super(IdlUnionType, self).__init__(is_nullable=is_nullable) |
260 self.member_types = member_types | 326 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 | 327 |
309 @property | 328 @property |
310 def is_union_type(self): | 329 def is_union_type(self): |
311 return True | 330 return True |
312 | 331 |
313 @property | 332 @property |
314 def name(self): | 333 def inner_name(self): |
| 334 """Return type name (or inner type name if nullable) |
| 335 |
| 336 http://heycam.github.io/webidl/#dfn-type-name |
| 337 """ |
315 return 'Or'.join(member_type.name for member_type in self.member_types) | 338 return 'Or'.join(member_type.name for member_type in self.member_types) |
316 | 339 |
317 def resolve_typedefs(self, typedefs): | 340 def resolve_typedefs(self, typedefs): |
318 self.member_types = [ | 341 self.member_types = [ |
319 typedefs.get(member_type, member_type) | 342 typedefs.get(member_type, member_type) |
320 for member_type in self.member_types] | 343 for member_type in self.member_types] |
321 return self | 344 return self |
| 345 |
| 346 |
| 347 ################################################################################ |
| 348 # IdlArrayOrSequenceType, IdlArrayType, IdlSequenceType |
| 349 ################################################################################ |
| 350 |
| 351 class IdlArrayOrSequenceType(IdlTypeBase): |
| 352 """Base class for IdlArrayType and IdlSequenceType.""" |
| 353 |
| 354 def __init__(self, element_type, is_nullable=False): |
| 355 super(IdlArrayOrSequenceType, self).__init__(is_nullable) |
| 356 self.element_type = element_type |
| 357 |
| 358 def resolve_typedefs(self, typedefs): |
| 359 self.element_type = self.element_type.resolve_typedefs(typedefs) |
| 360 return self |
| 361 |
| 362 |
| 363 class IdlArrayType(IdlArrayOrSequenceType): |
| 364 def __init__(self, element_type, is_nullable=False): |
| 365 super(IdlArrayType, self).__init__(element_type, is_nullable) |
| 366 |
| 367 @property |
| 368 def inner_string(self): |
| 369 return '%s[]' % self.element_type |
| 370 |
| 371 @property |
| 372 def inner_name(self): |
| 373 return self.element_type.name + 'Array' |
| 374 |
| 375 |
| 376 class IdlSequenceType(IdlArrayOrSequenceType): |
| 377 def __init__(self, element_type, is_nullable=False): |
| 378 super(IdlSequenceType, self).__init__(element_type, is_nullable) |
| 379 |
| 380 @property |
| 381 def inner_string(self): |
| 382 return 'sequence<%s>' % self.element_type |
| 383 |
| 384 @property |
| 385 def inner_name(self): |
| 386 return self.element_type.name + 'Sequence' |
OLD | NEW |