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

Side by Side Diff: tools/dom/scripts/databasebuilder.py

Issue 444743002: Use Blink IDL parser for dart libraries. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Merged Created 6 years, 3 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
« no previous file with comments | « tools/dom/scripts/dartmetadata.py ('k') | tools/dom/scripts/fremontcutbuilder.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 2 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
3 # for details. All rights reserved. Use of this source code is governed by a 3 # for details. All rights reserved. Use of this source code is governed by a
4 # BSD-style license that can be found in the LICENSE file. 4 # BSD-style license that can be found in the LICENSE file.
5 5
6 import copy 6 import copy
7 import database 7 import database
8 import idlparser 8 import idlparser
9 import logging 9 import logging
10 import multiprocessing 10 import multiprocessing
11 import os 11 import os
12 import os.path 12 import os.path
13 import re 13 import re
14 import sys
15 import tempfile
16 import time
17 import traceback
18
19 import idl_validator
20
21 import compiler
22 import compute_interfaces_info_individual
23 from compute_interfaces_info_individual import compute_info_individual, info_ind ividual
24 import compute_interfaces_info_overall
25 from compute_interfaces_info_overall import compute_interfaces_info_overall, int erfaces_info
26 import idl_definitions
14 27
15 from idlnode import * 28 from idlnode import *
16 29
17 _logger = logging.getLogger('databasebuilder') 30 _logger = logging.getLogger('databasebuilder')
18 31
19 # Used in source annotations to specify the parent interface declaring 32 # Used in source annotations to specify the parent interface declaring
20 # a displaced declaration. The 'via' attribute specifies the parent interface 33 # a displaced declaration. The 'via' attribute specifies the parent interface
21 # which implements a displaced declaration. 34 # which implements a displaced declaration.
22 _VIA_ANNOTATION_ATTR_NAME = 'via' 35 _VIA_ANNOTATION_ATTR_NAME = 'via'
23 36
24 37
25 class DatabaseBuilderOptions(object): 38 class DatabaseBuilderOptions(object):
26 """Used in specifying options when importing new interfaces""" 39 """Used in specifying options when importing new interfaces"""
27 40
28 def __init__(self, 41 def __init__(self,
29 idl_syntax=idlparser.WEBIDL_SYNTAX, 42 idl_syntax=idlparser.WEBIDL_SYNTAX,
30 idl_defines=[], 43 idl_defines=[],
31 source=None, source_attributes={}, 44 source=None, source_attributes={},
32 rename_operation_arguments_on_merge=False, 45 rename_operation_arguments_on_merge=False,
33 add_new_interfaces=True, 46 add_new_interfaces=True,
34 obsolete_old_declarations=False): 47 obsolete_old_declarations=False,
48 logging_level=logging.WARNING):
35 """Constructor. 49 """Constructor.
36 Args: 50 Args:
37 idl_syntax -- the syntax of the IDL file that is imported. 51 idl_syntax -- the syntax of the IDL file that is imported.
38 idl_defines -- list of definitions for the idl gcc pre-processor 52 idl_defines -- list of definitions for the idl gcc pre-processor
39 source -- the origin of the IDL file, used for annotating the 53 source -- the origin of the IDL file, used for annotating the
40 database. 54 database.
41 source_attributes -- this map of attributes is used as 55 source_attributes -- this map of attributes is used as
42 annotation attributes. 56 annotation attributes.
43 rename_operation_arguments_on_merge -- if True, will rename 57 rename_operation_arguments_on_merge -- if True, will rename
44 operation arguments when merging using the new name rather 58 operation arguments when merging using the new name rather
45 than the old. 59 than the old.
46 add_new_interfaces -- when False, if an interface is a new 60 add_new_interfaces -- when False, if an interface is a new
47 addition, it will be ignored. 61 addition, it will be ignored.
48 obsolete_old_declarations -- when True, if a declaration 62 obsolete_old_declarations -- when True, if a declaration
49 from a certain source is not re-declared, it will be removed. 63 from a certain source is not re-declared, it will be removed.
50 """ 64 """
51 self.source = source 65 self.source = source
52 self.source_attributes = source_attributes 66 self.source_attributes = source_attributes
53 self.idl_syntax = idl_syntax 67 self.idl_syntax = idl_syntax
54 self.idl_defines = idl_defines 68 self.idl_defines = idl_defines
55 self.rename_operation_arguments_on_merge = \ 69 self.rename_operation_arguments_on_merge = \
56 rename_operation_arguments_on_merge 70 rename_operation_arguments_on_merge
57 self.add_new_interfaces = add_new_interfaces 71 self.add_new_interfaces = add_new_interfaces
58 self.obsolete_old_declarations = obsolete_old_declarations 72 self.obsolete_old_declarations = obsolete_old_declarations
73 _logger.setLevel(logging_level)
59 74
60 75
61 def _load_idl_file(file_name, import_options): 76 def _load_idl_file(build, file_name, import_options):
62 """Loads an IDL file into memory""" 77 """Loads an IDL file into memory"""
63 idl_parser = idlparser.IDLParser(import_options.idl_syntax) 78 idl_parser = idlparser.IDLParser(import_options.idl_syntax)
64 79
65 try: 80 try:
66 f = open(file_name, 'r') 81 f = open(file_name, 'r')
67 content = f.read() 82 content = f.read()
68 f.close() 83 f.close()
69 84
70 idl_ast = idl_parser.parse(content) 85 idl_ast = idl_parser.parse(content)
86
71 return IDLFile(idl_ast, file_name) 87 return IDLFile(idl_ast, file_name)
72 except SyntaxError, e: 88 except SyntaxError, e:
73 raise RuntimeError('Failed to load file %s: %s: Content: %s[end]' 89 raise RuntimeError('Failed to load file %s: %s: Content: %s[end]'
74 % (file_name, e, content)) 90 % (file_name, e, content))
75 91
76 92
93 def format_exception(e):
94 exception_list = traceback.format_stack()
95 exception_list = exception_list[:-2]
96 exception_list.extend(traceback.format_tb(sys.exc_info()[2]))
97 exception_list.extend(traceback.format_exception_only(sys.exc_info()[0], sys .exc_info()[1]))
98
99 exception_str = "Traceback (most recent call last):\n"
100 exception_str += "".join(exception_list)
101 # Removing the last \n
102 exception_str = exception_str[:-1]
103
104 return exception_str
105
106
107 # Compile IDL using Blink's IDL compiler.
108 def _new_compile_idl_file(build, file_name, import_options):
109 try:
110 idl_file_fullpath = os.path.realpath(file_name)
111 idl_definition = build.idl_compiler.compile_file(idl_file_fullpath)
112 return idl_definition
113 except Exception as err:
114 print 'ERROR: idl_compiler.py: ' + os.path.basename(file_name)
115 print err
116 print
117 print 'Stack Dump:'
118 print format_exception(err)
119
120 return 1
121
122
123 # Create the Model (IDLFile) from the new AST of the compiled IDL file.
124 def _new_load_idl_file(build, file_name, import_options):
125 try:
126 # Compute interface name from IDL filename (it's one for one in WebKit).
127 name = os.path.splitext(os.path.basename(file_name))[0]
128
129 idl_definition = new_asts[name]
130 return IDLFile(idl_definition, file_name)
131 except Exception as err:
132 print 'ERROR: loading AST from cache: ' + os.path.basename(file_name)
133 print err
134 print
135 print 'Stack Dump:'
136 print format_exception(err)
137
138 return 1
139
140
141 # New IDL parser builder.
142 class Build():
143 def __init__(self, provider):
144 # TODO(terry): Consider using the generator to do the work today we're
145 # driven by the databasebuilder. Blink compiler requires
146 # an output directory even though we don't use (yet). Might
147 # use the code generator portion of the new IDL compiler
148 # then we'd have a real output directory. Today we use the
149 # compiler to only create an AST.
150 self.output_directory = tempfile.mkdtemp()
151 attrib_file = os.path.join('Source', idl_validator.EXTENDED_ATTRIBUTES_F ILENAME)
152 # Create compiler.
153 self.idl_compiler = compiler.IdlCompilerDart(self.output_directory,
154 attrib_file,
155 interfaces_info=interfaces_info,
156 only_if_changed=True)
157
158 def format_exception(self, e):
159 exception_list = traceback.format_stack()
160 exception_list = exception_list[:-2]
161 exception_list.extend(traceback.format_tb(sys.exc_info()[2]))
162 exception_list.extend(traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1]))
163
164 exception_str = "Traceback (most recent call last):\n"
165 exception_str += "".join(exception_list)
166 # Removing the last \n
167 exception_str = exception_str[:-1]
168
169 return exception_str
170
171 def generate_from_idl(self, idl_file):
172 try:
173 idl_file_fullpath = os.path.realpath(idl_file)
174 self.idl_compiler.compile_file(idl_file_fullpath)
175 except Exception as err:
176 print 'ERROR: idl_compiler.py: ' + os.path.basename(idl_file)
177 print err
178 print
179 print 'Stack Dump:'
180 print self.format_exception(err)
181
182 return 1
183
184 return IDLFile(idl_ast, file_name)
185
186
77 class DatabaseBuilder(object): 187 class DatabaseBuilder(object):
78 def __init__(self, database): 188 def __init__(self, database):
79 """DatabaseBuilder is used for importing and merging interfaces into 189 """DatabaseBuilder is used for importing and merging interfaces into
80 the Database""" 190 the Database"""
81 self._database = database 191 self._database = database
82 self._imported_interfaces = [] 192 self._imported_interfaces = []
83 self._impl_stmts = [] 193 self._impl_stmts = []
84 self.conditionals_met = set() 194 self.conditionals_met = set()
85 195
196 # Spin up the new IDL parser.
197 self.build = Build(None)
198
86 def _resolve_type_defs(self, idl_file): 199 def _resolve_type_defs(self, idl_file):
87 type_def_map = {} 200 type_def_map = {}
88 # build map 201 # build map
89 for type_def in idl_file.typeDefs: 202 for type_def in idl_file.typeDefs:
90 if type_def.type.id != type_def.id: # sanity check 203 if type_def.type.id != type_def.id: # sanity check
91 type_def_map[type_def.id] = type_def.type.id 204 type_def_map[type_def.id] = type_def.type.id
92 # use the map 205 # use the map
93 for type_node in idl_file.all(IDLType): 206 for type_node in idl_file.all(IDLType):
94 while type_node.id in type_def_map: 207 while type_node.id in type_def_map:
95 type_node.id = type_def_map[type_node.id] 208 type_node.id = type_def_map[type_node.id]
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 298
186 def _build_signatures_map(self, idl_node_list): 299 def _build_signatures_map(self, idl_node_list):
187 """Creates a hash table mapping signatures to idl_nodes for the 300 """Creates a hash table mapping signatures to idl_nodes for the
188 given list of nodes""" 301 given list of nodes"""
189 res = {} 302 res = {}
190 for idl_node in idl_node_list: 303 for idl_node in idl_node_list:
191 sig = self._sign(idl_node) 304 sig = self._sign(idl_node)
192 if sig is None: 305 if sig is None:
193 continue 306 continue
194 if sig in res: 307 if sig in res:
195 raise RuntimeError('Warning: Multiple members have the same ' 308 op = res[sig]
196 'signature: "%s"' % sig) 309 # Only report if the the operations that match are either both suppresse d
310 # or both not suppressed. Optional args aren't part of type signature
311 # for this routine. Suppressing a non-optional type and supplementing
312 # with an optional type appear the same.
313 if idl_node.is_fc_suppressed == op.is_fc_suppressed:
314 raise RuntimeError('Warning: Multiple members have the same '
315 ' signature: "%s"' % sig)
197 res[sig] = idl_node 316 res[sig] = idl_node
198 return res 317 return res
199 318
200 def _get_parent_interfaces(self, interface): 319 def _get_parent_interfaces(self, interface):
201 """Return a list of all the parent interfaces of a given interface""" 320 """Return a list of all the parent interfaces of a given interface"""
202 res = [] 321 res = []
203 322
204 def recurse(current_interface): 323 def recurse(current_interface):
205 if current_interface in res: 324 if current_interface in res:
206 return 325 return
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 import_options.source_attributes) 487 import_options.source_attributes)
369 return 488 return
370 # not found, so add new one 489 # not found, so add new one
371 parent = IDLParentInterface(None) 490 parent = IDLParentInterface(None)
372 parent.type = IDLType(implemented_name) 491 parent.type = IDLType(implemented_name)
373 if source: 492 if source:
374 parent.annotations[source] = IDLAnnotation( 493 parent.annotations[source] = IDLAnnotation(
375 import_options.source_attributes) 494 import_options.source_attributes)
376 interface.parents.append(parent) 495 interface.parents.append(parent)
377 496
378 def merge_imported_interfaces(self): 497 def merge_imported_interfaces(self, blink_parser):
379 """Merges all imported interfaces and loads them into the DB.""" 498 """Merges all imported interfaces and loads them into the DB."""
499 imported_interfaces = self._imported_interfaces
380 500
381 # Step 1: Pre process imported interfaces 501 # Step 1: Pre process imported interfaces
382 for interface, import_options in self._imported_interfaces: 502 # for interface, import_options in imported_interfaces.iteritems():
503 for interface, import_options in imported_interfaces:
383 self._annotate(interface, import_options) 504 self._annotate(interface, import_options)
384 505
385 # Step 2: Add all new interfaces and merge overlapping ones 506 # Step 2: Add all new interfaces and merge overlapping ones
386 for interface, import_options in self._imported_interfaces: 507 for interface, import_options in imported_interfaces:
387 if not interface.is_supplemental: 508 if not interface.is_supplemental:
388 if self._database.HasInterface(interface.id): 509 if self._database.HasInterface(interface.id):
389 old_interface = self._database.GetInterface(interface.id) 510 old_interface = self._database.GetInterface(interface.id)
390 self._merge_interfaces(old_interface, interface, import_options) 511 self._merge_interfaces(old_interface, interface, import_options)
391 else: 512 else:
392 if import_options.add_new_interfaces: 513 if import_options.add_new_interfaces:
393 self._database.AddInterface(interface) 514 self._database.AddInterface(interface)
394 515
395 # Step 3: Merge in supplemental interfaces 516 # Step 3: Merge in supplemental interfaces
396 for interface, import_options in self._imported_interfaces: 517 for interface, import_options in imported_interfaces:
397 if interface.is_supplemental: 518 if interface.is_supplemental:
398 target_name = interface.ext_attrs['Supplemental'] 519 target = interface.id
399 if target_name:
400 # [Supplemental=Window] - merge into Window.
401 target = target_name
402 else:
403 # [Supplemental] - merge into existing inteface with same name.
404 target = interface.id
405 if self._database.HasInterface(target): 520 if self._database.HasInterface(target):
406 old_interface = self._database.GetInterface(target) 521 old_interface = self._database.GetInterface(target)
407 self._merge_interfaces(old_interface, interface, import_options) 522 self._merge_interfaces(old_interface, interface, import_options)
408 else: 523 else:
409 _logger.warning("Supplemental target '%s' not found", target) 524 _logger.warning("Supplemental target '%s' not found", target)
410 525
411 # Step 4: Resolve 'implements' statements 526 # Step 4: Resolve 'implements' statements
412 for impl_stmt, import_options in self._impl_stmts: 527 for impl_stmt, import_options in self._impl_stmts:
413 self._merge_impl_stmt(impl_stmt, import_options) 528 self._merge_impl_stmt(impl_stmt, import_options)
414 529
415 self._impl_stmts = [] 530 self._impl_stmts = []
416 self._imported_interfaces = [] 531 self._imported_interfaces = []
417 532
418 def import_idl_files(self, file_paths, import_options, parallel): 533 # Compile the IDL file with the Blink compiler and remember each AST for the
534 # IDL.
535 def _blink_compile_idl_files(self, file_paths, import_options, parallel, is_da rt_idl):
536 if not(is_dart_idl):
537 start_time = time.time()
538
539 # 2-stage computation: individual, then overall
540 for file_path in file_paths:
541 filename = os.path.splitext(os.path.basename(file_path))[0]
542 compute_info_individual(file_path, 'dart')
543 info_individuals = [info_individual()]
544 compute_interfaces_info_overall(info_individuals)
545
546 end_time = time.time()
547 print 'Compute dependencies %s seconds' % round((end_time - start_time),
548 2)
549
550 # use --parallel for async on a pool. Look at doing it like Blink
551 blink_compiler = _new_compile_idl_file
552 process_ast = self._process_ast
553
419 if parallel: 554 if parallel:
420 # Parse the IDL files in parallel. 555 # Parse the IDL files in parallel.
421 pool = multiprocessing.Pool() 556 pool = multiprocessing.Pool()
422 try: 557 try:
423 for file_path in file_paths: 558 for file_path in file_paths:
424 pool.apply_async(_load_idl_file, 559 pool.apply_async(blink_compiler,
425 [ file_path, import_options], 560 [ self.build, file_path, import_options],
561 callback = lambda new_ast: process_ast(new_ast, True) )
562 pool.close()
563 pool.join()
564 except:
565 pool.terminate()
566 raise
567 else:
568 # Parse the IDL files serially.
569 start_time = time.time()
570
571 for file_path in file_paths:
572 file_path = os.path.normpath(file_path)
573 ast = blink_compiler(self.build, file_path, import_options)
574 process_ast(os.path.splitext(os.path.basename(file_path))[0], ast, True)
575
576 end_time = time.time()
577 print 'Compiled %s IDL files in %s seconds' % (len(file_paths),
578 round((end_time - start_time ), 2))
579
580 def _process_ast(self, filename, ast, blink_parser = False):
581 if blink_parser:
582 new_asts[filename] = ast
583 else:
584 for name in ast.interfaces:
585 # Index by filename some files are partial on another interface (e.g.,
586 # DocumentFontFaceSet.idl).
587 new_asts[filename] = ast.interfaces
588
589 def import_idl_files(self, file_paths, import_options, parallel, blink_parser, is_dart_idl):
590 if blink_parser:
591 self._blink_compile_idl_files(file_paths, import_options, parallel, is_dar t_idl)
592
593 # use --parallel for async on a pool. Look at doing it like Blink
594 idl_loader = _new_load_idl_file if blink_parser else _load_idl_file
595
596 if parallel:
597 # Parse the IDL files in parallel.
598 pool = multiprocessing.Pool()
599 try:
600 for file_path in file_paths:
601 pool.apply_async(idl_loader,
602 [ self.build, file_path, import_options],
426 callback = lambda idl_file: 603 callback = lambda idl_file:
427 self._process_idl_file(idl_file, import_options)) 604 self._process_idl_file(idl_file, import_options))
428 pool.close() 605 pool.close()
429 pool.join() 606 pool.join()
430 except: 607 except:
431 pool.terminate() 608 pool.terminate()
432 raise 609 raise
433 else: 610 else:
611 start_time = time.time()
612
434 # Parse the IDL files in serial. 613 # Parse the IDL files in serial.
435 for file_path in file_paths: 614 for file_path in file_paths:
436 idl_file = _load_idl_file(file_path, import_options) 615 file_path = os.path.normpath(file_path)
437 self._process_idl_file(idl_file, import_options) 616 idl_file = idl_loader(self.build, file_path, import_options)
617 _logger.info('Processing %s' % os.path.splitext(os.path.basename(file_pa th))[0])
618 self._process_idl_file(idl_file, import_options, is_dart_idl)
438 619
439 def _process_idl_file(self, idl_file, 620 end_time = time.time()
440 import_options): 621
441 self._strip_ext_attributes(idl_file) 622 print 'Total %s files %sprocessed in databasebuilder in %s seconds' % \
623 (len(file_paths), '' if blink_parser else 'compiled/', \
624 round((end_time - start_time), 2))
625
626 def _process_idl_file(self, idl_file, import_options, dart_idl = False):
627 # TODO(terry): strip_ext_attributes on an idl_file does nothing.
628 #self._strip_ext_attributes(idl_file)
442 self._resolve_type_defs(idl_file) 629 self._resolve_type_defs(idl_file)
443 self._rename_types(idl_file, import_options) 630 self._rename_types(idl_file, import_options)
444 631
445 def enabled(idl_node): 632 def enabled(idl_node):
446 return self._is_node_enabled(idl_node, import_options.idl_defines) 633 return self._is_node_enabled(idl_node, import_options.idl_defines)
447 634
448 for interface in idl_file.interfaces: 635 for interface in idl_file.interfaces:
449 if not self._is_node_enabled(interface, import_options.idl_defines): 636 if not self._is_node_enabled(interface, import_options.idl_defines):
450 _logger.info('skipping interface %s (source=%s)' 637 _logger.info('skipping interface %s (source=%s)'
451 % (interface.id, import_options.source)) 638 % (interface.id, import_options.source))
452 continue 639 continue
453 640
454 _logger.info('importing interface %s (source=%s file=%s)' 641 _logger.info('importing interface %s (source=%s file=%s)'
455 % (interface.id, import_options.source, idl_file)) 642 % (interface.id, import_options.source, os.path.basename(idl_file.filena me)))
643
456 interface.attributes = filter(enabled, interface.attributes) 644 interface.attributes = filter(enabled, interface.attributes)
457 interface.operations = filter(enabled, interface.operations) 645 interface.operations = filter(enabled, interface.operations)
458 self._imported_interfaces.append((interface, import_options)) 646 self._imported_interfaces.append((interface, import_options))
459 647
460 for implStmt in idl_file.implementsStatements: 648 for implStmt in idl_file.implementsStatements:
461 self._impl_stmts.append((implStmt, import_options)) 649 self._impl_stmts.append((implStmt, import_options))
462 650
463 for enum in idl_file.enums: 651 for enum in idl_file.enums:
464 self._database.AddEnum(enum) 652 self._database.AddEnum(enum)
465 653
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
567 # TODO(antonm): Ideally we'd like to have pristine copy of WebKit IDLs and fetch 755 # TODO(antonm): Ideally we'd like to have pristine copy of WebKit IDLs and fetch
568 # this information directly from it. Unfortunately right now database is massaged 756 # this information directly from it. Unfortunately right now database is massaged
569 # a lot so it's difficult to maintain necessary information on Window itse lf. 757 # a lot so it's difficult to maintain necessary information on Window itse lf.
570 interface = self._database.GetInterface(type) 758 interface = self._database.GetInterface(type)
571 if 'V8EnabledPerContext' in attr.ext_attrs: 759 if 'V8EnabledPerContext' in attr.ext_attrs:
572 interface.ext_attrs['synthesizedV8EnabledPerContext'] = \ 760 interface.ext_attrs['synthesizedV8EnabledPerContext'] = \
573 attr.ext_attrs['V8EnabledPerContext'] 761 attr.ext_attrs['V8EnabledPerContext']
574 if 'V8EnabledAtRuntime' in attr.ext_attrs: 762 if 'V8EnabledAtRuntime' in attr.ext_attrs:
575 interface.ext_attrs['synthesizedV8EnabledAtRuntime'] = \ 763 interface.ext_attrs['synthesizedV8EnabledAtRuntime'] = \
576 attr.ext_attrs['V8EnabledAtRuntime'] or attr.id 764 attr.ext_attrs['V8EnabledAtRuntime'] or attr.id
OLDNEW
« no previous file with comments | « tools/dom/scripts/dartmetadata.py ('k') | tools/dom/scripts/fremontcutbuilder.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698