Ben Murdoch | 7757ec2 | 2013-07-23 11:17:36 +0100 | [diff] [blame] | 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 | """Builds an IdlDefinitions object from an AST (produced by blink_idl_parser).""" |
| 30 | |
| 31 | from idl_definitions import IdlDefinitions, IdlInterface, IdlException, IdlOperation, IdlCallbackFunction, IdlArgument, IdlAttribute, IdlConstant, IdlEnum, IdlTypedef, IdlUnionType |
| 32 | |
| 33 | SPECIAL_KEYWORD_LIST = ['GETTER', 'SETTER', 'DELETER'] |
| 34 | |
| 35 | |
| 36 | def build_idl_definitions_from_ast(node): |
| 37 | if node is None: |
| 38 | return None |
| 39 | node_class = node.GetClass() |
| 40 | if node_class != 'File': |
| 41 | raise ValueError('Unrecognized node class: %s' % node_class) |
| 42 | return file_node_to_idl_definitions(node) |
| 43 | |
| 44 | |
| 45 | def file_node_to_idl_definitions(node): |
| 46 | callback_functions = {} |
| 47 | enumerations = {} |
| 48 | exceptions = {} |
| 49 | file_name = node.GetName() # FIXME: only needed for Perl, remove later |
| 50 | interfaces = {} |
| 51 | typedefs = {} |
| 52 | |
| 53 | children = node.GetChildren() |
| 54 | for child in children: |
| 55 | child_class = child.GetClass() |
| 56 | if child_class == 'Interface': |
| 57 | interface = interface_node_to_idl_interface(child) |
| 58 | interfaces[interface.name] = interface |
| 59 | elif child_class == 'Exception': |
| 60 | exception = exception_node_to_idl_exception(child) |
| 61 | exceptions[exception.name] = exception |
| 62 | elif child_class == 'Typedef': |
| 63 | type_name = child.GetName() |
| 64 | typedefs[type_name] = typedef_node_to_idl_typedef(child) |
| 65 | elif child_class == 'Enum': |
| 66 | enumeration = enum_node_to_idl_enum(child) |
| 67 | enumerations[enumeration.name] = enumeration |
| 68 | elif child_class == 'Callback': |
| 69 | callback_function = callback_node_to_idl_callback_function(child) |
| 70 | callback_functions[callback_function.name] = callback_function |
| 71 | elif child_class == 'Implements': |
| 72 | # Implements is handled at the interface merging step |
| 73 | pass |
| 74 | else: |
| 75 | raise ValueError('Unrecognized node class: %s' % child_class) |
| 76 | |
| 77 | return IdlDefinitions(callback_functions=callback_functions, enumerations=enumerations, exceptions=exceptions, file_name=file_name, interfaces=interfaces, typedefs=typedefs) |
| 78 | |
| 79 | # Constructors for Interface definitions and interface members |
| 80 | |
| 81 | |
| 82 | def interface_node_to_idl_interface(node): |
| 83 | attributes = [] |
| 84 | constants = [] |
| 85 | constructors = None |
| 86 | custom_constructors = None |
| 87 | extended_attributes = None |
| 88 | operations = [] |
| 89 | is_callback = node.GetProperty('CALLBACK') or False |
| 90 | # FIXME: uppercase 'Partial' in base IDL parser |
| 91 | is_partial = node.GetProperty('Partial') or False |
| 92 | name = node.GetName() |
| 93 | parent = None |
| 94 | |
| 95 | children = node.GetChildren() |
| 96 | for child in children: |
| 97 | child_class = child.GetClass() |
| 98 | if child_class == 'Attribute': |
| 99 | attribute = attribute_node_to_idl_attribute(child) |
| 100 | # FIXME: This is a hack to support [CustomConstructor] for |
| 101 | # window.HTMLImageElement. Remove the hack. |
| 102 | clear_constructor_attributes(attribute.extended_attributes) |
| 103 | attributes.append(attribute) |
| 104 | elif child_class == 'Const': |
| 105 | constants.append(constant_node_to_idl_constant(child)) |
| 106 | elif child_class == 'ExtAttributes': |
| 107 | extended_attributes = ext_attributes_node_to_extended_attributes(child) |
| 108 | constructors, custom_constructors = extended_attributes_to_constructors(extended_attributes) |
| 109 | clear_constructor_attributes(extended_attributes) |
| 110 | elif child_class == 'Operation': |
| 111 | operations.append(operation_node_to_idl_operation(child)) |
| 112 | elif child_class == 'Inherit': |
| 113 | parent = child.GetName() |
| 114 | else: |
| 115 | raise ValueError('Unrecognized node class: %s' % child_class) |
| 116 | |
| 117 | return IdlInterface(name=name, attributes=attributes, constants=constants, constructors=constructors, custom_constructors=custom_constructors, extended_attributes=extended_attributes, operations=operations, is_callback=is_callback, is_partial=is_partial, parent=parent) |
| 118 | |
| 119 | |
| 120 | def attribute_node_to_idl_attribute(node): |
| 121 | data_type = None |
| 122 | extended_attributes = {} |
| 123 | is_nullable = False |
| 124 | is_read_only = node.GetProperty('READONLY') or False |
| 125 | is_static = node.GetProperty('STATIC') or False |
| 126 | name = node.GetName() |
| 127 | |
| 128 | children = node.GetChildren() |
| 129 | for child in children: |
| 130 | child_class = child.GetClass() |
| 131 | if child_class == 'Type': |
| 132 | data_type = type_node_to_type(child) |
| 133 | is_nullable = child.GetProperty('NULLABLE') or False |
| 134 | elif child_class == 'ExtAttributes': |
| 135 | extended_attributes = ext_attributes_node_to_extended_attributes(child) |
| 136 | else: |
| 137 | raise ValueError('Unrecognized node class: %s' % child_class) |
| 138 | |
| 139 | return IdlAttribute(data_type=data_type, extended_attributes=extended_attributes, is_nullable=is_nullable, is_read_only=is_read_only, is_static=is_static, name=name) |
| 140 | |
| 141 | |
| 142 | def constant_node_to_idl_constant(node): |
| 143 | name = node.GetName() |
| 144 | |
| 145 | children = node.GetChildren() |
| 146 | num_children = len(children) |
| 147 | if num_children < 2 or num_children > 3: |
| 148 | raise ValueError('Expected 2 or 3 children, got %s' % num_children) |
| 149 | |
| 150 | type_node = children[0] |
| 151 | # ConstType is more limited than Type, so subtree is smaller and we don't |
| 152 | # use the full type_node_to_type function. |
| 153 | data_type = type_node_inner_to_type(type_node) |
| 154 | |
| 155 | value_node = children[1] |
| 156 | value_node_class = value_node.GetClass() |
| 157 | if value_node_class != 'Value': |
| 158 | raise ValueError('Expected Value node, got %s' % value_node_class) |
| 159 | value = value_node.GetName() |
| 160 | |
| 161 | extended_attributes = None |
| 162 | if num_children == 3: |
| 163 | ext_attributes_node = children[2] |
| 164 | extended_attributes = ext_attributes_node_to_extended_attributes(ext_attributes_node) |
| 165 | |
| 166 | return IdlConstant(data_type=data_type, extended_attributes=extended_attributes, name=name, value=value) |
| 167 | |
| 168 | |
| 169 | def operation_node_to_idl_operation(node): |
| 170 | name = node.GetName() |
| 171 | # FIXME: AST should use None internally |
| 172 | if name == '_unnamed_': |
| 173 | name = None |
| 174 | |
| 175 | is_static = node.GetProperty('STATIC') or False |
| 176 | specials = [] |
| 177 | property_dictionary = node.GetProperties() |
| 178 | for special_keyword in SPECIAL_KEYWORD_LIST: |
| 179 | if special_keyword in property_dictionary: |
| 180 | specials.append(special_keyword.lower()) |
| 181 | |
| 182 | extended_attributes = None |
| 183 | arguments = [] |
| 184 | return_type = None |
| 185 | children = node.GetChildren() |
| 186 | for child in children: |
| 187 | child_class = child.GetClass() |
| 188 | if child_class == 'Arguments': |
| 189 | arguments = arguments_node_to_arguments(child) |
| 190 | elif child_class == 'Type': |
| 191 | return_type = type_node_to_type(child) |
| 192 | elif child_class == 'ExtAttributes': |
| 193 | extended_attributes = ext_attributes_node_to_extended_attributes(child) |
| 194 | else: |
| 195 | raise ValueError('Unrecognized node class: %s' % child_class) |
| 196 | |
| 197 | return IdlOperation(name=name, data_type=return_type, extended_attributes=extended_attributes, is_static=is_static, arguments=arguments, specials=specials) |
| 198 | |
| 199 | |
| 200 | def arguments_node_to_arguments(node): |
| 201 | # [Constructor] and [CustomConstructor] without arguments (the bare form) |
| 202 | # have None instead of an arguments node, but have the same meaning as using |
| 203 | # an empty argument list, [Constructor()], so special-case this. |
| 204 | # http://www.w3.org/TR/WebIDL/#Constructor |
| 205 | if node is None: |
| 206 | return [] |
| 207 | arguments = [] |
| 208 | argument_node_list = node.GetChildren() |
| 209 | for argument_node in argument_node_list: |
| 210 | arguments.append(argument_node_to_idl_argument(argument_node)) |
| 211 | return arguments |
| 212 | |
| 213 | |
| 214 | def argument_node_to_idl_argument(node): |
| 215 | name = node.GetName() |
| 216 | |
| 217 | data_type = None |
| 218 | extended_attributes = {} |
| 219 | # FIXME: Boolean values are inconsistent due to Perl compatibility. |
| 220 | # Make all default to False once Perl removed. |
| 221 | is_nullable = False |
| 222 | is_optional = node.GetProperty('OPTIONAL') |
| 223 | is_variadic = None |
| 224 | children = node.GetChildren() |
| 225 | for child in children: |
| 226 | child_class = child.GetClass() |
| 227 | if child_class == 'Type': |
| 228 | data_type = type_node_to_type(child) |
| 229 | is_nullable = child.GetProperty('NULLABLE') |
| 230 | elif child_class == 'ExtAttributes': |
| 231 | extended_attributes = ext_attributes_node_to_extended_attributes(child) |
| 232 | elif child_class == 'Argument': |
| 233 | child_name = child.GetName() |
| 234 | if child_name != '...': |
| 235 | raise ValueError('Unrecognized Argument node; expected "...", got "%s"' % child_name) |
| 236 | is_variadic = child.GetProperty('ELLIPSIS') or False |
| 237 | else: |
| 238 | raise ValueError('Unrecognized node class: %s' % child_class) |
| 239 | |
| 240 | return IdlArgument(name=name, data_type=data_type, extended_attributes=extended_attributes, is_nullable=is_nullable, is_optional=is_optional, is_variadic=is_variadic) |
| 241 | |
| 242 | # Constructors for for non-interface definitions |
| 243 | |
| 244 | |
| 245 | def callback_node_to_idl_callback_function(node): |
| 246 | name = node.GetName() |
| 247 | children = node.GetChildren() |
| 248 | num_children = len(children) |
| 249 | if num_children != 2: |
| 250 | raise ValueError('Expected 2 children, got %s' % num_children) |
| 251 | |
| 252 | type_node = children[0] |
| 253 | data_type = type_node_to_type(type_node) |
| 254 | |
| 255 | arguments_node = children[1] |
| 256 | arguments_node_class = arguments_node.GetClass() |
| 257 | if arguments_node_class != 'Arguments': |
| 258 | raise ValueError('Expected Value node, got %s' % arguments_node_class) |
| 259 | arguments = arguments_node_to_arguments(arguments_node) |
| 260 | |
| 261 | return IdlCallbackFunction(name=name, data_type=data_type, arguments=arguments) |
| 262 | |
| 263 | |
| 264 | def enum_node_to_idl_enum(node): |
| 265 | name = node.GetName() |
| 266 | values = [] |
| 267 | for child in node.GetChildren(): |
| 268 | values.append(child.GetName()) |
| 269 | return IdlEnum(name=name, values=values) |
| 270 | |
| 271 | |
| 272 | def exception_operation_node_to_idl_operation(node): |
| 273 | # Needed to handle one case in DOMException.idl: |
| 274 | # // Override in a Mozilla compatible format |
| 275 | # [NotEnumerable] DOMString toString(); |
| 276 | # FIXME: can we remove this? replace with a stringifier? |
| 277 | extended_attributes = {} |
| 278 | name = node.GetName() |
| 279 | children = node.GetChildren() |
| 280 | if len(children) < 1 or len(children) > 2: |
| 281 | raise ValueError('ExceptionOperation node with %s children, expected 1 or 2' % len(children)) |
| 282 | |
| 283 | type_node = children[0] |
| 284 | return_type = type_node_to_type(type_node) |
| 285 | |
| 286 | if len(children) > 1: |
| 287 | ext_attributes_node = children[1] |
| 288 | extended_attributes = ext_attributes_node_to_extended_attributes(ext_attributes_node) |
| 289 | |
| 290 | return IdlOperation(name=name, data_type=return_type, extended_attributes=extended_attributes) |
| 291 | |
| 292 | |
| 293 | def exception_node_to_idl_exception(node): |
| 294 | # Exceptions are similar to Interfaces, but simpler |
| 295 | attributes = [] |
| 296 | constants = [] |
| 297 | extended_attributes = None |
| 298 | operations = [] |
| 299 | name = node.GetName() |
| 300 | |
| 301 | children = node.GetChildren() |
| 302 | for child in children: |
| 303 | child_class = child.GetClass() |
| 304 | if child_class == 'Attribute': |
| 305 | attribute = attribute_node_to_idl_attribute(child) |
| 306 | attributes.append(attribute) |
| 307 | elif child_class == 'Const': |
| 308 | constants.append(constant_node_to_idl_constant(child)) |
| 309 | elif child_class == 'ExtAttributes': |
| 310 | extended_attributes = ext_attributes_node_to_extended_attributes(child) |
| 311 | elif child_class == 'ExceptionOperation': |
| 312 | operations.append(exception_operation_node_to_idl_operation(child)) |
| 313 | else: |
| 314 | raise ValueError('Unrecognized node class: %s' % child_class) |
| 315 | |
| 316 | return IdlException(name=name, attributes=attributes, constants=constants, extended_attributes=extended_attributes, operations=operations) |
| 317 | |
| 318 | |
| 319 | def typedef_node_to_idl_typedef(node): |
| 320 | data_type = None |
| 321 | extended_attributes = None |
| 322 | |
| 323 | children = node.GetChildren() |
| 324 | for child in children: |
| 325 | child_class = child.GetClass() |
| 326 | if child_class == 'Type': |
| 327 | data_type = type_node_to_type(child) |
| 328 | elif child_class == 'ExtAttributes': |
| 329 | extended_attributes = ext_attributes_node_to_extended_attributes(child) |
| 330 | raise ValueError('Extended attributes in a typedef are untested!') |
| 331 | else: |
| 332 | raise ValueError('Unrecognized node class: %s' % child_class) |
| 333 | |
| 334 | return IdlTypedef(data_type=data_type, extended_attributes=extended_attributes) |
| 335 | |
| 336 | # Extended attributes |
| 337 | |
| 338 | |
| 339 | def ext_attributes_node_to_extended_attributes(node): |
| 340 | """ |
| 341 | Returns: |
| 342 | Dictionary of {ExtAttributeName: ExtAttributeValue}. |
| 343 | Value is usually a string, with three exceptions: |
| 344 | Constructors: value is a list of Arguments nodes, corresponding to |
| 345 | possibly signatures of the constructor. |
| 346 | CustomConstructors: value is a list of Arguments nodes, corresponding to |
| 347 | possibly signatures of the custom constructor. |
| 348 | NamedConstructor: value is a Call node, corresponding to the single |
| 349 | signature of the named constructor. |
| 350 | """ |
| 351 | # Primarily just make a dictionary from the children. |
| 352 | # The only complexity is handling various types of constructors: |
| 353 | # Constructors and Custom Constructors can have duplicate entries due to |
| 354 | # overloading, and thus are stored in temporary lists. |
| 355 | # However, Named Constructors cannot be overloaded, and thus do not have |
| 356 | # a list. |
| 357 | # FIXME: Add overloading for Named Constructors and remove custom bindings |
| 358 | # for HTMLImageElement |
| 359 | constructors = [] |
| 360 | custom_constructors = [] |
| 361 | extended_attributes = {} |
| 362 | |
| 363 | attribute_list = node.GetChildren() |
| 364 | for attribute in attribute_list: |
| 365 | name = attribute.GetName() |
| 366 | children = attribute.GetChildren() |
| 367 | if name in ['Constructor', 'CustomConstructor', 'NamedConstructor']: |
| 368 | child = None |
| 369 | child_class = None |
| 370 | if children: |
| 371 | if len(children) > 1: |
| 372 | raise ValueError('ExtAttributes node with %s children, expected at most 1' % len(children)) |
| 373 | child = children[0] |
| 374 | child_class = child.GetClass() |
| 375 | if name == 'Constructor': |
| 376 | if child_class and child_class != 'Arguments': |
| 377 | raise ValueError('Constructor only supports Arguments as child, but has child of class: %s' % child_class) |
| 378 | constructors.append(child) |
| 379 | elif name == 'CustomConstructor': |
| 380 | if child_class and child_class != 'Arguments': |
| 381 | raise ValueError('Custom Constructor only supports Arguments as child, but has child of class: %s' % child_class) |
| 382 | custom_constructors.append(child) |
| 383 | else: # name == 'NamedConstructor' |
| 384 | if child_class and child_class != 'Call': |
| 385 | raise ValueError('Named Constructor only supports Call as child, but has child of class: %s' % child_class) |
| 386 | extended_attributes[name] = child |
| 387 | elif children: |
| 388 | raise ValueError('Non-constructor ExtAttributes node with children: %s' % name) |
| 389 | else: |
| 390 | value = attribute.GetProperty('VALUE') |
| 391 | extended_attributes[name] = value |
| 392 | |
| 393 | # Store constructors and custom constructors in special list attributes, |
| 394 | # which are deleted later. Note plural in key. |
| 395 | if constructors: |
| 396 | extended_attributes['Constructors'] = constructors |
| 397 | if custom_constructors: |
| 398 | extended_attributes['CustomConstructors'] = custom_constructors |
| 399 | |
| 400 | return extended_attributes |
| 401 | |
| 402 | |
| 403 | def extended_attributes_to_constructors(extended_attributes): |
| 404 | """Returns constructors and custom_constructors (lists of IdlOperations). |
| 405 | |
| 406 | Auxiliary function for interface_node_to_idl_interface. |
| 407 | """ |
| 408 | constructors = [] |
| 409 | custom_constructors = [] |
| 410 | if 'Constructors' in extended_attributes: |
| 411 | constructor_list = extended_attributes['Constructors'] |
| 412 | # If not overloaded, have index 0, otherwise index from 1 |
| 413 | overloaded_index = 0 if len(constructor_list) == 1 else 1 |
| 414 | for arguments_node in constructor_list: |
| 415 | name = 'Constructor' |
| 416 | arguments = arguments_node_to_arguments(arguments_node) |
| 417 | constructor = IdlOperation(name=name, extended_attributes=extended_attributes, overloaded_index=overloaded_index, arguments=arguments) |
| 418 | constructors.append(constructor) |
| 419 | overloaded_index += 1 |
| 420 | |
| 421 | # Prefix 'CallWith' and 'RaisesException' with 'Constructor' |
| 422 | # FIXME: Change extended attributes to include prefix explicitly. |
| 423 | if 'CallWith' in extended_attributes: |
| 424 | extended_attributes['ConstructorCallWith'] = extended_attributes['CallWith'] |
| 425 | del extended_attributes['CallWith'] |
| 426 | if 'RaisesException' in extended_attributes: |
| 427 | extended_attributes['ConstructorRaisesException'] = extended_attributes['RaisesException'] |
| 428 | del extended_attributes['RaisesException'] |
| 429 | |
| 430 | if 'CustomConstructors' in extended_attributes: |
| 431 | custom_constructor_list = extended_attributes['CustomConstructors'] |
| 432 | # If not overloaded, have index 0, otherwise index from 1 |
| 433 | overloaded_index = 0 if len(custom_constructor_list) == 1 else 1 |
| 434 | for arguments_node in custom_constructor_list: |
| 435 | name = 'CustomConstructor' |
| 436 | arguments = arguments_node_to_arguments(arguments_node) |
| 437 | custom_constructor = IdlOperation(name=name, extended_attributes=extended_attributes, overloaded_index=overloaded_index, arguments=arguments) |
| 438 | custom_constructors.append(custom_constructor) |
| 439 | overloaded_index += 1 |
| 440 | |
| 441 | if 'NamedConstructor' in extended_attributes: |
| 442 | name = 'NamedConstructor' |
| 443 | call_node = extended_attributes['NamedConstructor'] |
| 444 | extended_attributes['NamedConstructor'] = call_node.GetName() |
| 445 | overloaded_index = None # named constructors are not overloaded |
| 446 | children = call_node.GetChildren() |
| 447 | if len(children) != 1: |
| 448 | raise ValueError('NamedConstructor node expects 1 child, got %s.' % len(children)) |
| 449 | arguments_node = children[0] |
| 450 | arguments = arguments_node_to_arguments(arguments_node) |
| 451 | named_constructor = IdlOperation(name=name, extended_attributes=extended_attributes, overloaded_index=overloaded_index, arguments=arguments) |
| 452 | constructors.append(named_constructor) |
| 453 | |
| 454 | return constructors, custom_constructors |
| 455 | |
| 456 | |
| 457 | def clear_constructor_attributes(extended_attributes): |
| 458 | # Deletes Constructor*s* (plural), sets Constructor (singular) |
| 459 | if 'Constructors' in extended_attributes: |
| 460 | del extended_attributes['Constructors'] |
| 461 | extended_attributes['Constructor'] = None |
| 462 | if 'CustomConstructors' in extended_attributes: |
| 463 | del extended_attributes['CustomConstructors'] |
| 464 | extended_attributes['CustomConstructor'] = None |
| 465 | |
| 466 | |
| 467 | # Types |
| 468 | |
| 469 | |
| 470 | def type_node_to_type(node): |
| 471 | children = node.GetChildren() |
| 472 | if len(children) < 1 or len(children) > 2: |
| 473 | raise ValueError('Type node expects 1 or 2 children (type + optional array []), got %s (multi-dimensional arrays are not supported).' % len(children)) |
| 474 | |
| 475 | type_node_child = children[0] |
| 476 | data_type = type_node_inner_to_type(type_node_child) |
| 477 | |
| 478 | if len(children) == 2: |
| 479 | array_node = children[1] |
| 480 | array_node_class = array_node.GetClass() |
| 481 | if array_node_class != 'Array': |
| 482 | raise ValueError('Expected Array node as TypeSuffix, got %s node.' % array_node_class) |
| 483 | data_type += '[]' |
| 484 | |
| 485 | return data_type |
| 486 | |
| 487 | |
| 488 | def type_node_inner_to_type(node): |
| 489 | node_class = node.GetClass() |
| 490 | # FIXME: Typedef is misspelled as Type*r*ef in base parser. |
| 491 | if node_class in ['PrimitiveType', 'Typeref']: |
| 492 | return node.GetName() |
| 493 | elif node_class == 'Any': |
| 494 | return 'any' |
| 495 | elif node_class == 'Sequence': |
| 496 | return sequence_node_to_type(node) |
| 497 | elif node_class == 'UnionType': |
| 498 | return union_type_node_to_idl_union_type(node) |
| 499 | raise ValueError('Unrecognized node class: %s' % node_class) |
| 500 | |
| 501 | |
| 502 | def sequence_node_to_type(node): |
| 503 | children = node.GetChildren() |
| 504 | if len(children) != 1: |
| 505 | raise ValueError('Sequence node expects exactly 1 child, got %s' % len(children)) |
| 506 | sequence_child = children[0] |
| 507 | sequence_child_class = sequence_child.GetClass() |
| 508 | if sequence_child_class != 'Type': |
| 509 | raise ValueError('Unrecognized node class: %s' % sequence_child_class) |
| 510 | sequence_type = type_node_to_type(sequence_child) |
| 511 | return 'sequence<%s>' % sequence_type |
| 512 | |
| 513 | |
| 514 | def union_type_node_to_idl_union_type(node): |
| 515 | union_member_types = [] |
| 516 | for member_type_node in node.GetChildren(): |
| 517 | member_type = type_node_to_type(member_type_node) |
| 518 | union_member_types.append(member_type) |
| 519 | return IdlUnionType(union_member_types=union_member_types) |