Chromium Code Reviews| Index: client/dom/scripts/dartgenerator.py |
| diff --git a/client/dom/scripts/dartgenerator.py b/client/dom/scripts/dartgenerator.py |
| index 2b1b62c3738fef5212a367f7767ea34245e724ad..732b225a0511875209cdcbac3a596696dd619378 100755 |
| --- a/client/dom/scripts/dartgenerator.py |
| +++ b/client/dom/scripts/dartgenerator.py |
| @@ -401,7 +401,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, native=False): |
| """Generates Dart and JS files for the loaded interfaces. |
| Args: |
| @@ -426,28 +426,37 @@ 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) |
| + |
| + if native: |
| + native_system = NativeImplementationSystem( |
| + TemplateLoader(self._template_dir, ['dom/native', 'dom', '']), |
| + self._database, self._emitters, self._auxiliary_dir, |
| + self._output_dir) |
| + self._systems.append(native_system) |
| + else: |
|
sra1
2012/01/26 05:35:30
Is it possible to generate everything at once?
podivilov
2012/01/26 08:28:51
Yes, but it would be a little bit slower, will pro
sra1
2012/01/26 18:32:16
I want to make sure that all targets *can* be gene
podivilov
2012/01/30 19:23:50
Added --systems switch. It defaults to 'frog,wrapp
|
| + wrapping_system = WrappingImplementationSystem( |
| + TemplateLoader(self._template_dir, ['dom/wrapping', 'dom', '']), |
| + self._database, self._emitters, self._output_dir) |
| - wrapping_system = WrappingImplementationSystem( |
| - TemplateLoader(self._template_dir, ['dom/wrapping', 'dom', '']), |
| - self._database, self._emitters, self._output_dir) |
| + # Makes interface files available for listing in the library for the |
| + # wrapping implementation. |
| - # Makes interface files available for listing in the library for the |
| - # wrapping implementation. |
| + wrapping_system._interface_system = interface_system |
| + self._systems.append(wrapping_system) |
| - wrapping_system._interface_system = interface_system |
| + frog_system = FrogSystem( |
| + TemplateLoader(self._template_dir, ['dom/frog', '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) |
| + frog_system._interface_system = interface_system |
| + self._systems.append(frog_system) |
| - frog_system._interface_system = interface_system |
| - |
| - self._systems = [interface_system, |
| - wrapping_system, |
| - frog_system] |
| # Render all interfaces into Dart and save them in files. |
| for interface in database.GetInterfaces(): |
| @@ -1330,29 +1339,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( |
| @@ -1373,6 +1360,36 @@ class WrappingInterfaceGenerator(object): |
| def _ImplClassName(self, type_name): |
| return '_' + type_name + 'WrappingImplementation' |
| + def _BaseClassName(self, interface): |
|
antonm
2012/01/26 11:06:14
it looks like you can simplify this function w/ ea
podivilov
2012/01/26 14:18:57
Done.
|
| + base = 'DOMWrapperBase' |
| + |
| + if not interface.parents: |
| + return base |
| + |
| + 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) |
| + |
| + return base |
| + |
| def FinishInterface(self): |
| """.""" |
| pass |
| @@ -1466,24 +1483,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)): |
|
antonm
2012/01/26 11:06:14
nit: no need in extra ()
podivilov
2012/01/26 14:18:57
Done.
|
| + self._EmitNativeIndexGetter(self._interface, element_type) |
| else: |
| self._members_emitter.Emit( |
| '\n' |
| @@ -1494,24 +1495,7 @@ class WrappingInterfaceGenerator(object): |
| if 'HasCustomIndexSetter' in self._interface.ext_attrs: |
|
antonm
2012/01/26 11:06:14
for symmetry, shouldn't you add _HasNativeIndexSet
podivilov
2012/01/26 14:18:57
Done.
|
| - 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) |
| + self._EmitNativeIndexSetter(self._interface, element_type) |
| else: |
| self._members_emitter.Emit( |
| '\n' |
| @@ -1609,6 +1593,48 @@ 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' |
|
antonm
2012/01/26 11:06:14
looks like if you keep a blank line before $MEMBER
podivilov
2012/01/26 14:18:57
You could not rely on ordering here, native index
|
| + ' $TYPE operator[](int index) { return $METHOD(this, index); }\n' |
|
antonm
2012/01/26 11:06:14
$TYPE operator[](int index) => $METHOD(this, index
podivilov
2012/01/26 14:18:57
This change should produce zero diff in wrapping d
|
| + ' 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 _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: |
| @@ -2063,3 +2089,213 @@ 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_imports_emitter = emitter.Emitter() |
| + self._dom_impl_imports_emitter = emitter.Emitter() |
| + |
| + def InterfaceGenerator(self, |
| + interface, |
| + common_prefix, |
| + super_interface_name, |
| + source_filter): |
| + interface_name = interface.id |
| + |
| + self._dom_public_imports_emitter.Emit('#source("$PATH");\n', |
| + PATH=self._FilePathForDartInterface(interface_name)) |
| + self._dom_impl_imports_emitter.Emit('#source("$PATH");\n', |
| + PATH=self._FilePathForDartImpl(interface_name)) |
| + |
| + dart_impl_path = os.path.join(self._output_dir, |
| + self._FilePathForDartImpl(interface_name)) |
|
antonm
2012/01/26 11:06:14
do you want to invoke this _FilePathForDartImpl tw
|
| + dart_impl_emitter = self._emitters.FileEmitter(dart_impl_path) |
| + |
| + return NativeImplementationGenerator(interface, super_interface_name, |
| + dart_impl_emitter, |
| + self._BaseDefines(interface), |
| + self._templates) |
| + |
| + def ProcessCallback(self, interface, info): |
| + self._dom_public_imports_emitter.Emit('#source("$PATH");\n', |
| + PATH=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_emitter = self._emitters.FileEmitter(dom_public_path) |
| + dom_public_emitter.Emit(self._templates.Load('dom_public.darttemplate'), |
| + AUXILIARY_DIR=auxiliary_dir, |
| + SOURCES=self._dom_public_imports_emitter.Fragments()) |
| + |
| + # Generate dom_impl.dart |
| + dom_impl_path = os.path.join(self._output_dir, 'dom_impl.dart') |
| + dom_impl_emitter = self._emitters.FileEmitter(dom_impl_path) |
| + dom_impl_emitter.Emit(self._templates.Load('dom_impl.darttemplate'), |
| + AUXILIARY_DIR=auxiliary_dir, |
| + SOURCES=self._dom_impl_imports_emitter.Fragments()) |
| + |
| + def Finish(self): |
| + pass |
| + |
| + def _FilePathForDartInterface(self, interface_name): |
| + return os.path.join('src', 'interface', '%s.dart' % interface_name) |
| + |
| + def _FilePathForDartImpl(self, interface_name): |
| + return os.path.join('dart', '%sImplementation.dart' % interface_name) |
| + |
| + |
| +class NativeImplementationGenerator(WrappingInterfaceGenerator): |
| + """Generates Dart and c++ implementation for one DOM IDL interface.""" |
|
antonm
2012/01/26 11:06:14
nit: C++
podivilov
2012/01/26 14:18:57
Done.
|
| + |
| + 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): |
|
antonm
2012/01/26 11:06:14
do you need this override?
podivilov
2012/01/26 14:18:57
Yes, it repeats the logic in CodeGeneratorDart.pm.
|
| + 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': |
|
antonm
2012/01/26 11:06:14
do you need this if? Maybe introduce prefix which
podivilov
2012/01/26 14:18:57
Note that else clause has additional return statem
|
| + 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) |