OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 4 # BSD-style license that can be found in the LICENSE file. |
5 | 5 |
6 """This module generates Dart APIs from the IDL database.""" | 6 """This module generates Dart APIs from the IDL database.""" |
7 | 7 |
8 import emitter | 8 import emitter |
9 import idlnode | 9 import idlnode |
10 import logging | 10 import logging |
11 import multiemitter | 11 import multiemitter |
12 import os | 12 import os |
13 import re | 13 import re |
14 import shutil | 14 import shutil |
| 15 from systembase import * |
| 16 from systemfrog import * |
| 17 from systemhtml import * |
15 | 18 |
16 _logger = logging.getLogger('dartgenerator') | 19 _logger = logging.getLogger('dartgenerator') |
17 | 20 |
18 # IDL->Dart primitive types conversion. | |
19 _idl_to_dart_type_conversions = { | |
20 'any': 'Object', | |
21 'any[]': 'List', | |
22 'custom': 'Dynamic', | |
23 'boolean': 'bool', | |
24 'DOMObject': 'Object', | |
25 'DOMString': 'String', | |
26 'DOMStringList': 'List<String>', | |
27 'DOMTimeStamp': 'int', | |
28 'Date': 'Date', | |
29 # Map to num to enable callers to pass in Dart int, rational | |
30 # types. Our implementations will need to convert these to | |
31 # doubles or floats as needed. | |
32 'double': 'num', | |
33 'float': 'num', | |
34 'int': 'int', | |
35 # Map to extra precision - int is a bignum in Dart. | |
36 'long': 'int', | |
37 'long long': 'int', | |
38 'object': 'Object', | |
39 # Map to extra precision - int is a bignum in Dart. | |
40 'short': 'int', | |
41 'string': 'String', | |
42 'void': 'void', | |
43 'Array': 'List', | |
44 'sequence': 'List', | |
45 # TODO(sra): Come up with some meaningful name so that where this appears in | |
46 # the documentation, the user is made aware that only a limited subset of | |
47 # serializable types are actually permitted. | |
48 'SerializedScriptValue': 'Dynamic', | |
49 # TODO(vsm): Automatically recognize types defined in src. | |
50 'TimeoutHandler': 'TimeoutHandler', | |
51 'RequestAnimationFrameCallback': 'RequestAnimationFrameCallback', | |
52 | |
53 # TODO(sra): Flags is really a dictionary: {create:bool, exclusive:bool} | |
54 # http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#the-flags-interfa
ce | |
55 'WebKitFlags': 'Object', | |
56 } | |
57 | |
58 _dart_to_idl_type_conversions = dict((v,k) for k, v in | |
59 _idl_to_dart_type_conversions.iteritems()) | |
60 | |
61 | |
62 # | |
63 # Identifiers that are used in the IDL than need to be treated specially because | |
64 # *some* JavaScript processors forbid them as properties. | |
65 # | |
66 _javascript_keywords = ['delete', 'continue'] | |
67 | |
68 # | |
69 # Interface version of the DOM needs to delegate typed array constructors to a | |
70 # factory provider. | |
71 # | |
72 _interface_factories = { | |
73 'Float32Array': '_TypedArrayFactoryProvider', | |
74 'Float64Array': '_TypedArrayFactoryProvider', | |
75 'Int8Array': '_TypedArrayFactoryProvider', | |
76 'Int16Array': '_TypedArrayFactoryProvider', | |
77 'Int32Array': '_TypedArrayFactoryProvider', | |
78 'Uint8Array': '_TypedArrayFactoryProvider', | |
79 'Uint16Array': '_TypedArrayFactoryProvider', | |
80 'Uint32Array': '_TypedArrayFactoryProvider', | |
81 'Uint8ClampedArray': '_TypedArrayFactoryProvider', | |
82 } | |
83 | |
84 # | |
85 # Custom methods that must be implemented by hand. | |
86 # | |
87 _custom_methods = set([ | |
88 ('DOMWindow', 'setInterval'), | |
89 ('DOMWindow', 'setTimeout'), | |
90 ('WorkerContext', 'setInterval'), | |
91 ('WorkerContext', 'setTimeout'), | |
92 ('CanvasRenderingContext2D', 'setFillStyle'), | |
93 ('CanvasRenderingContext2D', 'setStrokeStyle'), | |
94 ('CanvasRenderingContext2D', 'setFillStyle'), | |
95 ]) | |
96 | |
97 # | |
98 # Custom getters that must be implemented by hand. | |
99 # | |
100 _custom_getters = set([ | |
101 ('DOMWindow', 'localStorage'), | |
102 ]) | |
103 | |
104 # | |
105 # Custom native specs for the Frog dom. | |
106 # | |
107 _frog_dom_custom_native_specs = { | |
108 # Decorate the singleton Console object, if present (workers do not have a | |
109 # console). | |
110 'Console': "=(typeof console == 'undefined' ? {} : console)", | |
111 | |
112 # DOMWindow aliased with global scope. | |
113 'DOMWindow': '@*DOMWindow', | |
114 } | |
115 | |
116 # | |
117 # Simple method substitution when one method had different names on different | |
118 # browsers, but are otherwise identical. The alternates are tried in order and | |
119 # the first one defined is used. | |
120 # | |
121 # This can be probably be removed when Chrome renames initWebKitWheelEvent to | |
122 # initWheelEvent. | |
123 # | |
124 _alternate_methods = { | |
125 ('WheelEvent', 'initWheelEvent'): ['initWebKitWheelEvent', 'initWheelEvent'] | |
126 } | |
127 | |
128 | |
129 def _MatchSourceFilter(filter, thing): | |
130 if not filter: | |
131 return True | |
132 else: | |
133 return any(token in thing.annotations for token in filter) | |
134 | |
135 def _IsDartListType(type): | |
136 return type == 'List' or type.startswith('List<') | |
137 | |
138 def _IsDartCollectionType(type): | |
139 return _IsDartListType(type) | |
140 | |
141 | |
142 class DartGenerator(object): | 21 class DartGenerator(object): |
143 """Utilities to generate Dart APIs and corresponding JavaScript.""" | 22 """Utilities to generate Dart APIs and corresponding JavaScript.""" |
144 | 23 |
145 def __init__(self, auxiliary_dir, template_dir, base_package): | 24 def __init__(self, auxiliary_dir, template_dir, base_package): |
146 """Constructor for the DartGenerator. | 25 """Constructor for the DartGenerator. |
147 | 26 |
148 Args: | 27 Args: |
149 auxiliary_dir -- location of auxiliary handwritten classes | 28 auxiliary_dir -- location of auxiliary handwritten classes |
150 template_dir -- location of template files | 29 template_dir -- location of template files |
151 base_package -- the base package name for the generated code. | 30 base_package -- the base package name for the generated code. |
152 """ | 31 """ |
153 self._auxiliary_dir = auxiliary_dir | 32 self._auxiliary_dir = auxiliary_dir |
154 self._template_dir = template_dir | 33 self._template_dir = template_dir |
155 self._base_package = base_package | 34 self._base_package = base_package |
156 self._auxiliary_files = {} | 35 self._auxiliary_files = {} |
157 self._dart_templates_re = re.compile(r'[\w.:]+<([\w\.<>:]+)>') | 36 self._dart_templates_re = re.compile(r'[\w.:]+<([\w\.<>:]+)>') |
158 | 37 |
159 self._emitters = None # set later | 38 self._emitters = None # set later |
160 | 39 |
161 | 40 |
162 def _StripModules(self, type_name): | 41 def _StripModules(self, type_name): |
163 return type_name.split('::')[-1] | 42 return type_name.split('::')[-1] |
164 | 43 |
165 def _IsPrimitiveType(self, type_name): | |
166 return (self._ConvertPrimitiveType(type_name) is not None or | |
167 type_name in _dart_to_idl_type_conversions) | |
168 | |
169 def _IsCompoundType(self, database, type_name): | 44 def _IsCompoundType(self, database, type_name): |
170 if self._IsPrimitiveType(type_name): | 45 if IsPrimitiveType(type_name): |
171 return True | 46 return True |
172 | 47 |
173 striped_type_name = self._StripModules(type_name) | 48 striped_type_name = self._StripModules(type_name) |
174 if database.HasInterface(striped_type_name): | 49 if database.HasInterface(striped_type_name): |
175 return True | 50 return True |
176 | 51 |
177 dart_template_match = self._dart_templates_re.match(type_name) | 52 dart_template_match = self._dart_templates_re.match(type_name) |
178 if dart_template_match: | 53 if dart_template_match: |
179 # Dart templates | 54 # Dart templates |
180 parent_type_name = type_name[0 : dart_template_match.start(1) - 1] | 55 parent_type_name = type_name[0 : dart_template_match.start(1) - 1] |
181 sub_type_name = dart_template_match.group(1) | 56 sub_type_name = dart_template_match.group(1) |
182 return (self._IsCompoundType(database, parent_type_name) and | 57 return (self._IsCompoundType(database, parent_type_name) and |
183 self._IsCompoundType(database, sub_type_name)) | 58 self._IsCompoundType(database, sub_type_name)) |
184 return False | 59 return False |
185 | 60 |
186 def _IsDartType(self, type_name): | 61 def _IsDartType(self, type_name): |
187 return '.' in type_name | 62 return '.' in type_name |
188 | 63 |
189 def _ConvertPrimitiveType(self, type_name): | |
190 if type_name.startswith('unsigned '): | |
191 type_name = type_name[len('unsigned '):] | |
192 | |
193 if type_name in _idl_to_dart_type_conversions: | |
194 # Primitive type conversion | |
195 return _idl_to_dart_type_conversions[type_name] | |
196 return None | |
197 | |
198 def LoadAuxiliary(self): | 64 def LoadAuxiliary(self): |
199 def Visitor(_, dirname, names): | 65 def Visitor(_, dirname, names): |
200 for name in names: | 66 for name in names: |
201 if name.endswith('.dart'): | 67 if name.endswith('.dart'): |
202 name = name[0:-5] # strip off ".dart" | 68 name = name[0:-5] # strip off ".dart" |
203 self._auxiliary_files[name] = os.path.join(dirname, name) | 69 self._auxiliary_files[name] = os.path.join(dirname, name) |
204 os.path.walk(self._auxiliary_dir, Visitor, None) | 70 os.path.walk(self._auxiliary_dir, Visitor, None) |
205 | 71 |
206 def RenameTypes(self, database, conversion_table=None): | 72 def RenameTypes(self, database, conversion_table, rename_javascript_binding_na
mes): |
207 """Renames interfaces using the given conversion table. | 73 """Renames interfaces using the given conversion table. |
208 | 74 |
209 References through all interfaces will be renamed as well. | 75 References through all interfaces will be renamed as well. |
210 | 76 |
211 Args: | 77 Args: |
212 database: the database to apply the renames to. | 78 database: the database to apply the renames to. |
213 conversion_table: maps old names to new names. | 79 conversion_table: maps old names to new names. |
214 """ | 80 """ |
215 | 81 |
216 if conversion_table is None: | 82 if conversion_table is None: |
217 conversion_table = {} | 83 conversion_table = {} |
218 | 84 |
219 # Rename interfaces: | 85 # Rename interfaces: |
220 for old_name, new_name in conversion_table.items(): | 86 for old_name, new_name in conversion_table.items(): |
221 if database.HasInterface(old_name): | 87 if database.HasInterface(old_name): |
222 _logger.info('renaming interface %s to %s' % | 88 _logger.info('renaming interface %s to %s' % (old_name, new_name)) |
223 (old_name, new_name)) | |
224 interface = database.GetInterface(old_name) | 89 interface = database.GetInterface(old_name) |
225 database.DeleteInterface(old_name) | 90 database.DeleteInterface(old_name) |
226 if not database.HasInterface(new_name): | 91 if not database.HasInterface(new_name): |
227 interface.id = new_name | 92 interface.id = new_name |
228 database.AddInterface(interface) | 93 database.AddInterface(interface) |
229 | 94 else: |
| 95 new_interface = database.GetInterface(new_name) |
| 96 new_interface.merge(interface) |
| 97 |
| 98 interface.javascript_binding_name = (old_name if rename_javascript_bindi
ng_names |
| 99 else new_name) |
| 100 |
230 # Fix references: | 101 # Fix references: |
231 for interface in database.GetInterfaces(): | 102 for interface in database.GetInterfaces(): |
232 for idl_type in interface.all(idlnode.IDLType): | 103 for idl_type in interface.all(idlnode.IDLType): |
233 type_name = self._StripModules(idl_type.id) | 104 type_name = self._StripModules(idl_type.id) |
234 if type_name in conversion_table: | 105 if type_name in conversion_table: |
235 idl_type.id = conversion_table[type_name] | 106 idl_type.id = conversion_table[type_name] |
236 | 107 |
237 def FilterMembersWithUnidentifiedTypes(self, database): | 108 def FilterMembersWithUnidentifiedTypes(self, database): |
238 """Removes unidentified types. | 109 """Removes unidentified types. |
239 | 110 |
(...skipping 18 matching lines...) Expand all Loading... |
258 interface.attributes = filter(IsIdentified, interface.attributes) | 129 interface.attributes = filter(IsIdentified, interface.attributes) |
259 interface.operations = filter(IsIdentified, interface.operations) | 130 interface.operations = filter(IsIdentified, interface.operations) |
260 interface.parents = filter(IsIdentified, interface.parents) | 131 interface.parents = filter(IsIdentified, interface.parents) |
261 | 132 |
262 def ConvertToDartTypes(self, database): | 133 def ConvertToDartTypes(self, database): |
263 """Converts all IDL types to Dart primitives or qualified types""" | 134 """Converts all IDL types to Dart primitives or qualified types""" |
264 | 135 |
265 def ConvertType(interface, type_name): | 136 def ConvertType(interface, type_name): |
266 """Helper method for converting a type name to the proper | 137 """Helper method for converting a type name to the proper |
267 Dart name""" | 138 Dart name""" |
268 if self._IsPrimitiveType(type_name): | 139 if IsPrimitiveType(type_name): |
269 return self._ConvertPrimitiveType(type_name) | 140 return ConvertPrimitiveType(type_name) |
270 | 141 |
271 if self._IsDartType(type_name): | 142 if self._IsDartType(type_name): |
272 # This is for when dart qualified names are explicitly | 143 # This is for when dart qualified names are explicitly |
273 # defined in the IDLs. Just let them be. | 144 # defined in the IDLs. Just let them be. |
274 return type_name | 145 return type_name |
275 | 146 |
276 dart_template_match = self._dart_templates_re.match(type_name) | 147 dart_template_match = self._dart_templates_re.match(type_name) |
277 if dart_template_match: | 148 if dart_template_match: |
278 # Dart templates | 149 # Dart templates |
279 parent_type_name = type_name[0 : dart_template_match.start(1) - 1] | 150 parent_type_name = type_name[0 : dart_template_match.start(1) - 1] |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
342 interface.parents = filter(HasAnnotations, interface.parents) | 213 interface.parents = filter(HasAnnotations, interface.parents) |
343 else: | 214 else: |
344 database.DeleteInterface(interface.id) | 215 database.DeleteInterface(interface.id) |
345 | 216 |
346 self.FilterMembersWithUnidentifiedTypes(database) | 217 self.FilterMembersWithUnidentifiedTypes(database) |
347 | 218 |
348 | 219 |
349 def Generate(self, database, output_dir, | 220 def Generate(self, database, output_dir, |
350 module_source_preference=[], source_filter=None, | 221 module_source_preference=[], source_filter=None, |
351 super_database=None, common_prefix=None, super_map={}, | 222 super_database=None, common_prefix=None, super_map={}, |
352 lib_dir=None, systems=[]): | 223 html_map={}, lib_dir=None, systems=[]): |
353 """Generates Dart and JS files for the loaded interfaces. | 224 """Generates Dart and JS files for the loaded interfaces. |
354 | 225 |
355 Args: | 226 Args: |
356 database -- database containing interfaces to generate code for. | 227 database -- database containing interfaces to generate code for. |
357 output_dir -- directory to write generated files to. | 228 output_dir -- directory to write generated files to. |
358 module_source_preference -- priority order list of source annotations to | 229 module_source_preference -- priority order list of source annotations to |
359 use when choosing a module name, if none specified uses the module name | 230 use when choosing a module name, if none specified uses the module name |
360 from the database. | 231 from the database. |
361 source_filter -- if specified, only outputs interfaces that have one of | 232 source_filter -- if specified, only outputs interfaces that have one of |
362 these source annotation and rewrites the names of superclasses not | 233 these source annotation and rewrites the names of superclasses not |
363 marked with this source to use the common prefix. | 234 marked with this source to use the common prefix. |
364 super_database -- database containing super interfaces that the generated | 235 super_database -- database containing super interfaces that the generated |
365 interfaces should extend. | 236 interfaces should extend. |
366 common_prefix -- prefix for the common library, if any. | 237 common_prefix -- prefix for the common library, if any. |
367 lib_file_path -- filename for generated .lib file, None if not required. | 238 lib_file_path -- filename for generated .lib file, None if not required. |
368 lib_template -- template file in this directory for generated lib file. | 239 lib_template -- template file in this directory for generated lib file. |
369 """ | 240 """ |
370 | 241 |
371 self._emitters = multiemitter.MultiEmitter() | 242 self._emitters = multiemitter.MultiEmitter() |
372 self._database = database | 243 self._database = database |
373 self._output_dir = output_dir | 244 self._output_dir = output_dir |
374 | 245 |
375 self._ComputeInheritanceClosure() | 246 self._ComputeInheritanceClosure() |
376 | 247 |
377 self._systems = [] | 248 self._systems = [] |
378 | 249 |
379 # TODO(jmesserly): only create these if needed | 250 # TODO(jmesserly): only create these if needed |
380 interface_system = InterfacesSystem( | 251 if ('htmlfrog' in systems) or ('htmldartium' in systems): |
381 TemplateLoader(self._template_dir, ['dom/interface', 'dom', '']), | 252 html_interface_system = HtmlInterfacesSystem( |
382 self._database, self._emitters, self._output_dir) | 253 TemplateLoader(self._template_dir, ['html/interface', 'html', '']), |
383 self._systems.append(interface_system) | 254 self._database, self._emitters, self._output_dir, self) |
384 | 255 self._systems.append(html_interface_system) |
385 html_interface_system = HtmlInterfacesSystem( | 256 else: |
386 TemplateLoader(self._template_dir, ['html/interface', 'html', '']), | 257 interface_system = InterfacesSystem( |
387 self._database, self._emitters, self._output_dir) | 258 TemplateLoader(self._template_dir, ['dom/interface', 'dom', '']), |
388 self._systems.append(html_interface_system) | 259 self._database, self._emitters, self._output_dir) |
| 260 self._systems.append(interface_system) |
389 | 261 |
390 if 'native' in systems: | 262 if 'native' in systems: |
391 native_system = NativeImplementationSystem( | 263 native_system = NativeImplementationSystem( |
392 TemplateLoader(self._template_dir, ['dom/native', 'dom', '']), | 264 TemplateLoader(self._template_dir, ['dom/native', 'dom', '']), |
393 self._database, self._emitters, self._auxiliary_dir, | 265 self._database, self._emitters, self._auxiliary_dir, |
394 self._output_dir) | 266 self._output_dir) |
395 | 267 |
396 self._systems.append(native_system) | 268 self._systems.append(native_system) |
397 | 269 |
398 if 'wrapping' in systems: | 270 if 'wrapping' in systems: |
(...skipping 20 matching lines...) Expand all Loading... |
419 frog_system = FrogSystem( | 291 frog_system = FrogSystem( |
420 TemplateLoader(self._template_dir, ['dom/frog', 'dom', '']), | 292 TemplateLoader(self._template_dir, ['dom/frog', 'dom', '']), |
421 self._database, self._emitters, self._output_dir) | 293 self._database, self._emitters, self._output_dir) |
422 | 294 |
423 frog_system._interface_system = interface_system | 295 frog_system._interface_system = interface_system |
424 self._systems.append(frog_system) | 296 self._systems.append(frog_system) |
425 | 297 |
426 if 'htmlfrog' in systems: | 298 if 'htmlfrog' in systems: |
427 html_system = HtmlFrogSystem( | 299 html_system = HtmlFrogSystem( |
428 TemplateLoader(self._template_dir, ['html/frog', 'html', '']), | 300 TemplateLoader(self._template_dir, ['html/frog', 'html', '']), |
429 self._database, self._emitters, self._output_dir) | 301 self._database, self._emitters, self._output_dir, self) |
430 | 302 |
431 html_system._interface_system = html_interface_system | 303 html_system._interface_system = html_interface_system |
432 self._systems.append(html_system) | 304 self._systems.append(html_system) |
433 | 305 |
434 if 'htmldartium' in systems: | 306 if 'htmldartium' in systems: |
435 html_system = HtmlDartiumSystem( | 307 html_system = HtmlDartiumSystem( |
436 TemplateLoader(self._template_dir, ['html/dartium', 'html', '']), | 308 TemplateLoader(self._template_dir, ['html/dartium', 'html', '']), |
437 self._database, self._emitters, self._output_dir) | 309 self._database, self._emitters, self._output_dir, self) |
438 | 310 |
439 html_system._interface_system = html_interface_system | 311 html_system._interface_system = html_interface_system |
440 self._systems.append(html_system) | 312 self._systems.append(html_system) |
441 | 313 |
442 | |
443 # Collect interfaces | 314 # Collect interfaces |
444 interfaces = [] | 315 interfaces = [] |
445 for interface in database.GetInterfaces(): | 316 for interface in database.GetInterfaces(): |
446 if not _MatchSourceFilter(source_filter, interface): | 317 if not MatchSourceFilter(source_filter, interface): |
447 # Skip this interface since it's not present in the required source | 318 # Skip this interface since it's not present in the required source |
448 _logger.info('Omitting interface - %s' % interface.id) | 319 _logger.info('Omitting interface - %s' % interface.id) |
449 continue | 320 continue |
450 interfaces.append(interface) | 321 interfaces.append(interface) |
451 | 322 |
452 # TODO(sra): Use this list of exception names to generate information to | 323 # TODO(sra): Use this list of exception names to generate information to |
453 # tell Frog which exceptions can be passed from JS to Dart code. | 324 # tell Frog which exceptions can be passed from JS to Dart code. |
454 exceptions = self._CollectExceptions(interfaces) | 325 exceptions = self._CollectExceptions(interfaces) |
455 | 326 |
456 # Render all interfaces into Dart and save them in files. | 327 # Render all interfaces into Dart and save them in files. |
(...skipping 10 matching lines...) Expand all Loading... |
467 super_interface = super_name | 338 super_interface = super_name |
468 | 339 |
469 interface_name = interface.id | 340 interface_name = interface.id |
470 auxiliary_file = self._auxiliary_files.get(interface_name) | 341 auxiliary_file = self._auxiliary_files.get(interface_name) |
471 if auxiliary_file is not None: | 342 if auxiliary_file is not None: |
472 _logger.info('Skipping %s because %s exists' % ( | 343 _logger.info('Skipping %s because %s exists' % ( |
473 interface_name, auxiliary_file)) | 344 interface_name, auxiliary_file)) |
474 continue | 345 continue |
475 | 346 |
476 | 347 |
477 info = _RecognizeCallback(interface) | 348 info = RecognizeCallback(interface) |
478 if info: | 349 if info: |
479 for system in self._systems: | 350 for system in self._systems: |
480 system.ProcessCallback(interface, info) | 351 system.ProcessCallback(interface, info) |
481 else: | 352 else: |
482 if 'Callback' in interface.ext_attrs: | 353 if 'Callback' in interface.ext_attrs: |
483 _logger.info('Malformed callback: %s' % interface.id) | 354 _logger.info('Malformed callback: %s' % interface.id) |
484 self._ProcessInterface(interface, super_interface, | 355 self._ProcessInterface(interface, super_interface, |
485 source_filter, common_prefix) | 356 source_filter, common_prefix) |
486 | 357 |
487 # Libraries | 358 # Libraries |
488 if lib_dir: | 359 if lib_dir: |
489 for system in self._systems: | 360 for system in self._systems: |
490 system.GenerateLibraries(lib_dir) | 361 system.GenerateLibraries(lib_dir) |
491 | 362 |
492 for system in self._systems: | 363 for system in self._systems: |
493 system.Finish() | 364 system.Finish() |
494 | 365 |
495 | 366 |
496 def _PreOrderInterfaces(self, interfaces): | 367 def _PreOrderInterfaces(self, interfaces): |
497 """Returns the interfaces in pre-order, i.e. parents first.""" | 368 """Returns the interfaces in pre-order, i.e. parents first.""" |
498 seen = set() | 369 seen = set() |
499 ordered = [] | 370 ordered = [] |
500 def visit(interface): | 371 def visit(interface): |
501 if interface.id in seen: | 372 if interface.id in seen: |
502 return | 373 return |
503 seen.add(interface.id) | 374 seen.add(interface.id) |
504 for parent in interface.parents: | 375 for parent in interface.parents: |
505 if _IsDartCollectionType(parent.type.id): | 376 if IsDartCollectionType(parent.type.id): |
506 continue | 377 continue |
507 if self._database.HasInterface(parent.type.id): | 378 if self._database.HasInterface(parent.type.id): |
508 parent_interface = self._database.GetInterface(parent.type.id) | 379 parent_interface = self._database.GetInterface(parent.type.id) |
509 visit(parent_interface) | 380 visit(parent_interface) |
510 ordered.append(interface) | 381 ordered.append(interface) |
511 | 382 |
512 for interface in interfaces: | 383 for interface in interfaces: |
513 visit(interface) | 384 visit(interface) |
514 return ordered | 385 return ordered |
515 | 386 |
(...skipping 16 matching lines...) Expand all Loading... |
532 for const in sorted(interface.constants, ConstantOutputOrder): | 403 for const in sorted(interface.constants, ConstantOutputOrder): |
533 for generator in generators: | 404 for generator in generators: |
534 generator.AddConstant(const) | 405 generator.AddConstant(const) |
535 | 406 |
536 attributes = [attr for attr in interface.attributes | 407 attributes = [attr for attr in interface.attributes |
537 if not self._IsEventAttribute(interface, attr)] | 408 if not self._IsEventAttribute(interface, attr)] |
538 for (getter, setter) in _PairUpAttributes(attributes): | 409 for (getter, setter) in _PairUpAttributes(attributes): |
539 for generator in generators: | 410 for generator in generators: |
540 generator.AddAttribute(getter, setter) | 411 generator.AddAttribute(getter, setter) |
541 | 412 |
542 events = _PairUpAttributes([attr for attr in interface.attributes | 413 events = set([attr for attr in interface.attributes |
543 if self._IsEventAttribute(interface, attr)]) | 414 if self._IsEventAttribute(interface, attr)]) |
| 415 |
544 if events: | 416 if events: |
545 for generator in generators: | 417 for generator in generators: |
546 generator.AddEventAttributes(events) | 418 generator.AddEventAttributes(events) |
547 | 419 |
548 # The implementation should define an indexer if the interface directly | 420 # The implementation should define an indexer if the interface directly |
549 # extends List. | 421 # extends List. |
550 element_type = MaybeListElementType(interface) | 422 element_type = MaybeListElementType(interface) |
551 if element_type: | 423 if element_type: |
552 for generator in generators: | 424 for generator in generators: |
553 generator.AddIndexer(element_type) | 425 generator.AddIndexer(element_type) |
554 | |
555 # Group overloaded operations by id | 426 # Group overloaded operations by id |
556 operationsById = {} | 427 operationsById = {} |
557 for operation in interface.operations: | 428 for operation in interface.operations: |
558 if operation.id not in operationsById: | 429 if operation.id not in operationsById: |
559 operationsById[operation.id] = [] | 430 operationsById[operation.id] = [] |
560 operationsById[operation.id].append(operation) | 431 operationsById[operation.id].append(operation) |
561 | 432 |
562 # Generate operations | 433 # Generate operations |
563 for id in sorted(operationsById.keys()): | 434 for id in sorted(operationsById.keys()): |
564 operations = operationsById[id] | 435 operations = operationsById[id] |
565 info = _AnalyzeOperation(interface, operations) | 436 info = AnalyzeOperation(interface, operations) |
566 for generator in generators: | 437 for generator in generators: |
567 generator.AddOperation(info) | 438 generator.AddOperation(info) |
568 | 439 |
569 # With multiple inheritance, attributes and operations of non-first | 440 # With multiple inheritance, attributes and operations of non-first |
570 # interfaces need to be added. Sometimes the attribute or operation is | 441 # interfaces need to be added. Sometimes the attribute or operation is |
571 # defined in the current interface as well as a parent. In that case we | 442 # defined in the current interface as well as a parent. In that case we |
572 # avoid making a duplicate definition and pray that the signatures match. | 443 # avoid making a duplicate definition and pray that the signatures match. |
573 | 444 |
574 for parent_interface in self._TransitiveSecondaryParents(interface): | 445 for parent_interface in self._TransitiveSecondaryParents(interface): |
575 if isinstance(parent_interface, str): # _IsDartCollectionType(parent_inte
rface) | 446 if isinstance(parent_interface, str): # IsDartCollectionType(parent_inter
face) |
576 continue | 447 continue |
577 attributes = [attr for attr in parent_interface.attributes | 448 attributes = [attr for attr in parent_interface.attributes |
578 if not _FindMatchingAttribute(interface, attr)] | 449 if not FindMatchingAttribute(interface, attr)] |
579 for (getter, setter) in _PairUpAttributes(attributes): | 450 for (getter, setter) in _PairUpAttributes(attributes): |
580 for generator in generators: | 451 for generator in generators: |
581 generator.AddSecondaryAttribute(parent_interface, getter, setter) | 452 generator.AddSecondaryAttribute(parent_interface, getter, setter) |
582 | 453 |
583 # Group overloaded operations by id | 454 # Group overloaded operations by id |
584 operationsById = {} | 455 operationsById = {} |
585 for operation in parent_interface.operations: | 456 for operation in parent_interface.operations: |
586 if operation.id not in operationsById: | 457 if operation.id not in operationsById: |
587 operationsById[operation.id] = [] | 458 operationsById[operation.id] = [] |
588 operationsById[operation.id].append(operation) | 459 operationsById[operation.id].append(operation) |
589 | 460 |
590 # Generate operations | 461 # Generate operations |
591 for id in sorted(operationsById.keys()): | 462 for id in sorted(operationsById.keys()): |
592 if not any(op.id == id for op in interface.operations): | 463 if not any(op.id == id for op in interface.operations): |
593 operations = operationsById[id] | 464 operations = operationsById[id] |
594 info = _AnalyzeOperation(interface, operations) | 465 info = AnalyzeOperation(interface, operations) |
595 for generator in generators: | 466 for generator in generators: |
596 generator.AddSecondaryOperation(parent_interface, info) | 467 generator.AddSecondaryOperation(parent_interface, info) |
597 | 468 |
598 for generator in generators: | 469 for generator in generators: |
599 generator.FinishInterface() | 470 generator.FinishInterface() |
600 return | 471 return |
601 | 472 |
602 def _IsEventAttribute(self, interface, attr): | 473 def _IsEventAttribute(self, interface, attr): |
603 # Remove EventListener attributes like 'onclick' when addEventListener | 474 # Remove EventListener attributes like 'onclick' when addEventListener |
604 # is available. | 475 # is available. |
605 if attr.type.id == 'EventListener': | 476 return (attr.type.id == 'EventListener' and |
606 if 'EventTarget' in self._AllImplementedInterfaces(interface): | 477 'EventTarget' in self._AllImplementedInterfaces(interface)) |
607 return True | |
608 return False | |
609 | 478 |
610 def _TransitiveSecondaryParents(self, interface): | 479 def _TransitiveSecondaryParents(self, interface): |
611 """Returns a list of all non-primary parents. | 480 """Returns a list of all non-primary parents. |
612 | 481 |
613 The list contains the interface objects for interfaces defined in the | 482 The list contains the interface objects for interfaces defined in the |
614 database, and the name for undefined interfaces. | 483 database, and the name for undefined interfaces. |
615 """ | 484 """ |
616 def walk(parents): | 485 def walk(parents): |
617 for parent in parents: | 486 for parent in parents: |
618 if _IsDartCollectionType(parent.type.id): | 487 if IsDartCollectionType(parent.type.id): |
619 result.append(parent.type.id) | 488 result.append(parent.type.id) |
620 continue | 489 continue |
621 if self._database.HasInterface(parent.type.id): | 490 if self._database.HasInterface(parent.type.id): |
622 parent_interface = self._database.GetInterface(parent.type.id) | 491 parent_interface = self._database.GetInterface(parent.type.id) |
623 result.append(parent_interface) | 492 result.append(parent_interface) |
624 walk(parent_interface.parents) | 493 walk(parent_interface.parents) |
625 | 494 |
626 result = [] | 495 result = [] |
627 walk(interface.parents[1:]) | 496 walk(interface.parents[1:]) |
628 return result; | 497 return result; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
671 collected = [] | 540 collected = [] |
672 Collect(interface, seen, collected) | 541 Collect(interface, seen, collected) |
673 self._inheritance_closure[interface.id] = collected | 542 self._inheritance_closure[interface.id] = collected |
674 | 543 |
675 def _AllImplementedInterfaces(self, interface): | 544 def _AllImplementedInterfaces(self, interface): |
676 """Returns a list of the names of all interfaces implemented by 'interface'. | 545 """Returns a list of the names of all interfaces implemented by 'interface'. |
677 List includes the name of 'interface'. | 546 List includes the name of 'interface'. |
678 """ | 547 """ |
679 return self._inheritance_closure[interface.id] | 548 return self._inheritance_closure[interface.id] |
680 | 549 |
681 | |
682 def _RecognizeCallback(interface): | |
683 """Returns the info for the callback method if the interface smells like a | |
684 callback. | |
685 """ | |
686 if 'Callback' not in interface.ext_attrs: return None | |
687 handlers = [op for op in interface.operations if op.id == 'handleEvent'] | |
688 if not handlers: return None | |
689 if not (handlers == interface.operations): return None | |
690 return _AnalyzeOperation(interface, handlers) | |
691 | |
692 | |
693 def _PairUpAttributes(attributes): | 550 def _PairUpAttributes(attributes): |
694 """Returns a list of (getter, setter) pairs sorted by name. | 551 """Returns a list of (getter, setter) pairs sorted by name. |
695 | 552 |
696 One element of the pair may be None. | 553 One element of the pair may be None. |
697 """ | 554 """ |
698 names = sorted(set(attr.id for attr in attributes)) | 555 names = sorted(set(attr.id for attr in attributes)) |
699 getters = {} | 556 getters = {} |
700 setters = {} | 557 setters = {} |
701 for attr in attributes: | 558 for attr in attributes: |
702 if attr.is_fc_getter: | 559 if attr.is_fc_getter: |
703 getters[attr.id] = attr | 560 getters[attr.id] = attr |
704 elif attr.is_fc_setter: | 561 elif attr.is_fc_setter: |
705 setters[attr.id] = attr | 562 setters[attr.id] = attr |
706 return [(getters.get(id), setters.get(id)) for id in names] | 563 return [(getters.get(id), setters.get(id)) for id in names] |
707 | 564 |
708 | |
709 def _FindMatchingAttribute(interface, attr1): | |
710 matches = [attr2 for attr2 in interface.attributes | |
711 if attr1.id == attr2.id | |
712 and attr1.is_fc_getter == attr2.is_fc_getter | |
713 and attr1.is_fc_setter == attr2.is_fc_setter] | |
714 if matches: | |
715 assert len(matches) == 1 | |
716 return matches[0] | |
717 return None | |
718 | |
719 | |
720 def _AnalyzeOperation(interface, operations): | |
721 """Makes operation calling convention decision for a set of overloads. | |
722 | |
723 Returns: An OperationInfo object. | |
724 """ | |
725 | |
726 # Zip together arguments from each overload by position, then convert | |
727 # to a dart argument. | |
728 | |
729 # Given a list of overloaded arguments, choose a suitable name. | |
730 def OverloadedName(args): | |
731 return '_OR_'.join(sorted(set(arg.id for arg in args))) | |
732 | |
733 # Given a list of overloaded arguments, choose a suitable type. | |
734 def OverloadedType(args): | |
735 typeIds = sorted(set(arg.type.id for arg in args)) | |
736 if len(typeIds) == 1: | |
737 return typeIds[0] | |
738 else: | |
739 return TypeName(typeIds, interface) | |
740 | |
741 # Given a list of overloaded arguments, render a dart argument. | |
742 def DartArg(args): | |
743 filtered = filter(None, args) | |
744 optional = any(not arg or arg.is_optional for arg in args) | |
745 type = OverloadedType(filtered) | |
746 name = OverloadedName(filtered) | |
747 if optional: | |
748 return (name, type, 'null') | |
749 else: | |
750 return (name, type, None) | |
751 | |
752 args = map(lambda *args: DartArg(args), | |
753 *(op.arguments for op in operations)) | |
754 | |
755 info = OperationInfo() | |
756 info.overloads = operations | |
757 info.declared_name = operations[0].id | |
758 info.name = operations[0].ext_attrs.get('DartName', info.declared_name) | |
759 info.js_name = info.declared_name | |
760 info.type_name = operations[0].type.id # TODO: widen. | |
761 info.arg_infos = args | |
762 return info | |
763 | |
764 | |
765 class OperationInfo(object): | |
766 """Holder for various derived information from a set of overloaded operations. | |
767 | |
768 Attributes: | |
769 overloads: A list of IDL operation overloads with the same name. | |
770 name: A string, the simple name of the operation. | |
771 type_name: A string, the name of the return type of the operation. | |
772 arg_infos: A list of (name, type, default_value) tuples. | |
773 default_value is None for mandatory arguments. | |
774 """ | |
775 | |
776 def ParametersInterfaceDeclaration(self): | |
777 """Returns a formatted string declaring the parameters for the interface.""" | |
778 return self._FormatArgs(self.arg_infos, True) | |
779 | |
780 def ParametersImplementationDeclaration(self, rename_type=None): | |
781 """Returns a formatted string declaring the parameters for the | |
782 implementation. | |
783 | |
784 Args: | |
785 rename_type: A function that allows the types to be renamed. | |
786 """ | |
787 args = self.arg_infos | |
788 if rename_type: | |
789 args = [(name, rename_type(type), default) | |
790 for (name, type, default) in args] | |
791 return self._FormatArgs(args, False) | |
792 | |
793 | |
794 def _FormatArgs(self, args, is_interface): | |
795 def FormatArg(arg_info): | |
796 """Returns an argument declaration fragment for an argument info tuple.""" | |
797 (name, type, default) = arg_info | |
798 if default: | |
799 return '%s %s = %s' % (type, name, default) | |
800 else: | |
801 return '%s %s' % (type, name) | |
802 | |
803 required = [] | |
804 optional = [] | |
805 for (name, type, default) in args: | |
806 if default: | |
807 if is_interface: | |
808 optional.append((name, type, None)) # Default values illegal. | |
809 else: | |
810 optional.append((name, type, default)) | |
811 else: | |
812 if optional: | |
813 raise Exception('Optional arguments cannot precede required ones: ' | |
814 + str(args)) | |
815 required.append((name, type, None)) | |
816 argtexts = map(FormatArg, required) | |
817 if optional: | |
818 argtexts.append('[' + ', '.join(map(FormatArg, optional)) + ']') | |
819 return ', '.join(argtexts) | |
820 | |
821 | |
822 def MaybeListElementTypeName(type_name): | |
823 """Returns the List element type T from string of form "List<T>", or None.""" | |
824 match = re.match(r'List<(\w*)>$', type_name) | |
825 if match: | |
826 return match.group(1) | |
827 return None | |
828 | |
829 def MaybeListElementType(interface): | |
830 """Returns the List element type T, or None in interface does not implement | |
831 List<T>. | |
832 """ | |
833 for parent in interface.parents: | |
834 element_type = MaybeListElementTypeName(parent.type.id) | |
835 if element_type: | |
836 return element_type | |
837 return None | |
838 | |
839 def MaybeTypedArrayElementType(interface): | |
840 """Returns the typed array element type, or None in interface is not a | |
841 TypedArray. | |
842 """ | |
843 # Typed arrays implement ArrayBufferView and List<T>. | |
844 for parent in interface.parents: | |
845 if parent.type.id == 'ArrayBufferView': | |
846 return MaybeListElementType(interface) | |
847 if parent.type.id == 'Uint8Array': | |
848 return 'int' | |
849 return None | |
850 | |
851 | |
852 def AttributeOutputOrder(a, b): | |
853 """Canonical output ordering for attributes.""" | |
854 # Getters before setters: | |
855 if a.id < b.id: return -1 | |
856 if a.id > b.id: return 1 | |
857 if a.is_fc_setter < b.is_fc_setter: return -1 | |
858 if a.is_fc_setter > b.is_fc_setter: return 1 | |
859 return 0 | |
860 | |
861 def ConstantOutputOrder(a, b): | |
862 """Canonical output ordering for constants.""" | |
863 if a.id < b.id: return -1 | |
864 if a.id > b.id: return 1 | |
865 return 0 | |
866 | |
867 | |
868 def _FormatNameList(names): | |
869 """Returns JavaScript array literal expression with one name per line.""" | |
870 #names = sorted(names) | |
871 if len(names) <= 1: | |
872 expression_string = str(names) # e.g. ['length'] | |
873 else: | |
874 expression_string = ',\n '.join(str(names).split(',')) | |
875 expression_string = expression_string.replace('[', '[\n ') | |
876 return expression_string | |
877 | |
878 | |
879 def IndentText(text, indent): | |
880 """Format lines of text with indent.""" | |
881 def FormatLine(line): | |
882 if line.strip(): | |
883 return '%s%s\n' % (indent, line) | |
884 else: | |
885 return '\n' | |
886 return ''.join(FormatLine(line) for line in text.split('\n')) | |
887 | |
888 # ------------------------------------------------------------------------------ | 565 # ------------------------------------------------------------------------------ |
889 | 566 |
890 class TemplateLoader(object): | 567 class TemplateLoader(object): |
891 """Loads template files from a path.""" | 568 """Loads template files from a path.""" |
892 | 569 |
893 def __init__(self, root, subpaths): | 570 def __init__(self, root, subpaths): |
894 """Initializes loader. | 571 """Initializes loader. |
895 | 572 |
896 Args: | 573 Args: |
897 root - a string, the directory under which the templates are stored. | 574 root - a string, the directory under which the templates are stored. |
(...skipping 18 matching lines...) Expand all Loading... |
916 return None | 593 return None |
917 | 594 |
918 def Load(self, name): | 595 def Load(self, name): |
919 """Returns contents of template file as a string, or raises an exception.""" | 596 """Returns contents of template file as a string, or raises an exception.""" |
920 template = self.TryLoad(name) | 597 template = self.TryLoad(name) |
921 if template is not None: # Can be empty string | 598 if template is not None: # Can be empty string |
922 return template | 599 return template |
923 raise Exception("Could not find template '%s' on %s / %s" % ( | 600 raise Exception("Could not find template '%s' on %s / %s" % ( |
924 name, self._root, self._subpaths)) | 601 name, self._root, self._subpaths)) |
925 | 602 |
926 | |
927 # ------------------------------------------------------------------------------ | |
928 | |
929 class System(object): | |
930 """Generates all the files for one implementation.""" | |
931 | |
932 def __init__(self, templates, database, emitters, output_dir): | |
933 self._templates = templates | |
934 self._database = database | |
935 self._emitters = emitters | |
936 self._output_dir = output_dir | |
937 self._dart_callback_file_paths = [] | |
938 | |
939 def InterfaceGenerator(self, | |
940 interface, | |
941 common_prefix, | |
942 super_interface_name, | |
943 source_filter): | |
944 """Returns an interface generator for |interface|.""" | |
945 return None | |
946 | |
947 def ProcessCallback(self, interface, info): | |
948 pass | |
949 | |
950 def GenerateLibraries(self, lib_dir): | |
951 pass | |
952 | |
953 def Finish(self): | |
954 pass | |
955 | |
956 | |
957 def _ProcessCallback(self, interface, info, file_path): | |
958 """Generates a typedef for the callback interface.""" | |
959 self._dart_callback_file_paths.append(file_path) | |
960 code = self._emitters.FileEmitter(file_path) | |
961 | |
962 code.Emit(self._templates.Load('callback.darttemplate')) | |
963 code.Emit('typedef $TYPE $NAME($PARAMS);\n', | |
964 NAME=interface.id, | |
965 TYPE=info.type_name, | |
966 PARAMS=info.ParametersImplementationDeclaration()) | |
967 | |
968 def _GenerateLibFile(self, lib_template, lib_file_path, file_paths, | |
969 **template_args): | |
970 """Generates a lib file from a template and a list of files. | |
971 | |
972 Additional keyword arguments are passed to the template. | |
973 """ | |
974 # Load template. | |
975 template = self._templates.Load(lib_template) | |
976 # Generate the .lib file. | |
977 lib_file_contents = self._emitters.FileEmitter(lib_file_path) | |
978 | |
979 # Emit the list of #source directives. | |
980 list_emitter = lib_file_contents.Emit(template, **template_args) | |
981 lib_file_dir = os.path.dirname(lib_file_path) | |
982 for path in sorted(file_paths): | |
983 relpath = os.path.relpath(path, lib_file_dir) | |
984 list_emitter.Emit("#source('$PATH');\n", PATH=relpath) | |
985 | |
986 | |
987 def _BaseDefines(self, interface): | |
988 """Returns a set of names (strings) for members defined in a base class. | |
989 """ | |
990 def WalkParentChain(interface): | |
991 if interface.parents: | |
992 # Only consider primary parent, secondary parents are not on the | |
993 # implementation class inheritance chain. | |
994 parent = interface.parents[0] | |
995 if _IsDartCollectionType(parent.type.id): | |
996 return | |
997 if self._database.HasInterface(parent.type.id): | |
998 parent_interface = self._database.GetInterface(parent.type.id) | |
999 for attr in parent_interface.attributes: | |
1000 result.add(attr.id) | |
1001 for op in parent_interface.operations: | |
1002 result.add(op.id) | |
1003 WalkParentChain(parent_interface) | |
1004 | |
1005 result = set() | |
1006 WalkParentChain(interface) | |
1007 return result; | |
1008 | |
1009 | |
1010 # ------------------------------------------------------------------------------ | |
1011 | |
1012 class InterfacesSystem(System): | |
1013 | |
1014 def __init__(self, templates, database, emitters, output_dir): | |
1015 super(InterfacesSystem, self).__init__( | |
1016 templates, database, emitters, output_dir) | |
1017 self._dart_interface_file_paths = [] | |
1018 | |
1019 | |
1020 def InterfaceGenerator(self, | |
1021 interface, | |
1022 common_prefix, | |
1023 super_interface_name, | |
1024 source_filter): | |
1025 """.""" | |
1026 interface_name = interface.id | |
1027 dart_interface_file_path = self._FilePathForDartInterface(interface_name) | |
1028 | |
1029 self._dart_interface_file_paths.append(dart_interface_file_path) | |
1030 | |
1031 dart_interface_code = self._emitters.FileEmitter(dart_interface_file_path) | |
1032 | |
1033 template_file = 'interface_%s.darttemplate' % interface_name | |
1034 template = self._templates.TryLoad(template_file) | |
1035 if not template: | |
1036 template = self._templates.Load('interface.darttemplate') | |
1037 | |
1038 return DartInterfaceGenerator( | |
1039 interface, dart_interface_code, | |
1040 template, | |
1041 common_prefix, super_interface_name, | |
1042 source_filter) | |
1043 | |
1044 def ProcessCallback(self, interface, info): | |
1045 """Generates a typedef for the callback interface.""" | |
1046 interface_name = interface.id | |
1047 file_path = self._FilePathForDartInterface(interface_name) | |
1048 self._ProcessCallback(interface, info, file_path) | |
1049 | |
1050 def GenerateLibraries(self, lib_dir): | |
1051 pass | |
1052 | |
1053 | |
1054 def _FilePathForDartInterface(self, interface_name): | |
1055 """Returns the file path of the Dart interface definition.""" | |
1056 return os.path.join(self._output_dir, 'src', 'interface', | |
1057 '%s.dart' % interface_name) | |
1058 | |
1059 | |
1060 # ------------------------------------------------------------------------------ | |
1061 | |
1062 class HtmlInterfacesSystem(System): | |
1063 | |
1064 def __init__(self, templates, database, emitters, output_dir): | |
1065 super(HtmlInterfacesSystem, self).__init__( | |
1066 templates, database, emitters, output_dir) | |
1067 self._dart_interface_file_paths = [] | |
1068 | |
1069 def InterfaceGenerator(self, | |
1070 interface, | |
1071 common_prefix, | |
1072 super_interface_name, | |
1073 source_filter): | |
1074 """.""" | |
1075 interface_name = interface.id | |
1076 dart_interface_file_path = self._FilePathForDartInterface(interface_name) | |
1077 | |
1078 self._dart_interface_file_paths.append(dart_interface_file_path) | |
1079 | |
1080 dart_interface_code = self._emitters.FileEmitter(dart_interface_file_path) | |
1081 | |
1082 template_file = 'interface_%s.darttemplate' % interface_name | |
1083 template = self._templates.TryLoad(template_file) | |
1084 if not template: | |
1085 template = self._templates.Load('interface.darttemplate') | |
1086 | |
1087 return HtmlDartInterfaceGenerator( | |
1088 interface, dart_interface_code, | |
1089 template, | |
1090 common_prefix, super_interface_name, | |
1091 source_filter) | |
1092 | |
1093 def ProcessCallback(self, interface, info): | |
1094 """Generates a typedef for the callback interface.""" | |
1095 interface_name = interface.id | |
1096 file_path = self._FilePathForDartInterface(interface_name) | |
1097 self._ProcessCallback(interface, info, file_path) | |
1098 | |
1099 def GenerateLibraries(self, lib_dir): | |
1100 pass | |
1101 | |
1102 | |
1103 def _FilePathForDartInterface(self, interface_name): | |
1104 """Returns the file path of the Dart interface definition.""" | |
1105 # TODO(jmesserly): is this the right path | |
1106 return os.path.join(self._output_dir, 'html', 'interface', | |
1107 '%s.dart' % interface_name) | |
1108 | |
1109 | |
1110 # ------------------------------------------------------------------------------ | 603 # ------------------------------------------------------------------------------ |
1111 | 604 |
1112 class DummyImplementationSystem(System): | 605 class DummyImplementationSystem(System): |
1113 """Generates a dummy implementation for use by the editor analysis. | 606 """Generates a dummy implementation for use by the editor analysis. |
1114 | 607 |
1115 All the code comes from hand-written library files. | 608 All the code comes from hand-written library files. |
1116 """ | 609 """ |
1117 | 610 |
1118 def __init__(self, templates, database, emitters, output_dir): | 611 def __init__(self, templates, database, emitters, output_dir): |
1119 super(DummyImplementationSystem, self).__init__( | 612 super(DummyImplementationSystem, self).__init__( |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1192 pass | 685 pass |
1193 | 686 |
1194 | 687 |
1195 def _FilePathForDartWrappingImpl(self, interface_name): | 688 def _FilePathForDartWrappingImpl(self, interface_name): |
1196 """Returns the file path of the Dart wrapping implementation.""" | 689 """Returns the file path of the Dart wrapping implementation.""" |
1197 return os.path.join(self._output_dir, 'src', 'wrapping', | 690 return os.path.join(self._output_dir, 'src', 'wrapping', |
1198 '_%sWrappingImplementation.dart' % interface_name) | 691 '_%sWrappingImplementation.dart' % interface_name) |
1199 | 692 |
1200 # ------------------------------------------------------------------------------ | 693 # ------------------------------------------------------------------------------ |
1201 | 694 |
1202 class FrogSystem(System): | |
1203 | |
1204 def __init__(self, templates, database, emitters, output_dir): | |
1205 super(FrogSystem, self).__init__( | |
1206 templates, database, emitters, output_dir) | |
1207 self._dart_frog_file_paths = [] | |
1208 | |
1209 def InterfaceGenerator(self, | |
1210 interface, | |
1211 common_prefix, | |
1212 super_interface_name, | |
1213 source_filter): | |
1214 """.""" | |
1215 dart_frog_file_path = self._FilePathForFrogImpl(interface.id) | |
1216 self._dart_frog_file_paths.append(dart_frog_file_path) | |
1217 | |
1218 template_file = 'impl_%s.darttemplate' % interface.id | |
1219 template = self._templates.TryLoad(template_file) | |
1220 if not template: | |
1221 template = self._templates.Load('frog_impl.darttemplate') | |
1222 | |
1223 dart_code = self._emitters.FileEmitter(dart_frog_file_path) | |
1224 return FrogInterfaceGenerator(self, interface, template, | |
1225 super_interface_name, dart_code) | |
1226 | |
1227 def GenerateLibraries(self, lib_dir): | |
1228 self._GenerateLibFile( | |
1229 'frog_dom.darttemplate', | |
1230 os.path.join(lib_dir, 'dom_frog.dart'), | |
1231 (self._interface_system._dart_interface_file_paths + | |
1232 self._interface_system._dart_callback_file_paths + | |
1233 self._dart_frog_file_paths)) | |
1234 | |
1235 def Finish(self): | |
1236 pass | |
1237 | |
1238 def _FilePathForFrogImpl(self, interface_name): | |
1239 """Returns the file path of the Frog implementation.""" | |
1240 return os.path.join(self._output_dir, 'src', 'frog', | |
1241 '%s.dart' % interface_name) | |
1242 | |
1243 | |
1244 # ------------------------------------------------------------------------------ | |
1245 | |
1246 class HtmlFrogSystem(System): | |
1247 | |
1248 def __init__(self, templates, database, emitters, output_dir): | |
1249 super(HtmlFrogSystem, self).__init__( | |
1250 templates, database, emitters, output_dir) | |
1251 self._dart_frog_file_paths = [] | |
1252 | |
1253 def InterfaceGenerator(self, | |
1254 interface, | |
1255 common_prefix, | |
1256 super_interface_name, | |
1257 source_filter): | |
1258 """.""" | |
1259 dart_frog_file_path = self._FilePathForFrogImpl(interface.id) | |
1260 self._dart_frog_file_paths.append(dart_frog_file_path) | |
1261 | |
1262 template_file = 'impl_%s.darttemplate' % interface.id | |
1263 template = self._templates.TryLoad(template_file) | |
1264 if not template: | |
1265 template = self._templates.Load('frog_impl.darttemplate') | |
1266 | |
1267 dart_code = self._emitters.FileEmitter(dart_frog_file_path) | |
1268 return HtmlFrogInterfaceGenerator(self, interface, template, | |
1269 super_interface_name, dart_code) | |
1270 | |
1271 def GenerateLibraries(self, lib_dir): | |
1272 self._GenerateLibFile( | |
1273 'html_frog.darttemplate', | |
1274 os.path.join(lib_dir, 'html_frog.dart'), | |
1275 (self._interface_system._dart_interface_file_paths + | |
1276 self._interface_system._dart_callback_file_paths + | |
1277 self._dart_frog_file_paths)) | |
1278 | |
1279 def Finish(self): | |
1280 pass | |
1281 | |
1282 def _FilePathForFrogImpl(self, interface_name): | |
1283 """Returns the file path of the Frog implementation.""" | |
1284 # TODO(jmesserly): is this the right path | |
1285 return os.path.join(self._output_dir, 'html', 'frog', | |
1286 '%s.dart' % interface_name) | |
1287 | |
1288 # ------------------------------------------------------------------------------ | |
1289 | |
1290 class DartInterfaceGenerator(object): | |
1291 """Generates Dart Interface definition for one DOM IDL interface.""" | |
1292 | |
1293 def __init__(self, interface, emitter, template, | |
1294 common_prefix, super_interface, source_filter): | |
1295 """Generates Dart code for the given interface. | |
1296 | |
1297 Args: | |
1298 interface -- an IDLInterface instance. It is assumed that all types have | |
1299 been converted to Dart types (e.g. int, String), unless they are in the | |
1300 same package as the interface. | |
1301 common_prefix -- the prefix for the common library, if any. | |
1302 super_interface -- the name of the common interface that this interface | |
1303 implements, if any. | |
1304 source_filter -- if specified, rewrites the names of any superinterfaces | |
1305 that are not from these sources to use the common prefix. | |
1306 """ | |
1307 self._interface = interface | |
1308 self._emitter = emitter | |
1309 self._template = template | |
1310 self._common_prefix = common_prefix | |
1311 self._super_interface = super_interface | |
1312 self._source_filter = source_filter | |
1313 | |
1314 | |
1315 def StartInterface(self): | |
1316 if self._super_interface: | |
1317 typename = self._super_interface | |
1318 else: | |
1319 typename = self._interface.id | |
1320 | |
1321 # TODO(vsm): Add appropriate package / namespace syntax. | |
1322 (extends_emitter, | |
1323 self._members_emitter, | |
1324 self._top_level_emitter) = self._emitter.Emit( | |
1325 self._template + '$!TOP_LEVEL', | |
1326 ID=typename) | |
1327 | |
1328 extends = [] | |
1329 suppressed_extends = [] | |
1330 | |
1331 for parent in self._interface.parents: | |
1332 # TODO(vsm): Remove source_filter. | |
1333 if _MatchSourceFilter(self._source_filter, parent): | |
1334 # Parent is a DOM type. | |
1335 extends.append(parent.type.id) | |
1336 elif '<' in parent.type.id: | |
1337 # Parent is a Dart collection type. | |
1338 # TODO(vsm): Make this check more robust. | |
1339 extends.append(parent.type.id) | |
1340 else: | |
1341 suppressed_extends.append('%s.%s' % | |
1342 (self._common_prefix, parent.type.id)) | |
1343 | |
1344 comment = ' extends' | |
1345 if extends: | |
1346 extends_emitter.Emit(' extends $SUPERS', SUPERS=', '.join(extends)) | |
1347 comment = ',' | |
1348 if suppressed_extends: | |
1349 extends_emitter.Emit(' /*$COMMENT $SUPERS */', | |
1350 COMMENT=comment, | |
1351 SUPERS=', '.join(suppressed_extends)) | |
1352 | |
1353 if typename in _interface_factories: | |
1354 extends_emitter.Emit(' default $F', F=_interface_factories[typename]) | |
1355 | |
1356 element_type = MaybeTypedArrayElementType(self._interface) | |
1357 if element_type: | |
1358 self._members_emitter.Emit( | |
1359 '\n' | |
1360 ' $CTOR(int length);\n' | |
1361 '\n' | |
1362 ' $CTOR.fromList(List<$TYPE> list);\n' | |
1363 '\n' | |
1364 ' $CTOR.fromBuffer(ArrayBuffer buffer);\n', | |
1365 CTOR=self._interface.id, | |
1366 TYPE=element_type) | |
1367 | |
1368 | |
1369 def FinishInterface(self): | |
1370 # TODO(vsm): Use typedef if / when that is supported in Dart. | |
1371 # Define variant as subtype. | |
1372 if (self._super_interface and | |
1373 self._interface.id is not self._super_interface): | |
1374 consts_emitter = self._top_level_emitter.Emit( | |
1375 '\n' | |
1376 'interface $NAME extends $BASE {\n' | |
1377 '$!CONSTS' | |
1378 '}\n', | |
1379 NAME=self._interface.id, | |
1380 BASE=self._super_interface) | |
1381 for const in sorted(self._interface.constants, ConstantOutputOrder): | |
1382 self._EmitConstant(consts_emitter, const) | |
1383 | |
1384 def AddConstant(self, constant): | |
1385 if (not self._super_interface or | |
1386 self._interface.id is self._super_interface): | |
1387 self._EmitConstant(self._members_emitter, constant) | |
1388 | |
1389 def _EmitConstant(self, emitter, constant): | |
1390 emitter.Emit('\n static final $TYPE $NAME = $VALUE;\n', | |
1391 NAME=constant.id, | |
1392 TYPE=constant.type.id, | |
1393 VALUE=constant.value) | |
1394 | |
1395 def AddAttribute(self, getter, setter): | |
1396 if getter and setter and getter.type.id == setter.type.id: | |
1397 self._members_emitter.Emit('\n $TYPE $NAME;\n', | |
1398 NAME=getter.id, TYPE=getter.type.id); | |
1399 return | |
1400 if getter and not setter: | |
1401 self._members_emitter.Emit('\n final $TYPE $NAME;\n', | |
1402 NAME=getter.id, TYPE=getter.type.id); | |
1403 return | |
1404 raise Exception('Unexpected getter/setter combination %s %s' % | |
1405 (getter, setter)) | |
1406 | |
1407 def AddIndexer(self, element_type): | |
1408 # Interface inherits all operations from List<element_type>. | |
1409 pass | |
1410 | |
1411 def AddOperation(self, info): | |
1412 """ | |
1413 Arguments: | |
1414 operations - contains the overloads, one or more operations with the same | |
1415 name. | |
1416 """ | |
1417 self._members_emitter.Emit('\n' | |
1418 ' $TYPE $NAME($PARAMS);\n', | |
1419 TYPE=info.type_name, | |
1420 NAME=info.name, | |
1421 PARAMS=info.ParametersInterfaceDeclaration()) | |
1422 | |
1423 # Interfaces get secondary members directly via the superinterfaces. | |
1424 def AddSecondaryAttribute(self, interface, getter, setter): | |
1425 pass | |
1426 | |
1427 def AddSecondaryOperation(self, interface, attr): | |
1428 pass | |
1429 | |
1430 def AddEventAttributes(self, event_attrs): | |
1431 pass | |
1432 | |
1433 # Given a sorted sequence of type identifiers, return an appropriate type | |
1434 # name | |
1435 def TypeName(typeIds, interface): | |
1436 # Dynamically type this field for now. | |
1437 return 'var' | |
1438 | |
1439 # ------------------------------------------------------------------------------ | |
1440 | |
1441 # TODO(jmesserly): inheritance is probably not the right way to factor this long | |
1442 # term, but it makes merging better for now. | |
1443 class HtmlDartInterfaceGenerator(DartInterfaceGenerator): | |
1444 """Generates Dart Interface definition for one DOM IDL interface.""" | |
1445 | |
1446 def __init__(self, interface, emitter, template, | |
1447 common_prefix, super_interface, source_filter): | |
1448 super(HtmlDartInterfaceGenerator, self).__init__(interface, | |
1449 emitter, template, common_prefix, super_interface, source_filter) | |
1450 | |
1451 def AddEventAttributes(self, event_attrs): | |
1452 events_interface = self._interface.id + 'Events' | |
1453 self._members_emitter.Emit('\n $TYPE get on();\n', | |
1454 TYPE=events_interface) | |
1455 events_members = self._emitter.Emit( | |
1456 '\ninterface $INTERFACE {\n$!MEMBERS}\n', | |
1457 INTERFACE=events_interface) | |
1458 | |
1459 for getter, setter in event_attrs: | |
1460 event = getter or setter | |
1461 events_members.Emit('\n EventListenerList get $NAME();\n', NAME=event.id) | |
1462 | |
1463 | |
1464 # ------------------------------------------------------------------------------ | |
1465 | |
1466 class DummyInterfaceGenerator(object): | |
1467 """Generates nothing.""" | |
1468 | |
1469 def __init__(self, system, interface): | |
1470 pass | |
1471 | |
1472 def StartInterface(self): | |
1473 pass | |
1474 | |
1475 def FinishInterface(self): | |
1476 pass | |
1477 | |
1478 def AddConstant(self, constant): | |
1479 pass | |
1480 | |
1481 def AddAttribute(self, getter, setter): | |
1482 pass | |
1483 | |
1484 def AddSecondaryAttribute(self, interface, getter, setter): | |
1485 pass | |
1486 | |
1487 def AddSecondaryOperation(self, interface, info): | |
1488 pass | |
1489 | |
1490 def AddIndexer(self, element_type): | |
1491 pass | |
1492 | |
1493 def AddTypedArrayConstructors(self, element_type): | |
1494 pass | |
1495 | |
1496 def AddOperation(self, info): | |
1497 pass | |
1498 | |
1499 def AddEventAttributes(self, event_attrs): | |
1500 pass | |
1501 | |
1502 # ------------------------------------------------------------------------------ | |
1503 | |
1504 class WrappingInterfaceGenerator(object): | |
1505 """Generates Dart and JS implementation for one DOM IDL interface.""" | |
1506 | |
1507 def __init__(self, interface, super_interface, dart_code, base_members): | |
1508 """Generates Dart and JS code for the given interface. | |
1509 | |
1510 Args: | |
1511 | |
1512 interface: an IDLInterface instance. It is assumed that all types have | |
1513 been converted to Dart types (e.g. int, String), unless they are in | |
1514 the same package as the interface. | |
1515 super_interface: A string or None, the name of the common interface that | |
1516 this interface implements, if any. | |
1517 dart_code: an Emitter for the file containing the Dart implementation | |
1518 class. | |
1519 base_members: a set of names of members defined in a base class. This is | |
1520 used to avoid static member 'overriding' in the generated Dart code. | |
1521 """ | |
1522 self._interface = interface | |
1523 self._super_interface = super_interface | |
1524 self._dart_code = dart_code | |
1525 self._base_members = base_members | |
1526 self._current_secondary_parent = None | |
1527 | |
1528 | |
1529 def StartInterface(self): | |
1530 interface = self._interface | |
1531 interface_name = interface.id | |
1532 | |
1533 self._class_name = self._ImplClassName(interface_name) | |
1534 | |
1535 base = self._BaseClassName(interface) | |
1536 | |
1537 (self._members_emitter, | |
1538 self._top_level_emitter) = self._dart_code.Emit( | |
1539 '\n' | |
1540 'class $CLASS extends $BASE implements $INTERFACE {\n' | |
1541 ' $CLASS() : super() {}\n' | |
1542 '\n' | |
1543 ' static create_$CLASS() native {\n' | |
1544 ' return new $CLASS();\n' | |
1545 ' }\n' | |
1546 '$!MEMBERS' | |
1547 '\n' | |
1548 ' String get typeName() { return "$INTERFACE"; }\n' | |
1549 '}\n' | |
1550 '$!TOP_LEVEL', | |
1551 CLASS=self._class_name, BASE=base, INTERFACE=interface_name) | |
1552 | |
1553 def _ImplClassName(self, type_name): | |
1554 return '_' + type_name + 'WrappingImplementation' | |
1555 | |
1556 def _BaseClassName(self, interface): | |
1557 if not interface.parents: | |
1558 return 'DOMWrapperBase' | |
1559 | |
1560 supertype = interface.parents[0].type.id | |
1561 | |
1562 # FIXME: We're currently injecting List<..> and EventTarget as | |
1563 # supertypes in dart.idl. We should annotate/preserve as | |
1564 # attributes instead. For now, this hack lets the interfaces | |
1565 # inherit, but not the classes. | |
1566 # List methods are injected in AddIndexer. | |
1567 if _IsDartListType(supertype) or _IsDartCollectionType(supertype): | |
1568 return 'DOMWrapperBase' | |
1569 | |
1570 if supertype == 'EventTarget': | |
1571 # Most implementors of EventTarget specify the EventListener operations | |
1572 # again. If the operations are not specified, try to inherit from the | |
1573 # EventTarget implementation. | |
1574 # | |
1575 # Applies to MessagePort. | |
1576 if not [op for op in interface.operations if op.id == 'addEventListener']: | |
1577 return self._ImplClassName(supertype) | |
1578 return 'DOMWrapperBase' | |
1579 | |
1580 return self._ImplClassName(supertype) | |
1581 | |
1582 def FinishInterface(self): | |
1583 """.""" | |
1584 pass | |
1585 | |
1586 def AddConstant(self, constant): | |
1587 # Constants are already defined on the interface. | |
1588 pass | |
1589 | |
1590 def _MethodName(self, prefix, name): | |
1591 method_name = prefix + name | |
1592 if name in self._base_members: # Avoid illegal Dart 'static override'. | |
1593 method_name = method_name + '_' + self._interface.id | |
1594 return method_name | |
1595 | |
1596 def AddAttribute(self, getter, setter): | |
1597 if getter: | |
1598 self._AddGetter(getter) | |
1599 if setter: | |
1600 self._AddSetter(setter) | |
1601 | |
1602 def _AddGetter(self, attr): | |
1603 # FIXME: Instead of injecting the interface name into the method when it is | |
1604 # also implemented in the base class, suppress the method altogether if it | |
1605 # has the same signature. I.e., let the JS do the virtual dispatch instead. | |
1606 method_name = self._MethodName('_get_', attr.id) | |
1607 self._members_emitter.Emit( | |
1608 '\n' | |
1609 ' $TYPE get $NAME() { return $METHOD(this); }\n' | |
1610 ' static $TYPE $METHOD(var _this) native;\n', | |
1611 NAME=attr.id, TYPE=attr.type.id, METHOD=method_name) | |
1612 | |
1613 def _AddSetter(self, attr): | |
1614 # FIXME: See comment on getter. | |
1615 method_name = self._MethodName('_set_', attr.id) | |
1616 self._members_emitter.Emit( | |
1617 '\n' | |
1618 ' void set $NAME($TYPE value) { $METHOD(this, value); }\n' | |
1619 ' static void $METHOD(var _this, $TYPE value) native;\n', | |
1620 NAME=attr.id, TYPE=attr.type.id, METHOD=method_name) | |
1621 | |
1622 def AddSecondaryAttribute(self, interface, getter, setter): | |
1623 self._SecondaryContext(interface) | |
1624 self.AddAttribute(getter, setter) | |
1625 | |
1626 def AddSecondaryOperation(self, interface, info): | |
1627 self._SecondaryContext(interface) | |
1628 self.AddOperation(info) | |
1629 | |
1630 def AddEventAttributes(self, event_attrs): | |
1631 pass | |
1632 | |
1633 def _SecondaryContext(self, interface): | |
1634 if interface is not self._current_secondary_parent: | |
1635 self._current_secondary_parent = interface | |
1636 self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id) | |
1637 | |
1638 def AddIndexer(self, element_type): | |
1639 """Adds all the methods required to complete implementation of List.""" | |
1640 # We would like to simply inherit the implementation of everything except | |
1641 # get length(), [], and maybe []=. It is possible to extend from a base | |
1642 # array implementation class only when there is no other implementation | |
1643 # inheritance. There might be no implementation inheritance other than | |
1644 # DOMBaseWrapper for many classes, but there might be some where the | |
1645 # array-ness is introduced by a non-root interface: | |
1646 # | |
1647 # interface Y extends X, List<T> ... | |
1648 # | |
1649 # In the non-root case we have to choose between: | |
1650 # | |
1651 # class YImpl extends XImpl { add List<T> methods; } | |
1652 # | |
1653 # and | |
1654 # | |
1655 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } | |
1656 # | |
1657 if self._HasNativeIndexGetter(self._interface): | |
1658 self._EmitNativeIndexGetter(self._interface, element_type) | |
1659 else: | |
1660 self._members_emitter.Emit( | |
1661 '\n' | |
1662 ' $TYPE operator[](int index) {\n' | |
1663 ' return item(index);\n' | |
1664 ' }\n', | |
1665 TYPE=element_type) | |
1666 | |
1667 if self._HasNativeIndexSetter(self._interface): | |
1668 self._EmitNativeIndexSetter(self._interface, element_type) | |
1669 else: | |
1670 self._members_emitter.Emit( | |
1671 '\n' | |
1672 ' void operator[]=(int index, $TYPE value) {\n' | |
1673 ' throw new UnsupportedOperationException("Cannot assign element of
immutable List.");\n' | |
1674 ' }\n', | |
1675 TYPE=element_type) | |
1676 | |
1677 self._members_emitter.Emit( | |
1678 '\n' | |
1679 ' void add($TYPE value) {\n' | |
1680 ' throw new UnsupportedOperationException("Cannot add to immutable Li
st.");\n' | |
1681 ' }\n' | |
1682 '\n' | |
1683 ' void addLast($TYPE value) {\n' | |
1684 ' throw new UnsupportedOperationException("Cannot add to immutable Li
st.");\n' | |
1685 ' }\n' | |
1686 '\n' | |
1687 ' void addAll(Collection<$TYPE> collection) {\n' | |
1688 ' throw new UnsupportedOperationException("Cannot add to immutable Li
st.");\n' | |
1689 ' }\n' | |
1690 '\n' | |
1691 ' void sort(int compare($TYPE a, $TYPE b)) {\n' | |
1692 ' throw new UnsupportedOperationException("Cannot sort immutable List
.");\n' | |
1693 ' }\n' | |
1694 '\n' | |
1695 ' void copyFrom(List<Object> src, int srcStart, ' | |
1696 'int dstStart, int count) {\n' | |
1697 ' throw new UnsupportedOperationException("This object is immutable."
);\n' | |
1698 ' }\n' | |
1699 '\n' | |
1700 ' int indexOf($TYPE element, [int start = 0]) {\n' | |
1701 ' return _Lists.indexOf(this, element, start, this.length);\n' | |
1702 ' }\n' | |
1703 '\n' | |
1704 ' int lastIndexOf($TYPE element, [int start = null]) {\n' | |
1705 ' if (start === null) start = length - 1;\n' | |
1706 ' return _Lists.lastIndexOf(this, element, start);\n' | |
1707 ' }\n' | |
1708 '\n' | |
1709 ' int clear() {\n' | |
1710 ' throw new UnsupportedOperationException("Cannot clear immutable Lis
t.");\n' | |
1711 ' }\n' | |
1712 '\n' | |
1713 ' $TYPE removeLast() {\n' | |
1714 ' throw new UnsupportedOperationException("Cannot removeLast on immut
able List.");\n' | |
1715 ' }\n' | |
1716 '\n' | |
1717 ' $TYPE last() {\n' | |
1718 ' return this[length - 1];\n' | |
1719 ' }\n' | |
1720 '\n' | |
1721 ' void forEach(void f($TYPE element)) {\n' | |
1722 ' _Collections.forEach(this, f);\n' | |
1723 ' }\n' | |
1724 '\n' | |
1725 ' Collection map(f($TYPE element)) {\n' | |
1726 ' return _Collections.map(this, [], f);\n' | |
1727 ' }\n' | |
1728 '\n' | |
1729 ' Collection<$TYPE> filter(bool f($TYPE element)) {\n' | |
1730 ' return _Collections.filter(this, new List<$TYPE>(), f);\n' | |
1731 ' }\n' | |
1732 '\n' | |
1733 ' bool every(bool f($TYPE element)) {\n' | |
1734 ' return _Collections.every(this, f);\n' | |
1735 ' }\n' | |
1736 '\n' | |
1737 ' bool some(bool f($TYPE element)) {\n' | |
1738 ' return _Collections.some(this, f);\n' | |
1739 ' }\n' | |
1740 '\n' | |
1741 ' void setRange(int start, int length, List<$TYPE> from, [int startFrom
]) {\n' | |
1742 ' throw new UnsupportedOperationException("Cannot setRange on immutab
le List.");\n' | |
1743 ' }\n' | |
1744 '\n' | |
1745 ' void removeRange(int start, int length) {\n' | |
1746 ' throw new UnsupportedOperationException("Cannot removeRange on immu
table List.");\n' | |
1747 ' }\n' | |
1748 '\n' | |
1749 ' void insertRange(int start, int length, [$TYPE initialValue]) {\n' | |
1750 ' throw new UnsupportedOperationException("Cannot insertRange on immu
table List.");\n' | |
1751 ' }\n' | |
1752 '\n' | |
1753 ' List<$TYPE> getRange(int start, int length) {\n' | |
1754 ' throw new NotImplementedException();\n' | |
1755 ' }\n' | |
1756 '\n' | |
1757 ' bool isEmpty() {\n' | |
1758 ' return length == 0;\n' | |
1759 ' }\n' | |
1760 '\n' | |
1761 ' Iterator<$TYPE> iterator() {\n' | |
1762 ' return new _FixedSizeListIterator<$TYPE>(this);\n' | |
1763 ' }\n', | |
1764 TYPE=element_type) | |
1765 | |
1766 def _HasNativeIndexGetter(self, interface): | |
1767 return ('HasIndexGetter' in interface.ext_attrs or | |
1768 'HasNumericIndexGetter' in interface.ext_attrs) | |
1769 | |
1770 def _EmitNativeIndexGetter(self, interface, element_type): | |
1771 method_name = '_index' | |
1772 self._members_emitter.Emit( | |
1773 '\n' | |
1774 ' $TYPE operator[](int index) { return $METHOD(this, index); }\n' | |
1775 ' static $TYPE $METHOD(var _this, int index) native;\n', | |
1776 TYPE=element_type, METHOD=method_name) | |
1777 | |
1778 def _HasNativeIndexSetter(self, interface): | |
1779 return 'HasCustomIndexSetter' in interface.ext_attrs | |
1780 | |
1781 def _EmitNativeIndexSetter(self, interface, element_type): | |
1782 method_name = '_set_index' | |
1783 self._members_emitter.Emit( | |
1784 '\n' | |
1785 ' void operator[]=(int index, $TYPE value) {\n' | |
1786 ' return $METHOD(this, index, value);\n' | |
1787 ' }\n' | |
1788 ' static $METHOD(_this, index, value) native;\n', | |
1789 TYPE=element_type, METHOD=method_name) | |
1790 | |
1791 def AddOperation(self, info): | |
1792 """ | |
1793 Arguments: | |
1794 info: An OperationInfo object. | |
1795 """ | |
1796 body = self._members_emitter.Emit( | |
1797 '\n' | |
1798 ' $TYPE $NAME($PARAMS) {\n' | |
1799 '$!BODY' | |
1800 ' }\n', | |
1801 TYPE=info.type_name, | |
1802 NAME=info.name, | |
1803 PARAMS=info.ParametersImplementationDeclaration()) | |
1804 | |
1805 # Process in order of ascending number of arguments to ensure missing | |
1806 # optional arguments are processed early. | |
1807 overloads = sorted(info.overloads, | |
1808 key=lambda overload: len(overload.arguments)) | |
1809 self._native_version = 0 | |
1810 fallthrough = self.GenerateDispatch(body, info, ' ', 0, overloads) | |
1811 if fallthrough: | |
1812 body.Emit(' throw "Incorrect number or type of arguments";\n'); | |
1813 | |
1814 def GenerateSingleOperation(self, emitter, info, indent, operation): | |
1815 """Generates a call to a single operation. | |
1816 | |
1817 Arguments: | |
1818 emitter: an Emitter for the body of a block of code. | |
1819 info: the compound information about the operation and its overloads. | |
1820 indent: an indentation string for generated code. | |
1821 operation: the IDLOperation to call. | |
1822 """ | |
1823 # TODO(sra): Do we need to distinguish calling with missing optional | |
1824 # arguments from passing 'null' which is represented as 'undefined'? | |
1825 def UnwrapArgExpression(name, type): | |
1826 # TODO: Type specific unwrapping. | |
1827 return '__dom_unwrap(%s)' % (name) | |
1828 | |
1829 def ArgNameAndUnwrapper(arg_info, overload_arg): | |
1830 (name, type, value) = arg_info | |
1831 return (name, UnwrapArgExpression(name, type)) | |
1832 | |
1833 names_and_unwrappers = [ArgNameAndUnwrapper(info.arg_infos[i], arg) | |
1834 for (i, arg) in enumerate(operation.arguments)] | |
1835 unwrap_args = [unwrap_arg for (_, unwrap_arg) in names_and_unwrappers] | |
1836 arg_names = [name for (name, _) in names_and_unwrappers] | |
1837 | |
1838 self._native_version += 1 | |
1839 native_name = self._MethodName('_', info.name) | |
1840 if self._native_version > 1: | |
1841 native_name = '%s_%s' % (native_name, self._native_version) | |
1842 | |
1843 argument_expressions = ', '.join(['this'] + arg_names) | |
1844 if info.type_name != 'void': | |
1845 emitter.Emit('$(INDENT)return $NATIVENAME($ARGS);\n', | |
1846 INDENT=indent, | |
1847 NATIVENAME=native_name, | |
1848 ARGS=argument_expressions) | |
1849 else: | |
1850 emitter.Emit('$(INDENT)$NATIVENAME($ARGS);\n' | |
1851 '$(INDENT)return;\n', | |
1852 INDENT=indent, | |
1853 NATIVENAME=native_name, | |
1854 ARGS=argument_expressions) | |
1855 | |
1856 self._members_emitter.Emit(' static $TYPE $NAME($PARAMS) native;\n', | |
1857 NAME=native_name, | |
1858 TYPE=info.type_name, | |
1859 PARAMS=', '.join(['receiver'] + arg_names) ) | |
1860 | |
1861 | |
1862 def GenerateDispatch(self, emitter, info, indent, position, overloads): | |
1863 """Generates a dispatch to one of the overloads. | |
1864 | |
1865 Arguments: | |
1866 emitter: an Emitter for the body of a block of code. | |
1867 info: the compound information about the operation and its overloads. | |
1868 indent: an indentation string for generated code. | |
1869 position: the index of the parameter to dispatch on. | |
1870 overloads: a list of the remaining IDLOperations to dispatch. | |
1871 | |
1872 Returns True if the dispatch can fall through on failure, False if the code | |
1873 always dispatches. | |
1874 """ | |
1875 | |
1876 def NullCheck(name): | |
1877 return '%s === null' % name | |
1878 | |
1879 def TypeCheck(name, type): | |
1880 return '%s is %s' % (name, type) | |
1881 | |
1882 if position == len(info.arg_infos): | |
1883 if len(overloads) > 1: | |
1884 raise Exception('Duplicate operations ' + str(overloads)) | |
1885 operation = overloads[0] | |
1886 self.GenerateSingleOperation(emitter, info, indent, operation) | |
1887 return False | |
1888 | |
1889 # FIXME: Consider a simpler dispatch that iterates over the | |
1890 # overloads and generates an overload specific check. Revisit | |
1891 # when we move to named optional arguments. | |
1892 | |
1893 # Partition the overloads to divide and conquer on the dispatch. | |
1894 positive = [] | |
1895 negative = [] | |
1896 first_overload = overloads[0] | |
1897 (param_name, param_type, param_default) = info.arg_infos[position] | |
1898 | |
1899 if position < len(first_overload.arguments): | |
1900 # FIXME: This will not work if the second overload has a more | |
1901 # precise type than the first. E.g., | |
1902 # void foo(Node x); | |
1903 # void foo(Element x); | |
1904 type = first_overload.arguments[position].type.id | |
1905 test = TypeCheck(param_name, type) | |
1906 pred = lambda op: len(op.arguments) > position and op.arguments[position].
type.id == type | |
1907 else: | |
1908 type = None | |
1909 test = NullCheck(param_name) | |
1910 pred = lambda op: position >= len(op.arguments) | |
1911 | |
1912 for overload in overloads: | |
1913 if pred(overload): | |
1914 positive.append(overload) | |
1915 else: | |
1916 negative.append(overload) | |
1917 | |
1918 if positive and negative: | |
1919 (true_code, false_code) = emitter.Emit( | |
1920 '$(INDENT)if ($COND) {\n' | |
1921 '$!TRUE' | |
1922 '$(INDENT)} else {\n' | |
1923 '$!FALSE' | |
1924 '$(INDENT)}\n', | |
1925 COND=test, INDENT=indent) | |
1926 fallthrough1 = self.GenerateDispatch( | |
1927 true_code, info, indent + ' ', position + 1, positive) | |
1928 fallthrough2 = self.GenerateDispatch( | |
1929 false_code, info, indent + ' ', position, negative) | |
1930 return fallthrough1 or fallthrough2 | |
1931 | |
1932 if negative: | |
1933 raise Exception('Internal error, must be all positive') | |
1934 | |
1935 # All overloads require the same test. Do we bother? | |
1936 | |
1937 # If the test is the same as the method's formal parameter then checked mode | |
1938 # will have done the test already. (It could be null too but we ignore that | |
1939 # case since all the overload behave the same and we don't know which types | |
1940 # in the IDL are not nullable.) | |
1941 if type == param_type: | |
1942 return self.GenerateDispatch( | |
1943 emitter, info, indent, position + 1, positive) | |
1944 | |
1945 # Otherwise the overloads have the same type but the type is a substype of | |
1946 # the method's synthesized formal parameter. e.g we have overloads f(X) and | |
1947 # f(Y), implemented by the synthesized method f(Z) where X<Z and Y<Z. The | |
1948 # dispatch has removed f(X), leaving only f(Y), but there is no guarantee | |
1949 # that Y = Z-X, so we need to check for Y. | |
1950 true_code = emitter.Emit( | |
1951 '$(INDENT)if ($COND) {\n' | |
1952 '$!TRUE' | |
1953 '$(INDENT)}\n', | |
1954 COND=test, INDENT=indent) | |
1955 self.GenerateDispatch( | |
1956 true_code, info, indent + ' ', position + 1, positive) | |
1957 return True | |
1958 | |
1959 | |
1960 # ------------------------------------------------------------------------------ | |
1961 | |
1962 class FrogInterfaceGenerator(object): | |
1963 """Generates a Frog class for a DOM IDL interface.""" | |
1964 | |
1965 def __init__(self, system, interface, template, super_interface, dart_code): | |
1966 """Generates Dart code for the given interface. | |
1967 | |
1968 Args: | |
1969 | |
1970 interface: an IDLInterface instance. It is assumed that all types have | |
1971 been converted to Dart types (e.g. int, String), unless they are in | |
1972 the same package as the interface. | |
1973 template: A string template. | |
1974 super_interface: A string or None, the name of the common interface that | |
1975 this interface implements, if any. | |
1976 dart_code: an Emitter for the file containing the Dart implementation | |
1977 class. | |
1978 """ | |
1979 self._system = system | |
1980 self._interface = interface | |
1981 self._template = template | |
1982 self._super_interface = super_interface | |
1983 self._dart_code = dart_code | |
1984 self._current_secondary_parent = None | |
1985 | |
1986 | |
1987 def StartInterface(self): | |
1988 interface = self._interface | |
1989 interface_name = interface.id | |
1990 | |
1991 self._class_name = self._ImplClassName(interface_name) | |
1992 | |
1993 base = None | |
1994 if interface.parents: | |
1995 supertype = interface.parents[0].type.id | |
1996 if _IsDartCollectionType(supertype): | |
1997 # List methods are injected in AddIndexer. | |
1998 pass | |
1999 else: | |
2000 base = self._ImplClassName(supertype) | |
2001 | |
2002 if interface_name in _frog_dom_custom_native_specs: | |
2003 native_spec = _frog_dom_custom_native_specs[interface_name] | |
2004 else: | |
2005 # Make the class 'hidden' so it is dynamically patched at runtime. This | |
2006 # is useful not only for browser compat, but to allow code that links | |
2007 # against dart:dom to load in a worker isolate. | |
2008 native_spec = '*' + interface_name | |
2009 | |
2010 if base: | |
2011 extends = ' extends ' + base | |
2012 elif native_spec[0] == '=': | |
2013 # The implementation is a singleton with no prototype. | |
2014 extends = '' | |
2015 else: | |
2016 extends = ' extends _DOMTypeJs' | |
2017 | |
2018 # TODO: Include all implemented interfaces, including other Lists. | |
2019 implements = [interface_name] | |
2020 element_type = MaybeTypedArrayElementType(self._interface) | |
2021 if element_type: | |
2022 implements.append('List<' + element_type + '>') | |
2023 | |
2024 self._members_emitter = self._dart_code.Emit( | |
2025 self._template, | |
2026 #class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { | |
2027 #$!MEMBERS | |
2028 #} | |
2029 CLASSNAME=self._class_name, | |
2030 EXTENDS=extends, | |
2031 IMPLEMENTS=' implements ' + ', '.join(implements), | |
2032 NATIVESPEC=' native "' + native_spec + '"') | |
2033 | |
2034 element_type = MaybeTypedArrayElementType(interface) | |
2035 if element_type: | |
2036 self.AddTypedArrayConstructors(element_type) | |
2037 | |
2038 | |
2039 def FinishInterface(self): | |
2040 """.""" | |
2041 pass | |
2042 | |
2043 def _ImplClassName(self, type_name): | |
2044 return '_' + type_name + 'Js' | |
2045 | |
2046 def _NarrowToImplementationType(self, type_name): | |
2047 # TODO(sra): Move into the 'system' and cache the result. | |
2048 if type_name == 'EventListener': | |
2049 # Callbacks are typedef functions so don't have a class. | |
2050 return type_name | |
2051 if self._system._database.HasInterface(type_name): | |
2052 interface = self._system._database.GetInterface(type_name) | |
2053 if _RecognizeCallback(interface): | |
2054 # Callbacks are typedef functions so don't have a class. | |
2055 return type_name | |
2056 else: | |
2057 return self._ImplClassName(type_name) | |
2058 return type_name | |
2059 | |
2060 def _NarrowInputType(self, type_name): | |
2061 return self._NarrowToImplementationType(type_name) | |
2062 | |
2063 def _NarrowOutputType(self, type_name): | |
2064 return self._NarrowToImplementationType(type_name) | |
2065 | |
2066 def AddConstant(self, constant): | |
2067 # Since we are currently generating native classes without interfaces, | |
2068 # generate the constants as part of the class. This will need to go away | |
2069 # if we revert back to generating interfaces. | |
2070 self._members_emitter.Emit('\n static final $TYPE $NAME = $VALUE;\n', | |
2071 NAME=constant.id, | |
2072 TYPE=constant.type.id, | |
2073 VALUE=constant.value) | |
2074 | |
2075 pass | |
2076 | |
2077 def AddAttribute(self, getter, setter): | |
2078 output_type = getter and self._NarrowOutputType(getter.type.id) | |
2079 input_type = setter and self._NarrowInputType(setter.type.id) | |
2080 | |
2081 # If the (getter, setter) pair is shadowing, we can't generate a shadowing | |
2082 # field (Issue 1633). | |
2083 (super_getter, super_getter_interface) = self._FindShadowedAttribute(getter) | |
2084 (super_setter, super_setter_interface) = self._FindShadowedAttribute(setter) | |
2085 if super_getter or super_setter: | |
2086 if getter and not setter and super_getter and not super_setter: | |
2087 if getter.type.id == super_getter.type.id: | |
2088 # Compatible getter, use the superclass property. This works because | |
2089 # JavaScript will do its own dynamic dispatch. | |
2090 self._members_emitter.Emit( | |
2091 '\n' | |
2092 ' // Use implementation from $SUPER.\n' | |
2093 ' // final $TYPE $NAME;\n', | |
2094 SUPER=super_getter_interface.id, | |
2095 NAME=getter.id, TYPE=output_type) | |
2096 return | |
2097 | |
2098 self._members_emitter.Emit('\n // Shadowing definition.') | |
2099 self._AddAttributeUsingProperties(getter, setter) | |
2100 return | |
2101 | |
2102 if getter and setter and input_type == output_type: | |
2103 self._members_emitter.Emit( | |
2104 '\n $TYPE $NAME;\n', | |
2105 NAME=getter.id, TYPE=output_type) | |
2106 return | |
2107 if getter and not setter: | |
2108 self._members_emitter.Emit( | |
2109 '\n final $TYPE $NAME;\n', | |
2110 NAME=getter.id, TYPE=output_type) | |
2111 return | |
2112 self._AddAttributeUsingProperties(getter, setter) | |
2113 | |
2114 def _AddAttributeUsingProperties(self, getter, setter): | |
2115 if getter: | |
2116 self._AddGetter(getter) | |
2117 if setter: | |
2118 self._AddSetter(setter) | |
2119 | |
2120 def _AddGetter(self, attr): | |
2121 # TODO(sra): Remove native body when Issue 829 fixed. | |
2122 self._members_emitter.Emit( | |
2123 '\n $TYPE get $NAME() native "return this.$NAME;";\n', | |
2124 NAME=attr.id, TYPE=self._NarrowOutputType(attr.type.id)) | |
2125 | |
2126 def _AddSetter(self, attr): | |
2127 # TODO(sra): Remove native body when Issue 829 fixed. | |
2128 self._members_emitter.Emit( | |
2129 ' void set $NAME($TYPE value) native "this.$NAME = value;";\n', | |
2130 NAME=attr.id, TYPE=self._NarrowInputType(attr.type.id)) | |
2131 | |
2132 def _FindShadowedAttribute(self, attr): | |
2133 """Returns (attribute, superinterface) or (None, None).""" | |
2134 def FindInParent(interface): | |
2135 """Returns matching attribute in parent, or None.""" | |
2136 if interface.parents: | |
2137 parent = interface.parents[0] | |
2138 if _IsDartCollectionType(parent.type.id): | |
2139 return (None, None) | |
2140 if self._system._database.HasInterface(parent.type.id): | |
2141 parent_interface = self._system._database.GetInterface(parent.type.id) | |
2142 attr2 = _FindMatchingAttribute(parent_interface, attr) | |
2143 if attr2: | |
2144 return (attr2, parent_interface) | |
2145 return FindInParent(parent_interface) | |
2146 return (None, None) | |
2147 | |
2148 return FindInParent(self._interface) if attr else (None, None) | |
2149 | |
2150 | |
2151 def AddSecondaryAttribute(self, interface, getter, setter): | |
2152 self._SecondaryContext(interface) | |
2153 self.AddAttribute(getter, setter) | |
2154 | |
2155 def AddSecondaryOperation(self, interface, info): | |
2156 self._SecondaryContext(interface) | |
2157 self.AddOperation(info) | |
2158 | |
2159 def AddEventAttributes(self, event_attrs): | |
2160 pass | |
2161 | |
2162 def _SecondaryContext(self, interface): | |
2163 if interface is not self._current_secondary_parent: | |
2164 self._current_secondary_parent = interface | |
2165 self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id) | |
2166 | |
2167 def AddIndexer(self, element_type): | |
2168 """Adds all the methods required to complete implementation of List.""" | |
2169 # We would like to simply inherit the implementation of everything except | |
2170 # get length(), [], and maybe []=. It is possible to extend from a base | |
2171 # array implementation class only when there is no other implementation | |
2172 # inheritance. There might be no implementation inheritance other than | |
2173 # DOMBaseWrapper for many classes, but there might be some where the | |
2174 # array-ness is introduced by a non-root interface: | |
2175 # | |
2176 # interface Y extends X, List<T> ... | |
2177 # | |
2178 # In the non-root case we have to choose between: | |
2179 # | |
2180 # class YImpl extends XImpl { add List<T> methods; } | |
2181 # | |
2182 # and | |
2183 # | |
2184 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; } | |
2185 # | |
2186 self._members_emitter.Emit( | |
2187 '\n' | |
2188 ' $TYPE operator[](int index) native "return this[index];";\n', | |
2189 TYPE=self._NarrowOutputType(element_type)) | |
2190 | |
2191 if 'HasCustomIndexSetter' in self._interface.ext_attrs: | |
2192 self._members_emitter.Emit( | |
2193 '\n' | |
2194 ' void operator[]=(int index, $TYPE value) native "this[index] = valu
e";\n', | |
2195 TYPE=self._NarrowInputType(element_type)) | |
2196 else: | |
2197 self._members_emitter.Emit( | |
2198 '\n' | |
2199 ' void operator[]=(int index, $TYPE value) {\n' | |
2200 ' throw new UnsupportedOperationException("Cannot assign element of
immutable List.");\n' | |
2201 ' }\n', | |
2202 TYPE=self._NarrowInputType(element_type)) | |
2203 | |
2204 # TODO(sra): Use separate mixins for mutable implementations of List<T>. | |
2205 # TODO(sra): Use separate mixins for typed array implementations of List<T>. | |
2206 template_file = 'immutable_list_mixin.darttemplate' | |
2207 template = self._system._templates.Load(template_file) | |
2208 self._members_emitter.Emit(template, E=element_type) | |
2209 | |
2210 | |
2211 def AddTypedArrayConstructors(self, element_type): | |
2212 self._members_emitter.Emit( | |
2213 '\n' | |
2214 ' factory $CTOR(int length) => _construct_$CTOR(length);\n' | |
2215 '\n' | |
2216 ' factory $CTOR.fromList(List<$TYPE> list) => _construct_$CTOR(list);\n
' | |
2217 '\n' | |
2218 ' factory $CTOR.fromBuffer(ArrayBuffer buffer) => _construct_$CTOR(buff
er);\n' | |
2219 '\n' | |
2220 ' static _construct_$CTOR(arg) native \'return new $CTOR(arg);\';\n', | |
2221 CTOR=self._interface.id, | |
2222 TYPE=element_type) | |
2223 | |
2224 | |
2225 def AddOperation(self, info): | |
2226 """ | |
2227 Arguments: | |
2228 info: An OperationInfo object. | |
2229 """ | |
2230 # TODO(vsm): Handle overloads. | |
2231 self._members_emitter.Emit( | |
2232 '\n' | |
2233 ' $TYPE $NAME($PARAMS) native;\n', | |
2234 TYPE=self._NarrowOutputType(info.type_name), | |
2235 NAME=info.name, | |
2236 PARAMS=info.ParametersImplementationDeclaration( | |
2237 lambda type_name: self._NarrowInputType(type_name))) | |
2238 | |
2239 | |
2240 # ------------------------------------------------------------------------------ | |
2241 | |
2242 # TODO(jmesserly): inheritance is probably not the right way to factor this long | |
2243 # term, but it makes merging better for now. | |
2244 class HtmlFrogInterfaceGenerator(FrogInterfaceGenerator): | |
2245 """Generates a Frog class for the dart:html library from a DOM IDL | |
2246 interface. | |
2247 """ | |
2248 | |
2249 def __init__(self, system, interface, template, super_interface, dart_code): | |
2250 super(HtmlFrogInterfaceGenerator, self).__init__( | |
2251 system, interface, template, super_interface, dart_code) | |
2252 | |
2253 def AddEventAttributes(self, event_attrs): | |
2254 events_class = self._interface.id + 'EventsImpl' | |
2255 events_interface = self._interface.id + 'Events' | |
2256 self._members_emitter.Emit('\n $TYPE get on() =>\n new $TYPE(this);\n', | |
2257 TYPE=events_class) | |
2258 | |
2259 events_members = self._dart_code.Emit( | |
2260 '\n' | |
2261 'class $CLASSNAME extends EventsImplementation ' | |
2262 'implements $INTERFACE {\n' | |
2263 ' $CLASSNAME(_ptr) : super._wrap(_ptr);\n' | |
2264 '$!MEMBERS}\n', | |
2265 CLASSNAME=events_class, | |
2266 INTERFACE=events_interface) | |
2267 | |
2268 for getter, setter in event_attrs: | |
2269 event = getter or setter | |
2270 events_members.Emit( | |
2271 "\n" | |
2272 "EventListenerList get $NAME() => _get('$NAME');\n", | |
2273 NAME=event.id) | |
2274 | |
2275 | |
2276 # ------------------------------------------------------------------------------ | |
2277 | |
2278 class NativeImplementationSystem(System): | 695 class NativeImplementationSystem(System): |
2279 | 696 |
2280 def __init__(self, templates, database, emitters, auxiliary_dir, output_dir): | 697 def __init__(self, templates, database, emitters, auxiliary_dir, output_dir): |
2281 super(NativeImplementationSystem, self).__init__( | 698 super(NativeImplementationSystem, self).__init__( |
2282 templates, database, emitters, output_dir) | 699 templates, database, emitters, output_dir) |
2283 | 700 |
2284 self._auxiliary_dir = auxiliary_dir | 701 self._auxiliary_dir = auxiliary_dir |
2285 self._dom_public_files = [] | 702 self._dom_public_files = [] |
2286 self._dom_impl_files = [] | 703 self._dom_impl_files = [] |
2287 self._cpp_header_files = [] | 704 self._cpp_header_files = [] |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2538 INDENT=indent, | 955 INDENT=indent, |
2539 NATIVENAME=native_name, | 956 NATIVENAME=native_name, |
2540 ARGS=argument_expressions) | 957 ARGS=argument_expressions) |
2541 | 958 |
2542 self._members_emitter.Emit(' $TYPE $NATIVE_NAME($PARAMS) native ' | 959 self._members_emitter.Emit(' $TYPE $NATIVE_NAME($PARAMS) native ' |
2543 '"$(INTERFACE)$(NATIVE_NAME)_Callback";\n', | 960 '"$(INTERFACE)$(NATIVE_NAME)_Callback";\n', |
2544 NATIVE_NAME=native_name, | 961 NATIVE_NAME=native_name, |
2545 TYPE=info.type_name, | 962 TYPE=info.type_name, |
2546 PARAMS=', '.join(arg_names), | 963 PARAMS=', '.join(arg_names), |
2547 INTERFACE=self._interface.id) | 964 INTERFACE=self._interface.id) |
OLD | NEW |