1 # Copyright (C) 2013 Google Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
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
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.
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.
29 """Blink IDL Intermediate Representation (IR) classes.
31 Classes are primarily constructors, which build an IdlDefinitions object
32 (and various contained objects) from an AST (produced by blink_idl_parser).
35 * Constructors walk the AST, creating objects.
38 Typedefs are all resolved here, and not stored in IR.
40 Typedef resolution uses some auxiliary classes and OOP techniques to make this
41 a generic call, via the resolve_typedefs() method.
43 Class hierarchy (mostly containment, '<' for inheritance):
46 IdlCallbackFunction < TypedObject
47 IdlEnum :: FIXME: remove, just use a dict for enums
49 IdlAttribute < TypedObject
50 IdlConstant < TypedObject
52 IdlOperation < TypedObject
53 IdlArgument < TypedObject
55 IdlException < IdlInterface
56 (same contents as IdlInterface)
58 TypedObject :: mixin for typedef resolution
60 Design doc: http://www.chromium.org/developers/design-documents/idl-compiler
65 from idl_types import IdlType, IdlUnionType, IdlArrayType, IdlSequenceType, IdlNullableType
67 SPECIAL_KEYWORD_LIST = ['GETTER', 'SETTER', 'DELETER']
69 # http://www.w3.org/TR/WebIDL/#common-DOMTimeStamp
70 'DOMTimeStamp': 'unsigned long long',
74 ################################################################################
75 # TypedObject (mixin for typedef resolution)
76 ################################################################################
78 class TypedObject(object):
79 """Object with a type, such as an Attribute or Operation (return value).
81 The type can be an actual type, or can be a typedef, which must be resolved
82 before passing data to the code generator.
84 __metaclass__ = abc.ABCMeta
87 def resolve_typedefs(self, typedefs):
88 """Resolve typedefs to actual types in the object."""
89 # Constructors don't have their own return type, because it's the
93 # Need to re-assign self.idl_type, not just mutate idl_type,
94 # since type(idl_type) may change.
95 self.idl_type = self.idl_type.resolve_typedefs(typedefs)
98 ################################################################################
99 # Definitions (main container class)
100 ################################################################################
102 class IdlDefinitions(object):
103 def __init__(self, idl_name, node):
104 """Args: node: AST root node, class == 'File'"""
105 self.callback_functions = {}
106 self.dictionaries = {}
107 self.enumerations = {}
109 self.idl_name = idl_name
111 node_class = node.GetClass()
112 if node_class != 'File':
113 raise ValueError('Unrecognized node class: %s' % node_class)
115 typedefs = dict((typedef_name, IdlType(type_name))
116 for typedef_name, type_name in
117 STANDARD_TYPEDEFS.iteritems())
119 children = node.GetChildren()
120 for child in children:
121 child_class = child.GetClass()
122 if child_class == 'Interface':
123 interface = IdlInterface(idl_name, child)
124 self.interfaces[interface.name] = interface
125 elif child_class == 'Exception':
126 exception = IdlException(idl_name, child)
127 # For simplicity, treat exceptions as interfaces
128 self.interfaces[exception.name] = exception
129 elif child_class == 'Typedef':
130 type_name = child.GetName()
131 typedefs[type_name] = typedef_node_to_type(child)
132 elif child_class == 'Enum':
133 enumeration = IdlEnum(idl_name, child)
134 self.enumerations[enumeration.name] = enumeration
135 elif child_class == 'Callback':
136 callback_function = IdlCallbackFunction(idl_name, child)
137 self.callback_functions[callback_function.name] = callback_function
138 elif child_class == 'Implements':
139 # Implements is handled at the interface merging step
141 elif child_class == 'Dictionary':
142 dictionary = IdlDictionary(idl_name, child)
143 self.dictionaries[dictionary.name] = dictionary
145 raise ValueError('Unrecognized node class: %s' % child_class)
147 # Typedefs are not stored in IR:
148 # Resolve typedefs with the actual types and then discard the Typedefs.
149 # http://www.w3.org/TR/WebIDL/#idl-typedefs
150 self.resolve_typedefs(typedefs)
152 def resolve_typedefs(self, typedefs):
153 for callback_function in self.callback_functions.itervalues():
154 callback_function.resolve_typedefs(typedefs)
155 for interface in self.interfaces.itervalues():
156 interface.resolve_typedefs(typedefs)
158 def update(self, other):
159 """Update with additional IdlDefinitions."""
160 for interface_name, new_interface in other.interfaces.iteritems():
161 if not new_interface.is_partial:
162 # Add as new interface
163 self.interfaces[interface_name] = new_interface
166 # Merge partial to existing interface
168 self.interfaces[interface_name].merge(new_interface)
170 raise Exception('Tried to merge partial interface for {0}, '
171 'but no existing interface by that name'
172 .format(interface_name))
174 # Merge callbacks and enumerations
175 self.enumerations.update(other.enumerations)
176 self.callback_functions.update(other.callback_functions)
179 ################################################################################
181 ################################################################################
183 class IdlCallbackFunction(TypedObject):
184 def __init__(self, idl_name, node):
185 children = node.GetChildren()
186 num_children = len(children)
187 if num_children != 2:
188 raise ValueError('Expected 2 children, got %s' % num_children)
189 type_node, arguments_node = children
190 arguments_node_class = arguments_node.GetClass()
191 if arguments_node_class != 'Arguments':
192 raise ValueError('Expected Arguments node, got %s' % arguments_node_class)
194 self.idl_name = idl_name
195 self.name = node.GetName()
196 self.idl_type = type_node_to_type(type_node)
197 self.arguments = arguments_node_to_arguments(idl_name, arguments_node)
199 def resolve_typedefs(self, typedefs):
200 TypedObject.resolve_typedefs(self, typedefs)
201 for argument in self.arguments:
202 argument.resolve_typedefs(typedefs)
205 ################################################################################
207 ################################################################################
209 class IdlDictionary(object):
210 def __init__(self, idl_name, node):
211 self.extended_attributes = {}
212 self.is_partial = node.GetProperty('Partial') or False
213 self.idl_name = idl_name
214 self.name = node.GetName()
217 for child in node.GetChildren():
218 child_class = child.GetClass()
219 if child_class == 'Inherit':
220 self.parent = child.GetName()
221 elif child_class == 'Key':
222 self.members.append(IdlDictionaryMember(idl_name, child))
223 elif child_class == 'ExtAttributes':
224 self.extended_attributes = (
225 ext_attributes_node_to_extended_attributes(idl_name, child))
227 raise ValueError('Unrecognized node class: %s' % child_class)
230 class IdlDictionaryMember(object):
231 def __init__(self, idl_name, node):
232 self.default_value = None
233 self.extended_attributes = {}
235 self.idl_name = idl_name
236 self.name = node.GetName()
237 for child in node.GetChildren():
238 child_class = child.GetClass()
239 if child_class == 'Type':
240 self.idl_type = type_node_to_type(child)
241 elif child_class == 'Default':
242 self.default_value = default_node_to_idl_literal(child)
243 elif child_class == 'ExtAttributes':
244 self.extended_attributes = (
245 ext_attributes_node_to_extended_attributes(idl_name, child))
247 raise ValueError('Unrecognized node class: %s' % child_class)
250 ################################################################################
252 ################################################################################
254 class IdlEnum(object):
255 # FIXME: remove, just treat enums as a dictionary
256 def __init__(self, idl_name, node):
257 self.idl_name = idl_name
258 self.name = node.GetName()
260 for child in node.GetChildren():
261 self.values.append(child.GetName())
264 ################################################################################
265 # Interfaces and Exceptions
266 ################################################################################
268 class IdlInterface(object):
269 def __init__(self, idl_name, node=None):
272 self.constructors = []
273 self.custom_constructors = []
274 self.extended_attributes = {}
277 self.stringifier = None
278 if not node: # Early exit for IdlException.__init__
281 self.is_callback = node.GetProperty('CALLBACK') or False
282 self.is_exception = False
283 # FIXME: uppercase 'Partial' => 'PARTIAL' in base IDL parser
284 self.is_partial = node.GetProperty('Partial') or False
285 self.idl_name = idl_name
286 self.name = node.GetName()
288 children = node.GetChildren()
289 for child in children:
290 child_class = child.GetClass()
291 if child_class == 'Attribute':
292 self.attributes.append(IdlAttribute(idl_name, child))
293 elif child_class == 'Const':
294 self.constants.append(IdlConstant(idl_name, child))
295 elif child_class == 'ExtAttributes':
296 extended_attributes = ext_attributes_node_to_extended_attributes(idl_name, child)
297 self.constructors, self.custom_constructors = (
298 extended_attributes_to_constructors(idl_name, extended_attributes))
299 clear_constructor_attributes(extended_attributes)
300 self.extended_attributes = extended_attributes
301 elif child_class == 'Operation':
302 self.operations.append(IdlOperation(idl_name, child))
303 elif child_class == 'Inherit':
304 self.parent = child.GetName()
305 elif child_class == 'Stringifier':
306 self.stringifier = IdlStringifier(idl_name, child)
307 self.process_stringifier()
309 raise ValueError('Unrecognized node class: %s' % child_class)
311 def resolve_typedefs(self, typedefs):
312 for attribute in self.attributes:
313 attribute.resolve_typedefs(typedefs)
314 for constant in self.constants:
315 constant.resolve_typedefs(typedefs)
316 for constructor in self.constructors:
317 constructor.resolve_typedefs(typedefs)
318 for custom_constructor in self.custom_constructors:
319 custom_constructor.resolve_typedefs(typedefs)
320 for operation in self.operations:
321 operation.resolve_typedefs(typedefs)
323 def process_stringifier(self):
324 """Add the stringifier's attribute or named operation child, if it has
325 one, as a regular attribute/operation of this interface."""
326 if self.stringifier.attribute:
327 self.attributes.append(self.stringifier.attribute)
328 elif self.stringifier.operation:
329 self.operations.append(self.stringifier.operation)
331 def merge(self, other):
332 """Merge in another interface's members (e.g., partial interface)"""
333 self.attributes.extend(other.attributes)
334 self.constants.extend(other.constants)
335 self.operations.extend(other.operations)
338 class IdlException(IdlInterface):
339 # Properly exceptions and interfaces are distinct, and thus should inherit a
340 # common base class (say, "IdlExceptionOrInterface").
341 # However, there is only one exception (DOMException), and new exceptions
342 # are not expected. Thus it is easier to implement exceptions as a
343 # restricted subclass of interfaces.
344 # http://www.w3.org/TR/WebIDL/#idl-exceptions
345 def __init__(self, idl_name, node):
346 # Exceptions are similar to Interfaces, but simpler
347 IdlInterface.__init__(self, idl_name)
348 self.is_callback = False
349 self.is_exception = True
350 self.is_partial = False
351 self.idl_name = idl_name
352 self.name = node.GetName()
354 children = node.GetChildren()
355 for child in children:
356 child_class = child.GetClass()
357 if child_class == 'Attribute':
358 attribute = IdlAttribute(idl_name, child)
359 self.attributes.append(attribute)
360 elif child_class == 'Const':
361 self.constants.append(IdlConstant(idl_name, child))
362 elif child_class == 'ExtAttributes':
363 self.extended_attributes = ext_attributes_node_to_extended_attributes(idl_name, child)
364 elif child_class == 'ExceptionOperation':
365 self.operations.append(IdlOperation.from_exception_operation_node(idl_name, child))
367 raise ValueError('Unrecognized node class: %s' % child_class)
370 ################################################################################
372 ################################################################################
374 class IdlAttribute(TypedObject):
375 def __init__(self, idl_name, node):
376 self.is_read_only = node.GetProperty('READONLY') or False
377 self.is_static = node.GetProperty('STATIC') or False
378 self.idl_name = idl_name
379 self.name = node.GetName()
380 # Defaults, overridden below
382 self.extended_attributes = {}
384 children = node.GetChildren()
385 for child in children:
386 child_class = child.GetClass()
387 if child_class == 'Type':
388 self.idl_type = type_node_to_type(child)
389 elif child_class == 'ExtAttributes':
390 self.extended_attributes = ext_attributes_node_to_extended_attributes(idl_name, child)
392 raise ValueError('Unrecognized node class: %s' % child_class)
395 ################################################################################
397 ################################################################################
399 class IdlConstant(TypedObject):
400 def __init__(self, idl_name, node):
401 children = node.GetChildren()
402 num_children = len(children)
403 if num_children < 2 or num_children > 3:
404 raise ValueError('Expected 2 or 3 children, got %s' % num_children)
405 type_node = children[0]
406 value_node = children[1]
407 value_node_class = value_node.GetClass()
408 if value_node_class != 'Value':
409 raise ValueError('Expected Value node, got %s' % value_node_class)
411 self.idl_name = idl_name
412 self.name = node.GetName()
413 # ConstType is more limited than Type, so subtree is smaller and
414 # we don't use the full type_node_to_type function.
415 self.idl_type = type_node_inner_to_type(type_node)
416 # FIXME: This code is unnecessarily complicated due to the rather
417 # inconsistent way the upstream IDL parser outputs default values.
418 # http://crbug.com/374178
419 if value_node.GetProperty('TYPE') == 'float':
420 self.value = value_node.GetProperty('VALUE')
422 self.value = value_node.GetName()
424 if num_children == 3:
425 ext_attributes_node = children[2]
426 self.extended_attributes = ext_attributes_node_to_extended_attributes(idl_name, ext_attributes_node)
428 self.extended_attributes = {}
431 ################################################################################
433 ################################################################################
435 class IdlLiteral(object):
436 def __init__(self, idl_type, value):
437 self.idl_type = idl_type
442 if self.idl_type == 'DOMString':
443 return 'String("%s")' % self.value
444 if self.idl_type == 'integer':
445 return '%d' % self.value
446 if self.idl_type == 'float':
447 return '%g' % self.value
448 if self.idl_type == 'boolean':
449 return 'true' if self.value else 'false'
450 raise ValueError('Unsupported literal type: %s' % self.idl_type)
453 class IdlLiteralNull(IdlLiteral):
455 self.idl_type = 'NULL'
463 def default_node_to_idl_literal(node):
464 # FIXME: This code is unnecessarily complicated due to the rather
465 # inconsistent way the upstream IDL parser outputs default values.
466 # http://crbug.com/374178
467 idl_type = node.GetProperty('TYPE')
468 if idl_type == 'DOMString':
469 value = node.GetProperty('NAME')
470 if '"' in value or '\\' in value:
471 raise ValueError('Unsupported string value: %r' % value)
472 return IdlLiteral(idl_type, value)
473 if idl_type == 'integer':
474 return IdlLiteral(idl_type, int(node.GetProperty('NAME'), base=0))
475 if idl_type == 'float':
476 return IdlLiteral(idl_type, float(node.GetProperty('VALUE')))
477 if idl_type == 'boolean':
478 return IdlLiteral(idl_type, node.GetProperty('VALUE'))
479 if idl_type == 'NULL':
480 return IdlLiteralNull()
481 raise ValueError('Unrecognized default value type: %s' % idl_type)
484 ################################################################################
486 ################################################################################
488 class IdlOperation(TypedObject):
489 def __init__(self, idl_name, node=None):
491 self.extended_attributes = {}
493 self.is_constructor = False
496 self.is_static = False
498 self.idl_name = idl_name
499 self.name = node.GetName() # FIXME: should just be: or ''
500 # FIXME: AST should use None internally
501 if self.name == '_unnamed_':
504 self.is_static = node.GetProperty('STATIC') or False
505 property_dictionary = node.GetProperties()
506 for special_keyword in SPECIAL_KEYWORD_LIST:
507 if special_keyword in property_dictionary:
508 self.specials.append(special_keyword.lower())
511 children = node.GetChildren()
512 for child in children:
513 child_class = child.GetClass()
514 if child_class == 'Arguments':
515 self.arguments = arguments_node_to_arguments(idl_name, child)
516 elif child_class == 'Type':
517 self.idl_type = type_node_to_type(child)
518 elif child_class == 'ExtAttributes':
519 self.extended_attributes = ext_attributes_node_to_extended_attributes(idl_name, child)
521 raise ValueError('Unrecognized node class: %s' % child_class)
524 def from_exception_operation_node(cls, idl_name, node):
525 # Needed to handle one case in DOMException.idl:
526 # // Override in a Mozilla compatible format
527 # [NotEnumerable] DOMString toString();
528 # FIXME: can we remove this? replace with a stringifier?
529 operation = cls(idl_name)
530 operation.name = node.GetName()
531 children = node.GetChildren()
532 if len(children) < 1 or len(children) > 2:
533 raise ValueError('ExceptionOperation node with %s children, expected 1 or 2' % len(children))
535 type_node = children[0]
536 operation.idl_type = type_node_to_type(type_node)
538 if len(children) > 1:
539 ext_attributes_node = children[1]
540 operation.extended_attributes = ext_attributes_node_to_extended_attributes(idl_name, ext_attributes_node)
545 def constructor_from_arguments_node(cls, name, idl_name, arguments_node):
546 constructor = cls(idl_name)
547 constructor.name = name
548 constructor.arguments = arguments_node_to_arguments(idl_name, arguments_node)
549 constructor.is_constructor = True
552 def resolve_typedefs(self, typedefs):
553 TypedObject.resolve_typedefs(self, typedefs)
554 for argument in self.arguments:
555 argument.resolve_typedefs(typedefs)
558 ################################################################################
560 ################################################################################
562 class IdlArgument(TypedObject):
563 def __init__(self, idl_name, node):
564 self.extended_attributes = {}
566 self.is_optional = node.GetProperty('OPTIONAL') # syntax: (optional T)
567 self.is_variadic = False # syntax: (T...)
568 self.idl_name = idl_name
569 self.name = node.GetName()
570 self.default_value = None
572 children = node.GetChildren()
573 for child in children:
574 child_class = child.GetClass()
575 if child_class == 'Type':
576 self.idl_type = type_node_to_type(child)
577 elif child_class == 'ExtAttributes':
578 self.extended_attributes = ext_attributes_node_to_extended_attributes(idl_name, child)
579 elif child_class == 'Argument':
580 child_name = child.GetName()
581 if child_name != '...':
582 raise ValueError('Unrecognized Argument node; expected "...", got "%s"' % child_name)
583 self.is_variadic = child.GetProperty('ELLIPSIS') or False
584 elif child_class == 'Default':
585 self.default_value = default_node_to_idl_literal(child)
587 raise ValueError('Unrecognized node class: %s' % child_class)
590 def arguments_node_to_arguments(idl_name, node):
591 # [Constructor] and [CustomConstructor] without arguments (the bare form)
592 # have None instead of an arguments node, but have the same meaning as using
593 # an empty argument list, [Constructor()], so special-case this.
594 # http://www.w3.org/TR/WebIDL/#Constructor
597 return [IdlArgument(idl_name, argument_node)
598 for argument_node in node.GetChildren()]
601 ################################################################################
603 ################################################################################
605 class IdlStringifier(object):
606 def __init__(self, idl_name, node):
607 self.attribute = None
608 self.operation = None
609 self.extended_attributes = {}
610 self.idl_name = idl_name
612 for child in node.GetChildren():
613 child_class = child.GetClass()
614 if child_class == 'Attribute':
615 self.attribute = IdlAttribute(idl_name, child)
616 elif child_class == 'Operation':
617 operation = IdlOperation(idl_name, child)
619 self.operation = operation
620 elif child_class == 'ExtAttributes':
621 self.extended_attributes = ext_attributes_node_to_extended_attributes(idl_name, child)
623 raise ValueError('Unrecognized node class: %s' % child_class)
625 # Copy the stringifier's extended attributes (such as [Unforgable]) onto
626 # the underlying attribute or operation, if there is one.
627 if self.attribute or self.operation:
628 (self.attribute or self.operation).extended_attributes.update(
629 self.extended_attributes)
632 ################################################################################
633 # Extended attributes
634 ################################################################################
636 def ext_attributes_node_to_extended_attributes(idl_name, node):
639 Dictionary of {ExtAttributeName: ExtAttributeValue}.
640 Value is usually a string, with these exceptions:
641 Constructors: value is a list of Arguments nodes, corresponding to
642 possible signatures of the constructor.
643 CustomConstructors: value is a list of Arguments nodes, corresponding to
644 possible signatures of the custom constructor.
645 NamedConstructor: value is a Call node, corresponding to the single
646 signature of the named constructor.
647 SetWrapperReferenceTo: value is an Arguments node.
649 # Primarily just make a dictionary from the children.
650 # The only complexity is handling various types of constructors:
651 # Constructors and Custom Constructors can have duplicate entries due to
652 # overloading, and thus are stored in temporary lists.
653 # However, Named Constructors cannot be overloaded, and thus do not have
655 # FIXME: move Constructor logic into separate function, instead of modifying
656 # extended attributes in-place.
658 custom_constructors = []
659 extended_attributes = {}
661 def child_node(extended_attribute_node):
662 children = extended_attribute_node.GetChildren()
665 if len(children) > 1:
666 raise ValueError('ExtAttributes node with %s children, expected at most 1' % len(children))
669 extended_attribute_node_list = node.GetChildren()
670 for extended_attribute_node in extended_attribute_node_list:
671 name = extended_attribute_node.GetName()
672 child = child_node(extended_attribute_node)
673 child_class = child and child.GetClass()
674 if name == 'Constructor':
675 if child_class and child_class != 'Arguments':
676 raise ValueError('Constructor only supports Arguments as child, but has child of class: %s' % child_class)
677 constructors.append(child)
678 elif name == 'CustomConstructor':
679 if child_class and child_class != 'Arguments':
680 raise ValueError('[CustomConstructor] only supports Arguments as child, but has child of class: %s' % child_class)
681 custom_constructors.append(child)
682 elif name == 'NamedConstructor':
683 if child_class and child_class != 'Call':
684 raise ValueError('[NamedConstructor] only supports Call as child, but has child of class: %s' % child_class)
685 extended_attributes[name] = child
686 elif name == 'SetWrapperReferenceTo':
688 raise ValueError('[SetWrapperReferenceTo] requires a child, but has none.')
689 if child_class != 'Arguments':
690 raise ValueError('[SetWrapperReferenceTo] only supports Arguments as child, but has child of class: %s' % child_class)
691 extended_attributes[name] = arguments_node_to_arguments(idl_name, child)
693 raise ValueError('ExtAttributes node with unexpected children: %s' % name)
695 value = extended_attribute_node.GetProperty('VALUE')
696 extended_attributes[name] = value
698 # Store constructors and custom constructors in special list attributes,
699 # which are deleted later. Note plural in key.
701 extended_attributes['Constructors'] = constructors
702 if custom_constructors:
703 extended_attributes['CustomConstructors'] = custom_constructors
705 return extended_attributes
708 def extended_attributes_to_constructors(idl_name, extended_attributes):
709 """Returns constructors and custom_constructors (lists of IdlOperations).
711 Auxiliary function for IdlInterface.__init__.
714 constructor_list = extended_attributes.get('Constructors', [])
716 IdlOperation.constructor_from_arguments_node('Constructor', idl_name, arguments_node)
717 for arguments_node in constructor_list]
719 custom_constructor_list = extended_attributes.get('CustomConstructors', [])
720 custom_constructors = [
721 IdlOperation.constructor_from_arguments_node('CustomConstructor', idl_name, arguments_node)
722 for arguments_node in custom_constructor_list]
724 if 'NamedConstructor' in extended_attributes:
725 # FIXME: support overloaded named constructors, and make homogeneous
726 name = 'NamedConstructor'
727 call_node = extended_attributes['NamedConstructor']
728 extended_attributes['NamedConstructor'] = call_node.GetName()
729 children = call_node.GetChildren()
730 if len(children) != 1:
731 raise ValueError('NamedConstructor node expects 1 child, got %s.' % len(children))
732 arguments_node = children[0]
733 named_constructor = IdlOperation.constructor_from_arguments_node('NamedConstructor', idl_name, arguments_node)
734 # FIXME: should return named_constructor separately; appended for Perl
735 constructors.append(named_constructor)
737 return constructors, custom_constructors
740 def clear_constructor_attributes(extended_attributes):
741 # Deletes Constructor*s* (plural), sets Constructor (singular)
742 if 'Constructors' in extended_attributes:
743 del extended_attributes['Constructors']
744 extended_attributes['Constructor'] = None
745 if 'CustomConstructors' in extended_attributes:
746 del extended_attributes['CustomConstructors']
747 extended_attributes['CustomConstructor'] = None
750 ################################################################################
752 ################################################################################
754 def type_node_to_type(node):
755 children = node.GetChildren()
756 if len(children) < 1 or len(children) > 2:
757 raise ValueError('Type node expects 1 or 2 children (type + optional array []), got %s (multi-dimensional arrays are not supported).' % len(children))
759 base_type = type_node_inner_to_type(children[0])
761 if node.GetProperty('NULLABLE'):
762 base_type = IdlNullableType(base_type)
764 if len(children) == 2:
765 array_node = children[1]
766 array_node_class = array_node.GetClass()
767 if array_node_class != 'Array':
768 raise ValueError('Expected Array node as TypeSuffix, got %s node.' % array_node_class)
769 array_type = IdlArrayType(base_type)
770 if array_node.GetProperty('NULLABLE'):
771 return IdlNullableType(array_type)
777 def type_node_inner_to_type(node):
778 node_class = node.GetClass()
779 # Note Type*r*ef, not Typedef, meaning the type is an identifier, thus
780 # either a typedef shorthand (but not a Typedef declaration itself) or an
781 # interface type. We do not distinguish these, and just use the type name.
782 if node_class in ['PrimitiveType', 'Typeref']:
783 # unrestricted syntax: unrestricted double | unrestricted float
784 is_unrestricted = node.GetProperty('UNRESTRICTED') or False
785 return IdlType(node.GetName(), is_unrestricted=is_unrestricted)
786 elif node_class == 'Any':
787 return IdlType('any')
788 elif node_class == 'Sequence':
789 return sequence_node_to_type(node)
790 elif node_class == 'UnionType':
791 return union_type_node_to_idl_union_type(node)
792 raise ValueError('Unrecognized node class: %s' % node_class)
795 def sequence_node_to_type(node):
796 children = node.GetChildren()
797 if len(children) != 1:
798 raise ValueError('Sequence node expects exactly 1 child, got %s' % len(children))
799 sequence_child = children[0]
800 sequence_child_class = sequence_child.GetClass()
801 if sequence_child_class != 'Type':
802 raise ValueError('Unrecognized node class: %s' % sequence_child_class)
803 element_type = type_node_to_type(sequence_child)
804 sequence_type = IdlSequenceType(element_type)
805 if node.GetProperty('NULLABLE'):
806 return IdlNullableType(sequence_type)
810 def typedef_node_to_type(node):
811 children = node.GetChildren()
812 if len(children) != 1:
813 raise ValueError('Typedef node with %s children, expected 1' % len(children))
815 child_class = child.GetClass()
816 if child_class != 'Type':
817 raise ValueError('Unrecognized node class: %s' % child_class)
818 return type_node_to_type(child)
821 def union_type_node_to_idl_union_type(node):
822 member_types = [type_node_to_type(member_type_node)
823 for member_type_node in node.GetChildren()]
824 return IdlUnionType(member_types)