OLD | NEW |
(Empty) | |
| 1 # Copyright (C) 2013 Google Inc. All rights reserved. |
| 2 # |
| 3 # Redistribution and use in source and binary forms, with or without |
| 4 # modification, are permitted provided that the following conditions are |
| 5 # met: |
| 6 # |
| 7 # * Redistributions of source code must retain the above copyright |
| 8 # notice, this list of conditions and the following disclaimer. |
| 9 # * Redistributions in binary form must reproduce the above |
| 10 # copyright notice, this list of conditions and the following disclaimer |
| 11 # in the documentation and/or other materials provided with the |
| 12 # distribution. |
| 13 # * Neither the name of Google Inc. nor the names of its |
| 14 # contributors may be used to endorse or promote products derived from |
| 15 # this software without specific prior written permission. |
| 16 # |
| 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 |
| 29 """Blink IDL Intermediate Representation (IR) classes. |
| 30 |
| 31 Classes are primarily constructors, which build an IdlDefinitions object |
| 32 (and various contained objects) from an AST (produced by blink_idl_parser). |
| 33 |
| 34 This is in two steps: |
| 35 * Constructors walk the AST, creating objects. |
| 36 * Typedef resolution. |
| 37 |
| 38 Typedefs are all resolved here, and not stored in IR. |
| 39 |
| 40 Typedef resolution uses some auxiliary classes and OOP techniques to make this |
| 41 a generic call, via the resolve_typedefs() method. |
| 42 |
| 43 Class hierarchy (mostly containment, '<' for inheritance): |
| 44 |
| 45 IdlDefinitions |
| 46 IdlCallbackFunction < TypedObject |
| 47 IdlEnum :: FIXME: remove, just use a dict for enums |
| 48 IdlInterface |
| 49 IdlAttribute < TypedObject |
| 50 IdlConstant < TypedObject |
| 51 IdlOperation < TypedObject |
| 52 IdlArgument < TypedObject |
| 53 IdlException < IdlInterface |
| 54 (same contents as IdlInterface) |
| 55 |
| 56 TypedObject :: mixin for typedef resolution |
| 57 |
| 58 Design doc: http://www.chromium.org/developers/design-documents/idl-compiler |
| 59 """ |
| 60 |
| 61 import abc |
| 62 |
| 63 from idl_types import IdlType, IdlUnionType |
| 64 |
| 65 SPECIAL_KEYWORD_LIST = ['GETTER', 'SETTER', 'DELETER'] |
| 66 STANDARD_TYPEDEFS = { |
| 67 # http://www.w3.org/TR/WebIDL/#common-DOMTimeStamp |
| 68 'DOMTimeStamp': 'unsigned long long', |
| 69 } |
| 70 |
| 71 |
| 72 ################################################################################ |
| 73 # TypedObject (mixin for typedef resolution) |
| 74 ################################################################################ |
| 75 |
| 76 class TypedObject(object): |
| 77 """Object with a type, such as an Attribute or Operation (return value). |
| 78 |
| 79 The type can be an actual type, or can be a typedef, which must be resolved |
| 80 before passing data to the code generator. |
| 81 """ |
| 82 __metaclass__ = abc.ABCMeta |
| 83 idl_type = None |
| 84 |
| 85 def resolve_typedefs(self, typedefs): |
| 86 """Resolve typedefs to actual types in the object.""" |
| 87 # Constructors don't have their own return type, because it's the |
| 88 # interface itself. |
| 89 if not self.idl_type: |
| 90 return |
| 91 # Need to re-assign self.idl_type, not just mutate idl_type, |
| 92 # since type(idl_type) may change. |
| 93 self.idl_type = self.idl_type.resolve_typedefs(typedefs) |
| 94 |
| 95 |
| 96 ################################################################################ |
| 97 # Definitions (main container class) |
| 98 ################################################################################ |
| 99 |
| 100 class IdlDefinitions(object): |
| 101 def __init__(self, node): |
| 102 """Args: node: AST root node, class == 'File'""" |
| 103 self.callback_functions = {} |
| 104 self.dictionaries = {} |
| 105 self.enumerations = {} |
| 106 self.interfaces = {} |
| 107 |
| 108 node_class = node.GetClass() |
| 109 if node_class != 'File': |
| 110 raise ValueError('Unrecognized node class: %s' % node_class) |
| 111 |
| 112 typedefs = dict((typedef_name, IdlType(type_name)) |
| 113 for typedef_name, type_name in |
| 114 STANDARD_TYPEDEFS.iteritems()) |
| 115 |
| 116 children = node.GetChildren() |
| 117 for child in children: |
| 118 child_class = child.GetClass() |
| 119 if child_class == 'Interface': |
| 120 interface = IdlInterface(child) |
| 121 self.interfaces[interface.name] = interface |
| 122 elif child_class == 'Exception': |
| 123 exception = IdlException(child) |
| 124 # For simplicity, treat exceptions as interfaces |
| 125 self.interfaces[exception.name] = exception |
| 126 elif child_class == 'Typedef': |
| 127 type_name = child.GetName() |
| 128 typedefs[type_name] = typedef_node_to_type(child) |
| 129 elif child_class == 'Enum': |
| 130 enumeration = IdlEnum(child) |
| 131 self.enumerations[enumeration.name] = enumeration |
| 132 elif child_class == 'Callback': |
| 133 callback_function = IdlCallbackFunction(child) |
| 134 self.callback_functions[callback_function.name] = callback_funct
ion |
| 135 elif child_class == 'Implements': |
| 136 # Implements is handled at the interface merging step |
| 137 pass |
| 138 elif child_class == 'Dictionary': |
| 139 dictionary = IdlDictionary(child) |
| 140 self.dictionaries[dictionary.name] = dictionary |
| 141 else: |
| 142 raise ValueError('Unrecognized node class: %s' % child_class) |
| 143 |
| 144 # Typedefs are not stored in IR: |
| 145 # Resolve typedefs with the actual types and then discard the Typedefs. |
| 146 # http://www.w3.org/TR/WebIDL/#idl-typedefs |
| 147 self.resolve_typedefs(typedefs) |
| 148 |
| 149 def resolve_typedefs(self, typedefs): |
| 150 for callback_function in self.callback_functions.itervalues(): |
| 151 callback_function.resolve_typedefs(typedefs) |
| 152 for interface in self.interfaces.itervalues(): |
| 153 interface.resolve_typedefs(typedefs) |
| 154 |
| 155 def update(self, other): |
| 156 """Update with additional IdlDefinitions.""" |
| 157 for interface_name, new_interface in other.interfaces.iteritems(): |
| 158 if not new_interface.is_partial: |
| 159 # Add as new interface |
| 160 self.interfaces[interface_name] = new_interface |
| 161 continue |
| 162 |
| 163 # Merge partial to existing interface |
| 164 try: |
| 165 self.interfaces[interface_name].merge(new_interface) |
| 166 except KeyError: |
| 167 raise Exception('Tried to merge partial interface for {0}, ' |
| 168 'but no existing interface by that name' |
| 169 .format(interface_name)) |
| 170 |
| 171 # Merge callbacks and enumerations |
| 172 self.enumerations.update(other.enumerations) |
| 173 self.callback_functions.update(other.callback_functions) |
| 174 |
| 175 |
| 176 ################################################################################ |
| 177 # Callback Functions |
| 178 ################################################################################ |
| 179 |
| 180 class IdlCallbackFunction(TypedObject): |
| 181 def __init__(self, node): |
| 182 children = node.GetChildren() |
| 183 num_children = len(children) |
| 184 if num_children != 2: |
| 185 raise ValueError('Expected 2 children, got %s' % num_children) |
| 186 type_node, arguments_node = children |
| 187 arguments_node_class = arguments_node.GetClass() |
| 188 if arguments_node_class != 'Arguments': |
| 189 raise ValueError('Expected Arguments node, got %s' % arguments_node_
class) |
| 190 |
| 191 self.name = node.GetName() |
| 192 self.idl_type = type_node_to_type(type_node) |
| 193 self.arguments = arguments_node_to_arguments(arguments_node) |
| 194 |
| 195 def resolve_typedefs(self, typedefs): |
| 196 TypedObject.resolve_typedefs(self, typedefs) |
| 197 for argument in self.arguments: |
| 198 argument.resolve_typedefs(typedefs) |
| 199 |
| 200 |
| 201 ################################################################################ |
| 202 # Dictionary |
| 203 ################################################################################ |
| 204 |
| 205 class IdlDictionary(object): |
| 206 def __init__(self, node): |
| 207 self.parent = None |
| 208 self.name = node.GetName() |
| 209 self.members = [] |
| 210 for child in node.GetChildren(): |
| 211 child_class = child.GetClass() |
| 212 if child_class == 'Inherit': |
| 213 self.parent = child.GetName() |
| 214 elif child_class == 'Key': |
| 215 self.members.append(IdlDictionaryMember(child)) |
| 216 else: |
| 217 raise ValueError('Unrecognized node class: %s' % child_class) |
| 218 |
| 219 |
| 220 class IdlDictionaryMember(object): |
| 221 def __init__(self, node): |
| 222 self.default_value = None |
| 223 self.extended_attributes = {} |
| 224 self.idl_type = None |
| 225 self.name = node.GetName() |
| 226 for child in node.GetChildren(): |
| 227 child_class = child.GetClass() |
| 228 if child_class == 'Type': |
| 229 self.idl_type = type_node_to_type(child) |
| 230 elif child_class == 'Default': |
| 231 self.default_value = child.GetProperty('VALUE') |
| 232 elif child_class == 'ExtAttributes': |
| 233 self.extended_attributes = ext_attributes_node_to_extended_attri
butes(child) |
| 234 else: |
| 235 raise ValueError('Unrecognized node class: %s' % child_class) |
| 236 |
| 237 |
| 238 ################################################################################ |
| 239 # Enumerations |
| 240 ################################################################################ |
| 241 |
| 242 class IdlEnum(object): |
| 243 # FIXME: remove, just treat enums as a dictionary |
| 244 def __init__(self, node): |
| 245 self.name = node.GetName() |
| 246 self.values = [] |
| 247 for child in node.GetChildren(): |
| 248 self.values.append(child.GetName()) |
| 249 |
| 250 |
| 251 ################################################################################ |
| 252 # Interfaces and Exceptions |
| 253 ################################################################################ |
| 254 |
| 255 class IdlInterface(object): |
| 256 def __init__(self, node=None): |
| 257 self.attributes = [] |
| 258 self.constants = [] |
| 259 self.constructors = [] |
| 260 self.custom_constructors = [] |
| 261 self.extended_attributes = {} |
| 262 self.operations = [] |
| 263 self.parent = None |
| 264 if not node: # Early exit for IdlException.__init__ |
| 265 return |
| 266 |
| 267 self.is_callback = node.GetProperty('CALLBACK') or False |
| 268 self.is_exception = False |
| 269 # FIXME: uppercase 'Partial' => 'PARTIAL' in base IDL parser |
| 270 self.is_partial = node.GetProperty('Partial') or False |
| 271 self.name = node.GetName() |
| 272 |
| 273 children = node.GetChildren() |
| 274 for child in children: |
| 275 child_class = child.GetClass() |
| 276 if child_class == 'Attribute': |
| 277 self.attributes.append(IdlAttribute(child)) |
| 278 elif child_class == 'Const': |
| 279 self.constants.append(IdlConstant(child)) |
| 280 elif child_class == 'ExtAttributes': |
| 281 extended_attributes = ext_attributes_node_to_extended_attributes
(child) |
| 282 self.constructors, self.custom_constructors = ( |
| 283 extended_attributes_to_constructors(extended_attributes)) |
| 284 clear_constructor_attributes(extended_attributes) |
| 285 self.extended_attributes = extended_attributes |
| 286 elif child_class == 'Operation': |
| 287 self.operations.append(IdlOperation(child)) |
| 288 elif child_class == 'Inherit': |
| 289 self.parent = child.GetName() |
| 290 else: |
| 291 raise ValueError('Unrecognized node class: %s' % child_class) |
| 292 |
| 293 def resolve_typedefs(self, typedefs): |
| 294 for attribute in self.attributes: |
| 295 attribute.resolve_typedefs(typedefs) |
| 296 for constant in self.constants: |
| 297 constant.resolve_typedefs(typedefs) |
| 298 for constructor in self.constructors: |
| 299 constructor.resolve_typedefs(typedefs) |
| 300 for custom_constructor in self.custom_constructors: |
| 301 custom_constructor.resolve_typedefs(typedefs) |
| 302 for operation in self.operations: |
| 303 operation.resolve_typedefs(typedefs) |
| 304 |
| 305 def merge(self, other): |
| 306 """Merge in another interface's members (e.g., partial interface)""" |
| 307 self.attributes.extend(other.attributes) |
| 308 self.constants.extend(other.constants) |
| 309 self.operations.extend(other.operations) |
| 310 |
| 311 |
| 312 class IdlException(IdlInterface): |
| 313 # Properly exceptions and interfaces are distinct, and thus should inherit a |
| 314 # common base class (say, "IdlExceptionOrInterface"). |
| 315 # However, there is only one exception (DOMException), and new exceptions |
| 316 # are not expected. Thus it is easier to implement exceptions as a |
| 317 # restricted subclass of interfaces. |
| 318 # http://www.w3.org/TR/WebIDL/#idl-exceptions |
| 319 def __init__(self, node): |
| 320 # Exceptions are similar to Interfaces, but simpler |
| 321 IdlInterface.__init__(self) |
| 322 self.is_callback = False |
| 323 self.is_exception = True |
| 324 self.is_partial = False |
| 325 self.name = node.GetName() |
| 326 |
| 327 children = node.GetChildren() |
| 328 for child in children: |
| 329 child_class = child.GetClass() |
| 330 if child_class == 'Attribute': |
| 331 attribute = IdlAttribute(child) |
| 332 self.attributes.append(attribute) |
| 333 elif child_class == 'Const': |
| 334 self.constants.append(IdlConstant(child)) |
| 335 elif child_class == 'ExtAttributes': |
| 336 self.extended_attributes = ext_attributes_node_to_extended_attri
butes(child) |
| 337 elif child_class == 'ExceptionOperation': |
| 338 self.operations.append(IdlOperation.from_exception_operation_nod
e(child)) |
| 339 else: |
| 340 raise ValueError('Unrecognized node class: %s' % child_class) |
| 341 |
| 342 |
| 343 ################################################################################ |
| 344 # Attributes |
| 345 ################################################################################ |
| 346 |
| 347 class IdlAttribute(TypedObject): |
| 348 def __init__(self, node): |
| 349 self.is_read_only = node.GetProperty('READONLY') or False |
| 350 self.is_static = node.GetProperty('STATIC') or False |
| 351 self.name = node.GetName() |
| 352 # Defaults, overridden below |
| 353 self.idl_type = None |
| 354 self.extended_attributes = {} |
| 355 |
| 356 children = node.GetChildren() |
| 357 for child in children: |
| 358 child_class = child.GetClass() |
| 359 if child_class == 'Type': |
| 360 self.idl_type = type_node_to_type(child) |
| 361 elif child_class == 'ExtAttributes': |
| 362 self.extended_attributes = ext_attributes_node_to_extended_attri
butes(child) |
| 363 else: |
| 364 raise ValueError('Unrecognized node class: %s' % child_class) |
| 365 |
| 366 |
| 367 ################################################################################ |
| 368 # Constants |
| 369 ################################################################################ |
| 370 |
| 371 class IdlConstant(TypedObject): |
| 372 def __init__(self, node): |
| 373 children = node.GetChildren() |
| 374 num_children = len(children) |
| 375 if num_children < 2 or num_children > 3: |
| 376 raise ValueError('Expected 2 or 3 children, got %s' % num_children) |
| 377 type_node = children[0] |
| 378 value_node = children[1] |
| 379 value_node_class = value_node.GetClass() |
| 380 if value_node_class != 'Value': |
| 381 raise ValueError('Expected Value node, got %s' % value_node_class) |
| 382 |
| 383 self.name = node.GetName() |
| 384 # ConstType is more limited than Type, so subtree is smaller and |
| 385 # we don't use the full type_node_to_type function. |
| 386 self.idl_type = type_node_inner_to_type(type_node) |
| 387 self.value = value_node.GetName() |
| 388 |
| 389 if num_children == 3: |
| 390 ext_attributes_node = children[2] |
| 391 self.extended_attributes = ext_attributes_node_to_extended_attribute
s(ext_attributes_node) |
| 392 else: |
| 393 self.extended_attributes = {} |
| 394 |
| 395 |
| 396 ################################################################################ |
| 397 # Literals |
| 398 ################################################################################ |
| 399 |
| 400 class IdlLiteral(object): |
| 401 def __init__(self, idl_type, value): |
| 402 self.idl_type = idl_type |
| 403 self.value = value |
| 404 self.is_null = False |
| 405 |
| 406 def __str__(self): |
| 407 if self.idl_type == 'DOMString': |
| 408 return 'String("%s")' % self.value |
| 409 if self.idl_type == 'integer': |
| 410 return '%d' % self.value |
| 411 if self.idl_type == 'float': |
| 412 return '%g' % self.value |
| 413 if self.idl_type == 'boolean': |
| 414 return 'true' if self.value else 'false' |
| 415 raise ValueError('Unsupported literal type: %s' % self.idl_type) |
| 416 |
| 417 |
| 418 class IdlLiteralNull(IdlLiteral): |
| 419 def __init__(self): |
| 420 self.idl_type = 'NULL' |
| 421 self.value = None |
| 422 self.is_null = True |
| 423 |
| 424 def __str__(self): |
| 425 return 'nullptr' |
| 426 |
| 427 |
| 428 def default_node_to_idl_literal(node): |
| 429 # FIXME: This code is unnecessarily complicated due to the rather |
| 430 # inconsistent way the upstream IDL parser outputs default values. |
| 431 # http://crbug.com/374178 |
| 432 idl_type = node.GetProperty('TYPE') |
| 433 if idl_type == 'DOMString': |
| 434 value = node.GetProperty('NAME') |
| 435 if '"' in value or '\\' in value: |
| 436 raise ValueError('Unsupported string value: %r' % value) |
| 437 return IdlLiteral(idl_type, value) |
| 438 if idl_type == 'integer': |
| 439 return IdlLiteral(idl_type, int(node.GetProperty('NAME'))) |
| 440 if idl_type == 'float': |
| 441 return IdlLiteral(idl_type, float(node.GetProperty('VALUE'))) |
| 442 if idl_type == 'boolean': |
| 443 return IdlLiteral(idl_type, node.GetProperty('VALUE')) |
| 444 if idl_type == 'NULL': |
| 445 return IdlLiteralNull() |
| 446 raise ValueError('Unrecognized default value type: %s' % idl_type) |
| 447 |
| 448 |
| 449 ################################################################################ |
| 450 # Operations |
| 451 ################################################################################ |
| 452 |
| 453 class IdlOperation(TypedObject): |
| 454 def __init__(self, node=None): |
| 455 self.arguments = [] |
| 456 self.extended_attributes = {} |
| 457 self.specials = [] |
| 458 self.is_constructor = False |
| 459 |
| 460 if not node: |
| 461 self.is_static = False |
| 462 return |
| 463 self.name = node.GetName() # FIXME: should just be: or '' |
| 464 # FIXME: AST should use None internally |
| 465 if self.name == '_unnamed_': |
| 466 self.name = '' |
| 467 |
| 468 self.is_static = node.GetProperty('STATIC') or False |
| 469 property_dictionary = node.GetProperties() |
| 470 for special_keyword in SPECIAL_KEYWORD_LIST: |
| 471 if special_keyword in property_dictionary: |
| 472 self.specials.append(special_keyword.lower()) |
| 473 |
| 474 self.idl_type = None |
| 475 children = node.GetChildren() |
| 476 for child in children: |
| 477 child_class = child.GetClass() |
| 478 if child_class == 'Arguments': |
| 479 self.arguments = arguments_node_to_arguments(child) |
| 480 elif child_class == 'Type': |
| 481 self.idl_type = type_node_to_type(child) |
| 482 elif child_class == 'ExtAttributes': |
| 483 self.extended_attributes = ext_attributes_node_to_extended_attri
butes(child) |
| 484 else: |
| 485 raise ValueError('Unrecognized node class: %s' % child_class) |
| 486 |
| 487 @classmethod |
| 488 def from_exception_operation_node(cls, node): |
| 489 # Needed to handle one case in DOMException.idl: |
| 490 # // Override in a Mozilla compatible format |
| 491 # [NotEnumerable] DOMString toString(); |
| 492 # FIXME: can we remove this? replace with a stringifier? |
| 493 operation = cls() |
| 494 operation.name = node.GetName() |
| 495 children = node.GetChildren() |
| 496 if len(children) < 1 or len(children) > 2: |
| 497 raise ValueError('ExceptionOperation node with %s children, expected
1 or 2' % len(children)) |
| 498 |
| 499 type_node = children[0] |
| 500 operation.idl_type = type_node_to_type(type_node) |
| 501 |
| 502 if len(children) > 1: |
| 503 ext_attributes_node = children[1] |
| 504 operation.extended_attributes = ext_attributes_node_to_extended_attr
ibutes(ext_attributes_node) |
| 505 |
| 506 return operation |
| 507 |
| 508 @classmethod |
| 509 def constructor_from_arguments_node(cls, name, arguments_node): |
| 510 constructor = cls() |
| 511 constructor.name = name |
| 512 constructor.arguments = arguments_node_to_arguments(arguments_node) |
| 513 constructor.is_constructor = True |
| 514 return constructor |
| 515 |
| 516 def resolve_typedefs(self, typedefs): |
| 517 TypedObject.resolve_typedefs(self, typedefs) |
| 518 for argument in self.arguments: |
| 519 argument.resolve_typedefs(typedefs) |
| 520 |
| 521 |
| 522 ################################################################################ |
| 523 # Arguments |
| 524 ################################################################################ |
| 525 |
| 526 class IdlArgument(TypedObject): |
| 527 def __init__(self, node): |
| 528 self.extended_attributes = {} |
| 529 self.idl_type = None |
| 530 self.is_optional = node.GetProperty('OPTIONAL') # syntax: (optional T) |
| 531 self.is_variadic = False # syntax: (T...) |
| 532 self.name = node.GetName() |
| 533 self.default_value = None |
| 534 |
| 535 children = node.GetChildren() |
| 536 for child in children: |
| 537 child_class = child.GetClass() |
| 538 if child_class == 'Type': |
| 539 self.idl_type = type_node_to_type(child) |
| 540 elif child_class == 'ExtAttributes': |
| 541 self.extended_attributes = ext_attributes_node_to_extended_attri
butes(child) |
| 542 elif child_class == 'Argument': |
| 543 child_name = child.GetName() |
| 544 if child_name != '...': |
| 545 raise ValueError('Unrecognized Argument node; expected "..."
, got "%s"' % child_name) |
| 546 self.is_variadic = child.GetProperty('ELLIPSIS') or False |
| 547 elif child_class == 'Default': |
| 548 self.default_value = default_node_to_idl_literal(child) |
| 549 else: |
| 550 raise ValueError('Unrecognized node class: %s' % child_class) |
| 551 |
| 552 |
| 553 def arguments_node_to_arguments(node): |
| 554 # [Constructor] and [CustomConstructor] without arguments (the bare form) |
| 555 # have None instead of an arguments node, but have the same meaning as using |
| 556 # an empty argument list, [Constructor()], so special-case this. |
| 557 # http://www.w3.org/TR/WebIDL/#Constructor |
| 558 if node is None: |
| 559 return [] |
| 560 return [IdlArgument(argument_node) |
| 561 for argument_node in node.GetChildren()] |
| 562 |
| 563 |
| 564 ################################################################################ |
| 565 # Extended attributes |
| 566 ################################################################################ |
| 567 |
| 568 def ext_attributes_node_to_extended_attributes(node): |
| 569 """ |
| 570 Returns: |
| 571 Dictionary of {ExtAttributeName: ExtAttributeValue}. |
| 572 Value is usually a string, with three exceptions: |
| 573 Constructors: value is a list of Arguments nodes, corresponding to |
| 574 possible signatures of the constructor. |
| 575 CustomConstructors: value is a list of Arguments nodes, corresponding to |
| 576 possible signatures of the custom constructor. |
| 577 NamedConstructor: value is a Call node, corresponding to the single |
| 578 signature of the named constructor. |
| 579 """ |
| 580 # Primarily just make a dictionary from the children. |
| 581 # The only complexity is handling various types of constructors: |
| 582 # Constructors and Custom Constructors can have duplicate entries due to |
| 583 # overloading, and thus are stored in temporary lists. |
| 584 # However, Named Constructors cannot be overloaded, and thus do not have |
| 585 # a list. |
| 586 # FIXME: move Constructor logic into separate function, instead of modifying |
| 587 # extended attributes in-place. |
| 588 constructors = [] |
| 589 custom_constructors = [] |
| 590 extended_attributes = {} |
| 591 |
| 592 def child_node(extended_attribute_node): |
| 593 children = extended_attribute_node.GetChildren() |
| 594 if not children: |
| 595 return None |
| 596 if len(children) > 1: |
| 597 raise ValueError('ExtAttributes node with %s children, expected at m
ost 1' % len(children)) |
| 598 return children[0] |
| 599 |
| 600 extended_attribute_node_list = node.GetChildren() |
| 601 for extended_attribute_node in extended_attribute_node_list: |
| 602 name = extended_attribute_node.GetName() |
| 603 child = child_node(extended_attribute_node) |
| 604 child_class = child and child.GetClass() |
| 605 if name == 'Constructor': |
| 606 if child_class and child_class != 'Arguments': |
| 607 raise ValueError('Constructor only supports Arguments as child,
but has child of class: %s' % child_class) |
| 608 constructors.append(child) |
| 609 elif name == 'CustomConstructor': |
| 610 if child_class and child_class != 'Arguments': |
| 611 raise ValueError('[CustomConstructor] only supports Arguments as
child, but has child of class: %s' % child_class) |
| 612 custom_constructors.append(child) |
| 613 elif name == 'NamedConstructor': |
| 614 if child_class and child_class != 'Call': |
| 615 raise ValueError('[NamedConstructor] only supports Call as child
, but has child of class: %s' % child_class) |
| 616 extended_attributes[name] = child |
| 617 elif name == 'SetWrapperReferenceTo': |
| 618 if not child: |
| 619 raise ValueError('[SetWrapperReferenceTo] requires a child, but
has none.') |
| 620 if child_class != 'Arguments': |
| 621 raise ValueError('[SetWrapperReferenceTo] only supports Argument
s as child, but has child of class: %s' % child_class) |
| 622 extended_attributes[name] = arguments_node_to_arguments(child) |
| 623 elif child: |
| 624 raise ValueError('ExtAttributes node with unexpected children: %s' %
name) |
| 625 else: |
| 626 value = extended_attribute_node.GetProperty('VALUE') |
| 627 extended_attributes[name] = value |
| 628 |
| 629 # Store constructors and custom constructors in special list attributes, |
| 630 # which are deleted later. Note plural in key. |
| 631 if constructors: |
| 632 extended_attributes['Constructors'] = constructors |
| 633 if custom_constructors: |
| 634 extended_attributes['CustomConstructors'] = custom_constructors |
| 635 |
| 636 return extended_attributes |
| 637 |
| 638 |
| 639 def extended_attributes_to_constructors(extended_attributes): |
| 640 """Returns constructors and custom_constructors (lists of IdlOperations). |
| 641 |
| 642 Auxiliary function for IdlInterface.__init__. |
| 643 """ |
| 644 |
| 645 constructor_list = extended_attributes.get('Constructors', []) |
| 646 constructors = [ |
| 647 IdlOperation.constructor_from_arguments_node('Constructor', arguments_no
de) |
| 648 for arguments_node in constructor_list] |
| 649 |
| 650 custom_constructor_list = extended_attributes.get('CustomConstructors', []) |
| 651 custom_constructors = [ |
| 652 IdlOperation.constructor_from_arguments_node('CustomConstructor', argume
nts_node) |
| 653 for arguments_node in custom_constructor_list] |
| 654 |
| 655 if 'NamedConstructor' in extended_attributes: |
| 656 # FIXME: support overloaded named constructors, and make homogeneous |
| 657 name = 'NamedConstructor' |
| 658 call_node = extended_attributes['NamedConstructor'] |
| 659 extended_attributes['NamedConstructor'] = call_node.GetName() |
| 660 children = call_node.GetChildren() |
| 661 if len(children) != 1: |
| 662 raise ValueError('NamedConstructor node expects 1 child, got %s.' %
len(children)) |
| 663 arguments_node = children[0] |
| 664 named_constructor = IdlOperation.constructor_from_arguments_node('NamedC
onstructor', arguments_node) |
| 665 # FIXME: should return named_constructor separately; appended for Perl |
| 666 constructors.append(named_constructor) |
| 667 |
| 668 return constructors, custom_constructors |
| 669 |
| 670 |
| 671 def clear_constructor_attributes(extended_attributes): |
| 672 # Deletes Constructor*s* (plural), sets Constructor (singular) |
| 673 if 'Constructors' in extended_attributes: |
| 674 del extended_attributes['Constructors'] |
| 675 extended_attributes['Constructor'] = None |
| 676 if 'CustomConstructors' in extended_attributes: |
| 677 del extended_attributes['CustomConstructors'] |
| 678 extended_attributes['CustomConstructor'] = None |
| 679 |
| 680 |
| 681 ################################################################################ |
| 682 # Types |
| 683 ################################################################################ |
| 684 |
| 685 def type_node_to_type(node): |
| 686 children = node.GetChildren() |
| 687 if len(children) < 1 or len(children) > 2: |
| 688 raise ValueError('Type node expects 1 or 2 children (type + optional arr
ay []), got %s (multi-dimensional arrays are not supported).' % len(children)) |
| 689 |
| 690 type_node_child = children[0] |
| 691 |
| 692 if len(children) == 2: |
| 693 array_node = children[1] |
| 694 array_node_class = array_node.GetClass() |
| 695 if array_node_class != 'Array': |
| 696 raise ValueError('Expected Array node as TypeSuffix, got %s node.' %
array_node_class) |
| 697 # FIXME: use IdlArrayType instead of is_array, once have that |
| 698 is_array = True |
| 699 else: |
| 700 is_array = False |
| 701 |
| 702 is_nullable = node.GetProperty('NULLABLE') or False # syntax: T? |
| 703 |
| 704 return type_node_inner_to_type(type_node_child, is_array=is_array, is_nullab
le=is_nullable) |
| 705 |
| 706 |
| 707 def type_node_inner_to_type(node, is_array=False, is_nullable=False): |
| 708 # FIXME: remove is_array and is_nullable once have IdlArrayType and IdlNulla
bleType |
| 709 node_class = node.GetClass() |
| 710 # Note Type*r*ef, not Typedef, meaning the type is an identifier, thus |
| 711 # either a typedef shorthand (but not a Typedef declaration itself) or an |
| 712 # interface type. We do not distinguish these, and just use the type name. |
| 713 if node_class in ['PrimitiveType', 'Typeref']: |
| 714 # unrestricted syntax: unrestricted double | unrestricted float |
| 715 is_unrestricted = node.GetProperty('UNRESTRICTED') or False |
| 716 return IdlType(node.GetName(), is_array=is_array, is_nullable=is_nullabl
e, is_unrestricted=is_unrestricted) |
| 717 elif node_class == 'Any': |
| 718 return IdlType('any', is_array=is_array, is_nullable=is_nullable) |
| 719 elif node_class == 'Sequence': |
| 720 if is_array: |
| 721 raise ValueError('Arrays of sequences are not supported') |
| 722 return sequence_node_to_type(node, is_nullable=is_nullable) |
| 723 elif node_class == 'UnionType': |
| 724 if is_array: |
| 725 raise ValueError('Arrays of unions are not supported') |
| 726 return union_type_node_to_idl_union_type(node, is_nullable=is_nullable) |
| 727 raise ValueError('Unrecognized node class: %s' % node_class) |
| 728 |
| 729 |
| 730 def sequence_node_to_type(node, is_nullable=False): |
| 731 children = node.GetChildren() |
| 732 if len(children) != 1: |
| 733 raise ValueError('Sequence node expects exactly 1 child, got %s' % len(c
hildren)) |
| 734 sequence_child = children[0] |
| 735 sequence_child_class = sequence_child.GetClass() |
| 736 if sequence_child_class != 'Type': |
| 737 raise ValueError('Unrecognized node class: %s' % sequence_child_class) |
| 738 element_type = type_node_to_type(sequence_child).base_type |
| 739 return IdlType(element_type, is_sequence=True, is_nullable=is_nullable) |
| 740 |
| 741 |
| 742 def typedef_node_to_type(node): |
| 743 children = node.GetChildren() |
| 744 if len(children) != 1: |
| 745 raise ValueError('Typedef node with %s children, expected 1' % len(child
ren)) |
| 746 child = children[0] |
| 747 child_class = child.GetClass() |
| 748 if child_class != 'Type': |
| 749 raise ValueError('Unrecognized node class: %s' % child_class) |
| 750 return type_node_to_type(child) |
| 751 |
| 752 |
| 753 def union_type_node_to_idl_union_type(node, is_nullable=False): |
| 754 member_types = [type_node_to_type(member_type_node) |
| 755 for member_type_node in node.GetChildren()] |
| 756 return IdlUnionType(member_types, is_nullable=is_nullable) |
OLD | NEW |