Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 2 # Copyright (c) 2012, 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 provides shared functionality for the system to generate | 6 """This module provides shared functionality for the system to generate |
| 7 Dart:html APIs from the IDL database.""" | 7 Dart:html APIs from the IDL database.""" |
| 8 | 8 |
| 9 from systemfrog import * | 9 from systemfrog import * |
| 10 from systeminterface import * | 10 from systeminterface import * |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 105 } | 105 } |
| 106 # Members and classes from the dom that should be removed completelly from | 106 # Members and classes from the dom that should be removed completelly from |
| 107 # dart:html. These could be expressed in the IDL instead but expressing this | 107 # dart:html. These could be expressed in the IDL instead but expressing this |
| 108 # as a simple table instead is more concise. | 108 # as a simple table instead is more concise. |
| 109 # Syntax is: ClassName.(get\.|set\.)?MemberName | 109 # Syntax is: ClassName.(get\.|set\.)?MemberName |
| 110 # Using get: and set: is optional and should only be used when a getter needs | 110 # Using get: and set: is optional and should only be used when a getter needs |
| 111 # to be suppressed but not the setter, etc. | 111 # to be suppressed but not the setter, etc. |
| 112 # TODO(jacobr): cleanup and augment this list. | 112 # TODO(jacobr): cleanup and augment this list. |
| 113 _html_library_remove = set([ | 113 _html_library_remove = set([ |
| 114 'Window.get:document', # Removed as we have a custom implementation. | 114 'Window.get:document', # Removed as we have a custom implementation. |
| 115 'Window.get:window', | |
| 115 'NodeList.item', | 116 'NodeList.item', |
| 116 "Attr.*", | 117 "Attr.*", |
| 117 # "BarProp.*", | 118 # "BarProp.*", |
| 118 # "BarInfo.*", | 119 # "BarInfo.*", |
| 119 # "Blob.webkitSlice", | 120 # "Blob.webkitSlice", |
| 120 # "CDATASection.*", | 121 # "CDATASection.*", |
| 121 # "Comment.*", | 122 # "Comment.*", |
| 122 # "DOMImplementation.*", | 123 # "DOMImplementation.*", |
| 123 "Document.get:forms", | 124 "Document.get:forms", |
| 124 # "Document.get:selectedStylesheetSet", | 125 # "Document.get:selectedStylesheetSet", |
| (...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 429 'write': 'write', | 430 'write': 'write', |
| 430 'writeend': 'writeEnd', | 431 'writeend': 'writeEnd', |
| 431 'writestart': 'writeStart' | 432 'writestart': 'writeStart' |
| 432 } | 433 } |
| 433 | 434 |
| 434 # These classes require an explicit declaration for the "on" method even though | 435 # These classes require an explicit declaration for the "on" method even though |
| 435 # they don't declare any unique events, because the concrete class hierarchy | 436 # they don't declare any unique events, because the concrete class hierarchy |
| 436 # doesn't match the interface hierarchy. | 437 # doesn't match the interface hierarchy. |
| 437 _html_explicit_event_classes = set(['DocumentFragment']) | 438 _html_explicit_event_classes = set(['DocumentFragment']) |
| 438 | 439 |
| 440 # These types are accessible from different frames. We provide a | |
| 441 # wrapper to restrict cross-frame access. Ideally, we capture this | |
| 442 # via the IDL CheckSecurity attribute. Currently, it is sometimes | |
| 443 # only defined under #define V8_BINDING. | |
|
sra1
2012/05/10 00:12:06
What are the tuple elements?
| |
| 444 _cross_frame_wrapped_types = { | |
| 445 'Window': ('get:window', 'window'), | |
| 446 'Location': ('Window.get:location', 'window.location'), | |
| 447 'History': ('Window.get:history', 'window.history'), | |
| 448 } | |
| 449 | |
| 450 _wrapped_types = _cross_frame_wrapped_types.keys() | |
|
sra1
2012/05/10 00:12:06
Comment that this list may be extended to non-cros
| |
| 451 | |
| 452 def _WrapAndReturnObject(container_interface, return_interface, expr, getter): | |
|
sra1
2012/05/10 00:12:06
Just make this wrap the expression.
_WrapIfCrossFr
| |
| 453 if return_interface in _cross_frame_wrapped_types.keys(): | |
|
sra1
2012/05/10 00:12:06
You can use 'in' on dictionaries directly.
| |
| 454 full_name = container_interface + '.get:' + getter | |
| 455 if _cross_frame_wrapped_types[return_interface][0] == full_name: | |
| 456 return 'return %s' % expr | |
| 457 return 'return _%sCrossFrameImpl._createSafe(%s)' % (return_interface, expr) | |
| 458 return 'return %s' % expr | |
| 459 | |
| 439 def _OnAttributeToEventName(on_method): | 460 def _OnAttributeToEventName(on_method): |
| 440 event_name = on_method.id[2:] | 461 event_name = on_method.id[2:] |
| 441 if event_name in _on_attribute_to_event_name_mapping: | 462 if event_name in _on_attribute_to_event_name_mapping: |
| 442 return _on_attribute_to_event_name_mapping[event_name] | 463 return _on_attribute_to_event_name_mapping[event_name] |
| 443 else: | 464 else: |
| 444 return event_name | 465 return event_name |
| 445 | 466 |
| 446 def _DomToHtmlEvents(interface_id, events): | 467 def _DomToHtmlEvents(interface_id, events): |
| 447 event_names = set(map(_OnAttributeToEventName, events)) | 468 event_names = set(map(_OnAttributeToEventName, events)) |
| 448 if interface_id in _html_manual_events: | 469 if interface_id in _html_manual_events: |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 614 def GenerateLibraries(self, lib_dir): | 635 def GenerateLibraries(self, lib_dir): |
| 615 pass | 636 pass |
| 616 | 637 |
| 617 | 638 |
| 618 def _FilePathForDartInterface(self, interface_name): | 639 def _FilePathForDartInterface(self, interface_name): |
| 619 """Returns the file path of the Dart interface definition.""" | 640 """Returns the file path of the Dart interface definition.""" |
| 620 # TODO(jmesserly): is this the right path | 641 # TODO(jmesserly): is this the right path |
| 621 return os.path.join(self._output_dir, 'html', 'interface', | 642 return os.path.join(self._output_dir, 'html', 'interface', |
| 622 '%s.dart' % interface_name) | 643 '%s.dart' % interface_name) |
| 623 | 644 |
| 645 class HtmlCrossFrameSystem(HtmlSystem): | |
|
sra1
2012/05/10 00:12:06
I have been ordering them: System1 InterfaceGener
| |
| 646 | |
| 647 def __init__(self, templates, database, emitters, output_dir, generator): | |
| 648 super(HtmlCrossFrameSystem, self).__init__( | |
| 649 templates, database, emitters, output_dir, generator) | |
| 650 self._dart_cross_frame_file_paths = [] | |
| 651 | |
| 652 def InterfaceGenerator(self, | |
| 653 interface, | |
| 654 common_prefix, | |
| 655 super_interface_name, | |
| 656 source_filter): | |
| 657 """.""" | |
| 658 if interface.id not in _cross_frame_wrapped_types.keys(): | |
| 659 return None | |
| 660 template_file = 'crossframe_%s.darttemplate' % interface.id | |
| 661 template = self._templates.TryLoad(template_file) | |
| 662 if not template: | |
| 663 template = self._templates.Load('crossframe_impl.darttemplate') | |
| 664 | |
| 665 dart_code = self._ImplFileEmitter(interface.id) | |
| 666 return HtmlCrossFrameGenerator(self, interface, template, | |
| 667 super_interface_name, dart_code, | |
| 668 self._shared) | |
| 669 | |
| 670 def GenerateLibraries(self, lib_dir): | |
| 671 pass | |
| 672 | |
| 673 def Finish(self): | |
| 674 pass | |
| 675 | |
| 676 def ProcessCallback(self, interface, info): | |
| 677 pass | |
| 678 | |
| 679 def _ImplFileEmitter(self, name): | |
| 680 """Returns the file emitter of the Frog implementation file.""" | |
| 681 # TODO(jmesserly): is this the right path | |
| 682 path = os.path.join(self._output_dir, 'html', 'crossframe', | |
| 683 '%sCrossFrame.dart' % name) | |
| 684 self._dart_cross_frame_file_paths.append(path) | |
| 685 return self._emitters.FileEmitter(path) | |
| 686 | |
| 624 # ------------------------------------------------------------------------------ | 687 # ------------------------------------------------------------------------------ |
| 625 | 688 |
| 626 # TODO(jmesserly): inheritance is probably not the right way to factor this long | 689 # TODO(jmesserly): inheritance is probably not the right way to factor this long |
| 627 # term, but it makes merging better for now. | 690 # term, but it makes merging better for now. |
| 628 class HtmlDartInterfaceGenerator(DartInterfaceGenerator): | 691 class HtmlDartInterfaceGenerator(DartInterfaceGenerator): |
| 629 """Generates Dart Interface definition for one DOM IDL interface.""" | 692 """Generates Dart Interface definition for one DOM IDL interface.""" |
| 630 | 693 |
| 631 def __init__(self, interface, emitter, template, | 694 def __init__(self, interface, emitter, template, |
| 632 common_prefix, super_interface, source_filter, system, shared): | 695 common_prefix, super_interface, source_filter, system, shared): |
| 633 super(HtmlDartInterfaceGenerator, self).__init__(interface, | 696 super(HtmlDartInterfaceGenerator, self).__init__(interface, |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 706 | 769 |
| 707 emit_events, events = self._shared.GetEventAttributes(self._interface) | 770 emit_events, events = self._shared.GetEventAttributes(self._interface) |
| 708 if not emit_events: | 771 if not emit_events: |
| 709 return | 772 return |
| 710 elif events: | 773 elif events: |
| 711 self.AddEventAttributes(events) | 774 self.AddEventAttributes(events) |
| 712 else: | 775 else: |
| 713 self._EmitEventGetter(self._shared.GetParentEventsClass(self._interface)) | 776 self._EmitEventGetter(self._shared.GetParentEventsClass(self._interface)) |
| 714 | 777 |
| 715 def AddAttribute(self, getter, setter): | 778 def AddAttribute(self, getter, setter): |
| 779 if 'CheckSecurityForNode' in (getter or setter).ext_attrs: | |
|
sra1
2012/05/10 00:12:06
Comment on why.
| |
| 780 return | |
| 781 | |
| 716 dom_name = DartDomNameOfAttribute(getter) | 782 dom_name = DartDomNameOfAttribute(getter) |
| 717 html_getter_name = self._shared.RenameInHtmlLibrary( | 783 html_getter_name = self._shared.RenameInHtmlLibrary( |
| 718 self._interface, dom_name, 'get:') | 784 self._interface, dom_name, 'get:') |
| 719 html_setter_name = self._shared.RenameInHtmlLibrary( | 785 html_setter_name = self._shared.RenameInHtmlLibrary( |
| 720 self._interface, dom_name, 'set:') | 786 self._interface, dom_name, 'set:') |
| 721 | 787 |
| 722 if not html_getter_name or self._shared.IsPrivate(html_getter_name): | 788 if not html_getter_name or self._shared.IsPrivate(html_getter_name): |
| 723 getter = None | 789 getter = None |
| 724 if not html_setter_name or self._shared.IsPrivate(html_setter_name): | 790 if not html_setter_name or self._shared.IsPrivate(html_setter_name): |
| 725 setter = None | 791 setter = None |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 755 """ | 821 """ |
| 756 html_name = self._shared.RenameInHtmlLibrary( | 822 html_name = self._shared.RenameInHtmlLibrary( |
| 757 self._interface, info.name) | 823 self._interface, info.name) |
| 758 if html_name and not self._shared.IsPrivate(html_name): | 824 if html_name and not self._shared.IsPrivate(html_name): |
| 759 self._members_emitter.Emit('\n /** @domName $DOMINTERFACE.$DOMNAME */', | 825 self._members_emitter.Emit('\n /** @domName $DOMINTERFACE.$DOMNAME */', |
| 760 DOMINTERFACE=info.overloads[0].doc_js_interface_name, | 826 DOMINTERFACE=info.overloads[0].doc_js_interface_name, |
| 761 DOMNAME=info.name) | 827 DOMNAME=info.name) |
| 762 | 828 |
| 763 self._members_emitter.Emit('\n' | 829 self._members_emitter.Emit('\n' |
| 764 ' $TYPE $NAME($PARAMS);\n', | 830 ' $TYPE $NAME($PARAMS);\n', |
| 765 TYPE=info.type_name, | 831 TYPE=info.type_name, |
| 766 NAME=html_name, | 832 NAME=html_name, |
| 767 PARAMS=info.ParametersInterfaceDeclaration()) | 833 PARAMS=info.ParametersInterfaceDeclaration()) |
| 768 | 834 |
| 769 def FinishInterface(self): | 835 def FinishInterface(self): |
| 770 pass | 836 pass |
| 771 | 837 |
| 772 def AddConstant(self, constant): | 838 def AddConstant(self, constant): |
| 773 self._EmitConstant(self._members_emitter, constant) | 839 self._EmitConstant(self._members_emitter, constant) |
| 774 | 840 |
| 775 def AddEventAttributes(self, event_attrs): | 841 def AddEventAttributes(self, event_attrs): |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 898 # interface Y extends X, List<T> ... | 964 # interface Y extends X, List<T> ... |
| 899 # | 965 # |
| 900 # In the non-root case we have to choose between: | 966 # In the non-root case we have to choose between: |
| 901 # | 967 # |
| 902 # class YImpl extends XImpl { add List<T> methods; } | 968 # class YImpl extends XImpl { add List<T> methods; } |
| 903 # | 969 # |
| 904 # and | 970 # and |
| 905 # | 971 # |
| 906 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } | 972 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } |
| 907 # | 973 # |
| 974 | |
| 975 # TODO(vsm): Wrap return value if necessary. | |
| 908 self._members_emitter.Emit( | 976 self._members_emitter.Emit( |
| 909 '\n' | 977 '\n' |
| 910 ' $TYPE operator[](int index) native "return this[index];";\n', | 978 ' $TYPE operator[](int index) native "return this[index];";\n', |
| 911 TYPE=self._NarrowOutputType(element_type)) | 979 TYPE=self._NarrowOutputType(element_type)) |
| 912 | 980 |
| 913 if 'CustomIndexedSetter' in self._interface.ext_attrs: | 981 if 'CustomIndexedSetter' in self._interface.ext_attrs: |
| 914 self._members_emitter.Emit( | 982 self._members_emitter.Emit( |
| 915 '\n' | 983 '\n' |
| 916 ' void operator[]=(int index, $TYPE value) native "this[index] = valu e";\n', | 984 ' void operator[]=(int index, $TYPE value) native "this[index] = valu e";\n', |
| 917 TYPE=self._NarrowInputType(element_type)) | 985 TYPE=self._NarrowInputType(element_type)) |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 928 TYPE=self._NarrowInputType(element_type)) | 996 TYPE=self._NarrowInputType(element_type)) |
| 929 | 997 |
| 930 # TODO(sra): Use separate mixins for mutable implementations of List<T>. | 998 # TODO(sra): Use separate mixins for mutable implementations of List<T>. |
| 931 # TODO(sra): Use separate mixins for typed array implementations of List<T>. | 999 # TODO(sra): Use separate mixins for typed array implementations of List<T>. |
| 932 if self._interface.id != 'NodeList': | 1000 if self._interface.id != 'NodeList': |
| 933 template_file = 'immutable_list_mixin.darttemplate' | 1001 template_file = 'immutable_list_mixin.darttemplate' |
| 934 template = self._system._templates.Load(template_file) | 1002 template = self._system._templates.Load(template_file) |
| 935 self._members_emitter.Emit(template, E=DartType(element_type)) | 1003 self._members_emitter.Emit(template, E=DartType(element_type)) |
| 936 | 1004 |
| 937 def AddAttribute(self, getter, setter): | 1005 def AddAttribute(self, getter, setter): |
| 938 | 1006 if 'CheckSecurityForNode' in (getter or setter).ext_attrs: |
| 1007 return | |
| 939 html_getter_name = self._shared.RenameInHtmlLibrary( | 1008 html_getter_name = self._shared.RenameInHtmlLibrary( |
| 940 self._interface, DartDomNameOfAttribute(getter), 'get:', | 1009 self._interface, DartDomNameOfAttribute(getter), 'get:', |
| 941 implementation_class=True) | 1010 implementation_class=True) |
| 942 html_setter_name = self._shared.RenameInHtmlLibrary( | 1011 html_setter_name = self._shared.RenameInHtmlLibrary( |
| 943 self._interface, DartDomNameOfAttribute(getter), 'set:', | 1012 self._interface, DartDomNameOfAttribute(getter), 'set:', |
| 944 implementation_class=True) | 1013 implementation_class=True) |
| 945 | 1014 |
| 946 if not html_getter_name: | 1015 if not html_getter_name: |
| 947 getter = None | 1016 getter = None |
| 948 if not html_setter_name: | 1017 if not html_setter_name: |
| 949 setter = None | 1018 setter = None |
| 950 | 1019 |
| 951 if not getter and not setter: | 1020 if not getter and not setter: |
| 952 return | 1021 return |
| 953 | 1022 |
| 954 if ((getter and html_getter_name != getter.id) or | 1023 if ((getter and html_getter_name != getter.id) or |
| 955 (setter and html_setter_name != setter.id)): | 1024 (setter and html_setter_name != setter.id)): |
| 956 if getter: | 1025 if getter: |
| 957 self._AddRenamingGetter(getter, html_getter_name) | 1026 self._AddRenamingGetter(getter, html_getter_name) |
| 958 if setter: | 1027 if setter: |
| 959 self._AddRenamingSetter(setter, html_setter_name) | 1028 self._AddRenamingSetter(setter, html_setter_name) |
| 960 return | 1029 return |
| 961 | 1030 |
| 962 # If the (getter, setter) pair is shadowing, we can't generate a shadowing | 1031 # If the (getter, setter) pair is shadowing, we can't generate a shadowing |
| 963 # field (Issue 1633). | 1032 # field (Issue 1633). |
| 1033 | |
| 964 (super_getter, super_getter_interface) = self._FindShadowedAttribute(getter) | 1034 (super_getter, super_getter_interface) = self._FindShadowedAttribute(getter) |
| 965 (super_setter, super_setter_interface) = self._FindShadowedAttribute(setter) | 1035 (super_setter, super_setter_interface) = self._FindShadowedAttribute(setter) |
| 966 if super_getter or super_setter: | 1036 if super_getter or super_setter: |
| 967 if getter and not setter and super_getter and not super_setter: | 1037 if getter and not setter and super_getter and not super_setter: |
| 968 if DartType(getter.type.id) == DartType(super_getter.type.id): | 1038 if DartType(getter.type.id) == DartType(super_getter.type.id): |
| 969 # Compatible getter, use the superclass property. This works because | 1039 # Compatible getter, use the superclass property. This works because |
| 970 # JavaScript will do its own dynamic dispatch. | 1040 # JavaScript will do its own dynamic dispatch. |
| 971 output_type = getter and self._NarrowOutputType(getter.type.id) | 1041 output_type = getter and self._NarrowOutputType(getter.type.id) |
| 972 self._members_emitter.Emit( | 1042 self._members_emitter.Emit( |
| 973 '\n' | 1043 '\n' |
| 974 ' // Use implementation from $SUPER.\n' | 1044 ' // Use implementation from $SUPER.\n' |
| 975 ' // final $TYPE $NAME;\n', | 1045 ' // final $TYPE $NAME;\n', |
| 976 SUPER=super_getter_interface.id, | 1046 SUPER=super_getter_interface.id, |
| 977 NAME=DartDomNameOfAttribute(getter), | 1047 NAME=DartDomNameOfAttribute(getter), |
| 978 TYPE=output_type) | 1048 TYPE=output_type) |
| 979 return | 1049 return |
| 980 | 1050 |
| 981 self._members_emitter.Emit('\n // Shadowing definition.') | 1051 self._members_emitter.Emit('\n // Shadowing definition.') |
| 982 self._AddAttributeUsingProperties(getter, setter) | 1052 self._AddAttributeUsingProperties(getter, setter) |
| 983 return | 1053 return |
| 984 | 1054 |
| 985 output_type = getter and self._NarrowOutputType(getter.type.id) | 1055 # If the return type is wrapped, we cannot just map to a field. |
| 986 input_type = setter and self._NarrowInputType(setter.type.id) | 1056 if not getter or getter.type.id not in _wrapped_types: |
| 987 if getter and setter and input_type == output_type: | 1057 output_type = getter and self._NarrowOutputType(getter.type.id) |
| 988 self._members_emitter.Emit( | 1058 input_type = setter and self._NarrowInputType(setter.type.id) |
| 989 '\n $TYPE $NAME;\n', | 1059 if getter and setter and input_type == output_type: |
| 990 NAME=DartDomNameOfAttribute(getter), | 1060 self._members_emitter.Emit( |
| 991 TYPE=output_type) | 1061 '\n $TYPE $NAME;\n', |
| 992 return | 1062 NAME=DartDomNameOfAttribute(getter), |
| 993 if getter and not setter: | 1063 TYPE=output_type) |
| 994 self._members_emitter.Emit( | 1064 return |
| 995 '\n final $TYPE $NAME;\n', | 1065 if getter and not setter: |
| 996 NAME=DartDomNameOfAttribute(getter), | 1066 self._members_emitter.Emit( |
| 997 TYPE=output_type) | 1067 '\n final $TYPE $NAME;\n', |
| 998 return | 1068 NAME=DartDomNameOfAttribute(getter), |
| 1069 TYPE=output_type) | |
| 1070 return | |
| 999 self._AddAttributeUsingProperties(getter, setter) | 1071 self._AddAttributeUsingProperties(getter, setter) |
| 1000 | 1072 |
| 1001 def _AddAttributeUsingProperties(self, getter, setter): | 1073 def _AddAttributeUsingProperties(self, getter, setter): |
| 1002 if getter: | 1074 if getter: |
| 1003 self._AddGetter(getter) | 1075 self._AddGetter(getter) |
| 1004 if setter: | 1076 if setter: |
| 1005 self._AddSetter(setter) | 1077 self._AddSetter(setter) |
| 1006 | 1078 |
| 1007 def _AddGetter(self, attr): | 1079 def _AddGetter(self, attr): |
| 1008 self._AddRenamingGetter(attr, DartDomNameOfAttribute(attr)) | 1080 self._AddRenamingGetter(attr, DartDomNameOfAttribute(attr)) |
| 1009 | 1081 |
| 1010 def _AddSetter(self, attr): | 1082 def _AddSetter(self, attr): |
| 1011 self._AddRenamingSetter(attr, DartDomNameOfAttribute(attr)) | 1083 self._AddRenamingSetter(attr, DartDomNameOfAttribute(attr)) |
| 1012 | 1084 |
| 1013 def _AddRenamingGetter(self, attr, html_name): | 1085 def _AddRenamingGetter(self, attr, html_name): |
| 1086 if attr.type.id in _wrapped_types: | |
| 1087 getter = '_' + html_name | |
| 1088 else: | |
| 1089 getter = html_name | |
| 1014 return_type = self._NarrowOutputType(attr.type.id) | 1090 return_type = self._NarrowOutputType(attr.type.id) |
| 1015 self._members_emitter.Emit( | 1091 self._members_emitter.Emit( |
| 1016 '\n $TYPE get $(HTML_NAME)() native "return this.$NAME;";\n', | 1092 '\n $TYPE get $(HTML_NAME)() native "return this.$NAME;";\n', |
| 1017 HTML_NAME=html_name, | 1093 HTML_NAME=getter, |
| 1018 NAME=attr.id, | 1094 NAME=attr.id, |
| 1019 TYPE=return_type) | 1095 TYPE=return_type) |
| 1096 if attr.type.id in _wrapped_types: | |
| 1097 self._members_emitter.Emit( | |
| 1098 '\n $TYPE get $(HTML_NAME)() {' | |
|
sra1
2012/05/10 00:12:06
Any reason not to use => syntax?
| |
| 1099 '\n $BODY;' | |
| 1100 '\n }', | |
| 1101 HTML_NAME=html_name, | |
| 1102 BODY=_WrapAndReturnObject(self._interface.id, attr.type.id, | |
| 1103 getter, html_name), | |
| 1104 TYPE=attr.type.id) | |
| 1020 | 1105 |
| 1021 def _AddRenamingSetter(self, attr, html_name): | 1106 def _AddRenamingSetter(self, attr, html_name): |
| 1022 self._members_emitter.Emit( | 1107 self._members_emitter.Emit( |
| 1023 '\n void set $HTML_NAME($TYPE value)' | 1108 '\n void set $HTML_NAME($TYPE value)' |
| 1024 ' native "this.$NAME = value;";\n', | 1109 ' native "this.$NAME = value;";\n', |
| 1025 HTML_NAME=html_name, | 1110 HTML_NAME=html_name, |
| 1026 NAME=attr.id, | 1111 NAME=attr.id, |
| 1027 TYPE=self._NarrowInputType(attr.type.id)) | 1112 TYPE=self._NarrowInputType(attr.type.id)) |
| 1028 | 1113 |
| 1029 def AddOperation(self, info): | 1114 def AddOperation(self, info): |
| 1030 """ | 1115 """ |
| 1031 Arguments: | 1116 Arguments: |
| 1032 info: An OperationInfo object. | 1117 info: An OperationInfo object. |
| 1033 """ | 1118 """ |
| 1034 html_name = self._shared.RenameInHtmlLibrary( | 1119 html_name = self._shared.RenameInHtmlLibrary( |
| 1035 self._interface, info.name, implementation_class=True) | 1120 self._interface, info.name, implementation_class=True) |
| 1036 if not html_name: | 1121 if not html_name: |
| 1037 return | 1122 return |
| 1038 | 1123 |
| 1039 # Do we need a native body? | 1124 # Do we need a native body? |
|
sra1
2012/05/10 00:12:06
"Do we need a wrapper or a native body?"
| |
| 1040 if html_name != info.declared_name: | 1125 if info.type_name in _wrapped_types: |
| 1041 return_type = self._NarrowOutputType(info.type_name) | 1126 return_type = self._NarrowOutputType(info.type_name) |
| 1042 | 1127 |
| 1128 operation_emitter = self._members_emitter.Emit('$!SCOPE', | |
| 1129 INTERFACE=info.type_name, | |
| 1130 TYPE=return_type, | |
| 1131 HTML_NAME=html_name, | |
| 1132 NAME=info.declared_name, | |
| 1133 PARAMS=info.ParametersImplementationDeclaration( | |
| 1134 lambda type_name: self._NarrowInputType(type_name)), | |
| 1135 ARGLIST=info.ParametersAsArgumentList()) | |
| 1136 | |
| 1137 operation_emitter.Emit( | |
| 1138 '\n' | |
| 1139 ' $TYPE _$(HTML_NAME)($PARAMS) native "$NAME";\n') | |
| 1140 operation_emitter.Emit( | |
|
sra1
2012/05/10 00:12:06
Could fold this into the previous one.
| |
| 1141 '\n' | |
| 1142 ' $INTERFACE $(HTML_NAME)($PARAMS) =>' | |
| 1143 ' _$(INTERFACE)CrossFrameImpl._createSafe(_$HTML_NAME($ARGLIST));\n') | |
| 1144 | |
| 1145 elif html_name != info.declared_name: | |
| 1146 return_type = self._NarrowOutputType(info.type_name) | |
| 1147 | |
| 1043 operation_emitter = self._members_emitter.Emit('$!SCOPE', | 1148 operation_emitter = self._members_emitter.Emit('$!SCOPE', |
| 1044 TYPE=return_type, | 1149 TYPE=return_type, |
| 1045 HTML_NAME=html_name, | 1150 HTML_NAME=html_name, |
| 1046 NAME=info.declared_name, | 1151 NAME=info.declared_name, |
| 1047 PARAMS=info.ParametersImplementationDeclaration( | 1152 PARAMS=info.ParametersImplementationDeclaration( |
| 1048 lambda type_name: self._NarrowInputType(type_name))) | 1153 lambda type_name: self._NarrowInputType(type_name))) |
| 1049 | 1154 |
| 1050 operation_emitter.Emit( | 1155 operation_emitter.Emit( |
| 1051 '\n' | 1156 '\n' |
| 1052 ' $TYPE $(HTML_NAME)($PARAMS) native "$NAME";\n') | 1157 ' $TYPE $(HTML_NAME)($PARAMS) native "$NAME";\n') |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1118 dart_code = self._ImplFileEmitter(interface.id) | 1223 dart_code = self._ImplFileEmitter(interface.id) |
| 1119 return HtmlFrogClassGenerator(self, interface, template, | 1224 return HtmlFrogClassGenerator(self, interface, template, |
| 1120 super_interface_name, dart_code, self._shared) | 1225 super_interface_name, dart_code, self._shared) |
| 1121 | 1226 |
| 1122 def GenerateLibraries(self, lib_dir): | 1227 def GenerateLibraries(self, lib_dir): |
| 1123 self._GenerateLibFile( | 1228 self._GenerateLibFile( |
| 1124 'html_frog.darttemplate', | 1229 'html_frog.darttemplate', |
| 1125 os.path.join(lib_dir, 'html_frog.dart'), | 1230 os.path.join(lib_dir, 'html_frog.dart'), |
| 1126 (self._interface_system._dart_interface_file_paths + | 1231 (self._interface_system._dart_interface_file_paths + |
| 1127 self._interface_system._dart_callback_file_paths + | 1232 self._interface_system._dart_callback_file_paths + |
| 1233 self._cross_frame_system._dart_cross_frame_file_paths + | |
| 1128 self._dart_frog_file_paths)) | 1234 self._dart_frog_file_paths)) |
| 1129 | 1235 |
| 1130 def Finish(self): | 1236 def Finish(self): |
| 1131 pass | 1237 pass |
| 1132 | 1238 |
| 1133 def _ImplFileEmitter(self, name): | 1239 def _ImplFileEmitter(self, name): |
| 1134 """Returns the file emitter of the Frog implementation file.""" | 1240 """Returns the file emitter of the Frog implementation file.""" |
| 1135 # TODO(jmesserly): is this the right path | 1241 # TODO(jmesserly): is this the right path |
| 1136 path = os.path.join(self._output_dir, 'html', 'frog', '%s.dart' % name) | 1242 path = os.path.join(self._output_dir, 'html', 'frog', '%s.dart' % name) |
| 1137 self._dart_frog_file_paths.append(path) | 1243 self._dart_frog_file_paths.append(path) |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1182 | 1288 |
| 1183 def GenerateLibraries(self, lib_dir): | 1289 def GenerateLibraries(self, lib_dir): |
| 1184 # Library generated for implementation. | 1290 # Library generated for implementation. |
| 1185 auxiliary_dir = os.path.relpath(self._auxiliary_dir, self._output_dir) | 1291 auxiliary_dir = os.path.relpath(self._auxiliary_dir, self._output_dir) |
| 1186 | 1292 |
| 1187 self._GenerateLibFile( | 1293 self._GenerateLibFile( |
| 1188 'html_dartium.darttemplate', | 1294 'html_dartium.darttemplate', |
| 1189 os.path.join(lib_dir, 'html_dartium.dart'), | 1295 os.path.join(lib_dir, 'html_dartium.dart'), |
| 1190 (self._interface_system._dart_interface_file_paths + | 1296 (self._interface_system._dart_interface_file_paths + |
| 1191 self._interface_system._dart_callback_file_paths + | 1297 self._interface_system._dart_callback_file_paths + |
| 1298 self._cross_frame_system._dart_cross_frame_file_paths + | |
| 1192 self._dart_dartium_file_paths | 1299 self._dart_dartium_file_paths |
| 1193 ), | 1300 ), |
| 1194 AUXILIARY_DIR=MassagePath(auxiliary_dir), | 1301 AUXILIARY_DIR=MassagePath(auxiliary_dir), |
| 1195 WRAPCASES='\n'.join(self._wrap_cases)) | 1302 WRAPCASES='\n'.join(self._wrap_cases)) |
| 1196 | 1303 |
| 1197 def Finish(self): | 1304 def Finish(self): |
| 1198 pass | 1305 pass |
| 1199 | 1306 |
| 1200 # ------------------------------------------------------------------------------ | 1307 # ------------------------------------------------------------------------------ |
| 1201 | 1308 |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1379 # Constants are already defined on the interface. | 1486 # Constants are already defined on the interface. |
| 1380 pass | 1487 pass |
| 1381 | 1488 |
| 1382 def _MethodName(self, prefix, name): | 1489 def _MethodName(self, prefix, name): |
| 1383 method_name = prefix + name | 1490 method_name = prefix + name |
| 1384 if name in self._base_members: # Avoid illegal Dart 'static override'. | 1491 if name in self._base_members: # Avoid illegal Dart 'static override'. |
| 1385 method_name = method_name + '_' + self._interface.id | 1492 method_name = method_name + '_' + self._interface.id |
| 1386 return method_name | 1493 return method_name |
| 1387 | 1494 |
| 1388 def AddAttribute(self, getter, setter): | 1495 def AddAttribute(self, getter, setter): |
| 1496 if 'CheckSecurityForNode' in (getter or setter).ext_attrs: | |
| 1497 return | |
| 1389 dom_name = DartDomNameOfAttribute(getter or setter) | 1498 dom_name = DartDomNameOfAttribute(getter or setter) |
| 1390 html_getter_name = self._shared.RenameInHtmlLibrary( | 1499 html_getter_name = self._shared.RenameInHtmlLibrary( |
| 1391 self._interface, dom_name, 'get:', implementation_class=True) | 1500 self._interface, dom_name, 'get:', implementation_class=True) |
| 1392 html_setter_name = self._shared.RenameInHtmlLibrary( | 1501 html_setter_name = self._shared.RenameInHtmlLibrary( |
| 1393 self._interface, dom_name, 'set:', implementation_class=True) | 1502 self._interface, dom_name, 'set:', implementation_class=True) |
| 1394 | 1503 |
| 1395 if getter and html_getter_name: | 1504 if getter and html_getter_name: |
| 1396 self._AddGetter(getter, html_getter_name) | 1505 self._AddGetter(getter, html_getter_name) |
| 1397 if setter and html_setter_name: | 1506 if setter and html_setter_name: |
| 1398 self._AddSetter(setter, html_setter_name) | 1507 self._AddSetter(setter, html_setter_name) |
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1700 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee | 1809 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee |
| 1701 # that Y = Z-X, so we need to check for Y. | 1810 # that Y = Z-X, so we need to check for Y. |
| 1702 true_code = emitter.Emit( | 1811 true_code = emitter.Emit( |
| 1703 '$(INDENT)if ($COND) {\n' | 1812 '$(INDENT)if ($COND) {\n' |
| 1704 '$!TRUE' | 1813 '$!TRUE' |
| 1705 '$(INDENT)}\n', | 1814 '$(INDENT)}\n', |
| 1706 COND=test, INDENT=indent) | 1815 COND=test, INDENT=indent) |
| 1707 self.GenerateDispatch( | 1816 self.GenerateDispatch( |
| 1708 true_code, info, indent + ' ', position + 1, positive) | 1817 true_code, info, indent + ' ', position + 1, positive) |
| 1709 return True | 1818 return True |
| 1819 | |
| 1820 # ------------------------------------------------------------------------------ | |
| 1821 | |
| 1822 # TODO(jacobr): there is far too much duplicated code between these bindings | |
| 1823 # and the Frog bindings. A larger scale refactoring needs to be performed to | |
| 1824 # reduce the duplicated logic. | |
| 1825 class HtmlCrossFrameGenerator(object): | |
| 1826 """Generates a cross-frame implementation of interfaces that must be | |
| 1827 securely exposed to other frames/isolates. The cross-frame | |
| 1828 implementation wraps the underlying implemation, only providing APIs | |
| 1829 deemded secure.""" | |
| 1830 | |
| 1831 def __init__(self, system, interface, template, super_interface, dart_code, | |
| 1832 shared): | |
| 1833 """Generates Dart cross-frame wrapper code for the given interface. | |
| 1834 | |
| 1835 Args: | |
| 1836 system: system that is executing this generator. | |
| 1837 template: template that output is generated into. | |
| 1838 interface: an IDLInterface instance. It is assumed that all types have | |
| 1839 been converted to Dart types (e.g. int, String), unless they are in | |
| 1840 the same package as the interface. | |
| 1841 super_interface: A string or None, the name of the common interface that | |
| 1842 this interface implements, if any. | |
| 1843 dart_code: an Emitter for the file containing the Dart implementation | |
| 1844 class. | |
| 1845 shared: functionaly shared across all Html generators. | |
| 1846 """ | |
| 1847 self._system = system | |
| 1848 self._interface = interface | |
| 1849 self._super_interface = super_interface | |
| 1850 self._dart_code = dart_code | |
| 1851 self._current_secondary_parent = None | |
| 1852 self._shared = shared | |
| 1853 self._template = template | |
| 1854 | |
| 1855 def NativeObjectName(self): | |
| 1856 return '_ptr' | |
| 1857 | |
| 1858 def StartInterface(self): | |
| 1859 interface = self._interface | |
| 1860 interface_name = interface.id | |
| 1861 self._class_name = self._ImplClassName(interface_name) | |
| 1862 | |
| 1863 self._members_emitter = self._dart_code.Emit(self._template, | |
| 1864 NAME=interface_name, | |
| 1865 CLASSNAME=self._class_name, | |
| 1866 POINTER=self.NativeObjectName(), | |
| 1867 LOCAL=_cross_frame_wrapped_types[interface_name][1] | |
| 1868 ) | |
| 1869 | |
| 1870 def _ImplClassName(self, type_name): | |
| 1871 return self._shared._ImplClassName(type_name) | |
| 1872 | |
| 1873 def FinishInterface(self): | |
| 1874 """.""" | |
| 1875 pass | |
| 1876 | |
| 1877 def AddConstant(self, constant): | |
| 1878 # Constants are already defined on the interface. | |
| 1879 pass | |
| 1880 | |
| 1881 def AddAttribute(self, getter, setter): | |
| 1882 dom_name = DartDomNameOfAttribute(getter or setter) | |
| 1883 html_getter_name = self._shared.RenameInHtmlLibrary( | |
| 1884 self._interface, dom_name, 'get:', implementation_class=True) | |
| 1885 html_setter_name = self._shared.RenameInHtmlLibrary( | |
| 1886 self._interface, dom_name, 'set:', implementation_class=True) | |
| 1887 | |
| 1888 # TODO(vsm): Generate stubs that throws an error if getter or | |
| 1889 # setter is suppressed. | |
| 1890 if (getter and html_getter_name and | |
| 1891 ('DoNotCheckSecurityOnGetter' in getter.ext_attrs or | |
| 1892 'DoNotCheckSecurity' in getter.ext_attrs)): | |
| 1893 self._AddGetter(getter, html_getter_name) | |
| 1894 if (setter and html_setter_name and | |
| 1895 ('DoNotCheckSecurityOnSetter' in setter.ext_attrs or | |
| 1896 'DoNotCheckSecurity' in setter.ext_attrs)): | |
| 1897 self._AddSetter(setter, html_setter_name) | |
| 1898 | |
| 1899 def _AddGetter(self, attr, html_name): | |
| 1900 self._members_emitter.Emit( | |
| 1901 '\n' | |
| 1902 ' $TYPE get $(NAME)() => $(THIS).$NAME;\n', | |
| 1903 NAME=html_name, | |
| 1904 TYPE=DartType(attr.type.id), | |
| 1905 THIS=self.NativeObjectName()) | |
| 1906 | |
| 1907 def _AddSetter(self, attr, html_name): | |
| 1908 self._members_emitter.Emit( | |
| 1909 '\n' | |
| 1910 ' void set $(NAME)($TYPE value) { ' | |
| 1911 '$(THIS).$NAME = value; }\n', | |
| 1912 NAME=html_name, | |
| 1913 TYPE=DartType(attr.type.id), | |
| 1914 THIS=self.NativeObjectName()) | |
| 1915 | |
| 1916 def AddSecondaryAttribute(self, interface, getter, setter): | |
| 1917 pass | |
| 1918 | |
| 1919 def AddSecondaryOperation(self, interface, info): | |
| 1920 pass | |
| 1921 | |
| 1922 def AddEventAttributes(self, event_attrs): | |
| 1923 pass | |
| 1924 | |
| 1925 def AddIndexer(self, element_type): | |
| 1926 """Adds all the methods required to complete implementation of List.""" | |
| 1927 raise Exception('Indexers not yet supported for cross frame types') | |
| 1928 | |
| 1929 def AddOperation(self, info): | |
| 1930 """ | |
| 1931 Arguments: | |
| 1932 info: An OperationInfo object. | |
| 1933 """ | |
| 1934 if 'DoNotCheckSecurity' not in info.overloads[0].ext_attrs: | |
| 1935 # TODO(vsm): Generate stub that throws an error. | |
| 1936 return | |
| 1937 | |
| 1938 html_name = self._shared.RenameInHtmlLibrary( | |
| 1939 self._interface, info.name, implementation_class=True) | |
| 1940 | |
| 1941 if not html_name: | |
| 1942 return | |
| 1943 | |
| 1944 body = self._members_emitter.Emit( | |
| 1945 '\n' | |
| 1946 ' $TYPE $NAME($PARAMS) {\n' | |
| 1947 '$!BODY' | |
| 1948 ' }\n', | |
| 1949 TYPE=info.type_name, | |
| 1950 NAME=html_name, | |
| 1951 PARAMS=info.ParametersImplementationDeclaration()) | |
| 1952 | |
| 1953 # Process in order of ascending number of arguments to ensure missing | |
| 1954 # optional arguments are processed early. | |
| 1955 overloads = sorted(info.overloads, | |
| 1956 key=lambda overload: len(overload.arguments)) | |
| 1957 self._native_version = 0 | |
| 1958 fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads) | |
| 1959 if fallthrough: | |
| 1960 body.Emit(' throw "Incorrect number or type of arguments";\n'); | |
| 1961 | |
| 1962 def GenerateSingleOperation(self, emitter, info, indent, operation): | |
|
sra1
2012/05/10 00:12:06
We really need to avoid another copy of the dispat
| |
| 1963 """Generates a call to a single operation. | |
| 1964 | |
| 1965 Arguments: | |
| 1966 emitter: an Emitter for the body of a block of code. | |
| 1967 info: the compound information about the operation and its overloads. | |
| 1968 indent: an indentation string for generated code. | |
| 1969 operation: the IDLOperation to call. | |
| 1970 """ | |
| 1971 argument_expressions = ', '.join([i.name for i in info.param_infos]) | |
| 1972 | |
| 1973 if info.type_name != 'void': | |
| 1974 # We could place the logic for handling Document directly in _wrap | |
| 1975 # but we chose to place it here so that bugs in the wrapper and | |
| 1976 # wrapperless implementations are more consistent. | |
| 1977 emitter.Emit('$(INDENT)return $(THIS).$NAME($ARGS);\n', | |
| 1978 INDENT=indent, | |
| 1979 THIS=self.NativeObjectName(), | |
| 1980 NAME=info.name, | |
| 1981 ARGS=argument_expressions) | |
| 1982 else: | |
| 1983 emitter.Emit('$(INDENT)$(THIS).$NAME($ARGS);\n' | |
| 1984 '$(INDENT)return;\n', | |
| 1985 INDENT=indent, | |
| 1986 THIS=self.NativeObjectName(), | |
| 1987 NAME=info.name, | |
| 1988 ARGS=argument_expressions) | |
| 1989 | |
| 1990 def GenerateDispatch(self, emitter, info, indent, position, overloads): | |
| 1991 """Generates a dispatch to one of the overloads. | |
| 1992 | |
| 1993 Arguments: | |
| 1994 emitter: an Emitter for the body of a block of code. | |
| 1995 info: the compound information about the operation and its overloads. | |
| 1996 indent: an indentation string for generated code. | |
| 1997 position: the index of the parameter to dispatch on. | |
| 1998 overloads: a list of the remaining IDLOperations to dispatch. | |
| 1999 | |
| 2000 Returns True if the dispatch can fall through on failure, False if the code | |
| 2001 always dispatches. | |
| 2002 """ | |
| 2003 | |
| 2004 def NullCheck(name): | |
| 2005 return '%s === null' % name | |
| 2006 | |
| 2007 def TypeCheck(name, type): | |
| 2008 return '%s is %s' % (name, type) | |
| 2009 | |
| 2010 if position == len(info.param_infos): | |
| 2011 if len(overloads) > 1: | |
| 2012 raise Exception('Duplicate operations ' + str(overloads)) | |
| 2013 operation = overloads[0] | |
| 2014 self.GenerateSingleOperation(emitter, info, indent, operation) | |
| 2015 return False | |
| 2016 | |
| 2017 # FIXME: Consider a simpler dispatch that iterates over the | |
| 2018 # overloads and generates an overload specific check. Revisit | |
| 2019 # when we move to named optional arguments. | |
| 2020 | |
| 2021 # Partition the overloads to divide and conquer on the dispatch. | |
| 2022 positive = [] | |
| 2023 negative = [] | |
| 2024 first_overload = overloads[0] | |
| 2025 param = info.param_infos[position] | |
| 2026 | |
| 2027 if position < len(first_overload.arguments): | |
| 2028 # FIXME: This will not work if the second overload has a more | |
| 2029 # precise type than the first. E.g., | |
| 2030 # void foo(Node x); | |
| 2031 # void foo(Element x); | |
| 2032 type = DartType(first_overload.arguments[position].type.id) | |
| 2033 test = TypeCheck(param.name, type) | |
| 2034 pred = lambda op: (len(op.arguments) > position and | |
| 2035 DartType(op.arguments[position].type.id) == type) | |
| 2036 else: | |
| 2037 type = None | |
| 2038 test = NullCheck(param.name) | |
| 2039 pred = lambda op: position >= len(op.arguments) | |
| 2040 | |
| 2041 for overload in overloads: | |
| 2042 if pred(overload): | |
| 2043 positive.append(overload) | |
| 2044 else: | |
| 2045 negative.append(overload) | |
| 2046 | |
| 2047 if positive and negative: | |
| 2048 (true_code, false_code) = emitter.Emit( | |
| 2049 '$(INDENT)if ($COND) {\n' | |
| 2050 '$!TRUE' | |
| 2051 '$(INDENT)} else {\n' | |
| 2052 '$!FALSE' | |
| 2053 '$(INDENT)}\n', | |
| 2054 COND=test, INDENT=indent) | |
| 2055 fallthrough1 = self.GenerateDispatch( | |
| 2056 true_code, info, indent + ' ', position + 1, positive) | |
| 2057 fallthrough2 = self.GenerateDispatch( | |
| 2058 false_code, info, indent + ' ', position, negative) | |
| 2059 return fallthrough1 or fallthrough2 | |
| 2060 | |
| 2061 if negative: | |
| 2062 raise Exception('Internal error, must be all positive') | |
| 2063 | |
| 2064 # All overloads require the same test. Do we bother? | |
| 2065 | |
| 2066 # If the test is the same as the method's formal parameter then checked mode | |
| 2067 # will have done the test already. (It could be null too but we ignore that | |
| 2068 # case since all the overload behave the same and we don't know which types | |
| 2069 # in the IDL are not nullable.) | |
| 2070 if type == param.dart_type: | |
| 2071 return self.GenerateDispatch( | |
| 2072 emitter, info, indent, position + 1, positive) | |
| 2073 | |
| 2074 # Otherwise the overloads have the same type but the type is a substype of | |
| 2075 # the method's synthesized formal parameter. e.g we have overloads f(X) and | |
| 2076 # f(Y), implemented by the synthesized method f(Z) where X<Z and Y<Z. The | |
| 2077 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee | |
| 2078 # that Y = Z-X, so we need to check for Y. | |
| 2079 true_code = emitter.Emit( | |
| 2080 '$(INDENT)if ($COND) {\n' | |
| 2081 '$!TRUE' | |
| 2082 '$(INDENT)}\n', | |
| 2083 COND=test, INDENT=indent) | |
| 2084 self.GenerateDispatch( | |
| 2085 true_code, info, indent + ' ', position + 1, positive) | |
| 2086 return True | |
| OLD | NEW |