Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / bindings / scripts / idl_definitions.py
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_function
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_attributes(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_attributes(child)
337             elif child_class == 'ExceptionOperation':
338                 self.operations.append(IdlOperation.from_exception_operation_node(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_attributes(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_attributes(ext_attributes_node)
392         else:
393             self.extended_attributes = {}
394
395
396 ################################################################################
397 # Operations
398 ################################################################################
399
400 class IdlOperation(TypedObject):
401     def __init__(self, node=None):
402         self.arguments = []
403         self.extended_attributes = {}
404         self.specials = []
405
406         if not node:
407             self.is_static = False
408             return
409         self.name = node.GetName()  # FIXME: should just be: or ''
410         # FIXME: AST should use None internally
411         if self.name == '_unnamed_':
412             self.name = ''
413
414         self.is_static = node.GetProperty('STATIC') or False
415         property_dictionary = node.GetProperties()
416         for special_keyword in SPECIAL_KEYWORD_LIST:
417             if special_keyword in property_dictionary:
418                 self.specials.append(special_keyword.lower())
419
420         self.idl_type = None
421         children = node.GetChildren()
422         for child in children:
423             child_class = child.GetClass()
424             if child_class == 'Arguments':
425                 self.arguments = arguments_node_to_arguments(child)
426             elif child_class == 'Type':
427                 self.idl_type = type_node_to_type(child)
428             elif child_class == 'ExtAttributes':
429                 self.extended_attributes = ext_attributes_node_to_extended_attributes(child)
430             else:
431                 raise ValueError('Unrecognized node class: %s' % child_class)
432
433     @classmethod
434     def from_exception_operation_node(cls, node):
435         # Needed to handle one case in DOMException.idl:
436         # // Override in a Mozilla compatible format
437         # [NotEnumerable] DOMString toString();
438         # FIXME: can we remove this? replace with a stringifier?
439         operation = cls()
440         operation.name = node.GetName()
441         children = node.GetChildren()
442         if len(children) < 1 or len(children) > 2:
443             raise ValueError('ExceptionOperation node with %s children, expected 1 or 2' % len(children))
444
445         type_node = children[0]
446         operation.idl_type = type_node_to_type(type_node)
447
448         if len(children) > 1:
449             ext_attributes_node = children[1]
450             operation.extended_attributes = ext_attributes_node_to_extended_attributes(ext_attributes_node)
451
452         return operation
453
454     @classmethod
455     def constructor_from_arguments_node(cls, name, arguments_node):
456         constructor = cls()
457         constructor.name = name
458         constructor.arguments = arguments_node_to_arguments(arguments_node)
459         return constructor
460
461     def resolve_typedefs(self, typedefs):
462         TypedObject.resolve_typedefs(self, typedefs)
463         for argument in self.arguments:
464             argument.resolve_typedefs(typedefs)
465
466
467 ################################################################################
468 # Arguments
469 ################################################################################
470
471 class IdlArgument(TypedObject):
472     def __init__(self, node):
473         self.extended_attributes = {}
474         self.idl_type = None
475         self.is_optional = node.GetProperty('OPTIONAL')  # syntax: (optional T)
476         self.is_variadic = False  # syntax: (T...)
477         self.name = node.GetName()
478
479         children = node.GetChildren()
480         for child in children:
481             child_class = child.GetClass()
482             if child_class == 'Type':
483                 self.idl_type = type_node_to_type(child)
484             elif child_class == 'ExtAttributes':
485                 self.extended_attributes = ext_attributes_node_to_extended_attributes(child)
486             elif child_class == 'Argument':
487                 child_name = child.GetName()
488                 if child_name != '...':
489                     raise ValueError('Unrecognized Argument node; expected "...", got "%s"' % child_name)
490                 self.is_variadic = child.GetProperty('ELLIPSIS') or False
491             else:
492                 raise ValueError('Unrecognized node class: %s' % child_class)
493
494
495 def arguments_node_to_arguments(node):
496     # [Constructor] and [CustomConstructor] without arguments (the bare form)
497     # have None instead of an arguments node, but have the same meaning as using
498     # an empty argument list, [Constructor()], so special-case this.
499     # http://www.w3.org/TR/WebIDL/#Constructor
500     if node is None:
501         return []
502     return [IdlArgument(argument_node)
503             for argument_node in node.GetChildren()]
504
505
506 ################################################################################
507 # Extended attributes
508 ################################################################################
509
510 def ext_attributes_node_to_extended_attributes(node):
511     """
512     Returns:
513       Dictionary of {ExtAttributeName: ExtAttributeValue}.
514       Value is usually a string, with three exceptions:
515       Constructors: value is a list of Arguments nodes, corresponding to
516         possible signatures of the constructor.
517       CustomConstructors: value is a list of Arguments nodes, corresponding to
518         possible signatures of the custom constructor.
519       NamedConstructor: value is a Call node, corresponding to the single
520         signature of the named constructor.
521     """
522     # Primarily just make a dictionary from the children.
523     # The only complexity is handling various types of constructors:
524     # Constructors and Custom Constructors can have duplicate entries due to
525     # overloading, and thus are stored in temporary lists.
526     # However, Named Constructors cannot be overloaded, and thus do not have
527     # a list.
528     # FIXME: move Constructor logic into separate function, instead of modifying
529     #        extended attributes in-place.
530     constructors = []
531     custom_constructors = []
532     extended_attributes = {}
533
534     def child_node(extended_attribute_node):
535         children = extended_attribute_node.GetChildren()
536         if not children:
537             return None
538         if len(children) > 1:
539             raise ValueError('ExtAttributes node with %s children, expected at most 1' % len(children))
540         return children[0]
541
542     extended_attribute_node_list = node.GetChildren()
543     for extended_attribute_node in extended_attribute_node_list:
544         name = extended_attribute_node.GetName()
545         child = child_node(extended_attribute_node)
546         child_class = child and child.GetClass()
547         if name == 'Constructor':
548             if child_class and child_class != 'Arguments':
549                 raise ValueError('Constructor only supports Arguments as child, but has child of class: %s' % child_class)
550             constructors.append(child)
551         elif name == 'CustomConstructor':
552             if child_class and child_class != 'Arguments':
553                 raise ValueError('[CustomConstructor] only supports Arguments as child, but has child of class: %s' % child_class)
554             custom_constructors.append(child)
555         elif name == 'NamedConstructor':
556             if child_class and child_class != 'Call':
557                 raise ValueError('[NamedConstructor] only supports Call as child, but has child of class: %s' % child_class)
558             extended_attributes[name] = child
559         elif name == 'SetWrapperReferenceTo':
560             if not child:
561                 raise ValueError('[SetWrapperReferenceTo] requires a child, but has none.')
562             if child_class != 'Arguments':
563                 raise ValueError('[SetWrapperReferenceTo] only supports Arguments as child, but has child of class: %s' % child_class)
564             extended_attributes[name] = arguments_node_to_arguments(child)
565         elif child:
566             raise ValueError('ExtAttributes node with unexpected children: %s' % name)
567         else:
568             value = extended_attribute_node.GetProperty('VALUE')
569             extended_attributes[name] = value
570
571     # Store constructors and custom constructors in special list attributes,
572     # which are deleted later. Note plural in key.
573     if constructors:
574         extended_attributes['Constructors'] = constructors
575     if custom_constructors:
576         extended_attributes['CustomConstructors'] = custom_constructors
577
578     return extended_attributes
579
580
581 def extended_attributes_to_constructors(extended_attributes):
582     """Returns constructors and custom_constructors (lists of IdlOperations).
583
584     Auxiliary function for IdlInterface.__init__.
585     """
586
587     constructor_list = extended_attributes.get('Constructors', [])
588     constructors = [
589         IdlOperation.constructor_from_arguments_node('Constructor', arguments_node)
590         for arguments_node in constructor_list]
591
592     custom_constructor_list = extended_attributes.get('CustomConstructors', [])
593     custom_constructors = [
594         IdlOperation.constructor_from_arguments_node('CustomConstructor', arguments_node)
595         for arguments_node in custom_constructor_list]
596
597     if 'NamedConstructor' in extended_attributes:
598         # FIXME: support overloaded named constructors, and make homogeneous
599         name = 'NamedConstructor'
600         call_node = extended_attributes['NamedConstructor']
601         extended_attributes['NamedConstructor'] = call_node.GetName()
602         children = call_node.GetChildren()
603         if len(children) != 1:
604             raise ValueError('NamedConstructor node expects 1 child, got %s.' % len(children))
605         arguments_node = children[0]
606         named_constructor = IdlOperation.constructor_from_arguments_node('NamedConstructor', arguments_node)
607         # FIXME: should return named_constructor separately; appended for Perl
608         constructors.append(named_constructor)
609
610     return constructors, custom_constructors
611
612
613 def clear_constructor_attributes(extended_attributes):
614     # Deletes Constructor*s* (plural), sets Constructor (singular)
615     if 'Constructors' in extended_attributes:
616         del extended_attributes['Constructors']
617         extended_attributes['Constructor'] = None
618     if 'CustomConstructors' in extended_attributes:
619         del extended_attributes['CustomConstructors']
620         extended_attributes['CustomConstructor'] = None
621
622
623 ################################################################################
624 # Types
625 ################################################################################
626
627 def type_node_to_type(node):
628     children = node.GetChildren()
629     if len(children) < 1 or len(children) > 2:
630         raise ValueError('Type node expects 1 or 2 children (type + optional array []), got %s (multi-dimensional arrays are not supported).' % len(children))
631
632     type_node_child = children[0]
633
634     if len(children) == 2:
635         array_node = children[1]
636         array_node_class = array_node.GetClass()
637         if array_node_class != 'Array':
638             raise ValueError('Expected Array node as TypeSuffix, got %s node.' % array_node_class)
639         # FIXME: use IdlArrayType instead of is_array, once have that
640         is_array = True
641     else:
642         is_array = False
643
644     is_nullable = node.GetProperty('NULLABLE') or False  # syntax: T?
645
646     return type_node_inner_to_type(type_node_child, is_array=is_array, is_nullable=is_nullable)
647
648
649 def type_node_inner_to_type(node, is_array=False, is_nullable=False):
650     # FIXME: remove is_array and is_nullable once have IdlArrayType and IdlNullableType
651     node_class = node.GetClass()
652     # Note Type*r*ef, not Typedef, meaning the type is an identifier, thus
653     # either a typedef shorthand (but not a Typedef declaration itself) or an
654     # interface type. We do not distinguish these, and just use the type name.
655     if node_class in ['PrimitiveType', 'Typeref']:
656         # unrestricted syntax: unrestricted double | unrestricted float
657         is_unrestricted = node.GetProperty('UNRESTRICTED') or False
658         return IdlType(node.GetName(), is_array=is_array, is_nullable=is_nullable, is_unrestricted=is_unrestricted)
659     elif node_class == 'Any':
660         return IdlType('any', is_array=is_array, is_nullable=is_nullable)
661     elif node_class == 'Sequence':
662         if is_array:
663             raise ValueError('Arrays of sequences are not supported')
664         return sequence_node_to_type(node, is_nullable=is_nullable)
665     elif node_class == 'UnionType':
666         if is_array:
667             raise ValueError('Arrays of unions are not supported')
668         return union_type_node_to_idl_union_type(node, is_nullable=is_nullable)
669     raise ValueError('Unrecognized node class: %s' % node_class)
670
671
672 def sequence_node_to_type(node, is_nullable=False):
673     children = node.GetChildren()
674     if len(children) != 1:
675         raise ValueError('Sequence node expects exactly 1 child, got %s' % len(children))
676     sequence_child = children[0]
677     sequence_child_class = sequence_child.GetClass()
678     if sequence_child_class != 'Type':
679         raise ValueError('Unrecognized node class: %s' % sequence_child_class)
680     element_type = type_node_to_type(sequence_child).base_type
681     return IdlType(element_type, is_sequence=True, is_nullable=is_nullable)
682
683
684 def typedef_node_to_type(node):
685     children = node.GetChildren()
686     if len(children) != 1:
687         raise ValueError('Typedef node with %s children, expected 1' % len(children))
688     child = children[0]
689     child_class = child.GetClass()
690     if child_class != 'Type':
691         raise ValueError('Unrecognized node class: %s' % child_class)
692     return type_node_to_type(child)
693
694
695 def union_type_node_to_idl_union_type(node, is_nullable=False):
696     member_types = [type_node_to_type(member_type_node)
697                     for member_type_node in node.GetChildren()]
698     return IdlUnionType(member_types, is_nullable=is_nullable)