Index: client/dom/scripts/systemfrog.py |
diff --git a/client/dom/scripts/systemfrog.py b/client/dom/scripts/systemfrog.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..89fabb858bd77eefe4227e057f310eba22a660cc |
--- /dev/null |
+++ b/client/dom/scripts/systemfrog.py |
@@ -0,0 +1,324 @@ |
+#!/usr/bin/python |
+# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
+# for details. All rights reserved. Use of this source code is governed by a |
+# BSD-style license that can be found in the LICENSE file. |
+ |
+"""This module provides shared functionality for the systems to generate |
+frog binding from the IDL database.""" |
+ |
+import os |
+from generator import * |
+from systembase import * |
+ |
+class FrogSystem(System): |
+ |
+ def __init__(self, templates, database, emitters, output_dir): |
+ super(FrogSystem, self).__init__( |
+ templates, database, emitters, output_dir) |
+ self._dart_frog_file_paths = [] |
+ |
+ def InterfaceGenerator(self, |
+ interface, |
+ common_prefix, |
+ super_interface_name, |
+ source_filter): |
+ """.""" |
+ dart_frog_file_path = self._FilePathForFrogImpl(interface.id) |
+ self._dart_frog_file_paths.append(dart_frog_file_path) |
+ |
+ template_file = 'impl_%s.darttemplate' % interface.id |
+ template = self._templates.TryLoad(template_file) |
+ if not template: |
+ template = self._templates.Load('frog_impl.darttemplate') |
+ |
+ dart_code = self._emitters.FileEmitter(dart_frog_file_path) |
+ return FrogInterfaceGenerator(self, interface, template, |
+ super_interface_name, dart_code) |
+ |
+ def GenerateLibraries(self, lib_dir): |
+ self._GenerateLibFile( |
+ 'frog_dom.darttemplate', |
+ os.path.join(lib_dir, 'dom_frog.dart'), |
+ (self._interface_system._dart_interface_file_paths + |
+ self._interface_system._dart_callback_file_paths + |
+ self._dart_frog_file_paths)) |
+ |
+ def Finish(self): |
+ pass |
+ |
+ def _FilePathForFrogImpl(self, interface_name): |
+ """Returns the file path of the Frog implementation.""" |
+ return os.path.join(self._output_dir, 'src', 'frog', |
+ '%s.dart' % interface_name) |
+ |
+# ------------------------------------------------------------------------------ |
+ |
+class FrogInterfaceGenerator(object): |
+ """Generates a Frog class for a DOM IDL interface.""" |
+ |
+ def __init__(self, system, interface, template, super_interface, dart_code): |
+ """Generates Dart code for the given interface. |
+ |
+ Args: |
+ |
+ interface: an IDLInterface instance. It is assumed that all types have |
+ been converted to Dart types (e.g. int, String), unless they are in |
+ the same package as the interface. |
+ template: A string template. |
+ super_interface: A string or None, the name of the common interface that |
+ this interface implements, if any. |
+ dart_code: an Emitter for the file containing the Dart implementation |
+ class. |
+ """ |
+ self._system = system |
+ self._interface = interface |
+ self._template = template |
+ self._super_interface = super_interface |
+ self._dart_code = dart_code |
+ self._current_secondary_parent = None |
+ |
+ |
+ def StartInterface(self): |
+ interface = self._interface |
+ interface_name = interface.id |
+ self._class_name = self._ImplClassName(interface_name) |
+ |
+ base = None |
+ if interface.parents: |
+ supertype = interface.parents[0].type.id |
+ if IsDartCollectionType(supertype): |
+ # List methods are injected in AddIndexer. |
+ pass |
+ else: |
+ base = self._ImplClassName(supertype) |
+ |
+ native_spec = MakeNativeSpec(interface.javascript_binding_name) |
+ |
+ if base: |
+ extends = ' extends ' + base |
+ elif native_spec[0] == '=': |
+ # The implementation is a singleton with no prototype. |
+ extends = '' |
+ else: |
+ extends = ' extends _DOMTypeJs' |
+ |
+ # TODO: Include all implemented interfaces, including other Lists. |
+ implements = [interface_name] |
+ element_type = MaybeTypedArrayElementType(self._interface) |
+ if element_type: |
+ implements.append('List<' + element_type + '>') |
+ |
+ self._members_emitter = self._dart_code.Emit( |
+ self._template, |
+ #class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { |
+ #$!MEMBERS |
+ #} |
+ CLASSNAME=self._class_name, |
+ EXTENDS=extends, |
+ IMPLEMENTS=' implements ' + ', '.join(implements), |
+ NATIVESPEC=' native "' + native_spec + '"') |
+ |
+ element_type = MaybeTypedArrayElementType(interface) |
+ if element_type: |
+ self.AddTypedArrayConstructors(element_type) |
+ |
+ |
+ def FinishInterface(self): |
+ """.""" |
+ pass |
+ |
+ def _ImplClassName(self, type_name): |
+ return '_' + type_name + 'Js' |
+ |
+ def _NarrowToImplementationType(self, type_name): |
+ # TODO(sra): Move into the 'system' and cache the result. |
+ if type_name == 'EventListener': |
+ # Callbacks are typedef functions so don't have a class. |
+ return type_name |
+ if self._system._database.HasInterface(type_name): |
+ interface = self._system._database.GetInterface(type_name) |
+ if RecognizeCallback(interface): |
+ # Callbacks are typedef functions so don't have a class. |
+ return type_name |
+ else: |
+ return self._ImplClassName(type_name) |
+ return type_name |
+ |
+ def _NarrowInputType(self, type_name): |
+ return self._NarrowToImplementationType(type_name) |
+ |
+ def _NarrowOutputType(self, type_name): |
+ return self._NarrowToImplementationType(type_name) |
+ |
+ def AddConstant(self, constant): |
+ # Since we are currently generating native classes without interfaces, |
+ # generate the constants as part of the class. This will need to go away |
+ # if we revert back to generating interfaces. |
+ self._members_emitter.Emit('\n static final $TYPE $NAME = $VALUE;\n', |
+ NAME=constant.id, |
+ TYPE=constant.type.id, |
+ VALUE=constant.value) |
+ |
+ pass |
+ |
+ def AddAttribute(self, getter, setter): |
+ output_type = getter and self._NarrowOutputType(getter.type.id) |
+ input_type = setter and self._NarrowInputType(setter.type.id) |
+ |
+ # If the (getter, setter) pair is shadowing, we can't generate a shadowing |
+ # field (Issue 1633). |
+ (super_getter, super_getter_interface) = self._FindShadowedAttribute(getter) |
+ (super_setter, super_setter_interface) = self._FindShadowedAttribute(setter) |
+ if super_getter or super_setter: |
+ if getter and not setter and super_getter and not super_setter: |
+ if getter.type.id == super_getter.type.id: |
+ # Compatible getter, use the superclass property. This works because |
+ # JavaScript will do its own dynamic dispatch. |
+ self._members_emitter.Emit( |
+ '\n' |
+ ' // Use implementation from $SUPER.\n' |
+ ' // final $TYPE $NAME;\n', |
+ SUPER=super_getter_interface.id, |
+ NAME=getter.id, TYPE=output_type) |
+ return |
+ |
+ self._members_emitter.Emit('\n // Shadowing definition.') |
+ self._AddAttributeUsingProperties(getter, setter) |
+ return |
+ |
+ if getter and setter and input_type == output_type: |
+ self._members_emitter.Emit( |
+ '\n $TYPE $NAME;\n', |
+ NAME=getter.id, TYPE=output_type) |
+ return |
+ if getter and not setter: |
+ self._members_emitter.Emit( |
+ '\n final $TYPE $NAME;\n', |
+ NAME=getter.id, TYPE=output_type) |
+ return |
+ self._AddAttributeUsingProperties(getter, setter) |
+ |
+ def _AddAttributeUsingProperties(self, getter, setter): |
+ if getter: |
+ self._AddGetter(getter) |
+ if setter: |
+ self._AddSetter(setter) |
+ |
+ def _AddGetter(self, attr): |
+ # TODO(sra): Remove native body when Issue 829 fixed. |
+ self._members_emitter.Emit( |
+ '\n $TYPE get $NAME() native "return this.$NAME;";\n', |
+ NAME=attr.id, TYPE=self._NarrowOutputType(attr.type.id)) |
+ |
+ def _AddSetter(self, attr): |
+ # TODO(sra): Remove native body when Issue 829 fixed. |
+ self._members_emitter.Emit( |
+ ' void set $NAME($TYPE value) native "this.$NAME = value;";\n', |
+ NAME=attr.id, TYPE=self._NarrowInputType(attr.type.id)) |
+ |
+ def _FindShadowedAttribute(self, attr): |
+ """Returns (attribute, superinterface) or (None, None).""" |
+ def FindInParent(interface): |
+ """Returns matching attribute in parent, or None.""" |
+ if interface.parents: |
+ parent = interface.parents[0] |
+ if IsDartCollectionType(parent.type.id): |
+ return (None, None) |
+ if self._system._database.HasInterface(parent.type.id): |
+ parent_interface = self._system._database.GetInterface(parent.type.id) |
+ attr2 = FindMatchingAttribute(parent_interface, attr) |
+ if attr2: |
+ return (attr2, parent_interface) |
+ return FindInParent(parent_interface) |
+ return (None, None) |
+ |
+ return FindInParent(self._interface) if attr else (None, None) |
+ |
+ |
+ def AddSecondaryAttribute(self, interface, getter, setter): |
+ self._SecondaryContext(interface) |
+ self.AddAttribute(getter, setter) |
+ |
+ def AddSecondaryOperation(self, interface, info): |
+ self._SecondaryContext(interface) |
+ self.AddOperation(info) |
+ |
+ def AddEventAttributes(self, event_attrs): |
+ pass |
+ |
+ def _SecondaryContext(self, interface): |
+ if interface is not self._current_secondary_parent: |
+ self._current_secondary_parent = interface |
+ self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id) |
+ |
+ def AddIndexer(self, element_type): |
+ """Adds all the methods required to complete implementation of List.""" |
+ # We would like to simply inherit the implementation of everything except |
+ # get length(), [], and maybe []=. It is possible to extend from a base |
+ # array implementation class only when there is no other implementation |
+ # inheritance. There might be no implementation inheritance other than |
+ # DOMBaseWrapper for many classes, but there might be some where the |
+ # array-ness is introduced by a non-root interface: |
+ # |
+ # interface Y extends X, List<T> ... |
+ # |
+ # In the non-root case we have to choose between: |
+ # |
+ # class YImpl extends XImpl { add List<T> methods; } |
+ # |
+ # and |
+ # |
+ # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } |
+ # |
+ self._members_emitter.Emit( |
+ '\n' |
+ ' $TYPE operator[](int index) native "return this[index];";\n', |
+ TYPE=self._NarrowOutputType(element_type)) |
+ |
+ if 'CustomIndexedSetter' in self._interface.ext_attrs: |
+ self._members_emitter.Emit( |
+ '\n' |
+ ' void operator[]=(int index, $TYPE value) native "this[index] = value";\n', |
+ TYPE=self._NarrowInputType(element_type)) |
+ else: |
+ self._members_emitter.Emit( |
+ '\n' |
+ ' void operator[]=(int index, $TYPE value) {\n' |
+ ' throw new UnsupportedOperationException("Cannot assign element of immutable List.");\n' |
+ ' }\n', |
+ TYPE=self._NarrowInputType(element_type)) |
+ |
+ # TODO(sra): Use separate mixins for mutable implementations of List<T>. |
+ # TODO(sra): Use separate mixins for typed array implementations of List<T>. |
+ template_file = 'immutable_list_mixin.darttemplate' |
+ template = self._system._templates.Load(template_file) |
+ self._members_emitter.Emit(template, E=element_type) |
+ |
+ |
+ def AddTypedArrayConstructors(self, element_type): |
+ self._members_emitter.Emit( |
+ '\n' |
+ ' factory $CTOR(int length) => _construct_$CTOR(length);\n' |
+ '\n' |
+ ' factory $CTOR.fromList(List<$TYPE> list) => _construct_$CTOR(list);\n' |
+ '\n' |
+ ' factory $CTOR.fromBuffer(ArrayBuffer buffer) => _construct_$CTOR(buffer);\n' |
+ '\n' |
+ ' static _construct_$CTOR(arg) native \'return new $CTOR(arg);\';\n', |
+ CTOR=self._interface.id, |
+ TYPE=element_type) |
+ |
+ |
+ def AddOperation(self, info): |
+ """ |
+ Arguments: |
+ info: An OperationInfo object. |
+ """ |
+ # TODO(vsm): Handle overloads. |
+ self._members_emitter.Emit( |
+ '\n' |
+ ' $TYPE $NAME($PARAMS) native;\n', |
+ TYPE=self._NarrowOutputType(info.type_name), |
+ NAME=info.name, |
+ PARAMS=info.ParametersImplementationDeclaration( |
+ lambda type_name: self._NarrowInputType(type_name))) |