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

Side by Side Diff: lib/dom/scripts/systemwrapping.py

Issue 10388085: Merge wrapping system into native system. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 7 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 #!/usr/bin/python
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
4 # BSD-style license that can be found in the LICENSE file.
5
6 """This module provides shared functionality for the systems to generate
7 wrapping binding from the IDL database."""
8
9 import os
10 from generator import *
11 from systembase import *
12
13 class WrappingImplementationSystem(System):
14
15 def __init__(self, templates, database, emitters, output_dir):
16 """Prepared for generating wrapping implementation.
17
18 - Creates emitter for JS code.
19 - Creates emitter for Dart code.
20 """
21 super(WrappingImplementationSystem, self).__init__(
22 templates, database, emitters, output_dir)
23 self._dart_wrapping_file_paths = []
24
25
26 def InterfaceGenerator(self,
27 interface,
28 common_prefix,
29 super_interface_name,
30 source_filter):
31 """."""
32 interface_name = interface.id
33 dart_wrapping_file_path = self._FilePathForDartWrappingImpl(interface_name)
34
35 self._dart_wrapping_file_paths.append(dart_wrapping_file_path)
36
37 dart_code = self._emitters.FileEmitter(dart_wrapping_file_path)
38 dart_code.Emit(self._templates.Load('wrapping_impl.darttemplate'))
39 return WrappingInterfaceGenerator(interface, super_interface_name,
40 dart_code,
41 self._BaseDefines(interface))
42
43 def ProcessCallback(self, interface, info):
44 pass
45
46 def GenerateLibraries(self, lib_dir):
47 # Library generated for implementation.
48 self._GenerateLibFile(
49 'wrapping_dom.darttemplate',
50 os.path.join(lib_dir, 'wrapping_dom.dart'),
51 (self._interface_system._dart_interface_file_paths +
52 self._interface_system._dart_callback_file_paths +
53 # FIXME: Move the implementation to a separate library.
54 self._dart_wrapping_file_paths
55 ))
56
57
58 def Finish(self):
59 pass
60
61
62 def _FilePathForDartWrappingImpl(self, interface_name):
63 """Returns the file path of the Dart wrapping implementation."""
64 return os.path.join(self._output_dir, 'src', 'wrapping',
65 '_%sWrappingImplementation.dart' % interface_name)
66
67 class WrappingInterfaceGenerator(object):
68 """Generates Dart and JS implementation for one DOM IDL interface."""
69
70 def __init__(self, interface, super_interface, dart_code, base_members):
71 """Generates Dart and JS code for the given interface.
72
73 Args:
74
75 interface: an IDLInterface instance. It is assumed that all types have
76 been converted to Dart types (e.g. int, String), unless they are in
77 the same package as the interface.
78 super_interface: A string or None, the name of the common interface that
79 this interface implements, if any.
80 dart_code: an Emitter for the file containing the Dart implementation
81 class.
82 base_members: a set of names of members defined in a base class. This is
83 used to avoid static member 'overriding' in the generated Dart code.
84 """
85 self._interface = interface
86 self._super_interface = super_interface
87 self._dart_code = dart_code
88 self._base_members = base_members
89 self._current_secondary_parent = None
90
91
92 def StartInterface(self):
93 interface = self._interface
94 interface_name = interface.id
95
96 self._class_name = self._ImplClassName(interface_name)
97
98 base = self._BaseClassName(interface)
99
100 (self._members_emitter,
101 self._top_level_emitter) = self._dart_code.Emit(
102 '\n'
103 'class $CLASS extends $BASE implements $INTERFACE {\n'
104 ' $CLASS() : super() {}\n'
105 '\n'
106 ' static create_$CLASS() native {\n'
107 ' return new $CLASS();\n'
108 ' }\n'
109 '$!MEMBERS'
110 '\n'
111 ' String get typeName() { return "$INTERFACE"; }\n'
112 '}\n'
113 '$!TOP_LEVEL',
114 CLASS=self._class_name, BASE=base, INTERFACE=interface_name)
115
116 def _ImplClassName(self, type_name):
117 return '_' + type_name + 'WrappingImplementation'
118
119 def _BaseClassName(self, interface):
120 if not interface.parents:
121 return 'DOMWrapperBase'
122
123 supertype = interface.parents[0].type.id
124
125 # FIXME: We're currently injecting List<..> and EventTarget as
126 # supertypes in dart.idl. We should annotate/preserve as
127 # attributes instead. For now, this hack lets the interfaces
128 # inherit, but not the classes.
129 # List methods are injected in AddIndexer.
130 if IsDartListType(supertype) or IsDartCollectionType(supertype):
131 return 'DOMWrapperBase'
132
133 if supertype == 'EventTarget':
134 # Most implementors of EventTarget specify the EventListener operations
135 # again. If the operations are not specified, try to inherit from the
136 # EventTarget implementation.
137 #
138 # Applies to MessagePort.
139 if not [op for op in interface.operations if op.id == 'addEventListener']:
140 return self._ImplClassName(supertype)
141 return 'DOMWrapperBase'
142
143 return self._ImplClassName(supertype)
144
145 def FinishInterface(self):
146 """."""
147 pass
148
149 def AddConstant(self, constant):
150 # Constants are already defined on the interface.
151 pass
152
153 def _MethodName(self, prefix, name):
154 method_name = prefix + name
155 if name in self._base_members: # Avoid illegal Dart 'static override'.
156 method_name = method_name + '_' + self._interface.id
157 return method_name
158
159 def AddAttribute(self, getter, setter):
160 if getter:
161 self._AddGetter(getter)
162 if setter:
163 self._AddSetter(setter)
164
165 def _AddGetter(self, attr):
166 # FIXME: Instead of injecting the interface name into the method when it is
167 # also implemented in the base class, suppress the method altogether if it
168 # has the same signature. I.e., let the JS do the virtual dispatch instead.
169 method_name = self._MethodName('_get_', attr.id)
170 self._members_emitter.Emit(
171 '\n'
172 ' $TYPE get $NAME() { return $METHOD(this); }\n'
173 ' static $TYPE $METHOD(var _this) native;\n',
174 NAME=DartDomNameOfAttribute(attr),
175 TYPE=DartType(attr.type.id),
176 METHOD=method_name)
177
178 def _AddSetter(self, attr):
179 # FIXME: See comment on getter.
180 method_name = self._MethodName('_set_', attr.id)
181 self._members_emitter.Emit(
182 '\n'
183 ' void set $NAME($TYPE value) { $METHOD(this, value); }\n'
184 ' static void $METHOD(var _this, $TYPE value) native;\n',
185 NAME=DartDomNameOfAttribute(attr),
186 TYPE=DartType(attr.type.id),
187 METHOD=method_name)
188
189 def AddSecondaryAttribute(self, interface, getter, setter):
190 self._SecondaryContext(interface)
191 self.AddAttribute(getter, setter)
192
193 def AddSecondaryOperation(self, interface, info):
194 self._SecondaryContext(interface)
195 self.AddOperation(info)
196
197 def _SecondaryContext(self, interface):
198 if interface is not self._current_secondary_parent:
199 self._current_secondary_parent = interface
200 self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id)
201
202 def AddIndexer(self, element_type):
203 """Adds all the methods required to complete implementation of List."""
204 # We would like to simply inherit the implementation of everything except
205 # get length(), [], and maybe []=. It is possible to extend from a base
206 # array implementation class only when there is no other implementation
207 # inheritance. There might be no implementation inheritance other than
208 # DOMBaseWrapper for many classes, but there might be some where the
209 # array-ness is introduced by a non-root interface:
210 #
211 # interface Y extends X, List<T> ...
212 #
213 # In the non-root case we have to choose between:
214 #
215 # class YImpl extends XImpl { add List<T> methods; }
216 #
217 # and
218 #
219 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; }
220 #
221 dart_element_type = DartType(element_type)
222 if self._HasNativeIndexGetter(self._interface):
223 self._EmitNativeIndexGetter(self._interface, dart_element_type)
224 else:
225 self._members_emitter.Emit(
226 '\n'
227 ' $TYPE operator[](int index) {\n'
228 ' return item(index);\n'
229 ' }\n',
230 TYPE=dart_element_type)
231
232 if self._HasNativeIndexSetter(self._interface):
233 self._EmitNativeIndexSetter(self._interface, dart_element_type)
234 else:
235 self._members_emitter.Emit(
236 '\n'
237 ' void operator[]=(int index, $TYPE value) {\n'
238 ' throw new UnsupportedOperationException("Cannot assign element of immutable List.");\n'
239 ' }\n',
240 TYPE=dart_element_type)
241
242 self._members_emitter.Emit(
243 '\n'
244 ' void add($TYPE value) {\n'
245 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n'
246 ' }\n'
247 '\n'
248 ' void addLast($TYPE value) {\n'
249 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n'
250 ' }\n'
251 '\n'
252 ' void addAll(Collection<$TYPE> collection) {\n'
253 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n'
254 ' }\n'
255 '\n'
256 ' void sort(int compare($TYPE a, $TYPE b)) {\n'
257 ' throw new UnsupportedOperationException("Cannot sort immutable List .");\n'
258 ' }\n'
259 '\n'
260 ' void copyFrom(List<Object> src, int srcStart, '
261 'int dstStart, int count) {\n'
262 ' throw new UnsupportedOperationException("This object is immutable." );\n'
263 ' }\n'
264 '\n'
265 ' int indexOf($TYPE element, [int start = 0]) {\n'
266 ' return _Lists.indexOf(this, element, start, this.length);\n'
267 ' }\n'
268 '\n'
269 ' int lastIndexOf($TYPE element, [int start = null]) {\n'
270 ' if (start === null) start = length - 1;\n'
271 ' return _Lists.lastIndexOf(this, element, start);\n'
272 ' }\n'
273 '\n'
274 ' int clear() {\n'
275 ' throw new UnsupportedOperationException("Cannot clear immutable Lis t.");\n'
276 ' }\n'
277 '\n'
278 ' $TYPE removeLast() {\n'
279 ' throw new UnsupportedOperationException("Cannot removeLast on immut able List.");\n'
280 ' }\n'
281 '\n'
282 ' $TYPE last() {\n'
283 ' return this[length - 1];\n'
284 ' }\n'
285 '\n'
286 ' void forEach(void f($TYPE element)) {\n'
287 ' _Collections.forEach(this, f);\n'
288 ' }\n'
289 '\n'
290 ' Collection map(f($TYPE element)) {\n'
291 ' return _Collections.map(this, [], f);\n'
292 ' }\n'
293 '\n'
294 ' Collection<$TYPE> filter(bool f($TYPE element)) {\n'
295 ' return _Collections.filter(this, new List<$TYPE>(), f);\n'
296 ' }\n'
297 '\n'
298 ' bool every(bool f($TYPE element)) {\n'
299 ' return _Collections.every(this, f);\n'
300 ' }\n'
301 '\n'
302 ' bool some(bool f($TYPE element)) {\n'
303 ' return _Collections.some(this, f);\n'
304 ' }\n'
305 '\n'
306 ' void setRange(int start, int length, List<$TYPE> from, [int startFrom ]) {\n'
307 ' throw new UnsupportedOperationException("Cannot setRange on immutab le List.");\n'
308 ' }\n'
309 '\n'
310 ' void removeRange(int start, int length) {\n'
311 ' throw new UnsupportedOperationException("Cannot removeRange on immu table List.");\n'
312 ' }\n'
313 '\n'
314 ' void insertRange(int start, int length, [$TYPE initialValue]) {\n'
315 ' throw new UnsupportedOperationException("Cannot insertRange on immu table List.");\n'
316 ' }\n'
317 '\n'
318 ' List<$TYPE> getRange(int start, int length) {\n'
319 ' throw new NotImplementedException();\n'
320 ' }\n'
321 '\n'
322 ' bool isEmpty() {\n'
323 ' return length == 0;\n'
324 ' }\n'
325 '\n'
326 ' Iterator<$TYPE> iterator() {\n'
327 ' return new _FixedSizeListIterator<$TYPE>(this);\n'
328 ' }\n',
329 TYPE=dart_element_type)
330
331 def _HasNativeIndexGetter(self, interface):
332 return ('IndexedGetter' in interface.ext_attrs or
333 'NumericIndexedGetter' in interface.ext_attrs)
334
335 def _EmitNativeIndexGetter(self, interface, dart_element_type):
336 method_name = '_index'
337 self._members_emitter.Emit(
338 '\n'
339 ' $TYPE operator[](int index) { return $METHOD(this, index); }\n'
340 ' static $TYPE $METHOD(var _this, int index) native;\n',
341 TYPE=dart_element_type, METHOD=method_name)
342
343 def _HasNativeIndexSetter(self, interface):
344 return 'CustomIndexedSetter' in interface.ext_attrs
345
346 def _EmitNativeIndexSetter(self, interface, dart_element_type):
347 method_name = '_set_index'
348 self._members_emitter.Emit(
349 '\n'
350 ' void operator[]=(int index, $TYPE value) {\n'
351 ' return $METHOD(this, index, value);\n'
352 ' }\n'
353 ' static $METHOD(_this, index, value) native;\n',
354 TYPE=dart_element_type, METHOD=method_name)
355
356 def AddOperation(self, info):
357 """
358 Arguments:
359 info: An OperationInfo object.
360 """
361 body = self._members_emitter.Emit(
362 '\n'
363 ' $TYPE $NAME($PARAMS) {\n'
364 '$!BODY'
365 ' }\n',
366 TYPE=info.type_name,
367 NAME=info.name,
368 PARAMS=info.ParametersImplementationDeclaration())
369
370 # Process in order of ascending number of arguments to ensure missing
371 # optional arguments are processed early.
372 overloads = sorted(info.overloads,
373 key=lambda overload: len(overload.arguments))
374 self._native_version = 0
375 fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads)
376 if fallthrough:
377 body.Emit(' throw "Incorrect number or type of arguments";\n');
378
379 def AddStaticOperation(self, info):
380 pass
381
382 def GenerateSingleOperation(self, emitter, info, indent, operation):
383 """Generates a call to a single operation.
384
385 Arguments:
386 emitter: an Emitter for the body of a block of code.
387 info: the compound information about the operation and its overloads.
388 indent: an indentation string for generated code.
389 operation: the IDLOperation to call.
390 """
391 # TODO(sra): Do we need to distinguish calling with missing optional
392 # arguments from passing 'null' which is represented as 'undefined'?
393 def UnwrapArgExpression(name, type):
394 # TODO: Type specific unwrapping.
395 return '__dom_unwrap(%s)' % (name)
396
397 def ArgNameAndUnwrapper(param_info, overload_arg):
398 return (param_info.name,
399 UnwrapArgExpression(param_info.name, param_info.dart_type))
400
401 names_and_unwrappers = [ArgNameAndUnwrapper(info.param_infos[i], arg)
402 for (i, arg) in enumerate(operation.arguments)]
403 unwrap_args = [unwrap_arg for (_, unwrap_arg) in names_and_unwrappers]
404 arg_names = [name for (name, _) in names_and_unwrappers]
405
406 self._native_version += 1
407 native_name = self._MethodName('_', info.name)
408 if self._native_version > 1:
409 native_name = '%s_%s' % (native_name, self._native_version)
410
411 argument_expressions = ', '.join(['this'] + arg_names)
412 if info.type_name != 'void':
413 emitter.Emit('$(INDENT)return $NATIVENAME($ARGS);\n',
414 INDENT=indent,
415 NATIVENAME=native_name,
416 ARGS=argument_expressions)
417 else:
418 emitter.Emit('$(INDENT)$NATIVENAME($ARGS);\n'
419 '$(INDENT)return;\n',
420 INDENT=indent,
421 NATIVENAME=native_name,
422 ARGS=argument_expressions)
423
424 self._members_emitter.Emit(' static $TYPE $NAME($PARAMS) native;\n',
425 NAME=native_name,
426 TYPE=info.type_name,
427 PARAMS=', '.join(['receiver'] + arg_names) )
428
429
430 def GenerateDispatch(self, emitter, info, indent, position, overloads):
431 """Generates a dispatch to one of the overloads.
432
433 Arguments:
434 emitter: an Emitter for the body of a block of code.
435 info: the compound information about the operation and its overloads.
436 indent: an indentation string for generated code.
437 position: the index of the parameter to dispatch on.
438 overloads: a list of the remaining IDLOperations to dispatch.
439
440 Returns True if the dispatch can fall through on failure, False if the code
441 always dispatches.
442 """
443
444 def NullCheck(name):
445 return '%s === null' % name
446
447 def TypeCheck(name, type):
448 return '%s is %s' % (name, type)
449
450 def ShouldGenerateSingleOperation():
451 if position == len(info.param_infos):
452 if len(overloads) > 1:
453 raise Exception('Duplicate operations ' + str(overloads))
454 return True
455
456 # Check if we dispatch on RequiredCppParameter arguments. In this
457 # case all trailing arguments must be RequiredCppParameter and there
458 # is no need in dispatch.
459 # TODO(antonm): better diagnositics.
460 if position >= len(overloads[0].arguments):
461 def IsRequiredCppParameter(arg):
462 return 'RequiredCppParameter' in arg.ext_attrs
463 last_overload = overloads[-1]
464 if (len(last_overload.arguments) > position and
465 IsRequiredCppParameter(last_overload.arguments[position])):
466 for overload in overloads:
467 args = overload.arguments[position:]
468 if not all([IsRequiredCppParameter(arg) for arg in args]):
469 raise Exception('Invalid overload for RequiredCppParameter')
470 return True
471
472 return False
473
474 if ShouldGenerateSingleOperation():
475 self.GenerateSingleOperation(emitter, info, indent, overloads[-1])
476 return False
477
478 # FIXME: Consider a simpler dispatch that iterates over the
479 # overloads and generates an overload specific check. Revisit
480 # when we move to named optional arguments.
481
482 # Partition the overloads to divide and conquer on the dispatch.
483 positive = []
484 negative = []
485 first_overload = overloads[0]
486 param = info.param_infos[position]
487
488 if position < len(first_overload.arguments):
489 # FIXME: This will not work if the second overload has a more
490 # precise type than the first. E.g.,
491 # void foo(Node x);
492 # void foo(Element x);
493 type = DartType(first_overload.arguments[position].type.id)
494 test = TypeCheck(param.name, type)
495 pred = lambda op: len(op.arguments) > position and DartType(op.arguments[p osition].type.id) == type
496 else:
497 type = None
498 test = NullCheck(param.name)
499 pred = lambda op: position >= len(op.arguments)
500
501 for overload in overloads:
502 if pred(overload):
503 positive.append(overload)
504 else:
505 negative.append(overload)
506
507 if positive and negative:
508 (true_code, false_code) = emitter.Emit(
509 '$(INDENT)if ($COND) {\n'
510 '$!TRUE'
511 '$(INDENT)} else {\n'
512 '$!FALSE'
513 '$(INDENT)}\n',
514 COND=test, INDENT=indent)
515 fallthrough1 = self.GenerateDispatch(
516 true_code, info, indent + ' ', position + 1, positive)
517 fallthrough2 = self.GenerateDispatch(
518 false_code, info, indent + ' ', position, negative)
519 return fallthrough1 or fallthrough2
520
521 if negative:
522 raise Exception('Internal error, must be all positive')
523
524 # All overloads require the same test. Do we bother?
525
526 # If the test is the same as the method's formal parameter then checked mode
527 # will have done the test already. (It could be null too but we ignore that
528 # case since all the overload behave the same and we don't know which types
529 # in the IDL are not nullable.)
530 if type == param.dart_type:
531 return self.GenerateDispatch(
532 emitter, info, indent, position + 1, positive)
533
534 # Otherwise the overloads have the same type but the type is a subtype of
535 # the method's synthesized formal parameter. e.g we have overloads f(X) and
536 # f(Y), implemented by the synthesized method f(Z) where X<Z and Y<Z. The
537 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee
538 # that Y = Z-X, so we need to check for Y.
539 true_code = emitter.Emit(
540 '$(INDENT)if ($COND) {\n'
541 '$!TRUE'
542 '$(INDENT)}\n',
543 COND=test, INDENT=indent)
544 self.GenerateDispatch(
545 true_code, info, indent + ' ', position + 1, positive)
546 return True
OLDNEW
« lib/dom/scripts/systemnative.py ('K') | « lib/dom/scripts/systemnative.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698