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

Side by Side 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 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=attr.id, TYPE=attr.type.id, METHOD=method_name)
175
176 def _AddSetter(self, attr):
177 # FIXME: See comment on getter.
178 method_name = self._MethodName('_set_', attr.id)
179 self._members_emitter.Emit(
180 '\n'
181 ' void set $NAME($TYPE value) { $METHOD(this, value); }\n'
182 ' static void $METHOD(var _this, $TYPE value) native;\n',
183 NAME=attr.id, TYPE=attr.type.id, METHOD=method_name)
184
185 def AddSecondaryAttribute(self, interface, getter, setter):
186 self._SecondaryContext(interface)
187 self.AddAttribute(getter, setter)
188
189 def AddSecondaryOperation(self, interface, info):
190 self._SecondaryContext(interface)
191 self.AddOperation(info)
192
193 def AddEventAttributes(self, event_attrs):
194 pass
195
196 def _SecondaryContext(self, interface):
197 if interface is not self._current_secondary_parent:
198 self._current_secondary_parent = interface
199 self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id)
200
201 def AddIndexer(self, element_type):
202 """Adds all the methods required to complete implementation of List."""
203 # We would like to simply inherit the implementation of everything except
204 # get length(), [], and maybe []=. It is possible to extend from a base
205 # array implementation class only when there is no other implementation
206 # inheritance. There might be no implementation inheritance other than
207 # DOMBaseWrapper for many classes, but there might be some where the
208 # array-ness is introduced by a non-root interface:
209 #
210 # interface Y extends X, List<T> ...
211 #
212 # In the non-root case we have to choose between:
213 #
214 # class YImpl extends XImpl { add List<T> methods; }
215 #
216 # and
217 #
218 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; }
219 #
220 if self._HasNativeIndexGetter(self._interface):
221 self._EmitNativeIndexGetter(self._interface, element_type)
222 else:
223 self._members_emitter.Emit(
224 '\n'
225 ' $TYPE operator[](int index) {\n'
226 ' return item(index);\n'
227 ' }\n',
228 TYPE=element_type)
229
230 if self._HasNativeIndexSetter(self._interface):
231 self._EmitNativeIndexSetter(self._interface, element_type)
232 else:
233 self._members_emitter.Emit(
234 '\n'
235 ' void operator[]=(int index, $TYPE value) {\n'
236 ' throw new UnsupportedOperationException("Cannot assign element of immutable List.");\n'
237 ' }\n',
238 TYPE=element_type)
239
240 self._members_emitter.Emit(
241 '\n'
242 ' void add($TYPE value) {\n'
243 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n'
244 ' }\n'
245 '\n'
246 ' void addLast($TYPE value) {\n'
247 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n'
248 ' }\n'
249 '\n'
250 ' void addAll(Collection<$TYPE> collection) {\n'
251 ' throw new UnsupportedOperationException("Cannot add to immutable Li st.");\n'
252 ' }\n'
253 '\n'
254 ' void sort(int compare($TYPE a, $TYPE b)) {\n'
255 ' throw new UnsupportedOperationException("Cannot sort immutable List .");\n'
256 ' }\n'
257 '\n'
258 ' void copyFrom(List<Object> src, int srcStart, '
259 'int dstStart, int count) {\n'
260 ' throw new UnsupportedOperationException("This object is immutable." );\n'
261 ' }\n'
262 '\n'
263 ' int indexOf($TYPE element, [int start = 0]) {\n'
264 ' return _Lists.indexOf(this, element, start, this.length);\n'
265 ' }\n'
266 '\n'
267 ' int lastIndexOf($TYPE element, [int start = null]) {\n'
268 ' if (start === null) start = length - 1;\n'
269 ' return _Lists.lastIndexOf(this, element, start);\n'
270 ' }\n'
271 '\n'
272 ' int clear() {\n'
273 ' throw new UnsupportedOperationException("Cannot clear immutable Lis t.");\n'
274 ' }\n'
275 '\n'
276 ' $TYPE removeLast() {\n'
277 ' throw new UnsupportedOperationException("Cannot removeLast on immut able List.");\n'
278 ' }\n'
279 '\n'
280 ' $TYPE last() {\n'
281 ' return this[length - 1];\n'
282 ' }\n'
283 '\n'
284 ' void forEach(void f($TYPE element)) {\n'
285 ' _Collections.forEach(this, f);\n'
286 ' }\n'
287 '\n'
288 ' Collection map(f($TYPE element)) {\n'
289 ' return _Collections.map(this, [], f);\n'
290 ' }\n'
291 '\n'
292 ' Collection<$TYPE> filter(bool f($TYPE element)) {\n'
293 ' return _Collections.filter(this, new List<$TYPE>(), f);\n'
294 ' }\n'
295 '\n'
296 ' bool every(bool f($TYPE element)) {\n'
297 ' return _Collections.every(this, f);\n'
298 ' }\n'
299 '\n'
300 ' bool some(bool f($TYPE element)) {\n'
301 ' return _Collections.some(this, f);\n'
302 ' }\n'
303 '\n'
304 ' void setRange(int start, int length, List<$TYPE> from, [int startFrom ]) {\n'
305 ' throw new UnsupportedOperationException("Cannot setRange on immutab le List.");\n'
306 ' }\n'
307 '\n'
308 ' void removeRange(int start, int length) {\n'
309 ' throw new UnsupportedOperationException("Cannot removeRange on immu table List.");\n'
310 ' }\n'
311 '\n'
312 ' void insertRange(int start, int length, [$TYPE initialValue]) {\n'
313 ' throw new UnsupportedOperationException("Cannot insertRange on immu table List.");\n'
314 ' }\n'
315 '\n'
316 ' List<$TYPE> getRange(int start, int length) {\n'
317 ' throw new NotImplementedException();\n'
318 ' }\n'
319 '\n'
320 ' bool isEmpty() {\n'
321 ' return length == 0;\n'
322 ' }\n'
323 '\n'
324 ' Iterator<$TYPE> iterator() {\n'
325 ' return new _FixedSizeListIterator<$TYPE>(this);\n'
326 ' }\n',
327 TYPE=element_type)
328
329 def _HasNativeIndexGetter(self, interface):
330 return ('IndexedGetter' in interface.ext_attrs or
331 'NumericIndexedGetter' in interface.ext_attrs)
332
333 def _EmitNativeIndexGetter(self, interface, element_type):
334 method_name = '_index'
335 self._members_emitter.Emit(
336 '\n'
337 ' $TYPE operator[](int index) { return $METHOD(this, index); }\n'
338 ' static $TYPE $METHOD(var _this, int index) native;\n',
339 TYPE=element_type, METHOD=method_name)
340
341 def _HasNativeIndexSetter(self, interface):
342 return 'CustomIndexedSetter' in interface.ext_attrs
343
344 def _EmitNativeIndexSetter(self, interface, element_type):
345 method_name = '_set_index'
346 self._members_emitter.Emit(
347 '\n'
348 ' void operator[]=(int index, $TYPE value) {\n'
349 ' return $METHOD(this, index, value);\n'
350 ' }\n'
351 ' static $METHOD(_this, index, value) native;\n',
352 TYPE=element_type, METHOD=method_name)
353
354 def AddOperation(self, info):
355 """
356 Arguments:
357 info: An OperationInfo object.
358 """
359 body = self._members_emitter.Emit(
360 '\n'
361 ' $TYPE $NAME($PARAMS) {\n'
362 '$!BODY'
363 ' }\n',
364 TYPE=info.type_name,
365 NAME=info.name,
366 PARAMS=info.ParametersImplementationDeclaration())
367
368 # Process in order of ascending number of arguments to ensure missing
369 # optional arguments are processed early.
370 overloads = sorted(info.overloads,
371 key=lambda overload: len(overload.arguments))
372 self._native_version = 0
373 fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads)
374 if fallthrough:
375 body.Emit(' throw "Incorrect number or type of arguments";\n');
376
377 def GenerateSingleOperation(self, emitter, info, indent, operation):
378 """Generates a call to a single operation.
379
380 Arguments:
381 emitter: an Emitter for the body of a block of code.
382 info: the compound information about the operation and its overloads.
383 indent: an indentation string for generated code.
384 operation: the IDLOperation to call.
385 """
386 # TODO(sra): Do we need to distinguish calling with missing optional
387 # arguments from passing 'null' which is represented as 'undefined'?
388 def UnwrapArgExpression(name, type):
389 # TODO: Type specific unwrapping.
390 return '__dom_unwrap(%s)' % (name)
391
392 def ArgNameAndUnwrapper(arg_info, overload_arg):
393 (name, type, value) = arg_info
394 return (name, UnwrapArgExpression(name, type))
395
396 names_and_unwrappers = [ArgNameAndUnwrapper(info.arg_infos[i], arg)
397 for (i, arg) in enumerate(operation.arguments)]
398 unwrap_args = [unwrap_arg for (_, unwrap_arg) in names_and_unwrappers]
399 arg_names = [name for (name, _) in names_and_unwrappers]
400
401 self._native_version += 1
402 native_name = self._MethodName('_', info.name)
403 if self._native_version > 1:
404 native_name = '%s_%s' % (native_name, self._native_version)
405
406 argument_expressions = ', '.join(['this'] + arg_names)
407 if info.type_name != 'void':
408 emitter.Emit('$(INDENT)return $NATIVENAME($ARGS);\n',
409 INDENT=indent,
410 NATIVENAME=native_name,
411 ARGS=argument_expressions)
412 else:
413 emitter.Emit('$(INDENT)$NATIVENAME($ARGS);\n'
414 '$(INDENT)return;\n',
415 INDENT=indent,
416 NATIVENAME=native_name,
417 ARGS=argument_expressions)
418
419 self._members_emitter.Emit(' static $TYPE $NAME($PARAMS) native;\n',
420 NAME=native_name,
421 TYPE=info.type_name,
422 PARAMS=', '.join(['receiver'] + arg_names) )
423
424
425 def GenerateDispatch(self, emitter, info, indent, position, overloads):
426 """Generates a dispatch to one of the overloads.
427
428 Arguments:
429 emitter: an Emitter for the body of a block of code.
430 info: the compound information about the operation and its overloads.
431 indent: an indentation string for generated code.
432 position: the index of the parameter to dispatch on.
433 overloads: a list of the remaining IDLOperations to dispatch.
434
435 Returns True if the dispatch can fall through on failure, False if the code
436 always dispatches.
437 """
438
439 def NullCheck(name):
440 return '%s === null' % name
441
442 def TypeCheck(name, type):
443 return '%s is %s' % (name, type)
444
445 if position == len(info.arg_infos):
446 if len(overloads) > 1:
447 raise Exception('Duplicate operations ' + str(overloads))
448 operation = overloads[0]
449 self.GenerateSingleOperation(emitter, info, indent, operation)
450 return False
451
452 # FIXME: Consider a simpler dispatch that iterates over the
453 # overloads and generates an overload specific check. Revisit
454 # when we move to named optional arguments.
455
456 # Partition the overloads to divide and conquer on the dispatch.
457 positive = []
458 negative = []
459 first_overload = overloads[0]
460 (param_name, param_type, param_default) = info.arg_infos[position]
461
462 if position < len(first_overload.arguments):
463 # FIXME: This will not work if the second overload has a more
464 # precise type than the first. E.g.,
465 # void foo(Node x);
466 # void foo(Element x);
467 type = first_overload.arguments[position].type.id
468 test = TypeCheck(param_name, type)
469 pred = lambda op: len(op.arguments) > position and op.arguments[position]. type.id == type
470 else:
471 type = None
472 test = NullCheck(param_name)
473 pred = lambda op: position >= len(op.arguments)
474
475 for overload in overloads:
476 if pred(overload):
477 positive.append(overload)
478 else:
479 negative.append(overload)
480
481 if positive and negative:
482 (true_code, false_code) = emitter.Emit(
483 '$(INDENT)if ($COND) {\n'
484 '$!TRUE'
485 '$(INDENT)} else {\n'
486 '$!FALSE'
487 '$(INDENT)}\n',
488 COND=test, INDENT=indent)
489 fallthrough1 = self.GenerateDispatch(
490 true_code, info, indent + ' ', position + 1, positive)
491 fallthrough2 = self.GenerateDispatch(
492 false_code, info, indent + ' ', position, negative)
493 return fallthrough1 or fallthrough2
494
495 if negative:
496 raise Exception('Internal error, must be all positive')
497
498 # All overloads require the same test. Do we bother?
499
500 # If the test is the same as the method's formal parameter then checked mode
501 # will have done the test already. (It could be null too but we ignore that
502 # case since all the overload behave the same and we don't know which types
503 # in the IDL are not nullable.)
504 if type == param_type:
505 return self.GenerateDispatch(
506 emitter, info, indent, position + 1, positive)
507
508 # Otherwise the overloads have the same type but the type is a substype of
509 # the method's synthesized formal parameter. e.g we have overloads f(X) and
510 # f(Y), implemented by the synthesized method f(Z) where X<Z and Y<Z. The
511 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee
512 # that Y = Z-X, so we need to check for Y.
513 true_code = emitter.Emit(
514 '$(INDENT)if ($COND) {\n'
515 '$!TRUE'
516 '$(INDENT)}\n',
517 COND=test, INDENT=indent)
518 self.GenerateDispatch(
519 true_code, info, indent + ' ', position + 1, positive)
520 return True
OLDNEW
« 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