 Chromium Code Reviews
 Chromium Code Reviews Issue 474173002:
  IDL: Use IdlNullableType wrapper to represent nullable types  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/blink.git@master
    
  
    Issue 474173002:
  IDL: Use IdlNullableType wrapper to represent nullable types  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/blink.git@master| 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 IdlTypeBase | 7 IdlTypeBase | 
| 8 IdlType | 8 IdlType | 
| 9 IdlUnionType | 9 IdlUnionType | 
| 10 IdlArrayOrSequenceType | 10 IdlArrayOrSequenceType | 
| 11 IdlArrayType | 11 IdlArrayType | 
| 12 IdlSequenceType | 12 IdlSequenceType | 
| 13 IdlNullableType | |
| 13 """ | 14 """ | 
| 14 | 15 | 
| 15 from collections import defaultdict | 16 from collections import defaultdict | 
| 16 | 17 | 
| 17 | 18 | 
| 18 ################################################################################ | 19 ################################################################################ | 
| 19 # IDL types | 20 # IDL types | 
| 20 ################################################################################ | 21 ################################################################################ | 
| 21 | 22 | 
| 22 INTEGER_TYPES = frozenset([ | 23 INTEGER_TYPES = frozenset([ | 
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 94 ancestor_name in ancestors[interface_name]) | 95 ancestor_name in ancestors[interface_name]) | 
| 95 | 96 | 
| 96 | 97 | 
| 97 def set_ancestors(new_ancestors): | 98 def set_ancestors(new_ancestors): | 
| 98 ancestors.update(new_ancestors) | 99 ancestors.update(new_ancestors) | 
| 99 | 100 | 
| 100 | 101 | 
| 101 class IdlTypeBase(object): | 102 class IdlTypeBase(object): | 
| 102 """Base class for IdlType, IdlUnionType and IdlArrayOrSequenceType.""" | 103 """Base class for IdlType, IdlUnionType and IdlArrayOrSequenceType.""" | 
| 103 | 104 | 
| 104 def __init__(self, is_nullable): | |
| 105 self.base_type = None | |
| 106 self.is_nullable = is_nullable | |
| 107 | |
| 108 def __str__(self): | 105 def __str__(self): | 
| 109 inner_string = self.inner_string | 106 raise NotImplementedError( | 
| 110 if self.is_nullable: | 107 '__str__() should be defined in subclasses') | 
| 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 | 108 | 
| 119 @property | 109 @property | 
| 120 def inner_string(self): | 110 def is_nullable(self): | 
| 121 raise NotImplementedError( | 111 return False | 
| 122 'inner_string property should be defined in subclasses') | |
| 123 | 112 | 
| 124 @property | 113 @property | 
| 125 def is_basic_type(self): | 114 def is_basic_type(self): | 
| 126 return False | 115 return False | 
| 127 | 116 | 
| 128 @property | 117 @property | 
| 129 def is_callback_function(self): | 118 def is_callback_function(self): | 
| 130 return False | 119 return False | 
| 131 | 120 | 
| 132 @property | 121 @property | 
| (...skipping 26 matching lines...) Expand all Loading... | |
| 159 | 148 | 
| 160 @property | 149 @property | 
| 161 def is_string_type(self): | 150 def is_string_type(self): | 
| 162 return False | 151 return False | 
| 163 | 152 | 
| 164 @property | 153 @property | 
| 165 def is_union_type(self): | 154 def is_union_type(self): | 
| 166 return False | 155 return False | 
| 167 | 156 | 
| 168 @property | 157 @property | 
| 158 def base_type(self): | |
| 159 return None | |
| 160 | |
| 161 @property | |
| 169 def may_raise_exception_on_conversion(self): | 162 def may_raise_exception_on_conversion(self): | 
| 170 return False | 163 return False | 
| 171 | 164 | 
| 172 @property | 165 @property | 
| 173 def name(self): | 166 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( | 167 raise NotImplementedError( | 
| 181 'inner_name property should be defined in subclasses') | 168 'name property should be defined in subclasses') | 
| 182 | 169 | 
| 183 def resolve_typedefs(self, typedefs): | 170 def resolve_typedefs(self, typedefs): | 
| 184 raise NotImplementedError( | 171 raise NotImplementedError( | 
| 185 'resolve_typedefs should be defined in subclasses') | 172 'resolve_typedefs should be defined in subclasses') | 
| 186 | 173 | 
| 187 | 174 | 
| 188 ################################################################################ | 175 ################################################################################ | 
| 189 # IdlType | 176 # IdlType | 
| 190 ################################################################################ | 177 ################################################################################ | 
| 191 | 178 | 
| 192 class IdlType(IdlTypeBase): | 179 class IdlType(IdlTypeBase): | 
| 193 # FIXME: incorporate Nullable, etc. | 180 # FIXME: incorporate Nullable, etc. | 
| 194 # to support types like short?[] vs. short[]?, instead of treating these | 181 # to support types like short?[] vs. short[]?, instead of treating these | 
| 195 # as orthogonal properties (via flags). | 182 # as orthogonal properties (via flags). | 
| 196 callback_functions = set() | 183 callback_functions = set() | 
| 197 callback_interfaces = set() | 184 callback_interfaces = set() | 
| 198 dictionaries = set() | 185 dictionaries = set() | 
| 199 enums = {} # name -> values | 186 enums = {} # name -> values | 
| 200 | 187 | 
| 201 def __init__(self, base_type, is_nullable=False, is_unrestricted=False): | 188 def __init__(self, base_type, is_unrestricted=False): | 
| 202 super(IdlType, self).__init__(is_nullable) | 189 super(IdlType, self).__init__() | 
| 203 if is_unrestricted: | 190 if is_unrestricted: | 
| 204 self.base_type = 'unrestricted %s' % base_type | 191 self.base_type_name = 'unrestricted %s' % base_type | 
| 205 else: | 192 else: | 
| 206 self.base_type = base_type | 193 self.base_type_name = base_type | 
| 207 | 194 | 
| 208 @property | 195 def __str__(self): | 
| 209 def inner_string(self): | |
| 210 return self.base_type | 196 return self.base_type | 
| 211 | 197 | 
| 212 @property | 198 @property | 
| 213 def is_basic_type(self): | 199 def is_basic_type(self): | 
| 214 return self.base_type in BASIC_TYPES | 200 return self.base_type in BASIC_TYPES | 
| 215 | 201 | 
| 216 @property | 202 @property | 
| 217 def is_callback_function(self): | 203 def is_callback_function(self): | 
| 218 return self.base_type in IdlType.callback_functions | 204 return self.base_type in IdlType.callback_functions | 
| 219 | 205 | 
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 256 return not(self.is_basic_type or | 242 return not(self.is_basic_type or | 
| 257 self.is_callback_function or | 243 self.is_callback_function or | 
| 258 self.is_dictionary or | 244 self.is_dictionary or | 
| 259 self.is_enum or | 245 self.is_enum or | 
| 260 self.name == 'Any' or | 246 self.name == 'Any' or | 
| 261 self.name == 'Object' or | 247 self.name == 'Object' or | 
| 262 self.name == 'Promise') # Promise will be basic in future | 248 self.name == 'Promise') # Promise will be basic in future | 
| 263 | 249 | 
| 264 @property | 250 @property | 
| 265 def is_string_type(self): | 251 def is_string_type(self): | 
| 266 return self.inner_name in STRING_TYPES | 252 return self.name in STRING_TYPES | 
| 267 | 253 | 
| 268 @property | 254 @property | 
| 269 def may_raise_exception_on_conversion(self): | 255 def may_raise_exception_on_conversion(self): | 
| 270 return (self.is_integer_type or | 256 return (self.is_integer_type or | 
| 271 self.name in ('ByteString', 'ScalarValueString')) | 257 self.name in ('ByteString', 'ScalarValueString')) | 
| 272 | 258 | 
| 273 @property | 259 @property | 
| 274 def is_union_type(self): | 260 def is_union_type(self): | 
| 275 return isinstance(self, IdlUnionType) | 261 return isinstance(self, IdlUnionType) | 
| 276 | 262 | 
| 277 @property | 263 @property | 
| 278 def inner_name(self): | 264 def base_type(self): | 
| 279 """Return type name (or inner type name if nullable) | 265 return self.base_type_name | 
| 266 | |
| 267 @property | |
| 268 def name(self): | |
| 269 """Return type name | |
| 280 | 270 | 
| 281 http://heycam.github.io/webidl/#dfn-type-name | 271 http://heycam.github.io/webidl/#dfn-type-name | 
| 282 """ | 272 """ | 
| 283 base_type = self.base_type | 273 base_type = self.base_type | 
| 284 return TYPE_NAMES.get(base_type, base_type) | 274 return TYPE_NAMES.get(base_type, base_type) | 
| 285 | 275 | 
| 286 @classmethod | 276 @classmethod | 
| 287 def set_callback_functions(cls, new_callback_functions): | 277 def set_callback_functions(cls, new_callback_functions): | 
| 288 cls.callback_functions.update(new_callback_functions) | 278 cls.callback_functions.update(new_callback_functions) | 
| 289 | 279 | 
| 290 @classmethod | 280 @classmethod | 
| 291 def set_callback_interfaces(cls, new_callback_interfaces): | 281 def set_callback_interfaces(cls, new_callback_interfaces): | 
| 292 cls.callback_interfaces.update(new_callback_interfaces) | 282 cls.callback_interfaces.update(new_callback_interfaces) | 
| 293 | 283 | 
| 294 @classmethod | 284 @classmethod | 
| 295 def set_dictionaries(cls, new_dictionaries): | 285 def set_dictionaries(cls, new_dictionaries): | 
| 296 cls.dictionaries.update(new_dictionaries) | 286 cls.dictionaries.update(new_dictionaries) | 
| 297 | 287 | 
| 298 @classmethod | 288 @classmethod | 
| 299 def set_enums(cls, new_enums): | 289 def set_enums(cls, new_enums): | 
| 300 cls.enums.update(new_enums) | 290 cls.enums.update(new_enums) | 
| 301 | 291 | 
| 302 def resolve_typedefs(self, typedefs): | 292 def resolve_typedefs(self, typedefs): | 
| 303 # This function either returns |self|, possibly mutated, or leaves this | 293 # This function either returns |self| or a different object. | 
| 304 # object unmodified and returns a different object. | 294 # FIXME: Rename typedefs_resolved(). | 
| 305 # FIXME: Change to never mutate |self|, and rename typedefs_resolved(). | 295 return typedefs.get(self.base_type, self) | 
| 306 if self.base_type not in typedefs: | |
| 307 return self | |
| 308 new_type = typedefs[self.base_type] | |
| 309 if type(new_type) != type(self): | |
| 310 # If type changes, need to return a different object, | |
| 311 # since can't change type(self) | |
| 312 return new_type | |
| 313 # If type doesn't change, just mutate self to avoid a new object | |
| 314 self.__init__(new_type.base_type, self.is_nullable or new_type.is_nullab le) | |
| 315 return self | |
| 316 | 296 | 
| 317 | 297 | 
| 318 ################################################################################ | 298 ################################################################################ | 
| 319 # IdlUnionType | 299 # IdlUnionType | 
| 320 ################################################################################ | 300 ################################################################################ | 
| 321 | 301 | 
| 322 class IdlUnionType(IdlTypeBase): | 302 class IdlUnionType(IdlTypeBase): | 
| 323 # http://heycam.github.io/webidl/#idl-union | 303 # http://heycam.github.io/webidl/#idl-union | 
| 324 def __init__(self, member_types, is_nullable=False): | 304 def __init__(self, member_types): | 
| 325 super(IdlUnionType, self).__init__(is_nullable=is_nullable) | 305 super(IdlUnionType, self).__init__() | 
| 326 self.member_types = member_types | 306 self.member_types = member_types | 
| 327 | 307 | 
| 328 @property | 308 @property | 
| 329 def is_union_type(self): | 309 def is_union_type(self): | 
| 330 return True | 310 return True | 
| 331 | 311 | 
| 332 @property | 312 @property | 
| 333 def inner_name(self): | 313 def name(self): | 
| 334 """Return type name (or inner type name if nullable) | 314 """Return type name (or inner type name if nullable) | 
| 335 | 315 | 
| 336 http://heycam.github.io/webidl/#dfn-type-name | 316 http://heycam.github.io/webidl/#dfn-type-name | 
| 337 """ | 317 """ | 
| 338 return 'Or'.join(member_type.name for member_type in self.member_types) | 318 return 'Or'.join(member_type.name for member_type in self.member_types) | 
| 339 | 319 | 
| 340 def resolve_typedefs(self, typedefs): | 320 def resolve_typedefs(self, typedefs): | 
| 341 self.member_types = [ | 321 self.member_types = [ | 
| 342 typedefs.get(member_type, member_type) | 322 typedefs.get(member_type, member_type) | 
| 343 for member_type in self.member_types] | 323 for member_type in self.member_types] | 
| 344 return self | 324 return self | 
| 345 | 325 | 
| 346 | 326 | 
| 347 ################################################################################ | 327 ################################################################################ | 
| 348 # IdlArrayOrSequenceType, IdlArrayType, IdlSequenceType | 328 # IdlArrayOrSequenceType, IdlArrayType, IdlSequenceType | 
| 349 ################################################################################ | 329 ################################################################################ | 
| 350 | 330 | 
| 351 class IdlArrayOrSequenceType(IdlTypeBase): | 331 class IdlArrayOrSequenceType(IdlTypeBase): | 
| 352 """Base class for IdlArrayType and IdlSequenceType.""" | 332 """Base class for IdlArrayType and IdlSequenceType.""" | 
| 353 | 333 | 
| 354 def __init__(self, element_type, is_nullable=False): | 334 def __init__(self, element_type): | 
| 355 super(IdlArrayOrSequenceType, self).__init__(is_nullable) | 335 super(IdlArrayOrSequenceType, self).__init__() | 
| 356 self.element_type = element_type | 336 self.element_type = element_type | 
| 357 | 337 | 
| 358 def resolve_typedefs(self, typedefs): | 338 def resolve_typedefs(self, typedefs): | 
| 359 self.element_type = self.element_type.resolve_typedefs(typedefs) | 339 self.element_type = self.element_type.resolve_typedefs(typedefs) | 
| 360 return self | 340 return self | 
| 361 | 341 | 
| 362 | 342 | 
| 363 class IdlArrayType(IdlArrayOrSequenceType): | 343 class IdlArrayType(IdlArrayOrSequenceType): | 
| 364 def __init__(self, element_type, is_nullable=False): | 344 def __init__(self, element_type): | 
| 365 super(IdlArrayType, self).__init__(element_type, is_nullable) | 345 super(IdlArrayType, self).__init__(element_type) | 
| 366 | 346 | 
| 367 @property | 347 def __str__(self): | 
| 368 def inner_string(self): | |
| 369 return '%s[]' % self.element_type | 348 return '%s[]' % self.element_type | 
| 370 | 349 | 
| 371 @property | 350 @property | 
| 372 def inner_name(self): | 351 def name(self): | 
| 373 return self.element_type.name + 'Array' | 352 return self.element_type.name + 'Array' | 
| 374 | 353 | 
| 375 | 354 | 
| 376 class IdlSequenceType(IdlArrayOrSequenceType): | 355 class IdlSequenceType(IdlArrayOrSequenceType): | 
| 377 def __init__(self, element_type, is_nullable=False): | 356 def __init__(self, element_type): | 
| 378 super(IdlSequenceType, self).__init__(element_type, is_nullable) | 357 super(IdlSequenceType, self).__init__(element_type) | 
| 379 | 358 | 
| 380 @property | 359 def __str__(self): | 
| 381 def inner_string(self): | |
| 382 return 'sequence<%s>' % self.element_type | 360 return 'sequence<%s>' % self.element_type | 
| 383 | 361 | 
| 384 @property | 362 @property | 
| 385 def inner_name(self): | 363 def name(self): | 
| 386 return self.element_type.name + 'Sequence' | 364 return self.element_type.name + 'Sequence' | 
| 365 | |
| 366 | |
| 367 ################################################################################ | |
| 368 # IdlNullableType | |
| 369 ################################################################################ | |
| 370 | |
| 371 class IdlNullableType(IdlTypeBase): | |
| 372 def __init__(self, inner_type): | |
| 373 super(IdlNullableType, self).__init__() | |
| 374 self.inner_type = inner_type | |
| 375 | |
| 376 def __str__(self): | |
| 377 # FIXME: Dictionary::ConversionContext::setConversionType can't | |
| 378 # handle the '?' in nullable types (passes nullability separately). | |
| 379 # Update that function to handle nullability from the type name, | |
| 380 # simplifying its signature. | |
| 381 # return str(self.inner_type) + '?' | |
| 382 return str(self.inner_type) | |
| 383 | |
| 384 def __getattr__(self, name): | |
| 385 return getattr(self.inner_type, name) | |
| 386 | |
| 387 @property | |
| 388 def is_nullable(self): | |
| 389 return True | |
| 390 | |
| 391 @property | |
| 392 def is_basic_type(self): | |
| 393 return self.inner_type.is_basic_type | |
| 
haraken
2014/08/15 07:43:57
Just a question about Python: Even if we have the
 
Jens Widell
2014/08/15 08:00:09
Yes, __getattr__ is called as a last resort, if th
 
haraken
2014/08/15 08:11:07
Makes sense.
 | |
| 394 | |
| 395 @property | |
| 396 def is_callback_function(self): | |
| 397 return self.inner_type.is_callback_function | |
| 398 | |
| 399 @property | |
| 400 def is_callback_interface(self): | |
| 401 return self.inner_type.is_callback_interface | |
| 402 | |
| 403 @property | |
| 404 def is_dictionary(self): | |
| 405 return self.inner_type.is_dictionary | |
| 406 | |
| 407 @property | |
| 408 def is_enum(self): | |
| 409 return self.inner_type.is_enum | |
| 410 | |
| 411 @property | |
| 412 def is_integer_type(self): | |
| 413 return self.inner_type.is_integer_type | |
| 414 | |
| 415 @property | |
| 416 def is_numeric_type(self): | |
| 417 return self.inner_type.is_numeric_type | |
| 418 | |
| 419 @property | |
| 420 def is_primitive_type(self): | |
| 421 return self.inner_type.is_primitive_type | |
| 422 | |
| 423 @property | |
| 424 def is_interface_type(self): | |
| 425 return self.inner_type.is_interface_type | |
| 426 | |
| 427 @property | |
| 428 def is_string_type(self): | |
| 429 return self.inner_type.is_string_type | |
| 430 | |
| 431 @property | |
| 432 def is_union_type(self): | |
| 433 return self.inner_type.is_union_type | |
| 434 | |
| 435 @property | |
| 436 def base_type(self): | |
| 437 return self.inner_type.base_type | |
| 438 | |
| 439 @property | |
| 440 def may_raise_exception_on_conversion(self): | |
| 441 return self.inner_type.may_raise_exception_on_conversion | |
| 442 | |
| 443 @property | |
| 444 def name(self): | |
| 445 return self.inner_type.name + 'OrNull' | |
| 446 | |
| 447 def resolve_typedefs(self, typedefs): | |
| 448 self.inner_type = self.inner_type.resolve_typedefs(typedefs) | |
| 449 return self | |
| OLD | NEW |