Index: client/dom/scripts/dartgenerator.py |
diff --git a/client/dom/scripts/dartgenerator.py b/client/dom/scripts/dartgenerator.py |
index 0a8184d4cacfab2ba85606a4f436a565665394fd..5952bbffd3228b2606f6f8fb19932705491772fb 100755 |
--- a/client/dom/scripts/dartgenerator.py |
+++ b/client/dom/scripts/dartgenerator.py |
@@ -365,7 +365,7 @@ class DartGenerator(object): |
def Generate(self, database, output_dir, |
module_source_preference=[], source_filter=None, |
super_database=None, common_prefix=None, super_map={}, |
- lib_dir = None): |
+ lib_dir=None, systems=[]): |
"""Generates Dart and JS files for the loaded interfaces. |
Args: |
@@ -390,28 +390,39 @@ class DartGenerator(object): |
self._ComputeInheritanceClosure() |
+ self._systems = [] |
+ |
interface_system = InterfacesSystem( |
TemplateLoader(self._template_dir, ['dom/interface', 'dom', '']), |
self._database, self._emitters, self._output_dir) |
+ self._systems.append(interface_system) |
- wrapping_system = WrappingImplementationSystem( |
- TemplateLoader(self._template_dir, ['dom/wrapping', 'dom', '']), |
- self._database, self._emitters, self._output_dir) |
+ if 'native' in systems: |
antonm
2012/02/01 13:03:43
nit: some concerns: systems may have system we don
|
+ native_system = NativeImplementationSystem( |
+ TemplateLoader(self._template_dir, ['dom/native', 'dom', '']), |
+ self._database, self._emitters, self._auxiliary_dir, |
+ self._output_dir) |
- # Makes interface files available for listing in the library for the |
- # wrapping implementation. |
+ self._systems.append(native_system) |
- wrapping_system._interface_system = interface_system |
+ if 'wrapping' in systems: |
+ wrapping_system = WrappingImplementationSystem( |
+ TemplateLoader(self._template_dir, ['dom/wrapping', 'dom', '']), |
+ self._database, self._emitters, self._output_dir) |
- frog_system = FrogSystem( |
- TemplateLoader(self._template_dir, ['dom/frog', 'dom', '']), |
- self._database, self._emitters, self._output_dir) |
+ # Makes interface files available for listing in the library for the |
+ # wrapping implementation. |
+ wrapping_system._interface_system = interface_system |
+ self._systems.append(wrapping_system) |
+ |
+ if 'frog' in systems: |
+ frog_system = FrogSystem( |
+ TemplateLoader(self._template_dir, ['dom/frog', 'dom', '']), |
+ self._database, self._emitters, self._output_dir) |
- frog_system._interface_system = interface_system |
+ frog_system._interface_system = interface_system |
+ self._systems.append(frog_system) |
- self._systems = [interface_system, |
- wrapping_system, |
- frog_system] |
# Render all interfaces into Dart and save them in files. |
for interface in database.GetInterfaces(): |
@@ -1305,29 +1316,7 @@ class WrappingInterfaceGenerator(object): |
self._type_map.Emit(' "$INTERFACE": native_$(CLASS)_create_$(CLASS),\n', |
INTERFACE=interface_name, CLASS=self._class_name) |
- base = 'DOMWrapperBase' |
- if interface.parents: |
- supertype = interface.parents[0].type.id |
- # FIXME: We're currently injecting List<..> and EventTarget as |
- # supertypes in dart.idl. We should annotate/preserve as |
- # attributes instead. For now, this hack lets the interfaces |
- # inherit, but not the classes. |
- if (not _IsDartListType(supertype) and |
- not supertype == 'EventTarget'): |
- base = self._ImplClassName(supertype) |
- if _IsDartCollectionType(supertype): |
- # List methods are injected in AddIndexer. |
- pass |
- elif supertype == 'EventTarget': |
- # Most implementors of EventTarget specify the EventListener operations |
- # again. If the operations are not specified, try to inherit from the |
- # EventTarget implementation. |
- # |
- # Applies to MessagePort. |
- if not [op for op in interface.operations if op.id == 'addEventListener']: |
- base = self._ImplClassName(supertype) |
- else: |
- base = self._ImplClassName(supertype) |
+ base = self._BaseClassName(interface) |
(self._members_emitter, |
self._top_level_emitter) = self._dart_code.Emit( |
@@ -1348,6 +1337,32 @@ class WrappingInterfaceGenerator(object): |
def _ImplClassName(self, type_name): |
return '_' + type_name + 'WrappingImplementation' |
+ def _BaseClassName(self, interface): |
+ if not interface.parents: |
+ return 'DOMWrapperBase' |
+ |
+ supertype = interface.parents[0].type.id |
+ |
+ # FIXME: We're currently injecting List<..> and EventTarget as |
+ # supertypes in dart.idl. We should annotate/preserve as |
+ # attributes instead. For now, this hack lets the interfaces |
+ # inherit, but not the classes. |
+ # List methods are injected in AddIndexer. |
+ if _IsDartListType(supertype) or _IsDartCollectionType(supertype): |
+ return 'DOMWrapperBase' |
+ |
+ if supertype == 'EventTarget': |
+ # Most implementors of EventTarget specify the EventListener operations |
+ # again. If the operations are not specified, try to inherit from the |
+ # EventTarget implementation. |
+ # |
+ # Applies to MessagePort. |
+ if not [op for op in interface.operations if op.id == 'addEventListener']: |
+ return self._ImplClassName(supertype) |
+ return 'DOMWrapperBase' |
+ |
+ return self._ImplClassName(supertype) |
+ |
def FinishInterface(self): |
""".""" |
pass |
@@ -1441,24 +1456,8 @@ class WrappingInterfaceGenerator(object): |
# |
# class YImpl extends ListBase<T> { copies of transitive XImpl methods; } |
# |
- if ('HasIndexGetter' in self._interface.ext_attrs or |
- 'HasNumericIndexGetter' in self._interface.ext_attrs): |
- method_name = '_index' |
- self._members_emitter.Emit( |
- '\n' |
- ' $TYPE operator[](int index) { return $METHOD(this, index); }\n' |
- ' static $TYPE $METHOD(var _this, int index) native;\n', |
- TYPE=element_type, METHOD=method_name) |
- self._js_code.Emit( |
- '\n' |
- 'function native_$(CLASS)_$(METHOD)(_this, index) {\n' |
- ' try {\n' |
- ' return __dom_wrap(_this.$dom[index]);\n' |
- ' } catch (e) {\n' |
- ' throw __dom_wrap_exception(e);\n' |
- ' }\n' |
- '}\n', |
- CLASS=self._class_name, METHOD=method_name) |
+ if self._HasNativeIndexGetter(self._interface): |
+ self._EmitNativeIndexGetter(self._interface, element_type) |
else: |
self._members_emitter.Emit( |
'\n' |
@@ -1467,26 +1466,8 @@ class WrappingInterfaceGenerator(object): |
' }\n', |
TYPE=element_type) |
- |
- if 'HasCustomIndexSetter' in self._interface.ext_attrs: |
- method_name = '_set_index' |
- self._members_emitter.Emit( |
- '\n' |
- ' void operator[]=(int index, $TYPE value) {\n' |
- ' return $METHOD(this, index, value);\n' |
- ' }\n' |
- ' static $METHOD(_this, index, value) native;\n', |
- TYPE=element_type, METHOD=method_name) |
- self._js_code.Emit( |
- '\n' |
- 'function native_$(CLASS)_$(METHOD)(_this, index, value) {\n' |
- ' try {\n' |
- ' return _this.$dom[index] = __dom_unwrap(value);\n' |
- ' } catch (e) {\n' |
- ' throw __dom_wrap_exception(e);\n' |
- ' }\n' |
- '}\n', |
- CLASS=self._class_name, METHOD=method_name) |
+ if self._HasNativeIndexSetter(self._interface): |
+ self._EmitNativeIndexSetter(self._interface, element_type) |
else: |
self._members_emitter.Emit( |
'\n' |
@@ -1584,6 +1565,51 @@ class WrappingInterfaceGenerator(object): |
' }\n', |
TYPE=element_type) |
+ def _HasNativeIndexGetter(self, interface): |
+ return ('HasIndexGetter' in interface.ext_attrs or |
+ 'HasNumericIndexGetter' in interface.ext_attrs) |
+ |
+ def _EmitNativeIndexGetter(self, interface, element_type): |
+ method_name = '_index' |
+ self._members_emitter.Emit( |
+ '\n' |
+ ' $TYPE operator[](int index) { return $METHOD(this, index); }\n' |
+ ' static $TYPE $METHOD(var _this, int index) native;\n', |
+ TYPE=element_type, METHOD=method_name) |
+ self._js_code.Emit( |
+ '\n' |
+ 'function native_$(CLASS)_$(METHOD)(_this, index) {\n' |
+ ' try {\n' |
+ ' return __dom_wrap(_this.$dom[index]);\n' |
+ ' } catch (e) {\n' |
+ ' throw __dom_wrap_exception(e);\n' |
+ ' }\n' |
+ '}\n', |
+ CLASS=self._class_name, METHOD=method_name) |
+ |
+ def _HasNativeIndexSetter(self, interface): |
+ return 'HasCustomIndexSetter' in interface.ext_attrs |
+ |
+ def _EmitNativeIndexSetter(self, interface, element_type): |
+ method_name = '_set_index' |
+ self._members_emitter.Emit( |
+ '\n' |
+ ' void operator[]=(int index, $TYPE value) {\n' |
+ ' return $METHOD(this, index, value);\n' |
+ ' }\n' |
+ ' static $METHOD(_this, index, value) native;\n', |
+ TYPE=element_type, METHOD=method_name) |
+ self._js_code.Emit( |
+ '\n' |
+ 'function native_$(CLASS)_$(METHOD)(_this, index, value) {\n' |
+ ' try {\n' |
+ ' return _this.$dom[index] = __dom_unwrap(value);\n' |
+ ' } catch (e) {\n' |
+ ' throw __dom_wrap_exception(e);\n' |
+ ' }\n' |
+ '}\n', |
+ CLASS=self._class_name, METHOD=method_name) |
+ |
def AddOperation(self, info): |
""" |
Arguments: |
@@ -2034,3 +2060,223 @@ class FrogInterfaceGenerator(object): |
NAME=info.name, |
PARAMS=info.ParametersImplementationDeclaration( |
lambda type_name: self._NarrowInputType(type_name))) |
+ |
+ |
+# ------------------------------------------------------------------------------ |
+ |
+class NativeImplementationSystem(System): |
+ |
+ def __init__(self, templates, database, emitters, auxiliary_dir, output_dir): |
+ super(NativeImplementationSystem, self).__init__( |
+ templates, database, emitters, output_dir) |
+ |
+ self._auxiliary_dir = auxiliary_dir |
+ self._dom_public_files = [] |
+ self._dom_impl_files = [] |
+ |
+ def InterfaceGenerator(self, |
+ interface, |
+ common_prefix, |
+ super_interface_name, |
+ source_filter): |
+ interface_name = interface.id |
+ |
+ dart_interface_path = self._FilePathForDartInterface(interface_name) |
+ self._dom_public_files.append(dart_interface_path) |
+ |
+ dart_impl_path = self._FilePathForDartImplementation(interface_name) |
+ self._dom_impl_files.append(dart_impl_path) |
+ |
+ return NativeImplementationGenerator(interface, super_interface_name, |
+ self._emitters.FileEmitter(dart_impl_path), |
+ self._BaseDefines(interface), |
+ self._templates) |
+ |
+ def ProcessCallback(self, interface, info): |
+ self._dom_public_files.append(self._FilePathForDartInterface(interface.id)) |
+ |
+ def GenerateLibraries(self, lib_dir): |
+ auxiliary_dir = os.path.relpath(self._auxiliary_dir, self._output_dir) |
+ |
+ # Generate dom_public.dart. |
+ dom_public_path = os.path.join(self._output_dir, 'dom_public.dart') |
+ |
+ dom_public_imports_emitter = emitter.Emitter() |
+ for file in self._dom_public_files: |
+ path = os.path.relpath(file, os.path.dirname(dom_public_path)) |
+ dom_public_imports_emitter.Emit('#source("$PATH");\n', PATH=path) |
+ |
+ dom_public_emitter = self._emitters.FileEmitter(dom_public_path) |
+ dom_public_emitter.Emit(self._templates.Load('dom_public.darttemplate'), |
+ AUXILIARY_DIR=auxiliary_dir, |
+ SOURCES=dom_public_imports_emitter.Fragments()) |
+ |
+ # Generate dom_impl.dart. |
+ dom_impl_path = os.path.join(self._output_dir, 'dom_impl.dart') |
+ |
+ dom_impl_imports_emitter = emitter.Emitter() |
+ for file in self._dom_impl_files: |
+ path = os.path.relpath(file, os.path.dirname(dom_impl_path)) |
+ dom_impl_imports_emitter.Emit('#source("$PATH");\n', PATH=path) |
+ |
+ dom_impl_emitter = self._emitters.FileEmitter(dom_impl_path) |
+ dom_impl_emitter.Emit(self._templates.Load('dom_impl.darttemplate'), |
+ AUXILIARY_DIR=auxiliary_dir, |
+ SOURCES=dom_impl_imports_emitter.Fragments()) |
+ |
+ def Finish(self): |
+ pass |
+ |
+ def _FilePathForDartInterface(self, interface_name): |
+ return os.path.join(self._output_dir, 'src', 'interface', |
+ '%s.dart' % interface_name) |
+ |
+ def _FilePathForDartImplementation(self, interface_name): |
+ return os.path.join(self._output_dir, 'dart', |
+ '%sImplementation.dart' % interface_name) |
+ |
+ |
+class NativeImplementationGenerator(WrappingInterfaceGenerator): |
+ """Generates Dart implementation for one DOM IDL interface.""" |
+ |
+ def __init__(self, interface, super_interface, dart_impl_emitter, |
+ base_members, templates): |
+ """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. |
+ super_interface: A string or None, the name of the common interface that |
+ this interface implements, if any. |
+ dart_impl_emitter: an Emitter for the file containing the Dart |
+ implementation class. |
+ base_members: a set of names of members defined in a base class. This is |
+ used to avoid static member 'overriding' in the generated Dart code. |
+ """ |
+ self._interface = interface |
+ self._super_interface = super_interface |
+ self._dart_impl_emitter = dart_impl_emitter |
+ self._base_members = base_members |
+ self._templates = templates |
+ self._current_secondary_parent = None |
+ |
+ def StartInterface(self): |
+ self._class_name = self._ImplClassName(self._interface.id) |
+ self._members_emitter = emitter.Emitter() |
+ |
+ def _ImplClassName(self, type_name): |
+ return type_name + 'Implementation' |
+ |
+ def FinishInterface(self): |
+ interface = self._interface |
+ interface_name = interface.id |
+ |
+ base = self._BaseClassName(interface) |
+ self._dart_impl_emitter.Emit( |
+ self._templates.Load('dart_implementation.darttemplate'), |
+ CLASS=self._class_name, BASE=base, INTERFACE=interface_name, |
+ MEMBERS=self._members_emitter.Fragments()) |
+ |
+ def AddGetter(self, attr): |
+ self._members_emitter.Emit( |
+ '\n' |
+ ' $TYPE get $NAME() native "$(INTERFACE)_$(NAME)_Getter";\n', |
+ NAME=attr.id, TYPE=attr.type.id, INTERFACE=self._interface.id) |
+ |
+ def AddSetter(self, attr): |
+ self._members_emitter.Emit( |
+ '\n' |
+ ' void set $NAME($TYPE) native "$(INTERFACE)_$(NAME)_Setter";\n', |
+ NAME=attr.id, TYPE=attr.type.id, INTERFACE=self._interface.id) |
+ |
+ def _HasNativeIndexGetter(self, interface): |
+ return ('HasCustomIndexGetter' in interface.ext_attrs or |
+ 'HasNumericIndexGetter' in interface.ext_attrs) |
+ |
+ def _EmitNativeIndexGetter(self, interface, element_type): |
+ native_binding = '%s_numericIndexGetter_Callback' % interface.id |
+ self._members_emitter.Emit( |
+ '\n' |
+ ' $TYPE operator[](int index) native "$NATIVE_BINDING";\n', |
+ TYPE=element_type, NATIVE_BINDING=native_binding) |
+ |
+ def _EmitNativeIndexSetter(self, interface, element_type): |
+ native_binding = '%s_numericIndexSetter_Callback' % self._interface.id |
+ self._members_emitter.Emit( |
+ '\n' |
+ ' void operator[]=(int index, $TYPE value) native "$NATIVE_BINDING";\n', |
+ TYPE=element_type, NATIVE_BINDING=native_binding) |
+ |
+ def AddOperation(self, info): |
+ """ |
+ Arguments: |
+ info: An OperationInfo object. |
+ """ |
+ |
+ if 'Custom' in info.overloads[0].ext_attrs: |
+ self._members_emitter.Emit( |
+ '\n' |
+ ' $TYPE $NAME($PARAMETERS) native "$(INTERFACE)_$(NAME)_Callback";\n', |
+ TYPE=info.type_name, |
+ NAME=info.name, |
+ PARAMETERS=info.ParametersImplementationDeclaration(), |
+ INTERFACE=self._interface.id) |
+ return |
+ |
+ body = self._members_emitter.Emit( |
+ '\n' |
+ ' $TYPE $NAME($PARAMETERS) {\n' |
+ '$!BODY' |
+ ' }\n', |
+ TYPE=info.type_name, |
+ NAME=info.name, |
+ PARAMETERS=info.ParametersImplementationDeclaration()) |
+ |
+ # Process in order of ascending number of arguments to ensure missing |
+ # optional arguments are processed early. |
+ overloads = sorted(info.overloads, |
+ key=lambda overload: len(overload.arguments)) |
+ self._native_version = 0 |
+ fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads) |
+ if fallthrough: |
+ body.Emit(' throw "Incorrect number or type of arguments";\n'); |
+ |
+ def GenerateSingleOperation(self, emitter, info, indent, operation): |
+ """Generates a call to a single operation. |
+ |
+ Arguments: |
+ emitter: an Emitter for the body of a block of code. |
+ info: the compound information about the operation and its overloads. |
+ indent: an indentation string for generated code. |
+ operation: the IDLOperation to call. |
+ """ |
+ |
+ arg_names = [info.arg_infos[i][0] |
+ for (i, arg) in enumerate(operation.arguments)] |
+ |
+ self._native_version += 1 |
+ native_name = '_%s' % info.name |
+ if self._native_version > 1: |
+ native_name = '%s_%s' % (native_name, self._native_version) |
+ |
+ argument_expressions = ', '.join(arg_names) |
+ if info.type_name != 'void': |
+ emitter.Emit('$(INDENT)return $NATIVENAME($ARGS);\n', |
+ INDENT=indent, |
+ NATIVENAME=native_name, |
+ ARGS=argument_expressions) |
+ else: |
+ emitter.Emit('$(INDENT)$NATIVENAME($ARGS);\n' |
+ '$(INDENT)return;\n', |
+ INDENT=indent, |
+ NATIVENAME=native_name, |
+ ARGS=argument_expressions) |
+ |
+ self._members_emitter.Emit(' $TYPE $NATIVE_NAME($PARAMS) native ' |
+ '"$(INTERFACE)$(NATIVE_NAME)_Callback";\n', |
+ NATIVE_NAME=native_name, |
+ TYPE=info.type_name, |
+ PARAMS=', '.join(arg_names), |
+ INTERFACE=self._interface.id) |