Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(504)

Unified Diff: client/dom/scripts/systemwrapping.py

Issue 9424035: Move native system generator to a separate script. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« client/dom/scripts/systemnative.py ('K') | « client/dom/scripts/systemnative.py ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: client/dom/scripts/systemwrapping.py
diff --git a/client/dom/scripts/systemwrapping.py b/client/dom/scripts/systemwrapping.py
new file mode 100644
index 0000000000000000000000000000000000000000..53d79a5cbe66930c387abe44cbdf8ee497e32edb
--- /dev/null
+++ b/client/dom/scripts/systemwrapping.py
@@ -0,0 +1,520 @@
+#!/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
+wrapping binding from the IDL database."""
+
+import os
+from generator import *
+from systembase import *
+
+class WrappingImplementationSystem(System):
+
+ def __init__(self, templates, database, emitters, output_dir):
+ """Prepared for generating wrapping implementation.
+
+ - Creates emitter for JS code.
+ - Creates emitter for Dart code.
+ """
+ super(WrappingImplementationSystem, self).__init__(
+ templates, database, emitters, output_dir)
+ self._dart_wrapping_file_paths = []
+
+
+ def InterfaceGenerator(self,
+ interface,
+ common_prefix,
+ super_interface_name,
+ source_filter):
+ """."""
+ interface_name = interface.id
+ dart_wrapping_file_path = self._FilePathForDartWrappingImpl(interface_name)
+
+ self._dart_wrapping_file_paths.append(dart_wrapping_file_path)
+
+ dart_code = self._emitters.FileEmitter(dart_wrapping_file_path)
+ dart_code.Emit(self._templates.Load('wrapping_impl.darttemplate'))
+ return WrappingInterfaceGenerator(interface, super_interface_name,
+ dart_code,
+ self._BaseDefines(interface))
+
+ def ProcessCallback(self, interface, info):
+ pass
+
+ def GenerateLibraries(self, lib_dir):
+ # Library generated for implementation.
+ self._GenerateLibFile(
+ 'wrapping_dom.darttemplate',
+ os.path.join(lib_dir, 'wrapping_dom.dart'),
+ (self._interface_system._dart_interface_file_paths +
+ self._interface_system._dart_callback_file_paths +
+ # FIXME: Move the implementation to a separate library.
+ self._dart_wrapping_file_paths
+ ))
+
+
+ def Finish(self):
+ pass
+
+
+ def _FilePathForDartWrappingImpl(self, interface_name):
+ """Returns the file path of the Dart wrapping implementation."""
+ return os.path.join(self._output_dir, 'src', 'wrapping',
+ '_%sWrappingImplementation.dart' % interface_name)
+
+class WrappingInterfaceGenerator(object):
+ """Generates Dart and JS implementation for one DOM IDL interface."""
+
+ def __init__(self, interface, super_interface, dart_code, base_members):
+ """Generates Dart and JS 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_code: 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_code = dart_code
+ self._base_members = base_members
+ self._current_secondary_parent = None
+
+
+ def StartInterface(self):
+ interface = self._interface
+ interface_name = interface.id
+
+ self._class_name = self._ImplClassName(interface_name)
+
+ base = self._BaseClassName(interface)
+
+ (self._members_emitter,
+ self._top_level_emitter) = self._dart_code.Emit(
+ '\n'
+ 'class $CLASS extends $BASE implements $INTERFACE {\n'
+ ' $CLASS() : super() {}\n'
+ '\n'
+ ' static create_$CLASS() native {\n'
+ ' return new $CLASS();\n'
+ ' }\n'
+ '$!MEMBERS'
+ '\n'
+ ' String get typeName() { return "$INTERFACE"; }\n'
+ '}\n'
+ '$!TOP_LEVEL',
+ CLASS=self._class_name, BASE=base, INTERFACE=interface_name)
+
+ 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
+
+ def AddConstant(self, constant):
+ # Constants are already defined on the interface.
+ pass
+
+ def _MethodName(self, prefix, name):
+ method_name = prefix + name
+ if name in self._base_members: # Avoid illegal Dart 'static override'.
+ method_name = method_name + '_' + self._interface.id
+ return method_name
+
+ def AddAttribute(self, getter, setter):
+ if getter:
+ self._AddGetter(getter)
+ if setter:
+ self._AddSetter(setter)
+
+ def _AddGetter(self, attr):
+ # FIXME: Instead of injecting the interface name into the method when it is
+ # also implemented in the base class, suppress the method altogether if it
+ # has the same signature. I.e., let the JS do the virtual dispatch instead.
+ method_name = self._MethodName('_get_', attr.id)
+ self._members_emitter.Emit(
+ '\n'
+ ' $TYPE get $NAME() { return $METHOD(this); }\n'
+ ' static $TYPE $METHOD(var _this) native;\n',
+ NAME=attr.id, TYPE=attr.type.id, METHOD=method_name)
+
+ def _AddSetter(self, attr):
+ # FIXME: See comment on getter.
+ method_name = self._MethodName('_set_', attr.id)
+ self._members_emitter.Emit(
+ '\n'
+ ' void set $NAME($TYPE value) { $METHOD(this, value); }\n'
+ ' static void $METHOD(var _this, $TYPE value) native;\n',
+ NAME=attr.id, TYPE=attr.type.id, METHOD=method_name)
+
+ 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; }
+ #
+ if self._HasNativeIndexGetter(self._interface):
+ self._EmitNativeIndexGetter(self._interface, element_type)
+ else:
+ self._members_emitter.Emit(
+ '\n'
+ ' $TYPE operator[](int index) {\n'
+ ' return item(index);\n'
+ ' }\n',
+ TYPE=element_type)
+
+ if self._HasNativeIndexSetter(self._interface):
+ self._EmitNativeIndexSetter(self._interface, 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=element_type)
+
+ self._members_emitter.Emit(
+ '\n'
+ ' void add($TYPE value) {\n'
+ ' throw new UnsupportedOperationException("Cannot add to immutable List.");\n'
+ ' }\n'
+ '\n'
+ ' void addLast($TYPE value) {\n'
+ ' throw new UnsupportedOperationException("Cannot add to immutable List.");\n'
+ ' }\n'
+ '\n'
+ ' void addAll(Collection<$TYPE> collection) {\n'
+ ' throw new UnsupportedOperationException("Cannot add to immutable List.");\n'
+ ' }\n'
+ '\n'
+ ' void sort(int compare($TYPE a, $TYPE b)) {\n'
+ ' throw new UnsupportedOperationException("Cannot sort immutable List.");\n'
+ ' }\n'
+ '\n'
+ ' void copyFrom(List<Object> src, int srcStart, '
+ 'int dstStart, int count) {\n'
+ ' throw new UnsupportedOperationException("This object is immutable.");\n'
+ ' }\n'
+ '\n'
+ ' int indexOf($TYPE element, [int start = 0]) {\n'
+ ' return _Lists.indexOf(this, element, start, this.length);\n'
+ ' }\n'
+ '\n'
+ ' int lastIndexOf($TYPE element, [int start = null]) {\n'
+ ' if (start === null) start = length - 1;\n'
+ ' return _Lists.lastIndexOf(this, element, start);\n'
+ ' }\n'
+ '\n'
+ ' int clear() {\n'
+ ' throw new UnsupportedOperationException("Cannot clear immutable List.");\n'
+ ' }\n'
+ '\n'
+ ' $TYPE removeLast() {\n'
+ ' throw new UnsupportedOperationException("Cannot removeLast on immutable List.");\n'
+ ' }\n'
+ '\n'
+ ' $TYPE last() {\n'
+ ' return this[length - 1];\n'
+ ' }\n'
+ '\n'
+ ' void forEach(void f($TYPE element)) {\n'
+ ' _Collections.forEach(this, f);\n'
+ ' }\n'
+ '\n'
+ ' Collection map(f($TYPE element)) {\n'
+ ' return _Collections.map(this, [], f);\n'
+ ' }\n'
+ '\n'
+ ' Collection<$TYPE> filter(bool f($TYPE element)) {\n'
+ ' return _Collections.filter(this, new List<$TYPE>(), f);\n'
+ ' }\n'
+ '\n'
+ ' bool every(bool f($TYPE element)) {\n'
+ ' return _Collections.every(this, f);\n'
+ ' }\n'
+ '\n'
+ ' bool some(bool f($TYPE element)) {\n'
+ ' return _Collections.some(this, f);\n'
+ ' }\n'
+ '\n'
+ ' void setRange(int start, int length, List<$TYPE> from, [int startFrom]) {\n'
+ ' throw new UnsupportedOperationException("Cannot setRange on immutable List.");\n'
+ ' }\n'
+ '\n'
+ ' void removeRange(int start, int length) {\n'
+ ' throw new UnsupportedOperationException("Cannot removeRange on immutable List.");\n'
+ ' }\n'
+ '\n'
+ ' void insertRange(int start, int length, [$TYPE initialValue]) {\n'
+ ' throw new UnsupportedOperationException("Cannot insertRange on immutable List.");\n'
+ ' }\n'
+ '\n'
+ ' List<$TYPE> getRange(int start, int length) {\n'
+ ' throw new NotImplementedException();\n'
+ ' }\n'
+ '\n'
+ ' bool isEmpty() {\n'
+ ' return length == 0;\n'
+ ' }\n'
+ '\n'
+ ' Iterator<$TYPE> iterator() {\n'
+ ' return new _FixedSizeListIterator<$TYPE>(this);\n'
+ ' }\n',
+ TYPE=element_type)
+
+ def _HasNativeIndexGetter(self, interface):
+ return ('IndexedGetter' in interface.ext_attrs or
+ 'NumericIndexedGetter' 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)
+
+ def _HasNativeIndexSetter(self, interface):
+ return 'CustomIndexedSetter' 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)
+
+ def AddOperation(self, info):
+ """
+ Arguments:
+ info: An OperationInfo object.
+ """
+ body = self._members_emitter.Emit(
+ '\n'
+ ' $TYPE $NAME($PARAMS) {\n'
+ '$!BODY'
+ ' }\n',
+ TYPE=info.type_name,
+ NAME=info.name,
+ PARAMS=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.
+ """
+ # TODO(sra): Do we need to distinguish calling with missing optional
+ # arguments from passing 'null' which is represented as 'undefined'?
+ def UnwrapArgExpression(name, type):
+ # TODO: Type specific unwrapping.
+ return '__dom_unwrap(%s)' % (name)
+
+ def ArgNameAndUnwrapper(arg_info, overload_arg):
+ (name, type, value) = arg_info
+ return (name, UnwrapArgExpression(name, type))
+
+ names_and_unwrappers = [ArgNameAndUnwrapper(info.arg_infos[i], arg)
+ for (i, arg) in enumerate(operation.arguments)]
+ unwrap_args = [unwrap_arg for (_, unwrap_arg) in names_and_unwrappers]
+ arg_names = [name for (name, _) in names_and_unwrappers]
+
+ self._native_version += 1
+ native_name = self._MethodName('_', info.name)
+ if self._native_version > 1:
+ native_name = '%s_%s' % (native_name, self._native_version)
+
+ argument_expressions = ', '.join(['this'] + 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(' static $TYPE $NAME($PARAMS) native;\n',
+ NAME=native_name,
+ TYPE=info.type_name,
+ PARAMS=', '.join(['receiver'] + arg_names) )
+
+
+ def GenerateDispatch(self, emitter, info, indent, position, overloads):
+ """Generates a dispatch to one of the overloads.
+
+ 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.
+ position: the index of the parameter to dispatch on.
+ overloads: a list of the remaining IDLOperations to dispatch.
+
+ Returns True if the dispatch can fall through on failure, False if the code
+ always dispatches.
+ """
+
+ def NullCheck(name):
+ return '%s === null' % name
+
+ def TypeCheck(name, type):
+ return '%s is %s' % (name, type)
+
+ if position == len(info.arg_infos):
+ if len(overloads) > 1:
+ raise Exception('Duplicate operations ' + str(overloads))
+ operation = overloads[0]
+ self.GenerateSingleOperation(emitter, info, indent, operation)
+ return False
+
+ # FIXME: Consider a simpler dispatch that iterates over the
+ # overloads and generates an overload specific check. Revisit
+ # when we move to named optional arguments.
+
+ # Partition the overloads to divide and conquer on the dispatch.
+ positive = []
+ negative = []
+ first_overload = overloads[0]
+ (param_name, param_type, param_default) = info.arg_infos[position]
+
+ if position < len(first_overload.arguments):
+ # FIXME: This will not work if the second overload has a more
+ # precise type than the first. E.g.,
+ # void foo(Node x);
+ # void foo(Element x);
+ type = first_overload.arguments[position].type.id
+ test = TypeCheck(param_name, type)
+ pred = lambda op: len(op.arguments) > position and op.arguments[position].type.id == type
+ else:
+ type = None
+ test = NullCheck(param_name)
+ pred = lambda op: position >= len(op.arguments)
+
+ for overload in overloads:
+ if pred(overload):
+ positive.append(overload)
+ else:
+ negative.append(overload)
+
+ if positive and negative:
+ (true_code, false_code) = emitter.Emit(
+ '$(INDENT)if ($COND) {\n'
+ '$!TRUE'
+ '$(INDENT)} else {\n'
+ '$!FALSE'
+ '$(INDENT)}\n',
+ COND=test, INDENT=indent)
+ fallthrough1 = self.GenerateDispatch(
+ true_code, info, indent + ' ', position + 1, positive)
+ fallthrough2 = self.GenerateDispatch(
+ false_code, info, indent + ' ', position, negative)
+ return fallthrough1 or fallthrough2
+
+ if negative:
+ raise Exception('Internal error, must be all positive')
+
+ # All overloads require the same test. Do we bother?
+
+ # If the test is the same as the method's formal parameter then checked mode
+ # will have done the test already. (It could be null too but we ignore that
+ # case since all the overload behave the same and we don't know which types
+ # in the IDL are not nullable.)
+ if type == param_type:
+ return self.GenerateDispatch(
+ emitter, info, indent, position + 1, positive)
+
+ # Otherwise the overloads have the same type but the type is a substype of
+ # the method's synthesized formal parameter. e.g we have overloads f(X) and
+ # f(Y), implemented by the synthesized method f(Z) where X<Z and Y<Z. The
+ # dispatch has removed f(X), leaving only f(Y), but there is no guarantee
+ # that Y = Z-X, so we need to check for Y.
+ true_code = emitter.Emit(
+ '$(INDENT)if ($COND) {\n'
+ '$!TRUE'
+ '$(INDENT)}\n',
+ COND=test, INDENT=indent)
+ self.GenerateDispatch(
+ true_code, info, indent + ' ', position + 1, positive)
+ return True
« client/dom/scripts/systemnative.py ('K') | « client/dom/scripts/systemnative.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698