Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(140)

Side by Side Diff: Source/bindings/scripts/ast_to_ir.py

Issue 15801003: IDL parser rewrite in Python (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: [WIP] Full parser Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # Copyright (C) 2013 Google Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
5 # met:
6 #
7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
12 # distribution.
13 # * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 """Convert generic Web IDL AST to Blink IR
30
31 Last phase of frontend, after lexer and parser.
32 IR then consumed by code_generator_v8.py to produce .cpp/.h files.
33 Currently contains legacy code for compatibility with Perl format.
34 Ideally parser would generate IR directly, rather then requiring another phase.
35 """
36
37 from ir import IdlDocument, DomInterface, DomFunction, CallbackFunction, DomPara meter, DomAttribute, DomConstant, DomEnum, Typedef, UnionType
38
39
40 SPECIAL_KEYWORD_LIST = ['GETTER', 'SETTER', 'CREATOR', 'DELETER', 'LEGACYCALLER' ]
41
42 # Generic Web IDL AST to Blink IR
43
44
45 def web_idl_ast_to_blink_ir(node):
46 if node is None:
47 return None
48 node_class = node.GetClass()
49 if node_class == 'File':
50 return file_node_to_idl_document(node)
51 raise ValueError('Unrecognized node class: %s' % node_class)
52
53
54 def file_node_to_idl_document(node):
55 callback_functions = []
56 enumerations = []
57 file_name = node.GetName()
58 interfaces = []
59 typedefs = {}
60
61 children = node.GetChildren()
62 for child in children:
63 child_class = child.GetClass()
64 if child_class == 'Interface':
65 interfaces.append(interface_node_to_dom_interface(child))
66 elif child_class == 'Exception':
67 interfaces.append(exception_node_to_dom_interface(child))
68 elif child_class == 'Typedef':
69 type_name = child.GetName()
70 typedefs[type_name] = typedef_node_to_typedef(child)
71 elif child_class == 'Enum':
72 enumerations.append(enum_node_to_dom_enum(child))
73 elif child_class == 'Callback':
74 callback_functions.append(callback_node_to_callback_function(child))
75 else:
76 raise ValueError('Unrecognized node class: %s' % child_class)
77
78 return IdlDocument(callback_functions=callback_functions, enumerations=enume rations, file_name=file_name, interfaces=interfaces, typedefs=typedefs)
79
80 # Interface
81
82
83 def interface_node_to_dom_interface(node, is_exception=None):
84 def multiple_inherit_node_to_parents(node):
85 parents = []
86 for child in node.GetChildren():
87 parents.append(child.GetName())
88 return parents
89
90 attributes = []
91 constants = []
92 extended_attributes = {}
93 functions = []
94 is_callback = node.GetProperty('Callback')
95 name = node.GetName()
96 parents = []
97
98 children = node.GetChildren()
99 for child in children:
100 child_class = child.GetClass()
101 if child_class == 'Attribute':
102 attributes.append(attribute_node_to_dom_attribute(child))
103 elif child_class == 'MultipleInherit':
104 parents = multiple_inherit_node_to_parents(child)
105 elif child_class == 'Const':
106 constants.append(constant_node_to_dom_constant(child))
107 elif child_class == 'Operation':
108 functions.append(operation_node_to_dom_function(child))
109 elif child_class == 'OperationOrIterator':
110 functions.append(operation_or_iterator_node_to_dom_function(child))
111 elif child_class == 'ExtAttributes':
112 extended_attributes = ext_attributes_node_to_extended_attributes(chi ld)
113 elif child_class == 'ExceptionFieldToString':
114 functions.append(exception_field_to_string_node_to_dom_function(chil d))
115 else:
116 raise ValueError('Unrecognized node class: %s' % child_class)
117 constructors, custom_constructors = extended_attributes_to_constructors(exte nded_attributes)
118
119 return DomInterface(name=name, attributes=attributes, constants=constants, c onstructors=constructors, custom_constructors=custom_constructors, extended_attr ibutes=extended_attributes, functions=functions, is_callback=is_callback, is_exc eption=is_exception, parents=parents)
120
121
122 def attribute_node_to_dom_attribute(node):
123 data_type = None
124 extended_attributes = {}
125 is_nullable = None
126 property_dictionary = node.GetProperties()
127 is_read_only = get_property('READONLY', property_dictionary)
128 name = node.GetName()
129
130 children = node.GetChildren()
131 for child in children:
132 child_class = child.GetClass()
133 if child_class == 'Type':
134 data_type = type_node_to_type(child)
135 type_property_dictionary = child.GetProperties()
136 is_nullable = get_quoted_property('NULLABLE', type_property_dictiona ry)
137 elif child_class == 'ExtAttributes':
138 extended_attributes = ext_attributes_node_to_extended_attributes(chi ld)
139 else:
140 raise ValueError('Unrecognized node class: %s' % child_class)
141
142 return DomAttribute(data_type=data_type, extended_attributes=extended_attrib utes, is_read_only=is_read_only, is_nullable=is_nullable, name=name)
143
144
145 def constant_node_to_dom_constant(node):
146 name = node.GetName()
147
148 children = node.GetChildren()
149 num_children = len(children)
150 if num_children > 3:
151 raise ValueError('Expected at most 3 children, got %s' % num_children)
152
153 type_node = children[0]
154 # FIXME: use inner get type function
155 data_type = type_node.GetName()
156
157 value_node = children[1]
158 value_node_class = value_node.GetClass()
159 if value_node_class != 'Value':
160 raise ValueError('Expected Value node, got %s' % value_node_class)
161 value = value_node.GetName()
162
163 extended_attributes = None
164 if num_children == 3:
165 ext_attributes_node = children[2]
166 extended_attributes = ext_attributes_node_to_extended_attributes(ext_att ributes_node)
167
168 return DomConstant(data_type=data_type, extended_attributes=extended_attribu tes, name=name, value=value)
169
170
171 def operation_node_to_dom_function(node):
172 # FIXME: make Operation, and OperationOrIterator have
173 # same tree structure so can merge these
174
175 name = node.GetName()
176 # FIXME: AST should use None internally
177 if name == '_unnamed_':
178 name = None
179
180 property_dictionary = node.GetProperties()
181 is_static = None
182 if 'STATIC' in property_dictionary:
183 is_static = property_dictionary['STATIC']
184 specials = []
185 for special_keyword in SPECIAL_KEYWORD_LIST:
186 if special_keyword in property_dictionary:
187 specials.append(special_keyword.lower())
188
189 extended_attributes = None
190 parameters = []
191 return_type = None
192 children = node.GetChildren()
193 for child in children:
194 child_class = child.GetClass()
195 if child_class == 'Arguments':
196 parameters = argument_list_node_to_parameters(child)
197 elif child_class == 'Type':
198 return_type = type_node_to_type(child)
199 elif child_class == 'ExtAttributes':
200 extended_attributes = ext_attributes_node_to_extended_attributes(chi ld)
201 else:
202 raise ValueError('Unrecognized node class: %s' % child_class)
203
204 return DomFunction(name=name, data_type=return_type, extended_attributes=ext ended_attributes, is_static=is_static, parameters=parameters, specials=specials)
205
206
207 def operation_or_iterator_node_to_dom_function(node):
208 extended_attributes = {}
209 name = None
210 parameters = []
211 return_type = None
212 children = node.GetChildren()
213 for child in children:
214 child_class = child.GetClass()
215 if child_class == 'Type':
216 return_type = type_node_to_type(child)
217 elif child_class == 'Operation':
218 name = child.GetName()
219 # FIXME: this nesting is really ugly
220 grandchildren = child.GetChildren()
221 for grandchild in grandchildren:
222 grandchild_class = grandchild.GetClass()
223 if grandchild_class == 'Arguments':
224 parameters = argument_list_node_to_parameters(grandchild)
225 elif grandchild_class == 'ExtAttributes':
226 extended_attributes = ext_attributes_node_to_extended_attrib utes(grandchild)
227 else:
228 raise ValueError('Unrecognized node class: %s' % grandchild_ class)
229 elif child_class == 'ExtAttributes':
230 extended_attributes = ext_attributes_node_to_extended_attributes(chi ld)
231 else:
232 raise ValueError('Unrecognized node class: %s' % child_class)
233
234 return DomFunction(name=name, data_type=return_type, extended_attributes=ext ended_attributes, parameters=parameters)
235
236
237 def argument_list_node_to_parameters(argument_list_node):
238 # FIXME: is this check necessary?
239 if argument_list_node is None:
240 return []
241 parameters = []
242 argument_list = argument_list_node.GetChildren()
243 for argument_node in argument_list:
244 parameters.append(argument_node_to_dom_parameter(argument_node))
245 return parameters
246
247
248 def argument_node_to_dom_parameter(node):
249 name = node.GetName()
250 is_optional = node.GetProperty('OPTIONAL')
251
252 data_type = None
253 extended_attributes = {}
254 is_nullable = False
255 is_variadic = None
256 children = node.GetChildren()
257 for child in children:
258 child_class = child.GetClass()
259 if child_class == 'Type':
260 data_type = type_node_to_type(child)
261 type_property_dictionary = child.GetProperties()
262 is_nullable = get_quoted_property('NULLABLE', type_property_dictiona ry)
263 elif child_class == 'ExtAttributes':
264 extended_attributes = ext_attributes_node_to_extended_attributes(chi ld)
265 elif child_class == 'Argument':
266 child_name = child.GetName()
267 if child_name != '...':
268 raise ValueError('Unrecognized Argument node; expected "...", go t "%s"' % child_name)
269 is_variadic = child.GetProperty('ELLIPSIS')
270 else:
271 raise ValueError('Unrecognized node class: %s' % child_class)
272
273 return DomParameter(name=name, data_type=data_type, extended_attributes=exte nded_attributes, is_nullable=is_nullable, is_optional=is_optional, is_variadic=i s_variadic)
274
275 # Minor definitions
276
277
278 def callback_node_to_callback_function(node):
279 name = node.GetName()
280 children = node.GetChildren()
281 num_children = len(children)
282 if num_children != 2:
283 raise ValueError('Expected 2 children, got %s' % num_children)
284
285 type_node = children[0]
286 data_type = type_node_to_type(type_node)
287
288 arguments_node = children[1]
289 arguments_node_class = arguments_node.GetClass()
290 if arguments_node_class != 'Arguments':
291 raise ValueError('Expected Value node, got %s' % arguments_node_class)
292 parameters = argument_list_node_to_parameters(arguments_node)
293
294 return CallbackFunction(name=name, data_type=data_type, parameters=parameter s)
295
296
297 def enum_node_to_dom_enum(node):
298 name = node.GetName()
299 values = []
300 for child in node.GetChildren():
301 values.append(child.GetName())
302 return DomEnum(name=name, values=values)
303
304
305 def exception_field_to_string_node_to_dom_function(node):
306 extended_attributes = {}
307 name = node.GetName()
308 children = node.GetChildren()
309 if len(children) > 2:
310 raise ValueError('ExceptionFieldToString node with %s children, expected at most 2' % len(children))
311
312 type_node = children[0]
313 return_type = type_node_to_type(type_node)
314
315 if len(children) > 1:
316 ext_attributes_node = children[1]
317 extended_attributes = ext_attributes_node_to_extended_attributes(ext_att ributes_node)
318
319 return DomFunction(name=name, data_type=return_type, extended_attributes=ext ended_attributes)
320
321
322 def exception_node_to_dom_interface(node):
323 # Exceptions treated as interfaces with a flag set,
324 # rather than a different class
325 return interface_node_to_dom_interface(node, is_exception=True)
326
327
328 def typedef_node_to_typedef(node):
329 data_type = None
330 extended_attributes = None
331
332 children = node.GetChildren()
333 for child in children:
334 child_class = child.GetClass()
335 if child_class == 'Type':
336 data_type = type_node_to_type(child)
337 elif child_class == 'ExtAttributes':
338 extended_attributes = ext_attributes_node_to_extended_attributes(chi ld)
339 raise ValueError('Extended attributes in a typedef are untested!')
340 else:
341 raise ValueError('Unrecognized node class: %s' % child_class)
342
343 return Typedef(data_type=data_type, extended_attributes=extended_attributes)
344
345 # Extended attributes
346
347
348 def ext_attributes_node_to_extended_attributes(node):
349 # Constructors and Custom Constructors can have duplicate entries due to
350 # overloading, but Named Constructors cannot
351 constructors = []
352 custom_constructors = []
353 extended_attributes = {}
354
355 attribute_list = node.GetChildren()
356 for attribute in attribute_list:
357 name = attribute.GetName()
358 children = attribute.GetChildren()
359 if name in ['Constructor', 'CustomConstructor', 'NamedConstructor']:
360 child = None
361 child_class = None
362 # FIXME: is child required?? append(None)??
363 if children:
364 if len(children) > 1:
365 raise ValueError('ExtAttributes node with %s children, expec ted at most 1' % len(children))
366 child = children[0]
367 child_class = child.GetClass()
368 if name == 'Constructor':
369 if child_class and child_class != 'Arguments':
370 raise ValueError('Constructor only supports Arguments as chi ld, but has child of class: %s' % child_class)
371 constructors.append(child)
372 elif name == 'CustomConstructor':
373 if child_class and child_class != 'Arguments':
374 raise ValueError('Custom Constructor only supports Arguments as child, but has child of class: %s' % child_class)
375 custom_constructors.append(child)
376 else: # name == 'NamedConstructor'
377 if child_class and child_class != 'Call':
378 raise ValueError('Named Constructor only supports Call as ch ild, but has child of class: %s' % child_class)
379 extended_attributes[name] = child
380 elif children:
381 raise ValueError('Non-constructor ExtAttributes node with children: %s' % name)
382 else:
383 value = attribute.GetProperty('VALUE')
384 extended_attributes[name] = value
385
386 # Store constructors and custom constructors in special list attributes,
387 # which are deleted later. Note plural in key.
388 if constructors:
389 extended_attributes['Constructors'] = constructors
390 if custom_constructors:
391 extended_attributes['CustomConstructors'] = custom_constructors
392
393 return extended_attributes
394
395
396 def extended_attributes_to_constructors(extended_attributes):
397 """Returns constructors and custom_constructors (lists of DomFunctions),
398 deletes the special list attributes, and puts dummy empty value in
399 Constructor and CustomConstructor extended attributes.
400 Auxiliary function for interface_node_to_dom_interface."""
401 constructors = []
402 custom_constructors = []
403 if 'Constructors' in extended_attributes:
404 constructor_list = extended_attributes['Constructors']
405 # If not overloaded, have index 0, otherwise index from 1
406 overloaded_index = 0 if len(constructor_list) == 1 else 1
407 for arguments in constructor_list:
408 name = 'Constructor'
409 parameters = argument_list_node_to_parameters(arguments)
410 # FIXME: other default for is_variadic
411 constructors.append(DomFunction(name=name, extended_attributes=exten ded_attributes, overloaded_index=overloaded_index, parameters=parameters))
412 overloaded_index += 1
413 del extended_attributes['Constructors']
414 extended_attributes['Constructor'] = None
415
416 # Prefix 'CallWith' and 'RaisesException' with 'Constructor'
417 # FIXME: I have no idea why this is necessary
418 if 'CallWith' in extended_attributes:
419 extended_attributes['ConstructorCallWith'] = extended_attributes['Ca llWith']
420 del extended_attributes['CallWith']
421 if 'RaisesException' in extended_attributes:
422 extended_attributes['ConstructorRaisesException'] = extended_attribu tes['RaisesException']
423 del extended_attributes['RaisesException']
424
425 if 'CustomConstructors' in extended_attributes:
426 custom_constructor_list = extended_attributes['CustomConstructors']
427 # If not overloaded, have index 0, otherwise index from 1
428 overloaded_index = 0 if len(custom_constructor_list) == 1 else 1
429 for arguments in custom_constructor_list:
430 name = 'CustomConstructor'
431 parameters = argument_list_node_to_parameters(arguments)
432 custom_constructors.append(DomFunction(name=name, extended_attribute s=extended_attributes, overloaded_index=overloaded_index, parameters=parameters) )
433 overloaded_index += 1
434 del extended_attributes['CustomConstructors']
435 extended_attributes['CustomConstructor'] = None
436
437 if 'NamedConstructor' in extended_attributes:
438 name = 'NamedConstructor'
439 call_node = extended_attributes['NamedConstructor']
440 extended_attributes['NamedConstructor'] = call_node.GetName()
441 arguments = call_node.GetChildren()[0]
442 parameters = argument_list_node_to_parameters(arguments)
443 overloaded_index = None # FIXME: handle overloaded named constructors
444 constructors.append(DomFunction(name=name, extended_attributes=extended_ attributes, overloaded_index=overloaded_index, parameters=parameters))
445
446 return constructors, custom_constructors
447
448 # Types
449
450
451 def type_node_to_type(node):
452 children = node.GetChildren()
453 if not children:
454 raise ValueError('Type node expects children, got none.')
455 if len(children) > 2:
456 raise ValueError('Type node expects at most 2 children (type + optional array []), got %s (multi-dimensional arrays are not supported).' % len(children) )
457
458 type_node_child = children[0]
459 data_type = type_node_inner_to_type(type_node_child)
460
461 if len(children) == 2:
462 array_node = children[1]
463 array_node_class = array_node.GetClass()
464 if array_node_class != 'Array':
465 raise ValueError('Expected Array node as TypeSuffix, got %s node.' % array_node_class)
466 data_type += '[]'
467
468 return data_type
469
470
471 def type_node_inner_to_type(node):
472 """Auxiliary."""
473 # FIXME: better comment
474 node_class = node.GetClass()
475 if node_class in ['PrimitiveType', 'Typeref']:
476 return node.GetName()
477 elif node_class == 'Any':
478 return 'any'
479 elif node_class == 'Sequence':
480 return sequence_node_to_type(node)
481 elif node_class == 'UnionType':
482 return union_type_node_to_type(node)
483 raise ValueError('Unrecognized node class: %s' % node_class)
484
485
486 def sequence_node_to_type(node):
487 children = node.GetChildren()
488 if len(children) != 1:
489 raise ValueError('Sequence node expects exactly 1 child, got %s' % len(c hildren))
490 sequence_child = children[0]
491 sequence_child_class = sequence_child.GetClass()
492 if sequence_child_class != 'Type':
493 raise ValueError('Unrecognized node class: %s' % sequence_child_class)
494 sequence_type = type_node_to_type(sequence_child)
495 return 'sequence<%s>' % sequence_type
496
497
498 def union_type_node_to_type(node):
499 union_member_types = []
500 for member_type_node in node.GetChildren():
501 member_type = type_node_inner_to_type(member_type_node)
502 union_member_types.append(member_type)
503 return UnionType(union_member_types=union_member_types)
504
505
506 # Perl JSON compatibility functions
507
508
509 def get_property(key, dictionary):
510 # Need to use 1/0/None rather than True/False for compatibility
511 # with Perl-generated JSON.
512 # FIXME: can this be replaced by boolean_to_perl in to_json instead?
513 # FIXME: removed once verify generated code same
514 if key in dictionary:
515 if dictionary[key]:
516 return 1
517 else:
518 return 0
519 return None
520
521
522 def get_quoted_property(key, dictionary):
523 # More bug-for-bug compatibility with Perl,
524 # here giving certain values as strings rather than integers.
525 # FIXME: remove once verify generated code same
526 if key in dictionary:
527 if dictionary[key]:
528 return '1'
529 else:
530 return '0'
531 return None
OLDNEW
« no previous file with comments | « no previous file | Source/bindings/scripts/blink_idl_lexer.py » ('j') | Source/bindings/scripts/ir.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698