| OLD | NEW |
| 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 """This module generates Dart APIs from the IDL database.""" | 6 """This module generates Dart APIs from the IDL database.""" |
| 7 | 7 |
| 8 import emitter | 8 import emitter |
| 9 import idlnode | 9 import idlnode |
| 10 import logging | 10 import logging |
| (...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 super_database -- database containing super interfaces that the generated | 372 super_database -- database containing super interfaces that the generated |
| 373 interfaces should extend. | 373 interfaces should extend. |
| 374 common_prefix -- prefix for the common library, if any. | 374 common_prefix -- prefix for the common library, if any. |
| 375 lib_file_path -- filename for generated .lib file, None if not required. | 375 lib_file_path -- filename for generated .lib file, None if not required. |
| 376 lib_template -- template file in this directory for generated lib file. | 376 lib_template -- template file in this directory for generated lib file. |
| 377 """ | 377 """ |
| 378 | 378 |
| 379 self._emitters = multiemitter.MultiEmitter() | 379 self._emitters = multiemitter.MultiEmitter() |
| 380 self._database = database | 380 self._database = database |
| 381 self._output_dir = output_dir | 381 self._output_dir = output_dir |
| 382 self._dart_callback_file_paths = [] | |
| 383 | 382 |
| 384 self._ComputeInheritanceClosure() | 383 self._ComputeInheritanceClosure() |
| 385 self._StartGenerateInterfaceLibrary() | 384 |
| 386 self._StartGenerateWrappingImpl(output_dir) | 385 interface_system = WrappingInterfacesSystem( |
| 387 self._StartGenerateFrogImpl(output_dir) | 386 self._database, self._emitters, self._output_dir) |
| 387 |
| 388 wrapping_system = WrappingImplementationSystem( |
| 389 self._database, self._emitters, self._output_dir) |
| 390 |
| 391 # Makes wrapper implementations available for listing in interface lib. |
| 392 interface_system._implementation_system = wrapping_system |
| 393 |
| 394 frog_system = FrogSystem( |
| 395 self._database, self._emitters, self._output_dir) |
| 396 |
| 397 self._systems = [interface_system, |
| 398 wrapping_system, |
| 399 frog_system] |
| 388 | 400 |
| 389 # Render all interfaces into Dart and save them in files. | 401 # Render all interfaces into Dart and save them in files. |
| 390 dart_file_paths = [] | |
| 391 processed_interfaces = [] | |
| 392 for interface in database.GetInterfaces(): | 402 for interface in database.GetInterfaces(): |
| 393 | 403 |
| 394 super_interface = None | 404 super_interface = None |
| 395 super_name = interface.id | 405 super_name = interface.id |
| 396 | 406 |
| 397 if not _MatchSourceFilter(source_filter, interface): | 407 if not _MatchSourceFilter(source_filter, interface): |
| 398 # Skip this interface since it's not present in the required source | 408 # Skip this interface since it's not present in the required source |
| 399 _logger.info('Omitting interface - %s' % interface.id) | 409 _logger.info('Omitting interface - %s' % interface.id) |
| 400 continue | 410 continue |
| 401 | 411 |
| 402 if super_name in super_map: | 412 if super_name in super_map: |
| 403 super_name = super_map[super_name] | 413 super_name = super_map[super_name] |
| 404 | 414 |
| 405 if (super_database is not None and | 415 if (super_database is not None and |
| 406 super_database.HasInterface(super_name)): | 416 super_database.HasInterface(super_name)): |
| 407 super_interface = super_name | 417 super_interface = super_name |
| 408 | 418 |
| 409 interface_name = interface.id | 419 interface_name = interface.id |
| 410 auxiliary_file = self._auxiliary_files.get(interface_name) | 420 auxiliary_file = self._auxiliary_files.get(interface_name) |
| 411 if auxiliary_file is not None: | 421 if auxiliary_file is not None: |
| 412 _logger.info('Skipping %s because %s exists' % ( | 422 _logger.info('Skipping %s because %s exists' % ( |
| 413 interface_name, auxiliary_file)) | 423 interface_name, auxiliary_file)) |
| 414 continue | 424 continue |
| 415 | 425 |
| 416 | 426 |
| 417 info = self._RecognizeCallback(interface) | 427 info = self._RecognizeCallback(interface) |
| 418 if info: | 428 if info: |
| 419 self._ProcessCallback(interface, info) | 429 for system in self._systems: |
| 430 system.ProcessCallback(interface, info) |
| 420 else: | 431 else: |
| 421 if 'Callback' in interface.ext_attrs: | 432 if 'Callback' in interface.ext_attrs: |
| 422 _logger.info('Malformed callback: %s' % interface.id) | 433 _logger.info('Malformed callback: %s' % interface.id) |
| 423 self._ProcessInterface(interface, super_interface, | 434 self._ProcessInterface(interface, super_interface, |
| 424 source_filter, common_prefix) | 435 source_filter, common_prefix) |
| 425 processed_interfaces.append(interface) | |
| 426 | 436 |
| 427 # Libraries | 437 # Libraries |
| 428 if lib_dir: | 438 if lib_dir: |
| 429 # New version: Wrapping implementation combined interface and | 439 for system in self._systems: |
| 430 # implementation library. | 440 system.GenerateLibraries(lib_dir) |
| 431 self.GenerateLibFile('template_wrapping_dom.darttemplate', | |
| 432 os.path.join(lib_dir, 'wrapping_dom.dart'), | |
| 433 (self._dart_interface_file_paths + | |
| 434 self._dart_callback_file_paths + | |
| 435 # FIXME: Move the implementation to a separate | |
| 436 # library. | |
| 437 self._dart_wrapping_file_paths)) | |
| 438 | 441 |
| 439 # New version: Frog | 442 for system in self._systems: |
| 440 self.GenerateLibFile('template_frog_dom.darttemplate', | 443 system.Finish() |
| 441 os.path.join(lib_dir, 'dom_frog.dart'), | |
| 442 self._dart_frog_file_paths + | |
| 443 self._dart_callback_file_paths) | |
| 444 | |
| 445 | |
| 446 # JavaScript externs files | |
| 447 self._GenerateJavaScriptExternsWrapping(database, output_dir) | |
| 448 | 444 |
| 449 | 445 |
| 450 def _RecognizeCallback(self, interface): | 446 def _RecognizeCallback(self, interface): |
| 451 """Returns the info for the callback method if the interface smells like a | 447 """Returns the info for the callback method if the interface smells like a |
| 452 callback. | 448 callback. |
| 453 """ | 449 """ |
| 454 if 'Callback' not in interface.ext_attrs: return None | 450 if 'Callback' not in interface.ext_attrs: return None |
| 455 handlers = [op for op in interface.operations if op.id == 'handleEvent'] | 451 handlers = [op for op in interface.operations if op.id == 'handleEvent'] |
| 456 if not handlers: return None | 452 if not handlers: return None |
| 457 if not (handlers == interface.operations): return None | 453 if not (handlers == interface.operations): return None |
| 458 return self._AnalyzeOperation(interface, handlers) | 454 return self._AnalyzeOperation(interface, handlers) |
| 459 | 455 |
| 460 def _ProcessCallback(self, interface, info): | |
| 461 """Generates a typedef for the callback interface.""" | |
| 462 interface_name = interface.id | |
| 463 file_path = self.FilePathForDartInterface(interface_name) | |
| 464 self._dart_callback_file_paths.append(file_path) | |
| 465 code = self._emitters.FileEmitter(file_path) | |
| 466 | |
| 467 template_file = 'template_callback.darttemplate' | |
| 468 code.Emit(''.join(open(template_file).readlines())) | |
| 469 code.Emit('typedef $TYPE $NAME($ARGS);\n', | |
| 470 NAME=interface.id, | |
| 471 TYPE=info.type_name, | |
| 472 ARGS=info.arg_implementation_declaration) | |
| 473 | |
| 474 | 456 |
| 475 def _ProcessInterface(self, interface, super_interface_name, | 457 def _ProcessInterface(self, interface, super_interface_name, |
| 476 source_filter, | 458 source_filter, |
| 477 common_prefix): | 459 common_prefix): |
| 478 """.""" | 460 """.""" |
| 479 _logger.info('Generating %s' % interface.id) | 461 _logger.info('Generating %s' % interface.id) |
| 480 | 462 |
| 481 dart_interface_generator = self._MakeDartInterfaceGenerator( | 463 generators = [system.InterfaceGenerator(interface, |
| 482 interface, | 464 common_prefix, |
| 483 common_prefix, | 465 super_interface_name, |
| 484 super_interface_name, | 466 source_filter) |
| 485 source_filter) | 467 for system in self._systems] |
| 486 | |
| 487 wrapping_interface_generator = self._MakeWrappingImplInterfaceGenerator( | |
| 488 interface, | |
| 489 common_prefix, | |
| 490 super_interface_name, | |
| 491 source_filter) | |
| 492 | |
| 493 frog_interface_generator = self._MakeFrogImplInterfaceGenerator( | |
| 494 interface, | |
| 495 common_prefix, | |
| 496 super_interface_name, | |
| 497 source_filter) | |
| 498 | |
| 499 generators = [dart_interface_generator, | |
| 500 wrapping_interface_generator, | |
| 501 frog_interface_generator] | |
| 502 | 468 |
| 503 for generator in generators: | 469 for generator in generators: |
| 504 generator.StartInterface() | 470 generator.StartInterface() |
| 505 | 471 |
| 506 for const in sorted(interface.constants, ConstantOutputOrder): | 472 for const in sorted(interface.constants, ConstantOutputOrder): |
| 507 for generator in generators: | 473 for generator in generators: |
| 508 generator.AddConstant(const) | 474 generator.AddConstant(const) |
| 509 | 475 |
| 510 for attr in sorted(interface.attributes, AttributeOutputOrder): | 476 for attr in sorted(interface.attributes, AttributeOutputOrder): |
| 511 if attr.type.id == 'EventListener': | 477 if attr.type.id == 'EventListener': |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 724 """Returns the file path of the Dart wrapping implementation.""" | 690 """Returns the file path of the Dart wrapping implementation.""" |
| 725 return os.path.join(self._output_dir, 'src', 'wrapping', | 691 return os.path.join(self._output_dir, 'src', 'wrapping', |
| 726 '_%sWrappingImplementation.dart' % interface_name) | 692 '_%sWrappingImplementation.dart' % interface_name) |
| 727 | 693 |
| 728 def FilePathForFrogImpl(self, interface_name): | 694 def FilePathForFrogImpl(self, interface_name): |
| 729 """Returns the file path of the Frog implementation.""" | 695 """Returns the file path of the Frog implementation.""" |
| 730 return os.path.join(self._output_dir, 'src', 'frog', | 696 return os.path.join(self._output_dir, 'src', 'frog', |
| 731 '%s.dart' % interface_name) | 697 '%s.dart' % interface_name) |
| 732 | 698 |
| 733 | 699 |
| 734 def _StartGenerateInterfaceLibrary(self): | |
| 735 """.""" | |
| 736 self._dart_interface_file_paths = [] | |
| 737 self._dart_wrapping_file_paths = [] | |
| 738 self._dart_frog_file_paths = [] | |
| 739 | |
| 740 | |
| 741 def _MakeDartInterfaceGenerator(self, | |
| 742 interface, | |
| 743 common_prefix, | |
| 744 super_interface_name, | |
| 745 source_filter): | |
| 746 """.""" | |
| 747 interface_name = interface.id | |
| 748 dart_interface_file_path = self.FilePathForDartInterface(interface_name) | |
| 749 | |
| 750 self._dart_interface_file_paths.append(dart_interface_file_path) | |
| 751 | |
| 752 dart_interface_code = self._emitters.FileEmitter(dart_interface_file_path) | |
| 753 | |
| 754 template_file = 'template_interface_%s.darttemplate' % interface_name | |
| 755 if not os.path.exists(template_file): | |
| 756 template_file = 'template_interface.darttemplate' | |
| 757 template = ''.join(open(template_file).readlines()) | |
| 758 | |
| 759 return DartInterfaceGenerator( | |
| 760 interface, dart_interface_code, | |
| 761 template, | |
| 762 common_prefix, super_interface_name, | |
| 763 source_filter) | |
| 764 | |
| 765 | |
| 766 def _StartGenerateWrappingImpl(self, output_dir): | |
| 767 """Prepared for generating wrapping implementation. | |
| 768 | |
| 769 - Creates emitter for JS code. | |
| 770 - Creates emitter for Dart code. | |
| 771 """ | |
| 772 js_file_name = os.path.join(output_dir, 'wrapping_dom.js') | |
| 773 code = self._emitters.FileEmitter(js_file_name) | |
| 774 template = ''.join(open('template_wrapping_dom.js').readlines()) | |
| 775 (self._wrapping_js_natives, | |
| 776 self._wrapping_map) = code.Emit(template) | |
| 777 | |
| 778 _logger.info('Started Generating %s' % js_file_name) | |
| 779 | |
| 780 # Set of (interface, name, kind), kind is 'attribute' or 'operation'. | |
| 781 self._wrapping_externs = set() | |
| 782 | |
| 783 | |
| 784 def _MakeWrappingImplInterfaceGenerator(self, | |
| 785 interface, | |
| 786 common_prefix, | |
| 787 super_interface_name, | |
| 788 source_filter): | |
| 789 """.""" | |
| 790 interface_name = interface.id | |
| 791 dart_wrapping_file_path = self.FilePathForDartWrappingImpl(interface_name) | |
| 792 | |
| 793 self._dart_wrapping_file_paths.append(dart_wrapping_file_path) | |
| 794 | |
| 795 dart_code = self._emitters.FileEmitter(dart_wrapping_file_path) | |
| 796 dart_code.Emit( | |
| 797 ''.join(open('template_wrapping_impl.darttemplate').readlines())) | |
| 798 return WrappingInterfaceGenerator(interface, super_interface_name, | |
| 799 dart_code, self._wrapping_js_natives, | |
| 800 self._wrapping_map, | |
| 801 self._wrapping_externs, | |
| 802 self._BaseDefines(interface)) | |
| 803 | |
| 804 def _BaseDefines(self, interface): | |
| 805 """Returns a set of names (strings) for members defined in a base class. | |
| 806 """ | |
| 807 def WalkParentChain(interface): | |
| 808 if interface.parents: | |
| 809 # Only consider primary parent, secondary parents are not on the | |
| 810 # implementation class inheritance chain. | |
| 811 parent = interface.parents[0] | |
| 812 if _IsDartCollectionType(parent.type.id): | |
| 813 return | |
| 814 if self._database.HasInterface(parent.type.id): | |
| 815 parent_interface = self._database.GetInterface(parent.type.id) | |
| 816 for attr in parent_interface.attributes: | |
| 817 result.add(attr.id) | |
| 818 for op in parent_interface.operations: | |
| 819 result.add(op.id) | |
| 820 WalkParentChain(parent_interface) | |
| 821 | |
| 822 result = set() | |
| 823 WalkParentChain(interface) | |
| 824 return result; | |
| 825 | |
| 826 | |
| 827 def _StartGenerateFrogImpl(self, output_dir): | |
| 828 """Prepared for generating frog implementation. | |
| 829 """ | |
| 830 self._interface_names_with_subtypes = set() | |
| 831 for interface in self._database.GetInterfaces(): | |
| 832 for parent in interface.parents: | |
| 833 self._interface_names_with_subtypes.add(parent.type.id) | |
| 834 | |
| 835 def _MakeFrogImplInterfaceGenerator(self, | |
| 836 interface, | |
| 837 common_prefix, | |
| 838 super_interface_name, | |
| 839 source_filter): | |
| 840 """.""" | |
| 841 interface_name = interface.id | |
| 842 dart_frog_file_path = self.FilePathForFrogImpl(interface_name) | |
| 843 | |
| 844 self._dart_frog_file_paths.append(dart_frog_file_path) | |
| 845 | |
| 846 dart_code = self._emitters.FileEmitter(dart_frog_file_path) | |
| 847 dart_code.Emit( | |
| 848 ''.join(open('template_frog_impl.darttemplate').readlines())) | |
| 849 return FrogInterfaceGenerator(interface, super_interface_name, | |
| 850 self._interface_names_with_subtypes, | |
| 851 dart_code) | |
| 852 | |
| 853 | |
| 854 def _ComputeInheritanceClosure(self): | 700 def _ComputeInheritanceClosure(self): |
| 855 def Collect(interface, seen, collected): | 701 def Collect(interface, seen, collected): |
| 856 name = interface.id | 702 name = interface.id |
| 857 if '<' in name: | 703 if '<' in name: |
| 858 # TODO(sra): Handle parameterized types. | 704 # TODO(sra): Handle parameterized types. |
| 859 return | 705 return |
| 860 if not name in seen: | 706 if not name in seen: |
| 861 seen.add(name) | 707 seen.add(name) |
| 862 collected.append(name) | 708 collected.append(name) |
| 863 for parent in interface.parents: | 709 for parent in interface.parents: |
| 864 # TODO(sra): Handle parameterized types. | 710 # TODO(sra): Handle parameterized types. |
| 865 if not '<' in parent.type.id: | 711 if not '<' in parent.type.id: |
| 866 if self._database.HasInterface(parent.type.id): | 712 if self._database.HasInterface(parent.type.id): |
| 867 Collect(self._database.GetInterface(parent.type.id), | 713 Collect(self._database.GetInterface(parent.type.id), |
| 868 seen, collected) | 714 seen, collected) |
| 869 | 715 |
| 870 self._inheritance_closure = {} | 716 self._inheritance_closure = {} |
| 871 for interface in self._database.GetInterfaces(): | 717 for interface in self._database.GetInterfaces(): |
| 872 seen = set() | 718 seen = set() |
| 873 collected = [] | 719 collected = [] |
| 874 Collect(interface, seen, collected) | 720 Collect(interface, seen, collected) |
| 875 self._inheritance_closure[interface.id] = collected | 721 self._inheritance_closure[interface.id] = collected |
| 876 | 722 |
| 877 def _AllImplementedInterfaces(self, interface): | 723 def _AllImplementedInterfaces(self, interface): |
| 878 """Returns a list of the names of all interfaces implemented by 'interface'. | 724 """Returns a list of the names of all interfaces implemented by 'interface'. |
| 879 List includes the name of 'interface'. | 725 List includes the name of 'interface'. |
| 880 """ | 726 """ |
| 881 return self._inheritance_closure[interface.id] | 727 return self._inheritance_closure[interface.id] |
| 882 | 728 |
| 883 def _GenerateProtoMap(self): | |
| 884 """Determine which DOM type prototypes can be obtained | |
| 885 from window properties. | |
| 886 """ | |
| 887 window = None | |
| 888 for interface in self._database.GetInterfaces(): | |
| 889 if interface.id == 'DOMWindow': | |
| 890 window = interface | |
| 891 prototype_table = {} | |
| 892 boring_type_ids = set(['bool', 'int', 'Number', 'String']) | |
| 893 if window: | |
| 894 for attr in window.attributes: | |
| 895 if attr.is_fc_getter: | |
| 896 if attr.type.id not in boring_type_ids: | |
| 897 prototype_table[attr.type.id] = [attr.id] | |
| 898 | |
| 899 # Manual fixups | |
| 900 prototype_table['EventListener'] = ['onload'] # avoid webkit specific. | |
| 901 prototype_table['PerformanceMemoryInfo'] = ['performance', 'memory'] | |
| 902 prototype_table['PerformanceNavigation'] = ['performance', 'navigation'] | |
| 903 prototype_table['PerformanceTiming'] = ['performance', 'timing'] | |
| 904 | |
| 905 return prototype_table | |
| 906 | |
| 907 def _GenerateJavaScriptExternsWrapping(self, database, output_dir): | |
| 908 """Generates a JavaScript externs file. | |
| 909 | |
| 910 Generates an externs file that is consistent with generated JavaScript code | |
| 911 and Dart APIs for the wrapping implementation. | |
| 912 """ | |
| 913 externs_file_name = os.path.join(output_dir, 'wrapping_dom_externs.js') | |
| 914 code = self._emitters.FileEmitter(externs_file_name) | |
| 915 _logger.info('Started generating %s' % externs_file_name) | |
| 916 | |
| 917 template = ''.join(open('template_wrapping_dom_externs.js').readlines()) | |
| 918 namespace = 'dom_externs' | |
| 919 members = code.Emit(template, NAMESPACE=namespace) | |
| 920 | |
| 921 # TODO: Filter out externs that are known to the JavaScript back-end. Some | |
| 922 # of the known externs have useful declarations like @nosideeffects that | |
| 923 # might improve back-end analysis. | |
| 924 | |
| 925 names = dict() # maps name to (interface, kind) | |
| 926 for (interface, name, kind) in self._wrapping_externs: | |
| 927 if name not in _javascript_keywords: | |
| 928 if name not in names: | |
| 929 names[name] = set() | |
| 930 names[name].add((interface, kind)) | |
| 931 | |
| 932 for name in sorted(names.keys()): | |
| 933 # Simply export the property name. | |
| 934 extern = emitter.Format('$NAMESPACE.$NAME;', | |
| 935 NAMESPACE=namespace, NAME=name) | |
| 936 members.EmitRaw(extern) | |
| 937 # Add a big comment of all the attributes and operations contributing to | |
| 938 # the export. | |
| 939 filler = ' ' * (40 - 2 - len(extern)) # '2' for 2 spaces before comment. | |
| 940 separator = filler + ' //' | |
| 941 for (interface, kind) in sorted(names[name]): | |
| 942 members.Emit('$SEP $KIND $INTERFACE.$NAME', | |
| 943 NAME=name, INTERFACE=interface, KIND=kind, SEP=separator) | |
| 944 separator = ',' | |
| 945 members.Emit('\n') | |
| 946 | 729 |
| 947 | 730 |
| 948 def _GenerateJavaScriptExternInterfaces(self, | 731 def _GenerateJavaScriptExternInterfaces(self, |
| 949 database, | 732 database, |
| 950 namespace, | 733 namespace, |
| 951 window_code, | 734 window_code, |
| 952 prop_code): | 735 prop_code): |
| 953 """Generate externs for JavaScript patch code. | 736 """Generate externs for JavaScript patch code. |
| 954 """ | 737 """ |
| 955 | 738 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1057 """Format lines of text with indent.""" | 840 """Format lines of text with indent.""" |
| 1058 def FormatLine(line): | 841 def FormatLine(line): |
| 1059 if line.strip(): | 842 if line.strip(): |
| 1060 return '%s%s\n' % (indent, line) | 843 return '%s%s\n' % (indent, line) |
| 1061 else: | 844 else: |
| 1062 return '\n' | 845 return '\n' |
| 1063 return ''.join(FormatLine(line) for line in text.split('\n')) | 846 return ''.join(FormatLine(line) for line in text.split('\n')) |
| 1064 | 847 |
| 1065 # ------------------------------------------------------------------------------ | 848 # ------------------------------------------------------------------------------ |
| 1066 | 849 |
| 850 class System(object): |
| 851 """Generates all the files for one implementation.""" |
| 852 |
| 853 def __init__(self, database, emitters, output_dir): |
| 854 self._database = database |
| 855 self._emitters = emitters |
| 856 self._output_dir = output_dir |
| 857 self._dart_callback_file_paths = [] |
| 858 |
| 859 def InterfaceGenerator(self, |
| 860 interface, |
| 861 common_prefix, |
| 862 super_interface_name, |
| 863 source_filter): |
| 864 """Returns an interface generator for |interface|.""" |
| 865 return None |
| 866 |
| 867 def ProcessCallback(self, interface, info): |
| 868 pass |
| 869 |
| 870 def GenerateLibraries(self, lib_dir): |
| 871 pass |
| 872 |
| 873 def Finish(self): |
| 874 pass |
| 875 |
| 876 |
| 877 def _ProcessCallback(self, interface, info, file_path): |
| 878 """Generates a typedef for the callback interface.""" |
| 879 self._dart_callback_file_paths.append(file_path) |
| 880 code = self._emitters.FileEmitter(file_path) |
| 881 |
| 882 template_file = 'template_callback.darttemplate' |
| 883 code.Emit(''.join(open(template_file).readlines())) |
| 884 code.Emit('typedef $TYPE $NAME($ARGS);\n', |
| 885 NAME=interface.id, |
| 886 TYPE=info.type_name, |
| 887 ARGS=info.arg_implementation_declaration) |
| 888 |
| 889 def _GenerateLibFile(self, lib_template, lib_file_path, file_paths): |
| 890 """Generates a lib file from a template and a list of files.""" |
| 891 # Load template. |
| 892 template = ''.join(open(lib_template).readlines()) |
| 893 # Generate the .lib file. |
| 894 lib_file_contents = self._emitters.FileEmitter(lib_file_path) |
| 895 |
| 896 # Emit the list of #source directives. |
| 897 list_emitter = lib_file_contents.Emit(template) |
| 898 lib_file_dir = os.path.dirname(lib_file_path) |
| 899 for path in sorted(file_paths): |
| 900 relpath = os.path.relpath(path, lib_file_dir) |
| 901 list_emitter.Emit("#source('$PATH');\n", PATH=relpath) |
| 902 |
| 903 |
| 904 def _BaseDefines(self, interface): |
| 905 """Returns a set of names (strings) for members defined in a base class. |
| 906 """ |
| 907 def WalkParentChain(interface): |
| 908 if interface.parents: |
| 909 # Only consider primary parent, secondary parents are not on the |
| 910 # implementation class inheritance chain. |
| 911 parent = interface.parents[0] |
| 912 if _IsDartCollectionType(parent.type.id): |
| 913 return |
| 914 if self._database.HasInterface(parent.type.id): |
| 915 parent_interface = self._database.GetInterface(parent.type.id) |
| 916 for attr in parent_interface.attributes: |
| 917 result.add(attr.id) |
| 918 for op in parent_interface.operations: |
| 919 result.add(op.id) |
| 920 WalkParentChain(parent_interface) |
| 921 |
| 922 result = set() |
| 923 WalkParentChain(interface) |
| 924 return result; |
| 925 |
| 926 |
| 927 # ------------------------------------------------------------------------------ |
| 928 |
| 929 class WrappingInterfacesSystem(System): |
| 930 |
| 931 def __init__(self, database, emitters, output_dir): |
| 932 super(WrappingInterfacesSystem, self).__init__( |
| 933 database, emitters, output_dir) |
| 934 self._dart_interface_file_paths = [] |
| 935 |
| 936 |
| 937 def InterfaceGenerator(self, |
| 938 interface, |
| 939 common_prefix, |
| 940 super_interface_name, |
| 941 source_filter): |
| 942 """.""" |
| 943 interface_name = interface.id |
| 944 dart_interface_file_path = self._FilePathForDartInterface(interface_name) |
| 945 |
| 946 self._dart_interface_file_paths.append(dart_interface_file_path) |
| 947 |
| 948 dart_interface_code = self._emitters.FileEmitter(dart_interface_file_path) |
| 949 |
| 950 template_file = 'template_interface_%s.darttemplate' % interface_name |
| 951 if not os.path.exists(template_file): |
| 952 template_file = 'template_interface.darttemplate' |
| 953 template = ''.join(open(template_file).readlines()) |
| 954 |
| 955 return DartInterfaceGenerator( |
| 956 interface, dart_interface_code, |
| 957 template, |
| 958 common_prefix, super_interface_name, |
| 959 source_filter) |
| 960 |
| 961 def ProcessCallback(self, interface, info): |
| 962 """Generates a typedef for the callback interface.""" |
| 963 interface_name = interface.id |
| 964 file_path = self._FilePathForDartInterface(interface_name) |
| 965 self._ProcessCallback(interface, info, file_path) |
| 966 |
| 967 def GenerateLibraries(self, lib_dir): |
| 968 # Library generated for implementation. |
| 969 self._GenerateLibFile( |
| 970 'template_wrapping_dom.darttemplate', |
| 971 os.path.join(lib_dir, 'wrapping_dom.dart'), |
| 972 (self._dart_interface_file_paths + |
| 973 self._dart_callback_file_paths + |
| 974 # FIXME: Move the implementation to a separate |
| 975 # library. |
| 976 self._implementation_system._dart_wrapping_file_paths |
| 977 )) |
| 978 |
| 979 |
| 980 def _FilePathForDartInterface(self, interface_name): |
| 981 """Returns the file path of the Dart interface definition.""" |
| 982 return os.path.join(self._output_dir, 'src', 'interface', |
| 983 '%s.dart' % interface_name) |
| 984 |
| 985 |
| 986 # ------------------------------------------------------------------------------ |
| 987 |
| 988 class WrappingImplementationSystem(System): |
| 989 |
| 990 def __init__(self, database, emitters, output_dir): |
| 991 """Prepared for generating wrapping implementation. |
| 992 |
| 993 - Creates emitter for JS code. |
| 994 - Creates emitter for Dart code. |
| 995 """ |
| 996 super(WrappingImplementationSystem, self).__init__( |
| 997 database, emitters, output_dir) |
| 998 self._dart_wrapping_file_paths = [] |
| 999 |
| 1000 js_file_name = os.path.join(output_dir, 'wrapping_dom.js') |
| 1001 code = self._emitters.FileEmitter(js_file_name) |
| 1002 template = ''.join(open('template_wrapping_dom.js').readlines()) |
| 1003 (self._wrapping_js_natives, |
| 1004 self._wrapping_map) = code.Emit(template) |
| 1005 |
| 1006 _logger.info('Started Generating %s' % js_file_name) |
| 1007 |
| 1008 # Set of (interface, name, kind), kind is 'attribute' or 'operation'. |
| 1009 self._wrapping_externs = set() |
| 1010 |
| 1011 |
| 1012 def InterfaceGenerator(self, |
| 1013 interface, |
| 1014 common_prefix, |
| 1015 super_interface_name, |
| 1016 source_filter): |
| 1017 """.""" |
| 1018 interface_name = interface.id |
| 1019 dart_wrapping_file_path = self._FilePathForDartWrappingImpl(interface_name) |
| 1020 |
| 1021 self._dart_wrapping_file_paths.append(dart_wrapping_file_path) |
| 1022 |
| 1023 dart_code = self._emitters.FileEmitter(dart_wrapping_file_path) |
| 1024 dart_code.Emit( |
| 1025 ''.join(open('template_wrapping_impl.darttemplate').readlines())) |
| 1026 return WrappingInterfaceGenerator(interface, super_interface_name, |
| 1027 dart_code, self._wrapping_js_natives, |
| 1028 self._wrapping_map, |
| 1029 self._wrapping_externs, |
| 1030 self._BaseDefines(interface)) |
| 1031 |
| 1032 def ProcessCallback(self, interface, info): |
| 1033 pass |
| 1034 |
| 1035 def GenerateLibraries(self, lib_dir): |
| 1036 pass |
| 1037 |
| 1038 def Finish(self): |
| 1039 self._GenerateJavaScriptExternsWrapping(self._database, self._output_dir) |
| 1040 |
| 1041 |
| 1042 def _FilePathForDartWrappingImpl(self, interface_name): |
| 1043 """Returns the file path of the Dart wrapping implementation.""" |
| 1044 return os.path.join(self._output_dir, 'src', 'wrapping', |
| 1045 '_%sWrappingImplementation.dart' % interface_name) |
| 1046 |
| 1047 def _GenerateJavaScriptExternsWrapping(self, database, output_dir): |
| 1048 """Generates a JavaScript externs file. |
| 1049 |
| 1050 Generates an externs file that is consistent with generated JavaScript code |
| 1051 and Dart APIs for the wrapping implementation. |
| 1052 """ |
| 1053 externs_file_name = os.path.join(output_dir, 'wrapping_dom_externs.js') |
| 1054 code = self._emitters.FileEmitter(externs_file_name) |
| 1055 _logger.info('Started generating %s' % externs_file_name) |
| 1056 |
| 1057 template = ''.join(open('template_wrapping_dom_externs.js').readlines()) |
| 1058 namespace = 'dom_externs' |
| 1059 members = code.Emit(template, NAMESPACE=namespace) |
| 1060 |
| 1061 # TODO: Filter out externs that are known to the JavaScript back-end. Some |
| 1062 # of the known externs have useful declarations like @nosideeffects that |
| 1063 # might improve back-end analysis. |
| 1064 |
| 1065 names = dict() # maps name to (interface, kind) |
| 1066 for (interface, name, kind) in self._wrapping_externs: |
| 1067 if name not in _javascript_keywords: |
| 1068 if name not in names: |
| 1069 names[name] = set() |
| 1070 names[name].add((interface, kind)) |
| 1071 |
| 1072 for name in sorted(names.keys()): |
| 1073 # Simply export the property name. |
| 1074 extern = emitter.Format('$NAMESPACE.$NAME;', |
| 1075 NAMESPACE=namespace, NAME=name) |
| 1076 members.EmitRaw(extern) |
| 1077 # Add a big comment of all the attributes and operations contributing to |
| 1078 # the export. |
| 1079 filler = ' ' * (40 - 2 - len(extern)) # '2' for 2 spaces before comment. |
| 1080 separator = filler + ' //' |
| 1081 for (interface, kind) in sorted(names[name]): |
| 1082 members.Emit('$SEP $KIND $INTERFACE.$NAME', |
| 1083 NAME=name, INTERFACE=interface, KIND=kind, SEP=separator) |
| 1084 separator = ',' |
| 1085 members.Emit('\n') |
| 1086 |
| 1087 # ------------------------------------------------------------------------------ |
| 1088 |
| 1089 class FrogSystem(System): |
| 1090 |
| 1091 def __init__(self, database, emitters, output_dir): |
| 1092 super(FrogSystem, self).__init__(database, emitters, output_dir) |
| 1093 self._dart_frog_file_paths = [] |
| 1094 |
| 1095 def InterfaceGenerator(self, |
| 1096 interface, |
| 1097 common_prefix, |
| 1098 super_interface_name, |
| 1099 source_filter): |
| 1100 """.""" |
| 1101 dart_frog_file_path = self._FilePathForFrogImpl(interface.id) |
| 1102 |
| 1103 self._dart_frog_file_paths.append(dart_frog_file_path) |
| 1104 |
| 1105 dart_code = self._emitters.FileEmitter(dart_frog_file_path) |
| 1106 dart_code.Emit( |
| 1107 ''.join(open('template_frog_impl.darttemplate').readlines())) |
| 1108 return FrogInterfaceGenerator(interface, super_interface_name, |
| 1109 dart_code) |
| 1110 |
| 1111 def ProcessCallback(self, interface, info): |
| 1112 """Generates a typedef for the callback interface.""" |
| 1113 file_path = self._FilePathForFrogImpl(interface.id) |
| 1114 self._ProcessCallback(interface, info, file_path) |
| 1115 |
| 1116 def GenerateLibraries(self, lib_dir): |
| 1117 self._GenerateLibFile( |
| 1118 'template_frog_dom.darttemplate', |
| 1119 os.path.join(lib_dir, 'dom_frog.dart'), |
| 1120 self._dart_frog_file_paths + |
| 1121 self._dart_callback_file_paths) |
| 1122 |
| 1123 def Finish(self): |
| 1124 pass |
| 1125 |
| 1126 def _FilePathForFrogImpl(self, interface_name): |
| 1127 """Returns the file path of the Frog implementation.""" |
| 1128 return os.path.join(self._output_dir, 'src', 'frog', |
| 1129 '%s.dart' % interface_name) |
| 1130 |
| 1131 |
| 1132 # ------------------------------------------------------------------------------ |
| 1133 |
| 1067 class DartInterfaceGenerator(object): | 1134 class DartInterfaceGenerator(object): |
| 1068 """Generates Dart Interface definition for one DOM IDL interface.""" | 1135 """Generates Dart Interface definition for one DOM IDL interface.""" |
| 1069 | 1136 |
| 1070 def __init__(self, interface, emitter, template, | 1137 def __init__(self, interface, emitter, template, |
| 1071 common_prefix, super_interface, source_filter): | 1138 common_prefix, super_interface, source_filter): |
| 1072 """Generates Dart code for the given interface. | 1139 """Generates Dart code for the given interface. |
| 1073 | 1140 |
| 1074 Args: | 1141 Args: |
| 1075 interface -- an IDLInterface instance. It is assumed that all types have | 1142 interface -- an IDLInterface instance. It is assumed that all types have |
| 1076 been converted to Dart types (e.g. int, String), unless they are in the | 1143 been converted to Dart types (e.g. int, String), unless they are in the |
| (...skipping 663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1740 self.GenerateDispatch( | 1807 self.GenerateDispatch( |
| 1741 true_code, info, indent + ' ', position + 1, positive) | 1808 true_code, info, indent + ' ', position + 1, positive) |
| 1742 return True | 1809 return True |
| 1743 | 1810 |
| 1744 | 1811 |
| 1745 # ------------------------------------------------------------------------------ | 1812 # ------------------------------------------------------------------------------ |
| 1746 | 1813 |
| 1747 class FrogInterfaceGenerator(object): | 1814 class FrogInterfaceGenerator(object): |
| 1748 """Generates a Frog class for a DOM IDL interface.""" | 1815 """Generates a Frog class for a DOM IDL interface.""" |
| 1749 | 1816 |
| 1750 def __init__(self, interface, super_interface, interfaces_with_subtypes, | 1817 def __init__(self, interface, super_interface, dart_code): |
| 1751 dart_code): | |
| 1752 """Generates Dart code for the given interface. | 1818 """Generates Dart code for the given interface. |
| 1753 | 1819 |
| 1754 Args: | 1820 Args: |
| 1755 | 1821 |
| 1756 interface: an IDLInterface instance. It is assumed that all types have | 1822 interface: an IDLInterface instance. It is assumed that all types have |
| 1757 been converted to Dart types (e.g. int, String), unless they are in | 1823 been converted to Dart types (e.g. int, String), unless they are in |
| 1758 the same package as the interface. | 1824 the same package as the interface. |
| 1759 super_interface: A string or None, the name of the common interface that | 1825 super_interface: A string or None, the name of the common interface that |
| 1760 this interface implements, if any. | 1826 this interface implements, if any. |
| 1761 interfaces_with_subtypes: A set of strings names of interfaces that have | |
| 1762 at least one subtype. | |
| 1763 dart_code: an Emitter for the file containing the Dart implementation | 1827 dart_code: an Emitter for the file containing the Dart implementation |
| 1764 class. | 1828 class. |
| 1765 """ | 1829 """ |
| 1766 self._interface = interface | 1830 self._interface = interface |
| 1767 self._super_interface = super_interface | 1831 self._super_interface = super_interface |
| 1768 self._interfaces_with_subtypes = interfaces_with_subtypes | |
| 1769 self._dart_code = dart_code | 1832 self._dart_code = dart_code |
| 1770 self._current_secondary_parent = None | 1833 self._current_secondary_parent = None |
| 1771 | 1834 |
| 1772 | 1835 |
| 1773 def StartInterface(self): | 1836 def StartInterface(self): |
| 1774 interface = self._interface | 1837 interface = self._interface |
| 1775 interface_name = interface.id | 1838 interface_name = interface.id |
| 1776 | 1839 |
| 1777 self._class_name = self._ImplClassName(interface_name) | 1840 self._class_name = self._ImplClassName(interface_name) |
| 1778 | 1841 |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1952 Arguments: | 2015 Arguments: |
| 1953 info: An OperationInfo object. | 2016 info: An OperationInfo object. |
| 1954 """ | 2017 """ |
| 1955 # TODO(vsm): Handle overloads. | 2018 # TODO(vsm): Handle overloads. |
| 1956 self._members_emitter.Emit( | 2019 self._members_emitter.Emit( |
| 1957 '\n' | 2020 '\n' |
| 1958 ' $TYPE $NAME($ARGS) native;\n', | 2021 ' $TYPE $NAME($ARGS) native;\n', |
| 1959 TYPE=info.type_name, | 2022 TYPE=info.type_name, |
| 1960 NAME=info.name, | 2023 NAME=info.name, |
| 1961 ARGS=info.arg_implementation_declaration) | 2024 ARGS=info.arg_implementation_declaration) |
| OLD | NEW |