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